Add timestap option to chat
This commit is contained in:
parent
21069ce867
commit
33c63d95cf
8 changed files with 116 additions and 22 deletions
|
|
@ -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),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue