add connection state management to ChatStore and update UI feedback in chat
This commit is contained in:
parent
d296a20aef
commit
c378b9b2fd
4 changed files with 76 additions and 18 deletions
|
|
@ -241,6 +241,15 @@ abstract class ChatStoreBase with Store {
|
|||
@readonly
|
||||
var _isWaitingForAck = false;
|
||||
|
||||
/// Whether the chat WebSocket is currently connected.
|
||||
@readonly
|
||||
var _isConnected = false;
|
||||
|
||||
/// Whether we've successfully connected at least once (to distinguish
|
||||
/// "connecting" from "disconnected" in the UI).
|
||||
@readonly
|
||||
var _hasConnected = false;
|
||||
|
||||
/// The logged-in user's appearance in chat.
|
||||
@readonly
|
||||
var _userState = const USERSTATE();
|
||||
|
|
@ -251,12 +260,6 @@ abstract class ChatStoreBase with Store {
|
|||
@observable
|
||||
IRCMessage? replyingToMessage;
|
||||
|
||||
/// Public getter for whether the chat is in shared chat mode.
|
||||
bool get isInSharedChatMode => _isInSharedChatMode;
|
||||
|
||||
/// Public getter for whether we're waiting for message acknowledgment.
|
||||
bool get isWaitingForAck => _isWaitingForAck;
|
||||
|
||||
/// Emotes matching the current autocomplete search term.
|
||||
@computed
|
||||
List<Emote> get matchingEmotes {
|
||||
|
|
@ -637,6 +640,10 @@ abstract class ChatStoreBase with Store {
|
|||
// Reset exponential backoff if successfully connected.
|
||||
_retries = 0;
|
||||
_backoffTime = 0;
|
||||
|
||||
// Mark connection as established for UI
|
||||
_isConnected = true;
|
||||
_hasConnected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -839,6 +846,9 @@ abstract class ChatStoreBase with Store {
|
|||
// Invalidate the current connection to cancel pending delayed callbacks
|
||||
currentConnectionId = 0;
|
||||
|
||||
// Mark connection as disconnected for UI
|
||||
_isConnected = false;
|
||||
|
||||
// Cancel chat delay countdown when disconnecting
|
||||
_cancelChatDelayCountdown();
|
||||
_chatDelaySyncCompleted = false;
|
||||
|
|
|
|||
|
|
@ -247,6 +247,46 @@ mixin _$ChatStore on ChatStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
late final _$_isConnectedAtom = Atom(
|
||||
name: 'ChatStoreBase._isConnected',
|
||||
context: context,
|
||||
);
|
||||
|
||||
bool get isConnected {
|
||||
_$_isConnectedAtom.reportRead();
|
||||
return super._isConnected;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get _isConnected => isConnected;
|
||||
|
||||
@override
|
||||
set _isConnected(bool value) {
|
||||
_$_isConnectedAtom.reportWrite(value, super._isConnected, () {
|
||||
super._isConnected = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$_hasConnectedAtom = Atom(
|
||||
name: 'ChatStoreBase._hasConnected',
|
||||
context: context,
|
||||
);
|
||||
|
||||
bool get hasConnected {
|
||||
_$_hasConnectedAtom.reportRead();
|
||||
return super._hasConnected;
|
||||
}
|
||||
|
||||
@override
|
||||
bool get _hasConnected => hasConnected;
|
||||
|
||||
@override
|
||||
set _hasConnected(bool value) {
|
||||
_$_hasConnectedAtom.reportWrite(value, super._hasConnected, () {
|
||||
super._hasConnected = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$_userStateAtom = Atom(
|
||||
name: 'ChatStoreBase._userState',
|
||||
context: context,
|
||||
|
|
|
|||
|
|
@ -245,7 +245,10 @@ class ChatBottomBar extends StatelessWidget {
|
|||
builder: (context) {
|
||||
final isLoggedIn = chatStore.auth.isLoggedIn;
|
||||
final isWaitingForAck = chatStore.isWaitingForAck;
|
||||
final isEnabled = isLoggedIn && !isWaitingForAck;
|
||||
final isConnected = chatStore.isConnected;
|
||||
final hasConnected = chatStore.hasConnected;
|
||||
final isEnabled =
|
||||
isLoggedIn && !isWaitingForAck && isConnected;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: !isLoggedIn
|
||||
|
|
@ -285,15 +288,19 @@ class ChatBottomBar extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
hintMaxLines: 1,
|
||||
hintText: isLoggedIn
|
||||
? isWaitingForAck
|
||||
? 'Sending...'
|
||||
: chatStore.replyingToMessage != null
|
||||
? 'Reply'
|
||||
: hasChatDelay
|
||||
? 'Chat (${chatStore.settings.chatDelay.toInt()}s delay)'
|
||||
: 'Chat'
|
||||
: loginTooltipMessage,
|
||||
hintText: !isLoggedIn
|
||||
? loginTooltipMessage
|
||||
: !isConnected
|
||||
? (hasConnected
|
||||
? 'Chat disconnected'
|
||||
: 'Connecting...')
|
||||
: isWaitingForAck
|
||||
? 'Sending...'
|
||||
: chatStore.replyingToMessage != null
|
||||
? 'Reply'
|
||||
: hasChatDelay
|
||||
? 'Chat (${chatStore.settings.chatDelay.toInt()}s delay)'
|
||||
: 'Chat',
|
||||
),
|
||||
controller: chatStore.textController,
|
||||
onSubmitted: chatStore.sendMessage,
|
||||
|
|
@ -326,7 +333,8 @@ class ChatBottomBar extends StatelessWidget {
|
|||
: const Icon(Icons.send_rounded),
|
||||
onPressed:
|
||||
chatStore.auth.isLoggedIn &&
|
||||
!chatStore.isWaitingForAck
|
||||
!chatStore.isWaitingForAck &&
|
||||
chatStore.isConnected
|
||||
? () => chatStore.sendMessage(
|
||||
chatStore.textController.text,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ abstract class _SettingsStoreBase with Store {
|
|||
|
||||
@JsonKey(defaultValue: defaultShowUserNotices)
|
||||
@observable
|
||||
var showUserNotices = defaultHighlightFirstTimeChatter;
|
||||
var showUserNotices = defaultShowUserNotices;
|
||||
|
||||
// Layout options
|
||||
@JsonKey(defaultValue: defaultEmoteMenuButtonOnLeft)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue