Enable zero width emotes by default
This commit is contained in:
parent
772055de4e
commit
d5e8d0c6c5
5 changed files with 104 additions and 169 deletions
|
|
@ -114,7 +114,6 @@ class IRCMessage {
|
|||
required bool launchExternal,
|
||||
required void Function()? onLongPressName,
|
||||
bool showMessage = true,
|
||||
bool useZeroWidth = false,
|
||||
bool useReadableColors = false,
|
||||
TimestampType timestamp = TimestampType.disabled,
|
||||
}) {
|
||||
|
|
@ -311,161 +310,138 @@ class IRCMessage {
|
|||
|
||||
// Add the message and any emotes to the span.
|
||||
if (words != null) {
|
||||
if (useZeroWidth) {
|
||||
// Keep a local span which will be reversed and added to the final span.
|
||||
final localSpan = <InlineSpan>[];
|
||||
// Keep a local span which will be reversed and added to the final span.
|
||||
final localSpan = <InlineSpan>[];
|
||||
|
||||
// Iterate through the words in reverse-order.
|
||||
// Index starts at the last word in the message.
|
||||
var index = words.length - 1;
|
||||
// Iterate through the words in reverse-order.
|
||||
// Index starts at the last word in the message.
|
||||
var index = words.length - 1;
|
||||
|
||||
// Terminate after the first word in the message reached.
|
||||
while (index != -1) {
|
||||
// Check if current word is a valid emote.
|
||||
final word = words[index];
|
||||
final emote = emoteToObject[word] ?? localEmotes?[word];
|
||||
// Terminate after the first word in the message reached.
|
||||
while (index != -1) {
|
||||
// Check if current word is a valid emote.
|
||||
final word = words[index];
|
||||
final emote = emoteToObject[word] ?? localEmotes?[word];
|
||||
|
||||
if (emote != null) {
|
||||
// If the emote is zero-width and not the first word, process the stack.
|
||||
if (emote.zeroWidth && index != 0) {
|
||||
final emoteStack = <Emote>[];
|
||||
if (emote != null) {
|
||||
// If the emote is zero-width and not the first word, process the stack.
|
||||
if (emote.zeroWidth && index != 0) {
|
||||
final emoteStack = <Emote>[];
|
||||
|
||||
// Handle stacking consecutive zero-width emotes.
|
||||
Emote? nextEmote = emote;
|
||||
while (nextEmote != null && nextEmote.zeroWidth && index != 0) {
|
||||
emoteStack.add(nextEmote);
|
||||
index--;
|
||||
nextEmote = emoteToObject[words[index]] ?? localEmotes?[words[index]];
|
||||
}
|
||||
// Handle stacking consecutive zero-width emotes.
|
||||
Emote? nextEmote = emote;
|
||||
while (nextEmote != null && nextEmote.zeroWidth && index != 0) {
|
||||
emoteStack.add(nextEmote);
|
||||
index--;
|
||||
nextEmote = emoteToObject[words[index]] ?? localEmotes?[words[index]];
|
||||
}
|
||||
|
||||
// If there's one more emote thats NOT zero-width, add it to the base of the stack.
|
||||
if (nextEmote != null) emoteStack.add(nextEmote);
|
||||
// If there's one more emote thats NOT zero-width, add it to the base of the stack.
|
||||
if (nextEmote != null) emoteStack.add(nextEmote);
|
||||
|
||||
// Check if the next word is an emoji to be added to the stack.
|
||||
final nextWordIsEmoji = regexEmoji.hasMatch(words[index]);
|
||||
// Check if the next word is an emoji to be added to the stack.
|
||||
final nextWordIsEmoji = regexEmoji.hasMatch(words[index]);
|
||||
|
||||
// Create the stack of emotes with the base emoji if there is one.
|
||||
// Will be used as the children of the Stack widget.
|
||||
final children = [
|
||||
if (nextWordIsEmoji)
|
||||
Text(
|
||||
words[index],
|
||||
style: textStyle?.copyWith(fontSize: emoteSize - 5),
|
||||
),
|
||||
...emoteStack.reversed.map(
|
||||
(emote) => CachedNetworkImage(
|
||||
imageUrl: emote.url,
|
||||
fadeInDuration: const Duration(),
|
||||
height: emote.height != null ? emote.height! * emoteScale : emoteSize,
|
||||
width: emote.width != null ? emote.width! * emoteScale : emoteSize,
|
||||
),
|
||||
)
|
||||
];
|
||||
// Create the stack of emotes with the base emoji if there is one.
|
||||
// Will be used as the children of the Stack widget.
|
||||
final children = [
|
||||
if (nextWordIsEmoji)
|
||||
Text(
|
||||
words[index],
|
||||
style: textStyle?.copyWith(fontSize: emoteSize - 5),
|
||||
),
|
||||
...emoteStack.reversed.map(
|
||||
(emote) => CachedNetworkImage(
|
||||
imageUrl: emote.url,
|
||||
fadeInDuration: const Duration(),
|
||||
height: emote.height != null ? emote.height! * emoteScale : emoteSize,
|
||||
width: emote.width != null ? emote.width! * emoteScale : emoteSize,
|
||||
),
|
||||
)
|
||||
];
|
||||
|
||||
// Create the message for the tooltip
|
||||
final message = emoteStack.reversed.map((emote) => '${emote.name} - ${emoteType[emote.type.index]}');
|
||||
localSpan.add(
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Tooltip(
|
||||
richMessage: WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
if (nextWordIsEmoji)
|
||||
Text(
|
||||
words[index],
|
||||
style: textStyle?.copyWith(fontSize: 75),
|
||||
),
|
||||
...emoteStack.reversed.map(
|
||||
(emote) => CachedNetworkImage(
|
||||
imageUrl: emote.url,
|
||||
fadeInDuration: const Duration(),
|
||||
height: 80,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5.0),
|
||||
Column(
|
||||
children: [
|
||||
// Create the message for the tooltip
|
||||
final message = emoteStack.reversed.map((emote) => '${emote.name} - ${emoteType[emote.type.index]}');
|
||||
localSpan.add(
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Tooltip(
|
||||
richMessage: WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
if (nextWordIsEmoji)
|
||||
Text(
|
||||
nextWordIsEmoji ? '${words[index]} - Emoji' : '${emoteStack.last.name} - ${emoteType[emoteStack.last.type.index]}',
|
||||
style: const TextStyle(color: Colors.black),
|
||||
words[index],
|
||||
style: textStyle?.copyWith(fontSize: 75),
|
||||
),
|
||||
Text(
|
||||
nextWordIsEmoji ? message.join(', ') : message.skip(1).join(', '),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
...emoteStack.reversed.map(
|
||||
(emote) => CachedNetworkImage(
|
||||
imageUrl: emote.url,
|
||||
fadeInDuration: const Duration(),
|
||||
height: 80,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5.0),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
nextWordIsEmoji ? '${words[index]} - Emoji' : '${emoteStack.last.name} - ${emoteType[emoteStack.last.type.index]}',
|
||||
style: const TextStyle(color: Colors.black),
|
||||
),
|
||||
Text(
|
||||
nextWordIsEmoji ? message.join(', ') : message.skip(1).join(', '),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
preferBelow: false,
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
preferBelow: false,
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
|
||||
// If the next word is neither an emote or emoji, add it as a text span.
|
||||
if (nextEmote == null && !nextWordIsEmoji) {
|
||||
localSpan.add(const TextSpan(text: ' '));
|
||||
localSpan.add(_createTextSpan(text: words[index], style: textStyle, launchExternal: launchExternal));
|
||||
}
|
||||
} else {
|
||||
localSpan.add(
|
||||
_createEmoteSpan(
|
||||
emote: emote,
|
||||
height: emote.height != null ? emote.height! * emoteScale : emoteSize,
|
||||
width: emote.width != null ? emote.width! * emoteScale : null,
|
||||
),
|
||||
);
|
||||
// If the next word is neither an emote or emoji, add it as a text span.
|
||||
if (nextEmote == null && !nextWordIsEmoji) {
|
||||
localSpan.add(const TextSpan(text: ' '));
|
||||
localSpan.add(_createTextSpan(text: words[index], style: textStyle, launchExternal: launchExternal));
|
||||
}
|
||||
} else {
|
||||
if (regexEmoji.hasMatch(word)) {
|
||||
localSpan.add(_createEmojiSpan(emoji: word, style: textStyle?.copyWith(fontSize: emoteSize - 5)));
|
||||
} else {
|
||||
localSpan.add(_createTextSpan(text: word, style: textStyle, launchExternal: launchExternal));
|
||||
}
|
||||
}
|
||||
localSpan.add(const TextSpan(text: ' '));
|
||||
index--;
|
||||
}
|
||||
|
||||
// Add the the local span reversed to the final span.
|
||||
span.addAll(localSpan.reversed);
|
||||
} else {
|
||||
// Iterate through the words and add to the span based on word, emote, and emoji.
|
||||
for (final word in words) {
|
||||
span.add(const TextSpan(text: ' '));
|
||||
|
||||
final emote = emoteToObject[word] ?? localEmotes?[word];
|
||||
if (emote != null) {
|
||||
span.add(
|
||||
localSpan.add(
|
||||
_createEmoteSpan(
|
||||
emote: emote,
|
||||
height: emote.height != null ? emote.height! * emoteScale : emoteSize,
|
||||
width: emote.width != null ? emote.width! * emoteScale : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (regexEmoji.hasMatch(word)) {
|
||||
localSpan.add(_createEmojiSpan(emoji: word, style: textStyle?.copyWith(fontSize: emoteSize - 5)));
|
||||
} else {
|
||||
if (regexEmoji.hasMatch(word)) {
|
||||
span.add(_createEmojiSpan(emoji: word, style: textStyle?.copyWith(fontSize: emoteSize - 5)));
|
||||
} else {
|
||||
span.add(_createTextSpan(text: word, style: textStyle, launchExternal: launchExternal));
|
||||
}
|
||||
localSpan.add(_createTextSpan(text: word, style: textStyle, launchExternal: launchExternal));
|
||||
}
|
||||
}
|
||||
|
||||
localSpan.add(const TextSpan(text: ' '));
|
||||
index--;
|
||||
}
|
||||
|
||||
// Add the the local span reversed to the final span.
|
||||
span.addAll(localSpan.reversed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ class ChatMessage extends StatelessWidget {
|
|||
assetsStore: chatStore.assetsStore,
|
||||
emoteScale: chatStore.settings.emoteScale,
|
||||
badgeScale: chatStore.settings.badgeScale,
|
||||
useZeroWidth: chatStore.settings.showZeroWidth,
|
||||
useReadableColors: chatStore.settings.useReadableColors,
|
||||
isLightTheme: Theme.of(context).brightness == Brightness.light,
|
||||
launchExternal: chatStore.settings.launchUrlExternal,
|
||||
|
|
@ -167,7 +166,6 @@ class ChatMessage extends StatelessWidget {
|
|||
emoteScale: chatStore.settings.emoteScale,
|
||||
badgeScale: chatStore.settings.badgeScale,
|
||||
showMessage: chatStore.settings.showDeletedMessages,
|
||||
useZeroWidth: chatStore.settings.showZeroWidth,
|
||||
useReadableColors: chatStore.settings.useReadableColors,
|
||||
isLightTheme: Theme.of(context).brightness == Brightness.light,
|
||||
launchExternal: chatStore.settings.launchUrlExternal,
|
||||
|
|
@ -221,7 +219,6 @@ class ChatMessage extends StatelessWidget {
|
|||
assetsStore: chatStore.assetsStore,
|
||||
emoteScale: chatStore.settings.emoteScale,
|
||||
badgeScale: chatStore.settings.badgeScale,
|
||||
useZeroWidth: chatStore.settings.showZeroWidth,
|
||||
useReadableColors: chatStore.settings.useReadableColors,
|
||||
isLightTheme: Theme.of(context).brightness == Brightness.light,
|
||||
launchExternal: chatStore.settings.launchUrlExternal,
|
||||
|
|
|
|||
|
|
@ -169,18 +169,6 @@ class _ChatSettingsState extends State<ChatSettings> {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SectionHeader(
|
||||
'Emotes',
|
||||
padding: sectionPadding,
|
||||
showDivider: true,
|
||||
),
|
||||
SwitchListTile.adaptive(
|
||||
isThreeLine: true,
|
||||
title: const Text('Zero-width emotes'),
|
||||
subtitle: const Text('Shows "stacked" emotes from BetterTTV and 7TV.'),
|
||||
value: settingsStore.showZeroWidth,
|
||||
onChanged: (newValue) => settingsStore.showZeroWidth = newValue,
|
||||
),
|
||||
const SectionHeader(
|
||||
'Message Appearance',
|
||||
padding: sectionPadding,
|
||||
|
|
|
|||
|
|
@ -97,8 +97,6 @@ abstract class _SettingsStoreBase with Store {
|
|||
static const defaultChatWidth = 0.3;
|
||||
static const defaultFullScreenChatOverlayOpacity = 0.5;
|
||||
|
||||
static const defaultShowZeroWidth = false;
|
||||
|
||||
static const defaultUseReadableColors = true;
|
||||
static const defaultShowDeletedMessages = false;
|
||||
static const defaultShowChatMessageDividers = false;
|
||||
|
|
@ -153,10 +151,6 @@ abstract class _SettingsStoreBase with Store {
|
|||
@observable
|
||||
var fullScreenChatOverlayOpacity = defaultFullScreenChatOverlayOpacity;
|
||||
|
||||
@JsonKey(defaultValue: defaultShowZeroWidth)
|
||||
@observable
|
||||
var showZeroWidth = defaultShowZeroWidth;
|
||||
|
||||
@JsonKey(defaultValue: defaultUseReadableColors)
|
||||
@observable
|
||||
var useReadableColors = defaultUseReadableColors;
|
||||
|
|
@ -213,7 +207,6 @@ abstract class _SettingsStoreBase with Store {
|
|||
landscapeCutout = defaultLandscapeCutout;
|
||||
chatWidth = defaultChatWidth;
|
||||
fullScreenChatOverlayOpacity = defaultFullScreenChatOverlayOpacity;
|
||||
showZeroWidth = defaultShowZeroWidth;
|
||||
useReadableColors = defaultUseReadableColors;
|
||||
showDeletedMessages = defaultShowDeletedMessages;
|
||||
showChatMessageDividers = defaultShowChatMessageDividers;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ SettingsStore _$SettingsStoreFromJson(Map<String, dynamic> json) =>
|
|||
..chatWidth = (json['chatWidth'] as num?)?.toDouble() ?? 0.3
|
||||
..fullScreenChatOverlayOpacity =
|
||||
(json['fullScreenChatOverlayOpacity'] as num?)?.toDouble() ?? 0.5
|
||||
..showZeroWidth = json['showZeroWidth'] as bool? ?? false
|
||||
..useReadableColors = json['useReadableColors'] as bool? ?? true
|
||||
..showDeletedMessages = json['showDeletedMessages'] as bool? ?? false
|
||||
..showChatMessageDividers =
|
||||
|
|
@ -79,7 +78,6 @@ Map<String, dynamic> _$SettingsStoreToJson(SettingsStore instance) =>
|
|||
_$LandscapeCutoutTypeEnumMap[instance.landscapeCutout]!,
|
||||
'chatWidth': instance.chatWidth,
|
||||
'fullScreenChatOverlayOpacity': instance.fullScreenChatOverlayOpacity,
|
||||
'showZeroWidth': instance.showZeroWidth,
|
||||
'useReadableColors': instance.useReadableColors,
|
||||
'showDeletedMessages': instance.showDeletedMessages,
|
||||
'showChatMessageDividers': instance.showChatMessageDividers,
|
||||
|
|
@ -450,22 +448,6 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
late final _$showZeroWidthAtom =
|
||||
Atom(name: '_SettingsStoreBase.showZeroWidth', context: context);
|
||||
|
||||
@override
|
||||
bool get showZeroWidth {
|
||||
_$showZeroWidthAtom.reportRead();
|
||||
return super.showZeroWidth;
|
||||
}
|
||||
|
||||
@override
|
||||
set showZeroWidth(bool value) {
|
||||
_$showZeroWidthAtom.reportWrite(value, super.showZeroWidth, () {
|
||||
super.showZeroWidth = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$useReadableColorsAtom =
|
||||
Atom(name: '_SettingsStoreBase.useReadableColors', context: context);
|
||||
|
||||
|
|
@ -801,7 +783,6 @@ chatNotificationsOnBottom: ${chatNotificationsOnBottom},
|
|||
landscapeCutout: ${landscapeCutout},
|
||||
chatWidth: ${chatWidth},
|
||||
fullScreenChatOverlayOpacity: ${fullScreenChatOverlayOpacity},
|
||||
showZeroWidth: ${showZeroWidth},
|
||||
useReadableColors: ${useReadableColors},
|
||||
showDeletedMessages: ${showDeletedMessages},
|
||||
showChatMessageDividers: ${showChatMessageDividers},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue