diff --git a/lib/core/settings/chat_settings.dart b/lib/core/settings/chat/chat_settings.dart similarity index 69% rename from lib/core/settings/chat_settings.dart rename to lib/core/settings/chat/chat_settings.dart index 176c6d0c..24e80a33 100644 --- a/lib/core/settings/chat_settings.dart +++ b/lib/core/settings/chat/chat_settings.dart @@ -15,24 +15,30 @@ class ChatSettings extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SectionHeader('CHAT'), + const SectionHeader('Chat'), SwitchListTile.adaptive( - title: const Text('Hide banned messages'), + isThreeLine: true, + title: const Text('Hide banned and deleted messages'), + subtitle: const Text('Replaces deleted, timed-out, and banned user messages with "".'), value: settingsStore.hideBannedMessages, onChanged: (newValue) => settingsStore.hideBannedMessages = newValue, ), SwitchListTile.adaptive( + isThreeLine: true, title: const Text('Zero-width emotes'), + subtitle: const Text('Enable the visibility of "stacked" emotes from BetterTTV and 7TV.'), value: settingsStore.zeroWidthEnabled, onChanged: (newValue) => settingsStore.zeroWidthEnabled = newValue, ), SwitchListTile.adaptive( - title: const Text('Timestamps'), + isThreeLine: true, + title: const Text('Show timestamps'), + subtitle: const Text('Display 24-hour timestamps for when a chat message was sent.'), value: settingsStore.timeStampsEnabled, onChanged: (newValue) => settingsStore.timeStampsEnabled = newValue, ), SwitchListTile.adaptive( - title: const Text('12-hour timestamps'), + title: const Text('Use 12-hour timestamps'), value: settingsStore.twelveHourTimeStamp, onChanged: settingsStore.timeStampsEnabled ? (newValue) => settingsStore.twelveHourTimeStamp = newValue : null, ), diff --git a/lib/core/settings/general_settings.dart b/lib/core/settings/general/general_settings.dart similarity index 82% rename from lib/core/settings/general_settings.dart rename to lib/core/settings/general/general_settings.dart index 6c4acc15..0fd2e3b8 100644 --- a/lib/core/settings/general_settings.dart +++ b/lib/core/settings/general/general_settings.dart @@ -15,9 +15,10 @@ class GeneralSettings extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SectionHeader('GENERAL'), + const SectionHeader('General'), SwitchListTile.adaptive( - title: const Text('OLED Theme'), + title: const Text('Use OLED theme'), + subtitle: const Text('An all-black theme for OLED screens.'), value: settingsStore.oledTheme, onChanged: (newValue) => settingsStore.oledTheme = newValue, ), diff --git a/lib/core/settings/settings.dart b/lib/core/settings/settings.dart index e45fe498..f5a2521d 100644 --- a/lib/core/settings/settings.dart +++ b/lib/core/settings/settings.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:frosty/core/auth/auth_store.dart'; -import 'package:frosty/core/settings/account_settings.dart'; -import 'package:frosty/core/settings/chat_settings.dart'; -import 'package:frosty/core/settings/general_settings.dart'; +import 'package:frosty/core/settings/account/account_settings.dart'; +import 'package:frosty/core/settings/chat/chat_settings.dart'; +import 'package:frosty/core/settings/general/general_settings.dart'; import 'package:frosty/core/settings/settings_store.dart'; -import 'package:frosty/core/settings/video_settings.dart'; +import 'package:frosty/core/settings/video/video_settings.dart'; import 'package:provider/provider.dart'; class Settings extends StatelessWidget { @@ -22,9 +22,9 @@ class Settings extends StatelessWidget { child: ListView( children: [ AccountSettings(settingsStore: settingsStore, authStore: context.read()), + GeneralSettings(settingsStore: settingsStore), VideoSettings(settingsStore: settingsStore), ChatSettings(settingsStore: settingsStore), - GeneralSettings(settingsStore: settingsStore), ], ), ), diff --git a/lib/core/settings/settings_store.dart b/lib/core/settings/settings_store.dart index e513e437..d3adb2d6 100644 --- a/lib/core/settings/settings_store.dart +++ b/lib/core/settings/settings_store.dart @@ -34,6 +34,7 @@ abstract class _SettingsStoreBase with Store { @observable var oledTheme = false; + @action Future init() async { // Retrieve the instance that will allow us to store and persist settings. final prefs = await SharedPreferences.getInstance(); diff --git a/lib/core/settings/video_settings.dart b/lib/core/settings/video/video_settings.dart similarity index 76% rename from lib/core/settings/video_settings.dart rename to lib/core/settings/video/video_settings.dart index eb94b7e8..3ab2b30f 100644 --- a/lib/core/settings/video_settings.dart +++ b/lib/core/settings/video/video_settings.dart @@ -15,14 +15,16 @@ class VideoSettings extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SectionHeader('VIDEO'), + const SectionHeader('Video'), SwitchListTile.adaptive( - title: const Text('Video'), + title: const Text('Show video'), value: settingsStore.videoEnabled, onChanged: (newValue) => settingsStore.videoEnabled = newValue, ), SwitchListTile.adaptive( - title: const Text('Video overlay'), + isThreeLine: true, + title: const Text('Use custom video overlay'), + subtitle: const Text('Replaces the default web video overlay with a simple and mobile-friendly version.'), value: settingsStore.overlayEnabled, onChanged: settingsStore.videoEnabled ? (newValue) => settingsStore.overlayEnabled = newValue : null, ), diff --git a/lib/core/user/user_store.dart b/lib/core/user/user_store.dart index ddb015e2..a9730805 100644 --- a/lib/core/user/user_store.dart +++ b/lib/core/user/user_store.dart @@ -15,6 +15,8 @@ abstract class _UserStoreBase with Store { @readonly var _blockedUsers = ObservableList(); + ReactionDisposer? disposeReaction; + @action Future init({required Map headers}) async { // Get and update the current user's info. @@ -22,11 +24,30 @@ abstract class _UserStoreBase with Store { // Get and update the current user's list of blocked users. if (_details?.id != null) _blockedUsers = (await Twitch.getUserBlockedList(id: _details!.id, headers: headers)).asObservable(); + + disposeReaction = autorun((_) => _blockedUsers.sort((a, b) => a.userLogin.compareTo(b.userLogin))); } + @action + Future block({required String targetId, required Map headers}) async { + final success = await Twitch.blockUser(userId: targetId, headers: headers); + if (success) await refreshBlockedUsers(headers: headers); + } + + @action + Future unblock({required String targetId, required Map headers}) async { + final success = await Twitch.unblockUser(userId: targetId, headers: headers); + if (success) await refreshBlockedUsers(headers: headers); + } + + @action + Future refreshBlockedUsers({required Map headers}) async => + _blockedUsers = (await Twitch.getUserBlockedList(id: _details!.id, headers: headers)).asObservable(); + @action void dispose() { _details = null; _blockedUsers.clear(); + if (disposeReaction != null) disposeReaction!(); } } diff --git a/lib/screens/home/home.dart b/lib/screens/home/home.dart index accfc198..fab456cc 100644 --- a/lib/screens/home/home.dart +++ b/lib/screens/home/home.dart @@ -63,16 +63,12 @@ class _HomeState extends State { actions: [ IconButton( icon: const Icon(Icons.settings), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return Settings(settingsStore: context.read()); - }, - ), - ); - }, + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => Settings(settingsStore: context.read()), + ), + ), ) ], ), diff --git a/lib/screens/search/search_results_channels.dart b/lib/screens/search/search_results_channels.dart index ada5085b..f0078b83 100644 --- a/lib/screens/search/search_results_channels.dart +++ b/lib/screens/search/search_results_channels.dart @@ -16,13 +16,11 @@ class SearchResultsChannels extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (_) { - return VideoChat( - title: channelInfo!.title, - userName: channelInfo.broadcasterName, - userLogin: channelInfo.broadcasterLogin, - ); - }, + builder: (_) => VideoChat( + title: channelInfo!.title, + userName: channelInfo.broadcasterName, + userLogin: channelInfo.broadcasterLogin, + ), ), ); } catch (e) { @@ -54,13 +52,11 @@ class SearchResultsChannels extends StatelessWidget { onTap: () => Navigator.push( context, MaterialPageRoute( - builder: (_) { - return VideoChat( - title: channel.title, - userName: channel.displayName, - userLogin: channel.broadcasterLogin, - ); - }, + builder: (_) => VideoChat( + title: channel.title, + userName: channel.displayName, + userLogin: channel.broadcasterLogin, + ), ), ), ), diff --git a/lib/screens/top/categories/category_card.dart b/lib/screens/top/categories/category_card.dart index 322ea5d0..aa22fa91 100644 --- a/lib/screens/top/categories/category_card.dart +++ b/lib/screens/top/categories/category_card.dart @@ -15,21 +15,17 @@ class CategoryCard extends StatelessWidget { @override Widget build(BuildContext context) { return InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return CategoryStreams( - store: CategoryStreamsStore( - categoryInfo: category, - authStore: context.read(), - ), - ); - }, + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CategoryStreams( + store: CategoryStreamsStore( + categoryInfo: category, + authStore: context.read(), + ), ), - ); - }, + ), + ), child: Padding( padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), child: Column( diff --git a/lib/widgets/stream_card.dart b/lib/widgets/stream_card.dart index 329335d5..4c5ea8aa 100644 --- a/lib/widgets/stream_card.dart +++ b/lib/widgets/stream_card.dart @@ -14,20 +14,16 @@ class StreamCard extends StatelessWidget { @override Widget build(BuildContext context) { return InkWell( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (_) { - return VideoChat( - title: streamInfo.title, - userName: streamInfo.userName, - userLogin: streamInfo.userLogin, - ); - }, + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => VideoChat( + title: streamInfo.title, + userName: streamInfo.userName, + userLogin: streamInfo.userLogin, ), - ); - }, + ), + ), child: Padding( padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0), child: Row(