Skip to content

Commit f42f5de

Browse files
committed
wip model: Add TypingNotifier.
Signed-off-by: Zixuan James Li <[email protected]>
1 parent 8876096 commit f42f5de

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

lib/model/store.dart

+7
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ class PerAccountStore extends ChangeNotifier with ChannelStore, MessageStore {
249249
selfUserId: account.userId,
250250
typingStartedExpiryPeriod: Duration(milliseconds: initialSnapshot.serverTypingStartedExpiryPeriodMilliseconds),
251251
),
252+
typingNotifier: TypingNotifier(
253+
typingStoppedWaitPeriod: Duration(milliseconds: initialSnapshot.serverTypingStoppedWaitPeriodMilliseconds),
254+
typingStartedWaitPeriod: Duration(milliseconds: initialSnapshot.serverTypingStartedWaitPeriodMilliseconds),
255+
),
252256
channels: channels,
253257
messages: MessageStoreImpl(),
254258
unreads: Unreads(
@@ -276,6 +280,7 @@ class PerAccountStore extends ChangeNotifier with ChannelStore, MessageStore {
276280
required this.userSettings,
277281
required this.users,
278282
required this.typingStatus,
283+
required this.typingNotifier,
279284
required ChannelStoreImpl channels,
280285
required MessageStoreImpl messages,
281286
required this.unreads,
@@ -342,6 +347,7 @@ class PerAccountStore extends ChangeNotifier with ChannelStore, MessageStore {
342347
final Map<int, User> users;
343348

344349
final TypingStatus typingStatus;
350+
final TypingNotifier typingNotifier;
345351

346352
////////////////////////////////
347353
// Streams, topics, and stuff about them.
@@ -410,6 +416,7 @@ class PerAccountStore extends ChangeNotifier with ChannelStore, MessageStore {
410416
unreads.dispose();
411417
_messages.dispose();
412418
typingStatus.dispose();
419+
typingNotifier.dispose();
413420
super.dispose();
414421
}
415422

lib/model/typing_status.dart

+74
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import 'dart:async';
22

33
import 'package:flutter/foundation.dart';
4+
import 'package:flutter/widgets.dart';
45

56
import '../api/model/events.dart';
7+
import '../api/route/messages.dart';
8+
import '../api/route/typing.dart';
69
import '../log.dart';
710
import 'narrow.dart';
11+
import 'store.dart';
812

913
/// The model for tracking the typing status organized by narrows.
1014
///
@@ -85,3 +89,73 @@ class TypingStatus extends ChangeNotifier {
8589
}
8690
}
8791
}
92+
93+
class TypingNotifier {
94+
TypingNotifier({
95+
required this.typingStoppedWaitPeriod,
96+
required this.typingStartedWaitPeriod,
97+
});
98+
99+
final Duration typingStoppedWaitPeriod;
100+
final Duration typingStartedWaitPeriod;
101+
102+
MessageDestination? _currentDestination;
103+
DateTime? _nextStartTime;
104+
Timer? _stopTimer;
105+
106+
void dispose() {
107+
_stopTimer?.cancel();
108+
}
109+
110+
void handleTypingStop(PerAccountStore store, MessageDestination destination) {
111+
if (destination != _currentDestination) return;
112+
113+
_notifyStop(store);
114+
}
115+
116+
void handleTyping(PerAccountStore store, MessageDestination destination) {
117+
// Two cases.
118+
// Renew a previous typing status,
119+
// or start a new typing status
120+
if (destination == _currentDestination) {
121+
_maybeNotifyStart(store);
122+
return;
123+
}
124+
125+
_nextStartTime = null;
126+
// Start new typing status
127+
_currentDestination = destination;
128+
_notifyStart(store);
129+
}
130+
131+
Future<void> _maybeNotifyStart(PerAccountStore store) async {
132+
if (_nextStartTime == null || DateTime.now().isAfter(_nextStartTime!)) {
133+
await _notifyStart(store);
134+
}
135+
}
136+
137+
Future<void> _notifyStart(PerAccountStore store) async {
138+
_nextStartTime = DateTime.now().add(typingStartedWaitPeriod);
139+
_startOrExtendIdleTimer(store);
140+
assert(debugLog('[$_currentDestination] notify start'));
141+
await setTypingStatus(store.connection,
142+
op: TypingOp.start,
143+
destination: _currentDestination!,
144+
);
145+
}
146+
147+
Future<void> _notifyStop(PerAccountStore store) async {
148+
assert(debugLog('[$_currentDestination] notify stop'));
149+
_stopTimer?.cancel();
150+
await setTypingStatus(store.connection,
151+
op: TypingOp.stop,
152+
destination: _currentDestination!,
153+
);
154+
_currentDestination = null;
155+
}
156+
157+
void _startOrExtendIdleTimer(PerAccountStore store) {
158+
_stopTimer?.cancel();
159+
_stopTimer = Timer(typingStoppedWaitPeriod, () => _notifyStop(store));
160+
}
161+
}

0 commit comments

Comments
 (0)