fix autocomplete bar blocking bottom of chat

This commit is contained in:
Tommy Chow 2026-01-04 20:36:53 -05:00
parent bd194e91c2
commit 4a9678bb15
4 changed files with 79 additions and 29 deletions

View file

@ -58,7 +58,7 @@ class Chat extends StatelessWidget {
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom:
68 +
chatStore.bottomBarHeight +
(chatStore.assetsStore.showEmoteMenu
? 0
: MediaQuery.of(context).padding.bottom),
@ -70,7 +70,7 @@ class Chat extends StatelessWidget {
padding: (listPadding ?? EdgeInsets.zero).add(
EdgeInsets.only(
bottom:
68 +
chatStore.bottomBarHeight +
(chatStore.assetsStore.showEmoteMenu
? 0
: MediaQuery.of(
@ -126,7 +126,7 @@ class Chat extends StatelessWidget {
top: 4,
right: 4,
bottom:
68 +
chatStore.bottomBarHeight +
(chatStore.assetsStore.showEmoteMenu
? 0
: MediaQuery.of(context).padding.bottom),

View file

@ -36,6 +36,12 @@ abstract class ChatStoreBase with Store {
'ROOMSTATE',
};
/// Base height of the bottom bar (input field area).
static const _baseBottomBarHeight = 68.0;
/// Height of the autocomplete bar (SizedBox + Divider).
static const _autocompleteHeight = 51.0;
/// Checks if IRC data contains a command that should bypass the chat delay.
/// Returns true if any message in the data contains a bypass command.
bool _shouldBypassDelay(String data) {
@ -203,6 +209,47 @@ abstract class ChatStoreBase with Store {
/// Public getter for whether the chat is in shared chat mode.
bool get isInSharedChatMode => _isInSharedChatMode;
/// Emotes matching the current autocomplete search term.
@computed
List<Emote> get matchingEmotes {
if (!_showEmoteAutocomplete) return const [];
final searchTerm = _inputText.split(' ').last.toLowerCase();
if (searchTerm.isEmpty) return const [];
return [
...assetsStore.userEmoteToObject.values,
...assetsStore.bttvEmotes,
...assetsStore.ffzEmotes,
...assetsStore.sevenTVEmotes,
].where((emote) => emote.name.toLowerCase().contains(searchTerm)).toList();
}
/// Chatters matching the current mention autocomplete search term.
@computed
List<String> get matchingChatters {
if (!_showMentionAutocomplete) return const [];
final searchTerm =
_inputText.split(' ').last.replaceFirst('@', '').toLowerCase();
return chatDetailsStore.chatUsers
.where((chatter) => chatter.contains(searchTerm))
.toList();
}
/// Current bottom bar height based on visible overlays.
/// Used to dynamically adjust chat message list padding.
@computed
double get bottomBarHeight {
var height = _baseBottomBarHeight;
if (settings.autocomplete &&
((_showEmoteAutocomplete && matchingEmotes.isNotEmpty) ||
(_showMentionAutocomplete && matchingChatters.isNotEmpty))) {
height += _autocompleteHeight;
}
return height;
}
ChatStoreBase({
required this.twitchApi,
required this.auth,

View file

@ -17,6 +17,29 @@ mixin _$ChatStore on ChatStoreBase, Store {
() => super.renderMessages,
name: 'ChatStoreBase.renderMessages',
)).value;
Computed<List<Emote>>? _$matchingEmotesComputed;
@override
List<Emote> get matchingEmotes =>
(_$matchingEmotesComputed ??= Computed<List<Emote>>(
() => super.matchingEmotes,
name: 'ChatStoreBase.matchingEmotes',
)).value;
Computed<List<String>>? _$matchingChattersComputed;
@override
List<String> get matchingChatters =>
(_$matchingChattersComputed ??= Computed<List<String>>(
() => super.matchingChatters,
name: 'ChatStoreBase.matchingChatters',
)).value;
Computed<double>? _$bottomBarHeightComputed;
@override
double get bottomBarHeight => (_$bottomBarHeightComputed ??= Computed<double>(
() => super.bottomBarHeight,
name: 'ChatStoreBase.bottomBarHeight',
)).value;
late final _$timeRemainingAtom = Atom(
name: 'ChatStoreBase.timeRemaining',
@ -489,7 +512,10 @@ mixin _$ChatStore on ChatStoreBase, Store {
timeRemaining: ${timeRemaining},
expandChat: ${expandChat},
replyingToMessage: ${replyingToMessage},
renderMessages: ${renderMessages}
renderMessages: ${renderMessages},
matchingEmotes: ${matchingEmotes},
matchingChatters: ${matchingChatters},
bottomBarHeight: ${bottomBarHeight}
''';
}
}

View file

@ -57,31 +57,8 @@ class ChatBottomBar extends StatelessWidget {
return Observer(
builder: (context) {
final matchingEmotes =
[
...chatStore.assetsStore.userEmoteToObject.values,
...chatStore.assetsStore.bttvEmotes,
...chatStore.assetsStore.ffzEmotes,
...chatStore.assetsStore.sevenTVEmotes,
]
.where(
(emote) => emote.name.toLowerCase().contains(
chatStore.inputText.split(' ').last.toLowerCase(),
),
)
.toList();
final matchingChatters = chatStore.chatDetailsStore.chatUsers
.where(
(chatter) => chatter.contains(
chatStore.inputText
.split(' ')
.last
.replaceFirst('@', '')
.toLowerCase(),
),
)
.toList();
final matchingEmotes = chatStore.matchingEmotes;
final matchingChatters = chatStore.matchingChatters;
final isFullscreenOverlay =
chatStore.settings.fullScreen && context.isLandscape;