Add timestap option to chat

This commit is contained in:
Tommy Chow 2021-12-29 19:54:32 -05:00
parent 21069ce867
commit 33c63d95cf
8 changed files with 116 additions and 22 deletions

View file

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/core/auth/auth_store.dart';
import 'package:frosty/core/settings/profile_card.dart';
import 'package:frosty/core/settings/settings_store.dart';
@ -17,16 +16,12 @@ class AccountSettings extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Observer(
builder: (context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SectionHeader('ACCOUNT'),
ProfileCard(authStore: authStore),
],
);
},
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SectionHeader('ACCOUNT'),
ProfileCard(authStore: authStore),
],
);
}
}

View file

@ -17,15 +17,25 @@ class ChatSettings extends StatelessWidget {
children: [
const SectionHeader('CHAT'),
SwitchListTile.adaptive(
title: const Text('Hide Banned Messages'),
title: const Text('Hide banned messages'),
value: settingsStore.hideBannedMessages,
onChanged: (newValue) => settingsStore.hideBannedMessages = newValue,
),
SwitchListTile.adaptive(
title: const Text('Enable Zero-Width Emotes'),
title: const Text('Zero-width emotes'),
value: settingsStore.zeroWidthEnabled,
onChanged: (newValue) => settingsStore.zeroWidthEnabled = newValue,
),
SwitchListTile.adaptive(
title: const Text('Timestamps'),
value: settingsStore.timeStampsEnabled,
onChanged: (newValue) => settingsStore.timeStampsEnabled = newValue,
),
SwitchListTile.adaptive(
title: const Text('12-hour timestamps'),
value: settingsStore.twelveHourTimeStamp,
onChanged: settingsStore.timeStampsEnabled ? (newValue) => settingsStore.twelveHourTimeStamp = newValue : null,
),
],
);
},

View file

@ -25,6 +25,12 @@ abstract class _SettingsStoreBase with Store {
@observable
var expandInfo = false;
@observable
var timeStampsEnabled = false;
@observable
var twelveHourTimeStamp = false;
Future<void> init() async {
// Retrieve the instance that will allow us to store and persist settings.
final prefs = await SharedPreferences.getInstance();
@ -35,6 +41,8 @@ abstract class _SettingsStoreBase with Store {
hideBannedMessages = prefs.getBool('hide_banned_messages') ?? hideBannedMessages;
zeroWidthEnabled = prefs.getBool('zero_width_enabled') ?? zeroWidthEnabled;
expandInfo = prefs.getBool('expand_info') ?? expandInfo;
timeStampsEnabled = prefs.getBool('time_stamps_enabled') ?? timeStampsEnabled;
twelveHourTimeStamp = prefs.getBool('twelve_hour_time_stamps') ?? twelveHourTimeStamp;
// Set up reactions to store setting anytime they're changed.
// The ReactionDisposer will not be needed since settings will always exist.
@ -43,6 +51,8 @@ abstract class _SettingsStoreBase with Store {
reaction((_) => zeroWidthEnabled, (bool newValue) => prefs.setBool('zero_width_enabled', newValue));
reaction((_) => hideBannedMessages, (bool newValue) => prefs.setBool('hide_banned_messages', newValue));
reaction((_) => expandInfo, (bool newValue) => prefs.setBool('expand_info', newValue));
reaction((_) => timeStampsEnabled, (bool newValue) => prefs.setBool('time_stamps_enabled', newValue));
reaction((_) => twelveHourTimeStamp, (bool newValue) => prefs.setBool('twelve_hour_time_stamps', newValue));
// A reaction that will enable immersive mode when entering fullscreen and disable it when exiting.
reaction(

View file

@ -101,6 +101,38 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
});
}
final _$timeStampsEnabledAtom =
Atom(name: '_SettingsStoreBase.timeStampsEnabled');
@override
bool get timeStampsEnabled {
_$timeStampsEnabledAtom.reportRead();
return super.timeStampsEnabled;
}
@override
set timeStampsEnabled(bool value) {
_$timeStampsEnabledAtom.reportWrite(value, super.timeStampsEnabled, () {
super.timeStampsEnabled = value;
});
}
final _$twelveHourTimeStampAtom =
Atom(name: '_SettingsStoreBase.twelveHourTimeStamp');
@override
bool get twelveHourTimeStamp {
_$twelveHourTimeStampAtom.reportRead();
return super.twelveHourTimeStamp;
}
@override
set twelveHourTimeStamp(bool value) {
_$twelveHourTimeStampAtom.reportWrite(value, super.twelveHourTimeStamp, () {
super.twelveHourTimeStamp = value;
});
}
@override
String toString() {
return '''
@ -109,7 +141,9 @@ overlayEnabled: ${overlayEnabled},
hideBannedMessages: ${hideBannedMessages},
zeroWidthEnabled: ${zeroWidthEnabled},
fullScreen: ${fullScreen},
expandInfo: ${expandInfo}
expandInfo: ${expandInfo},
timeStampsEnabled: ${timeStampsEnabled},
twelveHourTimeStamp: ${twelveHourTimeStamp}
''';
}
}

View file

@ -17,14 +17,14 @@ class VideoSettings extends StatelessWidget {
children: [
const SectionHeader('VIDEO'),
SwitchListTile.adaptive(
title: const Text('Enable Video'),
title: const Text('Video'),
value: settingsStore.videoEnabled,
onChanged: (newValue) => settingsStore.videoEnabled = newValue,
),
SwitchListTile.adaptive(
title: const Text('Enable Video Overlay'),
title: const Text('Video overlay'),
value: settingsStore.overlayEnabled,
onChanged: (newValue) => settingsStore.overlayEnabled = newValue,
onChanged: settingsStore.videoEnabled ? (newValue) => settingsStore.overlayEnabled = newValue : null,
),
],
);

View file

@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:frosty/models/badges.dart';
import 'package:frosty/models/emotes.dart';
import 'package:intl/intl.dart';
/// The object representation of a Twitch IRC message.
class IRCMessage {
@ -68,14 +69,39 @@ class IRCMessage {
/// Returns an [InlineSpan] list that corresponds to the badges, username, words, and emotes of the given [IRCMessage].
List<InlineSpan> generateSpan({
required TextStyle? style,
required Map<String, Emote> emoteToObject,
required Map<String, BadgeInfoTwitch> badgeToObject,
bool hideMessage = false,
bool zeroWidthEnabled = false,
Timestamp timestamp = Timestamp.none,
}) {
// The span list that will be used to render the chat message
final span = <InlineSpan>[];
if (timestamp != Timestamp.none) {
final time = tags['tmi-sent-ts'] ?? DateTime.now().millisecondsSinceEpoch.toString();
final parsedTime = DateTime.fromMillisecondsSinceEpoch(int.parse(time));
if (timestamp == Timestamp.twentyFour) {
span.add(
TextSpan(
text: '${DateFormat.Hm().format(parsedTime)} ',
style: style?.copyWith(color: style.color?.withOpacity(0.5)),
),
);
}
if (timestamp == Timestamp.twelve) {
span.add(
TextSpan(
text: '${DateFormat('h:mm').format(parsedTime)} ',
style: style?.copyWith(color: style.color?.withOpacity(0.5)),
),
);
}
}
// Add any badges to the span.
final badges = tags['badges'];
if (badges != null) {
@ -472,3 +498,9 @@ enum Command {
globalUserState,
none,
}
enum Timestamp {
none,
twelve,
twentyFour,
}

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/models/irc_message.dart';
import 'package:frosty/screens/channel/chat/chat_bottom_bar.dart';
import 'package:frosty/screens/channel/chat/chat_message.dart';
import 'package:frosty/screens/channel/chat/chat_store.dart';
@ -52,11 +53,15 @@ class _ChatState extends State<Chat> with WidgetsBindingObserver {
controller: chatStore.scrollController,
itemBuilder: (context, index) => Observer(
builder: (context) => ChatMessage(
ircMessage: chatStore.messages[index],
assetsStore: chatStore.assetsStore,
hideMessageIfBanned: chatStore.settings.hideBannedMessages,
zeroWidth: chatStore.settings.zeroWidthEnabled,
),
ircMessage: chatStore.messages[index],
assetsStore: chatStore.assetsStore,
hideMessageIfBanned: chatStore.settings.hideBannedMessages,
zeroWidth: chatStore.settings.zeroWidthEnabled,
timestamp: chatStore.settings.timeStampsEnabled
? chatStore.settings.twelveHourTimeStamp
? Timestamp.twelve
: Timestamp.twentyFour
: Timestamp.none),
),
),
),

View file

@ -7,6 +7,7 @@ class ChatMessage extends StatelessWidget {
final ChatAssetsStore assetsStore;
final bool hideMessageIfBanned;
final bool zeroWidth;
final Timestamp timestamp;
const ChatMessage({
Key? key,
@ -14,6 +15,7 @@ class ChatMessage extends StatelessWidget {
required this.assetsStore,
this.hideMessageIfBanned = true,
this.zeroWidth = false,
required this.timestamp,
}) : super(key: key);
@override
@ -29,9 +31,11 @@ class ChatMessage extends StatelessWidget {
child: Text.rich(
TextSpan(
children: ircMessage.generateSpan(
style: DefaultTextStyle.of(context).style,
emoteToObject: assetsStore.emoteToObject,
badgeToObject: assetsStore.badgesToObject,
zeroWidthEnabled: zeroWidth,
timestamp: timestamp,
),
),
),
@ -50,10 +54,12 @@ class ChatMessage extends StatelessWidget {
Text.rich(
TextSpan(
children: ircMessage.generateSpan(
style: DefaultTextStyle.of(context).style,
emoteToObject: assetsStore.emoteToObject,
badgeToObject: assetsStore.badgesToObject,
hideMessage: hideMessageIfBanned,
zeroWidthEnabled: zeroWidth,
timestamp: timestamp,
),
),
),
@ -97,9 +103,11 @@ class ChatMessage extends StatelessWidget {
Text.rich(
TextSpan(
children: ircMessage.generateSpan(
style: DefaultTextStyle.of(context).style,
emoteToObject: assetsStore.emoteToObject,
badgeToObject: assetsStore.badgesToObject,
zeroWidthEnabled: zeroWidth,
timestamp: timestamp,
),
),
),