diff --git a/.gitignore b/.gitignore index ddbe5584..1071fa4b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .buildlog/ .history .svn/ +migrate_working_dir/ # IntelliJ related *.iml diff --git a/README.md b/README.md index da5ba578..862ab221 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@

- Frosty Logo -

Frosty for Twitch

+ + Frosty Logo +

Frosty

+

@@ -11,7 +13,6 @@ Flutter.

-

7.10.1) + - Sentry (~> 7.11.0) - shared_preferences_ios (0.0.1): - Flutter - sqflite (0.0.2): @@ -80,8 +80,8 @@ SPEC CHECKSUMS: FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 - Sentry: 7bf9bfe713692cf87812e55f0999260494ba7982 - sentry_flutter: 77ccdac346608b8ce7e428e7284e7a3e4e7f4a02 + Sentry: 0c5cd63d714187b4a39c331c1f0eb04ba7868341 + sentry_flutter: efb3df2c203cd03aad255892a8d628a458656d14 shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e5a14f8f..983b0c25 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -52,5 +52,7 @@ UIStatusBarHidden - - \ No newline at end of file + CADisableMinimumFrameDurationOnPhone + + + diff --git a/lib/api/ffz_api.dart b/lib/api/ffz_api.dart index 85e15fbf..1249466c 100644 --- a/lib/api/ffz_api.dart +++ b/lib/api/ffz_api.dart @@ -33,8 +33,8 @@ class FFZApi { } /// Returns a channel's FFZ room info including custom badges and emote used. - Future>> getRoomInfo({required String name}) async { - final url = Uri.parse('https://api.frankerfacez.com/v1/room/$name'); + Future>> getRoomInfo({required String id}) async { + final url = Uri.parse('https://api.frankerfacez.com/v1/room/id/$id'); final response = await _client.get(url); if (response.statusCode == 200) { diff --git a/lib/api/seventv_api.dart b/lib/api/seventv_api.dart index f21eea19..0033c99c 100644 --- a/lib/api/seventv_api.dart +++ b/lib/api/seventv_api.dart @@ -26,8 +26,8 @@ class SevenTVApi { } /// Returns a map of a channel's 7TV emotes to their URL. - Future> getEmotesChannel({required String user}) async { - final url = Uri.parse('https://api.7tv.app/v2/users/$user/emotes'); + Future> getEmotesChannel({required String id}) async { + final url = Uri.parse('https://api.7tv.app/v2/users/$id/emotes'); final response = await _client.get(url); if (response.statusCode == 200) { diff --git a/lib/core/auth/auth_store.dart b/lib/core/auth/auth_store.dart index 1e19be2e..ee296a0f 100644 --- a/lib/core/auth/auth_store.dart +++ b/lib/core/auth/auth_store.dart @@ -8,9 +8,9 @@ import 'package:mobx/mobx.dart'; part 'auth_store.g.dart'; -class AuthStore = _AuthBase with _$AuthStore; +class AuthStore = AuthBase with _$AuthStore; -abstract class _AuthBase with Store { +abstract class AuthBase with Store { /// Secure storage to store tokens. static const _storage = FlutterSecureStorage(); @@ -44,7 +44,7 @@ abstract class _AuthBase with Store { @readonly String? _error; - _AuthBase({required this.twitchApi}) : user = UserStore(twitchApi: twitchApi); + AuthBase({required this.twitchApi}) : user = UserStore(twitchApi: twitchApi); /// Initialize by retrieving a token if it does not already exist. @action @@ -58,8 +58,8 @@ abstract class _AuthBase with Store { if (_token == null) { // Retrieve the currently stored default token if it exists. _token = await _storage.read(key: _defaultTokenKey); - // If the token does not exist, get a new token and store it. - if (_token == null) { + // If the token does not exist or is invalid, get a new token and store it. + if (_token == null || !await twitchApi.validateToken(token: _token!)) { _token = await twitchApi.getDefaultToken(); await _storage.write(key: _defaultTokenKey, value: _token); } @@ -127,7 +127,7 @@ abstract class _AuthBase with Store { await user.init(headers: headersTwitch); // Set the login status to logged in. - _isLoggedIn = true; + if (user.details != null) _isLoggedIn = true; } catch (error) { debugPrint('Login failed due to $error'); } @@ -147,20 +147,10 @@ abstract class _AuthBase with Store { // If the default token already exists, set it. _token = await _storage.read(key: _defaultTokenKey); - // If the default token does not already exist, get the new default token and store it. - // Else, validate the existing token. - if (_token == null) { + // If the default token does not already exist or it's invalid, get the new default token and store it. + if (_token == null || !await twitchApi.validateToken(token: _token!)) { _token = await twitchApi.getDefaultToken(); await _storage.write(key: _defaultTokenKey, value: _token); - } else { - // Validate the stored token. - _tokenIsValid = await twitchApi.validateToken(token: _token!); - - // If the stored token is invalid, get a new default token and store it. - if (!_tokenIsValid) { - _token = await twitchApi.getDefaultToken(); - await _storage.write(key: _defaultTokenKey, value: _token); - } } // Set the login status to logged out. diff --git a/lib/core/auth/auth_store.g.dart b/lib/core/auth/auth_store.g.dart index afb167c2..c7a3e505 100644 --- a/lib/core/auth/auth_store.g.dart +++ b/lib/core/auth/auth_store.g.dart @@ -6,18 +6,18 @@ part of 'auth_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$AuthStore on _AuthBase, Store { +mixin _$AuthStore on AuthBase, Store { Computed>? _$headersTwitchComputed; @override Map get headersTwitch => (_$headersTwitchComputed ??= Computed>(() => super.headersTwitch, - name: '_AuthBase.headersTwitch')) + name: 'AuthBase.headersTwitch')) .value; - final _$_tokenAtom = Atom(name: '_AuthBase._token'); + late final _$_tokenAtom = Atom(name: 'AuthBase._token', context: context); String? get token { _$_tokenAtom.reportRead(); @@ -34,7 +34,8 @@ mixin _$AuthStore on _AuthBase, Store { }); } - final _$_isLoggedInAtom = Atom(name: '_AuthBase._isLoggedIn'); + late final _$_isLoggedInAtom = + Atom(name: 'AuthBase._isLoggedIn', context: context); bool get isLoggedIn { _$_isLoggedInAtom.reportRead(); @@ -51,7 +52,7 @@ mixin _$AuthStore on _AuthBase, Store { }); } - final _$_errorAtom = Atom(name: '_AuthBase._error'); + late final _$_errorAtom = Atom(name: 'AuthBase._error', context: context); String? get error { _$_errorAtom.reportRead(); @@ -68,21 +69,23 @@ mixin _$AuthStore on _AuthBase, Store { }); } - final _$initAsyncAction = AsyncAction('_AuthBase.init'); + late final _$initAsyncAction = AsyncAction('AuthBase.init', context: context); @override Future init() { return _$initAsyncAction.run(() => super.init()); } - final _$loginAsyncAction = AsyncAction('_AuthBase.login'); + late final _$loginAsyncAction = + AsyncAction('AuthBase.login', context: context); @override Future login({String? customToken}) { return _$loginAsyncAction.run(() => super.login(customToken: customToken)); } - final _$logoutAsyncAction = AsyncAction('_AuthBase.logout'); + late final _$logoutAsyncAction = + AsyncAction('AuthBase.logout', context: context); @override Future logout() { diff --git a/lib/core/user/user_store.dart b/lib/core/user/user_store.dart index e1f50ca5..a4a2994a 100644 --- a/lib/core/user/user_store.dart +++ b/lib/core/user/user_store.dart @@ -4,9 +4,9 @@ import 'package:mobx/mobx.dart'; part 'user_store.g.dart'; -class UserStore = _UserStoreBase with _$UserStore; +class UserStore = UserStoreBase with _$UserStore; -abstract class _UserStoreBase with Store { +abstract class UserStoreBase with Store { final TwitchApi twitchApi; /// The current user's info. @@ -19,7 +19,7 @@ abstract class _UserStoreBase with Store { ReactionDisposer? _disposeReaction; - _UserStoreBase({required this.twitchApi}); + UserStoreBase({required this.twitchApi}); @action Future init({required Map headers}) async { diff --git a/lib/core/user/user_store.g.dart b/lib/core/user/user_store.g.dart index f5f94f98..3e3bf117 100644 --- a/lib/core/user/user_store.g.dart +++ b/lib/core/user/user_store.g.dart @@ -6,10 +6,11 @@ part of 'user_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$UserStore on _UserStoreBase, Store { - final _$_detailsAtom = Atom(name: '_UserStoreBase._details'); +mixin _$UserStore on UserStoreBase, Store { + late final _$_detailsAtom = + Atom(name: 'UserStoreBase._details', context: context); UserTwitch? get details { _$_detailsAtom.reportRead(); @@ -26,7 +27,8 @@ mixin _$UserStore on _UserStoreBase, Store { }); } - final _$_blockedUsersAtom = Atom(name: '_UserStoreBase._blockedUsers'); + late final _$_blockedUsersAtom = + Atom(name: 'UserStoreBase._blockedUsers', context: context); ObservableList get blockedUsers { _$_blockedUsersAtom.reportRead(); @@ -43,14 +45,16 @@ mixin _$UserStore on _UserStoreBase, Store { }); } - final _$initAsyncAction = AsyncAction('_UserStoreBase.init'); + late final _$initAsyncAction = + AsyncAction('UserStoreBase.init', context: context); @override Future init({required Map headers}) { return _$initAsyncAction.run(() => super.init(headers: headers)); } - final _$blockAsyncAction = AsyncAction('_UserStoreBase.block'); + late final _$blockAsyncAction = + AsyncAction('UserStoreBase.block', context: context); @override Future block( @@ -61,7 +65,8 @@ mixin _$UserStore on _UserStoreBase, Store { .block(targetId: targetId, displayName: displayName, headers: headers)); } - final _$unblockAsyncAction = AsyncAction('_UserStoreBase.unblock'); + late final _$unblockAsyncAction = + AsyncAction('UserStoreBase.unblock', context: context); @override Future unblock( @@ -70,8 +75,8 @@ mixin _$UserStore on _UserStoreBase, Store { .run(() => super.unblock(targetId: targetId, headers: headers)); } - final _$refreshBlockedUsersAsyncAction = - AsyncAction('_UserStoreBase.refreshBlockedUsers'); + late final _$refreshBlockedUsersAsyncAction = + AsyncAction('UserStoreBase.refreshBlockedUsers', context: context); @override Future refreshBlockedUsers({required Map headers}) { @@ -79,17 +84,17 @@ mixin _$UserStore on _UserStoreBase, Store { .run(() => super.refreshBlockedUsers(headers: headers)); } - final _$_UserStoreBaseActionController = - ActionController(name: '_UserStoreBase'); + late final _$UserStoreBaseActionController = + ActionController(name: 'UserStoreBase', context: context); @override void dispose() { - final _$actionInfo = _$_UserStoreBaseActionController.startAction( - name: '_UserStoreBase.dispose'); + final _$actionInfo = _$UserStoreBaseActionController.startAction( + name: 'UserStoreBase.dispose'); try { return super.dispose(); } finally { - _$_UserStoreBaseActionController.endAction(_$actionInfo); + _$UserStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/models/badges.dart b/lib/models/badges.dart index 574837fa..a2846f9b 100644 --- a/lib/models/badges.dart +++ b/lib/models/badges.dart @@ -151,7 +151,7 @@ class Badge { factory Badge.fromFFZ(BadgeInfoFFZ badge) => Badge( name: badge.title, - url: 'https:' + badge.urls.url4x, + url: 'https:${badge.urls.url4x}', color: badge.color, type: BadgeType.ffz, ); diff --git a/lib/models/emotes.dart b/lib/models/emotes.dart index 7ad09081..546bebb2 100644 --- a/lib/models/emotes.dart +++ b/lib/models/emotes.dart @@ -293,7 +293,7 @@ class Emote { zeroWidth: false, width: emote.width, height: emote.height, - url: 'https:' + (emote.urls.url4x ?? emote.urls.url2x ?? emote.urls.url1x), + url: 'https:${emote.urls.url4x ?? emote.urls.url2x ?? emote.urls.url1x}', type: type, ); @@ -301,7 +301,7 @@ class Emote { name: emote.name, width: emote.width.first, height: emote.height.first, - zeroWidth: emote.visibilitySimple.isNotEmpty ? emote.visibilitySimple.first == 'ZERO_WIDTH' : false, + zeroWidth: emote.visibilitySimple.contains('ZERO_WIDTH'), url: emote.urls[3][1], type: type, ); diff --git a/lib/models/irc.dart b/lib/models/irc.dart index 4c7ac2b5..4c0c8299 100644 --- a/lib/models/irc.dart +++ b/lib/models/irc.dart @@ -85,6 +85,7 @@ class IRCMessage { required double badgeScale, required double emoteScale, required bool isLightTheme, + required bool launchExternal, bool showMessage = true, bool useZeroWidth = false, bool useReadableColors = false, @@ -147,7 +148,7 @@ class IRCMessage { badgeUrl = botBadge.url; skipBot = true; } else if (ffzRoomInfo?.modUrls != null) { - badgeUrl = 'https:' + (ffzRoomInfo!.modUrls?.url4x ?? ffzRoomInfo.modUrls?.url2x ?? ffzRoomInfo.modUrls!.url1x); + badgeUrl = 'https:${ffzRoomInfo!.modUrls?.url4x ?? ffzRoomInfo.modUrls?.url2x ?? ffzRoomInfo.modUrls!.url1x}'; } final newBadge = Badge( @@ -169,7 +170,7 @@ class IRCMessage { // Add custom FFZ vip badge if it exists if (badgeInfo.name == 'VIP' && ffzRoomInfo?.vipBadge != null) { - badgeUrl = 'https:' + (ffzRoomInfo!.vipBadge?.url4x ?? ffzRoomInfo.vipBadge?.url2x ?? ffzRoomInfo.vipBadge!.url1x); + badgeUrl = 'https:${ffzRoomInfo!.vipBadge?.url4x ?? ffzRoomInfo.vipBadge?.url2x ?? ffzRoomInfo.vipBadge!.url1x}'; } final newBadge = Badge( @@ -393,7 +394,7 @@ class IRCMessage { // 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)); + localSpan.add(_createTextSpan(text: words[index], style: textStyle, launchExternal: launchExternal)); } } else { localSpan.add( @@ -408,7 +409,7 @@ class IRCMessage { if (regexEmoji.hasMatch(word)) { localSpan.add(_createEmojiSpan(emoji: word, style: textStyle?.copyWith(fontSize: emoteSize - 5))); } else { - localSpan.add(_createTextSpan(text: word, style: textStyle)); + localSpan.add(_createTextSpan(text: word, style: textStyle, launchExternal: launchExternal)); } } localSpan.add(const TextSpan(text: ' ')); @@ -435,7 +436,7 @@ class IRCMessage { if (regexEmoji.hasMatch(word)) { span.add(_createEmojiSpan(emoji: word, style: textStyle?.copyWith(fontSize: emoteSize - 5))); } else { - span.add(_createTextSpan(text: word, style: textStyle)); + span.add(_createTextSpan(text: word, style: textStyle, launchExternal: launchExternal)); } } } @@ -574,14 +575,15 @@ class IRCMessage { ); } - static TextSpan _createTextSpan({required String text, TextStyle? style}) { + static TextSpan _createTextSpan({required String text, required bool launchExternal, TextStyle? style}) { if (text.startsWith('@')) { return TextSpan(text: text, style: style?.copyWith(fontWeight: FontWeight.bold)); } else if (RegExp(r'https?:\/\/').hasMatch(text)) { return TextSpan( text: text, style: style?.copyWith(color: Colors.blue), - recognizer: TapGestureRecognizer()..onTap = () => launch(text), + recognizer: TapGestureRecognizer() + ..onTap = () => launchUrl(Uri.parse(text), mode: launchExternal ? LaunchMode.externalApplication : LaunchMode.inAppWebView), ); } else { return TextSpan(text: text, style: style); diff --git a/lib/screens/channel/chat/chat.dart b/lib/screens/channel/chat/chat.dart index afeb5f00..b8f7765e 100644 --- a/lib/screens/channel/chat/chat.dart +++ b/lib/screens/channel/chat/chat.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:frosty/screens/channel/chat/emote_menu/emote_menu.dart'; import 'package:frosty/screens/channel/chat/widgets/chat_bottom_bar.dart'; @@ -16,7 +15,7 @@ class Chat extends StatelessWidget { Widget build(BuildContext context) { return Observer( builder: (context) { - SchedulerBinding.instance?.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { if (chatStore.scrollController.hasClients) chatStore.scrollController.jumpTo(chatStore.scrollController.position.maxScrollExtent); }); diff --git a/lib/screens/channel/chat/details/chat_users_list.dart b/lib/screens/channel/chat/details/chat_users_list.dart index 7a9cefae..4a451811 100644 --- a/lib/screens/channel/chat/details/chat_users_list.dart +++ b/lib/screens/channel/chat/details/chat_users_list.dart @@ -25,7 +25,7 @@ class ChattersList extends StatefulWidget { }) : super(key: key); @override - _ChattersListState createState() => _ChattersListState(); + State createState() => _ChattersListState(); } class _ChattersListState extends State { diff --git a/lib/screens/channel/chat/emote_menu/recent_emotes_panel.dart b/lib/screens/channel/chat/emote_menu/recent_emotes_panel.dart index 383ba160..53e1dfde 100644 --- a/lib/screens/channel/chat/emote_menu/recent_emotes_panel.dart +++ b/lib/screens/channel/chat/emote_menu/recent_emotes_panel.dart @@ -28,8 +28,8 @@ class _RecentEmotesPanelState extends State { actions: [ TextButton( onPressed: Navigator.of(context).pop, - child: const Text('Cancel'), style: TextButton.styleFrom(primary: Colors.red), + child: const Text('Cancel'), ), ElevatedButton( onPressed: () { diff --git a/lib/screens/channel/chat/widgets/chat_bottom_bar.dart b/lib/screens/channel/chat/widgets/chat_bottom_bar.dart index 746c12ab..2efc169a 100644 --- a/lib/screens/channel/chat/widgets/chat_bottom_bar.dart +++ b/lib/screens/channel/chat/widgets/chat_bottom_bar.dart @@ -77,12 +77,14 @@ class ChatBottomBar extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), child: TextField( + textInputAction: TextInputAction.send, focusNode: chatStore.textFieldFocusNode, minLines: 1, maxLines: 5, enabled: chatStore.auth.isLoggedIn ? true : false, decoration: InputDecoration( suffixIcon: IconButton( + color: chatStore.assetsStore.showEmoteMenu ? Colors.deepPurple : null, tooltip: 'Emote Menu', icon: const Icon(Icons.emoji_emotions_outlined), onPressed: () { diff --git a/lib/screens/channel/chat/widgets/chat_message.dart b/lib/screens/channel/chat/widgets/chat_message.dart index c749c041..a74ef44e 100644 --- a/lib/screens/channel/chat/widgets/chat_message.dart +++ b/lib/screens/channel/chat/widgets/chat_message.dart @@ -36,6 +36,7 @@ class ChatMessage extends StatelessWidget { useZeroWidth: settingsStore.showZeroWidth, useReadableColors: settingsStore.useReadableColors, isLightTheme: Theme.of(context).brightness == Brightness.light, + launchExternal: settingsStore.launchUrlExternal, timestamp: settingsStore.timestampType, ), ), @@ -76,6 +77,7 @@ class ChatMessage extends StatelessWidget { useZeroWidth: settingsStore.showZeroWidth, useReadableColors: settingsStore.useReadableColors, isLightTheme: Theme.of(context).brightness == Brightness.light, + launchExternal: settingsStore.launchUrlExternal, timestamp: settingsStore.timestampType, ), ), @@ -142,6 +144,7 @@ class ChatMessage extends StatelessWidget { useZeroWidth: settingsStore.showZeroWidth, useReadableColors: settingsStore.useReadableColors, isLightTheme: Theme.of(context).brightness == Brightness.light, + launchExternal: settingsStore.launchUrlExternal, timestamp: settingsStore.timestampType, ), ), diff --git a/lib/screens/channel/chat/widgets/chat_user_modal.dart b/lib/screens/channel/chat/widgets/chat_user_modal.dart index 2f11a58b..f57f7ff8 100644 --- a/lib/screens/channel/chat/widgets/chat_user_modal.dart +++ b/lib/screens/channel/chat/widgets/chat_user_modal.dart @@ -6,7 +6,7 @@ import 'package:frosty/widgets/block_report_modal.dart'; import 'package:frosty/widgets/profile_picture.dart'; import 'package:frosty/widgets/section_header.dart'; -class ChatUserModal extends StatelessWidget { +class ChatUserModal extends StatefulWidget { final ChatStore chatStore; final String username; final String displayName; @@ -20,9 +20,14 @@ class ChatUserModal extends StatelessWidget { required this.userId, }) : super(key: key); + @override + State createState() => _ChatUserModalState(); +} + +class _ChatUserModalState extends State { @override Widget build(BuildContext context) { - final userMessages = chatStore.messages.reversed.where((message) => message.user == username).toList(); + final userMessages = widget.chatStore.messages.reversed.where((message) => message.user == widget.username).toList(); return Scaffold( body: SafeArea( @@ -34,12 +39,12 @@ class ChatUserModal extends StatelessWidget { padding: const EdgeInsets.all(5.0), child: ListTile( leading: ProfilePicture( - userLogin: username, + userLogin: widget.username, ), title: Row( children: [ Text( - displayName, + widget.displayName, style: const TextStyle(fontWeight: FontWeight.bold), ), IconButton( @@ -47,22 +52,22 @@ class ChatUserModal extends StatelessWidget { onPressed: () => showModalBottomSheet( context: context, builder: (context) => BlockReportModal( - authStore: chatStore.auth, - name: displayName, - userLogin: username, - userId: userId, + authStore: widget.chatStore.auth, + name: widget.displayName, + userLogin: widget.username, + userId: widget.userId, ), ), icon: Icon(Icons.adaptive.more), ), ], ), - trailing: chatStore.auth.isLoggedIn + trailing: widget.chatStore.auth.isLoggedIn ? OutlinedButton( onPressed: () { - chatStore.textController.text = '@$username '; + widget.chatStore.textController.text = '@${widget.username} '; Navigator.pop(context); - chatStore.textFieldFocusNode.requestFocus(); + widget.chatStore.textFieldFocusNode.requestFocus(); }, child: const Text('Reply'), ) @@ -75,14 +80,16 @@ class ChatUserModal extends StatelessWidget { ), Expanded( child: MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: chatStore.settings.messageScale), + data: MediaQuery.of(context).copyWith(textScaleFactor: widget.chatStore.settings.messageScale), child: DefaultTextStyle( - style: DefaultTextStyle.of(context).style.copyWith(fontSize: chatStore.settings.fontSize), + style: DefaultTextStyle.of(context).style.copyWith(fontSize: widget.chatStore.settings.fontSize), child: ListView.separated( reverse: true, itemBuilder: (context, index) => InkWell( onLongPress: () async { await Clipboard.setData(ClipboardData(text: userMessages[index].message)); + + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Message copied!'), @@ -92,16 +99,16 @@ class ChatUserModal extends StatelessWidget { }, child: ChatMessage( ircMessage: userMessages[index], - assetsStore: chatStore.assetsStore, - settingsStore: chatStore.settings, + assetsStore: widget.chatStore.assetsStore, + settingsStore: widget.chatStore.settings, ), ), - separatorBuilder: (context, index) => chatStore.settings.showChatMessageDividers + separatorBuilder: (context, index) => widget.chatStore.settings.showChatMessageDividers ? Divider( - height: chatStore.settings.messageSpacing, + height: widget.chatStore.settings.messageSpacing, thickness: 1.0, ) - : SizedBox(height: chatStore.settings.messageSpacing), + : SizedBox(height: widget.chatStore.settings.messageSpacing), itemCount: userMessages.length, ), ), diff --git a/lib/screens/channel/stores/chat_assets_store.dart b/lib/screens/channel/stores/chat_assets_store.dart index 59e41d32..fe51ba1b 100644 --- a/lib/screens/channel/stores/chat_assets_store.dart +++ b/lib/screens/channel/stores/chat_assets_store.dart @@ -11,9 +11,9 @@ import 'package:shared_preferences/shared_preferences.dart'; part 'chat_assets_store.g.dart'; -class ChatAssetsStore = _ChatAssetsStoreBase with _$ChatAssetsStore; +class ChatAssetsStore = ChatAssetsStoreBase with _$ChatAssetsStore; -abstract class _ChatAssetsStoreBase with Store { +abstract class ChatAssetsStoreBase with Store { final TwitchApi twitchApi; final BTTVApi bttvApi; final FFZApi ffzApi; @@ -79,7 +79,7 @@ abstract class _ChatAssetsStoreBase with Store { late final ReactionDisposer _disposeReaction; - _ChatAssetsStoreBase({ + ChatAssetsStoreBase({ required this.twitchApi, required this.bttvApi, required this.ffzApi, @@ -103,7 +103,6 @@ abstract class _ChatAssetsStoreBase with Store { /// Fetches global and channel assets (badges and emotes) and stores them in [_emoteToUrl] @action Future assetsFuture({ - required String channelName, required String channelId, required Map headers, required Function onEmoteError, @@ -113,7 +112,6 @@ abstract class _ChatAssetsStoreBase with Store { // Async awaits are placed in a list so they are performed in parallel. Future.wait([ emotesFuture( - channelName: channelName, channelId: channelId, headers: headers, onError: onEmoteError, @@ -128,7 +126,6 @@ abstract class _ChatAssetsStoreBase with Store { @action Future emotesFuture({ required String channelId, - required String channelName, required Map headers, required Function onError, }) => @@ -142,8 +139,8 @@ abstract class _ChatAssetsStoreBase with Store { twitchApi.getEmotesGlobal(headers: headers).catchError(onError), twitchApi.getEmotesChannel(id: channelId, headers: headers).catchError(onError), sevenTVApi.getEmotesGlobal().catchError(onError), - sevenTVApi.getEmotesChannel(user: channelName).catchError(onError), - ffzApi.getRoomInfo(name: channelName).then((ffzRoom) { + sevenTVApi.getEmotesChannel(id: channelId).catchError(onError), + ffzApi.getRoomInfo(id: channelId).then((ffzRoom) { ffzRoomInfo = ffzRoom.item1; return ffzRoom.item2; }).catchError(onError), diff --git a/lib/screens/channel/stores/chat_assets_store.g.dart b/lib/screens/channel/stores/chat_assets_store.g.dart index b2516fb4..ae1c2b4a 100644 --- a/lib/screens/channel/stores/chat_assets_store.g.dart +++ b/lib/screens/channel/stores/chat_assets_store.g.dart @@ -6,32 +6,33 @@ part of 'chat_assets_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { +mixin _$ChatAssetsStore on ChatAssetsStoreBase, Store { Computed>? _$bttvEmotesComputed; @override List get bttvEmotes => (_$bttvEmotesComputed ??= Computed>(() => super.bttvEmotes, - name: '_ChatAssetsStoreBase.bttvEmotes')) + name: 'ChatAssetsStoreBase.bttvEmotes')) .value; Computed>? _$ffzEmotesComputed; @override List get ffzEmotes => (_$ffzEmotesComputed ??= Computed>(() => super.ffzEmotes, - name: '_ChatAssetsStoreBase.ffzEmotes')) + name: 'ChatAssetsStoreBase.ffzEmotes')) .value; Computed>? _$sevenTVEmotesComputed; @override List get sevenTVEmotes => (_$sevenTVEmotesComputed ??= Computed>(() => super.sevenTVEmotes, - name: '_ChatAssetsStoreBase.sevenTVEmotes')) + name: 'ChatAssetsStoreBase.sevenTVEmotes')) .value; - final _$_recentEmotesAtom = Atom(name: '_ChatAssetsStoreBase._recentEmotes'); + late final _$_recentEmotesAtom = + Atom(name: 'ChatAssetsStoreBase._recentEmotes', context: context); ObservableList get recentEmotes { _$_recentEmotesAtom.reportRead(); @@ -48,8 +49,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$_emoteToObjectAtom = - Atom(name: '_ChatAssetsStoreBase._emoteToObject'); + late final _$_emoteToObjectAtom = + Atom(name: 'ChatAssetsStoreBase._emoteToObject', context: context); Map get emoteToObject { _$_emoteToObjectAtom.reportRead(); @@ -66,8 +67,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$_userEmoteToObjectAtom = - Atom(name: '_ChatAssetsStoreBase._userEmoteToObject'); + late final _$_userEmoteToObjectAtom = + Atom(name: 'ChatAssetsStoreBase._userEmoteToObject', context: context); Map get userEmoteToObject { _$_userEmoteToObjectAtom.reportRead(); @@ -84,8 +85,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$_userToFFZBadgesAtom = - Atom(name: '_ChatAssetsStoreBase._userToFFZBadges'); + late final _$_userToFFZBadgesAtom = + Atom(name: 'ChatAssetsStoreBase._userToFFZBadges', context: context); Map> get userToFFZBadges { _$_userToFFZBadgesAtom.reportRead(); @@ -102,8 +103,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$_userTo7TVBadgesAtom = - Atom(name: '_ChatAssetsStoreBase._userTo7TVBadges'); + late final _$_userTo7TVBadgesAtom = + Atom(name: 'ChatAssetsStoreBase._userTo7TVBadges', context: context); Map> get userTo7TVBadges { _$_userTo7TVBadgesAtom.reportRead(); @@ -120,8 +121,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$_userToBTTVBadgesAtom = - Atom(name: '_ChatAssetsStoreBase._userToBTTVBadges'); + late final _$_userToBTTVBadgesAtom = + Atom(name: 'ChatAssetsStoreBase._userToBTTVBadges', context: context); Map get userToBTTVBadges { _$_userToBTTVBadgesAtom.reportRead(); @@ -138,8 +139,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$emoteMenuIndexAtom = - Atom(name: '_ChatAssetsStoreBase.emoteMenuIndex'); + late final _$emoteMenuIndexAtom = + Atom(name: 'ChatAssetsStoreBase.emoteMenuIndex', context: context); @override int get emoteMenuIndex { @@ -154,7 +155,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$showEmoteMenuAtom = Atom(name: '_ChatAssetsStoreBase.showEmoteMenu'); + late final _$showEmoteMenuAtom = + Atom(name: 'ChatAssetsStoreBase.showEmoteMenu', context: context); @override bool get showEmoteMenu { @@ -169,53 +171,48 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { }); } - final _$initAsyncAction = AsyncAction('_ChatAssetsStoreBase.init'); + late final _$initAsyncAction = + AsyncAction('ChatAssetsStoreBase.init', context: context); @override Future init() { return _$initAsyncAction.run(() => super.init()); } - final _$_ChatAssetsStoreBaseActionController = - ActionController(name: '_ChatAssetsStoreBase'); + late final _$ChatAssetsStoreBaseActionController = + ActionController(name: 'ChatAssetsStoreBase', context: context); @override Future assetsFuture( - {required String channelName, - required String channelId, + {required String channelId, required Map headers, required Function onEmoteError, required Function onBadgeError}) { - final _$actionInfo = _$_ChatAssetsStoreBaseActionController.startAction( - name: '_ChatAssetsStoreBase.assetsFuture'); + final _$actionInfo = _$ChatAssetsStoreBaseActionController.startAction( + name: 'ChatAssetsStoreBase.assetsFuture'); try { return super.assetsFuture( - channelName: channelName, channelId: channelId, headers: headers, onEmoteError: onEmoteError, onBadgeError: onBadgeError); } finally { - _$_ChatAssetsStoreBaseActionController.endAction(_$actionInfo); + _$ChatAssetsStoreBaseActionController.endAction(_$actionInfo); } } @override Future emotesFuture( {required String channelId, - required String channelName, required Map headers, required Function onError}) { - final _$actionInfo = _$_ChatAssetsStoreBaseActionController.startAction( - name: '_ChatAssetsStoreBase.emotesFuture'); + final _$actionInfo = _$ChatAssetsStoreBaseActionController.startAction( + name: 'ChatAssetsStoreBase.emotesFuture'); try { return super.emotesFuture( - channelId: channelId, - channelName: channelName, - headers: headers, - onError: onError); + channelId: channelId, headers: headers, onError: onError); } finally { - _$_ChatAssetsStoreBaseActionController.endAction(_$actionInfo); + _$ChatAssetsStoreBaseActionController.endAction(_$actionInfo); } } @@ -224,13 +221,13 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { {required String channelId, required Map headers, required Function onError}) { - final _$actionInfo = _$_ChatAssetsStoreBaseActionController.startAction( - name: '_ChatAssetsStoreBase.badgesFuture'); + final _$actionInfo = _$ChatAssetsStoreBaseActionController.startAction( + name: 'ChatAssetsStoreBase.badgesFuture'); try { return super.badgesFuture( channelId: channelId, headers: headers, onError: onError); } finally { - _$_ChatAssetsStoreBaseActionController.endAction(_$actionInfo); + _$ChatAssetsStoreBaseActionController.endAction(_$actionInfo); } } @@ -239,13 +236,13 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store { {required List emoteSets, required Map headers, required Function onError}) { - final _$actionInfo = _$_ChatAssetsStoreBaseActionController.startAction( - name: '_ChatAssetsStoreBase.userEmotesFuture'); + final _$actionInfo = _$ChatAssetsStoreBaseActionController.startAction( + name: 'ChatAssetsStoreBase.userEmotesFuture'); try { return super.userEmotesFuture( emoteSets: emoteSets, headers: headers, onError: onError); } finally { - _$_ChatAssetsStoreBaseActionController.endAction(_$actionInfo); + _$ChatAssetsStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/screens/channel/stores/chat_details_store.dart b/lib/screens/channel/stores/chat_details_store.dart index 90bdc286..6178f9d4 100644 --- a/lib/screens/channel/stores/chat_details_store.dart +++ b/lib/screens/channel/stores/chat_details_store.dart @@ -8,9 +8,9 @@ import 'package:mobx/mobx.dart'; part 'chat_details_store.g.dart'; -class ChatDetailsStore = _ChatDetailsStoreBase with _$ChatDetailsStore; +class ChatDetailsStore = ChatDetailsStoreBase with _$ChatDetailsStore; -abstract class _ChatDetailsStoreBase with Store { +abstract class ChatDetailsStoreBase with Store { final TwitchApi twitchApi; /// The rules and modes being used in the chat. @@ -41,7 +41,7 @@ abstract class _ChatDetailsStoreBase with Store { @readonly String? _error; - _ChatDetailsStoreBase({required this.twitchApi}); + ChatDetailsStoreBase({required this.twitchApi}); @action Future updateChatters(String userLogin) async { diff --git a/lib/screens/channel/stores/chat_details_store.g.dart b/lib/screens/channel/stores/chat_details_store.g.dart index 2bb9d9ac..e443227d 100644 --- a/lib/screens/channel/stores/chat_details_store.g.dart +++ b/lib/screens/channel/stores/chat_details_store.g.dart @@ -6,18 +6,19 @@ part of 'chat_details_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store { +mixin _$ChatDetailsStore on ChatDetailsStoreBase, Store { Computed>>? _$filteredUsersComputed; @override Iterable> get filteredUsers => (_$filteredUsersComputed ??= Computed>>(() => super.filteredUsers, - name: '_ChatDetailsStoreBase.filteredUsers')) + name: 'ChatDetailsStoreBase.filteredUsers')) .value; - final _$roomStateAtom = Atom(name: '_ChatDetailsStoreBase.roomState'); + late final _$roomStateAtom = + Atom(name: 'ChatDetailsStoreBase.roomState', context: context); @override ROOMSTATE get roomState { @@ -32,8 +33,8 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store { }); } - final _$showJumpButtonAtom = - Atom(name: '_ChatDetailsStoreBase.showJumpButton'); + late final _$showJumpButtonAtom = + Atom(name: 'ChatDetailsStoreBase.showJumpButton', context: context); @override bool get showJumpButton { @@ -48,7 +49,8 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store { }); } - final _$filterTextAtom = Atom(name: '_ChatDetailsStoreBase.filterText'); + late final _$filterTextAtom = + Atom(name: 'ChatDetailsStoreBase.filterText', context: context); @override String get filterText { @@ -63,7 +65,8 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store { }); } - final _$_chatUsersAtom = Atom(name: '_ChatDetailsStoreBase._chatUsers'); + late final _$_chatUsersAtom = + Atom(name: 'ChatDetailsStoreBase._chatUsers', context: context); ChatUsers? get chatUsers { _$_chatUsersAtom.reportRead(); @@ -80,7 +83,8 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store { }); } - final _$_errorAtom = Atom(name: '_ChatDetailsStoreBase._error'); + late final _$_errorAtom = + Atom(name: 'ChatDetailsStoreBase._error', context: context); String? get error { _$_errorAtom.reportRead(); @@ -97,8 +101,8 @@ mixin _$ChatDetailsStore on _ChatDetailsStoreBase, Store { }); } - final _$updateChattersAsyncAction = - AsyncAction('_ChatDetailsStoreBase.updateChatters'); + late final _$updateChattersAsyncAction = + AsyncAction('ChatDetailsStoreBase.updateChatters', context: context); @override Future updateChatters(String userLogin) { diff --git a/lib/screens/channel/stores/chat_store.dart b/lib/screens/channel/stores/chat_store.dart index 1190b050..442d8079 100644 --- a/lib/screens/channel/stores/chat_store.dart +++ b/lib/screens/channel/stores/chat_store.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; import 'package:frosty/constants/constants.dart'; import 'package:frosty/core/auth/auth_store.dart'; import 'package:frosty/models/badges.dart'; @@ -16,9 +15,9 @@ import 'package:web_socket_channel/web_socket_channel.dart'; part 'chat_store.g.dart'; /// The store and view-model for chat-related activities. -class ChatStore = _ChatStoreBase with _$ChatStore; +class ChatStore = ChatStoreBase with _$ChatStore; -abstract class _ChatStoreBase with Store { +abstract class ChatStoreBase with Store { static const _messageUpperLimit = 7500; static const _messageLimit = 5000; @@ -81,7 +80,7 @@ abstract class _ChatStoreBase with Store { final reactions = []; - _ChatStoreBase({ + ChatStoreBase({ required this.auth, required this.chatDetailsStore, required this.assetsStore, @@ -188,7 +187,7 @@ abstract class _ChatStoreBase with Store { if (_autoScroll) { if (_messages.length >= _messageLimit) _messages.removeAt(0); - SchedulerBinding.instance?.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { if (scrollController.hasClients) scrollController.jumpTo(scrollController.position.maxScrollExtent); }); } @@ -207,7 +206,6 @@ abstract class _ChatStoreBase with Store { // Fetch the assets used in chat including badges and emotes. assetsStore.assetsFuture( - channelName: channelName, channelId: channelId, headers: auth.headersTwitch, onEmoteError: (error) { @@ -237,7 +235,7 @@ abstract class _ChatStoreBase with Store { scrollController.jumpTo(scrollController.position.maxScrollExtent); // Schedule a postFrameCallback in the event a new message is added at the same time. - SchedulerBinding.instance?.addPostFrameCallback((_) => scrollController.jumpTo(scrollController.position.maxScrollExtent)); + WidgetsBinding.instance.addPostFrameCallback((_) => scrollController.jumpTo(scrollController.position.maxScrollExtent)); } @action @@ -310,7 +308,7 @@ abstract class _ChatStoreBase with Store { if (message.length > 3 && message.substring(0, 3) == '/me') { userStateString += ' :\x01ACTION ${message.replaceRange(0, 3, '').trim()}\x01'; } else { - userStateString += ' :' + message.trim(); + userStateString += ' :${message.trim()}'; } final userChatMessage = IRCMessage.fromString(userStateString); @@ -324,7 +322,7 @@ abstract class _ChatStoreBase with Store { } // Scroll to the latest message after sending. - SchedulerBinding.instance?.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { if (scrollController.hasClients) scrollController.jumpTo(scrollController.position.maxScrollExtent); }); } @@ -333,15 +331,15 @@ abstract class _ChatStoreBase with Store { @action void addEmote(Emote emote, {bool autocompleteMode = false}) { if (textController.text.isEmpty || textController.text.endsWith(' ')) { - textController.text += emote.name + ' '; + textController.text += '${emote.name} '; } else if (autocompleteMode && _showAutocomplete && textController.text.endsWith('')) { final split = textController.text.split(' ') ..removeLast() - ..add(emote.name + ' '); + ..add('${emote.name} '); textController.text = split.join(' '); } else { - textController.text += ' ' + emote.name + ' '; + textController.text += ' ${emote.name} '; } assetsStore.recentEmotes diff --git a/lib/screens/channel/stores/chat_store.g.dart b/lib/screens/channel/stores/chat_store.g.dart index a1895d0f..26670a84 100644 --- a/lib/screens/channel/stores/chat_store.g.dart +++ b/lib/screens/channel/stores/chat_store.g.dart @@ -6,10 +6,11 @@ part of 'chat_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$ChatStore on _ChatStoreBase, Store { - final _$_messagesAtom = Atom(name: '_ChatStoreBase._messages'); +mixin _$ChatStore on ChatStoreBase, Store { + late final _$_messagesAtom = + Atom(name: 'ChatStoreBase._messages', context: context); ObservableList get messages { _$_messagesAtom.reportRead(); @@ -26,7 +27,8 @@ mixin _$ChatStore on _ChatStoreBase, Store { }); } - final _$_autoScrollAtom = Atom(name: '_ChatStoreBase._autoScroll'); + late final _$_autoScrollAtom = + Atom(name: 'ChatStoreBase._autoScroll', context: context); bool get autoScroll { _$_autoScrollAtom.reportRead(); @@ -43,8 +45,8 @@ mixin _$ChatStore on _ChatStoreBase, Store { }); } - final _$_showAutocompleteAtom = - Atom(name: '_ChatStoreBase._showAutocomplete'); + late final _$_showAutocompleteAtom = + Atom(name: 'ChatStoreBase._showAutocomplete', context: context); bool get showAutocomplete { _$_showAutocompleteAtom.reportRead(); @@ -61,7 +63,8 @@ mixin _$ChatStore on _ChatStoreBase, Store { }); } - final _$_userStateAtom = Atom(name: '_ChatStoreBase._userState'); + late final _$_userStateAtom = + Atom(name: 'ChatStoreBase._userState', context: context); USERSTATE get userState { _$_userStateAtom.reportRead(); @@ -78,61 +81,61 @@ mixin _$ChatStore on _ChatStoreBase, Store { }); } - final _$_ChatStoreBaseActionController = - ActionController(name: '_ChatStoreBase'); + late final _$ChatStoreBaseActionController = + ActionController(name: 'ChatStoreBase', context: context); @override void _handleIRCData(String data) { - final _$actionInfo = _$_ChatStoreBaseActionController.startAction( - name: '_ChatStoreBase._handleIRCData'); + final _$actionInfo = _$ChatStoreBaseActionController.startAction( + name: 'ChatStoreBase._handleIRCData'); try { return super._handleIRCData(data); } finally { - _$_ChatStoreBaseActionController.endAction(_$actionInfo); + _$ChatStoreBaseActionController.endAction(_$actionInfo); } } @override void resumeScroll() { - final _$actionInfo = _$_ChatStoreBaseActionController.startAction( - name: '_ChatStoreBase.resumeScroll'); + final _$actionInfo = _$ChatStoreBaseActionController.startAction( + name: 'ChatStoreBase.resumeScroll'); try { return super.resumeScroll(); } finally { - _$_ChatStoreBaseActionController.endAction(_$actionInfo); + _$ChatStoreBaseActionController.endAction(_$actionInfo); } } @override void connectToChat() { - final _$actionInfo = _$_ChatStoreBaseActionController.startAction( - name: '_ChatStoreBase.connectToChat'); + final _$actionInfo = _$ChatStoreBaseActionController.startAction( + name: 'ChatStoreBase.connectToChat'); try { return super.connectToChat(); } finally { - _$_ChatStoreBaseActionController.endAction(_$actionInfo); + _$ChatStoreBaseActionController.endAction(_$actionInfo); } } @override void sendMessage(String message) { - final _$actionInfo = _$_ChatStoreBaseActionController.startAction( - name: '_ChatStoreBase.sendMessage'); + final _$actionInfo = _$ChatStoreBaseActionController.startAction( + name: 'ChatStoreBase.sendMessage'); try { return super.sendMessage(message); } finally { - _$_ChatStoreBaseActionController.endAction(_$actionInfo); + _$ChatStoreBaseActionController.endAction(_$actionInfo); } } @override void addEmote(Emote emote, {bool autocompleteMode = false}) { - final _$actionInfo = _$_ChatStoreBaseActionController.startAction( - name: '_ChatStoreBase.addEmote'); + final _$actionInfo = _$ChatStoreBaseActionController.startAction( + name: 'ChatStoreBase.addEmote'); try { return super.addEmote(emote, autocompleteMode: autocompleteMode); } finally { - _$_ChatStoreBaseActionController.endAction(_$actionInfo); + _$ChatStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/screens/channel/stores/video_store.dart b/lib/screens/channel/stores/video_store.dart index 46f65f09..f33b38da 100644 --- a/lib/screens/channel/stores/video_store.dart +++ b/lib/screens/channel/stores/video_store.dart @@ -11,9 +11,9 @@ import 'package:webview_flutter/webview_flutter.dart'; part 'video_store.g.dart'; -class VideoStore = _VideoStoreBase with _$VideoStore; +class VideoStore = VideoStoreBase with _$VideoStore; -abstract class _VideoStoreBase with Store { +abstract class VideoStoreBase with Store { final TwitchApi twitchApi; WebViewController? controller; @@ -60,7 +60,7 @@ abstract class _VideoStoreBase with Store { final AuthStore authStore; final SettingsStore settingsStore; - _VideoStoreBase({ + VideoStoreBase({ required this.userLogin, required this.twitchApi, required this.authStore, diff --git a/lib/screens/channel/stores/video_store.g.dart b/lib/screens/channel/stores/video_store.g.dart index 3563099e..28710c74 100644 --- a/lib/screens/channel/stores/video_store.g.dart +++ b/lib/screens/channel/stores/video_store.g.dart @@ -6,18 +6,19 @@ part of 'video_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$VideoStore on _VideoStoreBase, Store { +mixin _$VideoStore on VideoStoreBase, Store { Computed? _$videoUrlComputed; @override String get videoUrl => (_$videoUrlComputed ??= Computed(() => super.videoUrl, - name: '_VideoStoreBase.videoUrl')) + name: 'VideoStoreBase.videoUrl')) .value; - final _$sleepHoursAtom = Atom(name: '_VideoStoreBase.sleepHours'); + late final _$sleepHoursAtom = + Atom(name: 'VideoStoreBase.sleepHours', context: context); @override int get sleepHours { @@ -32,7 +33,8 @@ mixin _$VideoStore on _VideoStoreBase, Store { }); } - final _$sleepMinutesAtom = Atom(name: '_VideoStoreBase.sleepMinutes'); + late final _$sleepMinutesAtom = + Atom(name: 'VideoStoreBase.sleepMinutes', context: context); @override int get sleepMinutes { @@ -47,7 +49,8 @@ mixin _$VideoStore on _VideoStoreBase, Store { }); } - final _$timeRemainingAtom = Atom(name: '_VideoStoreBase.timeRemaining'); + late final _$timeRemainingAtom = + Atom(name: 'VideoStoreBase.timeRemaining', context: context); @override Duration get timeRemaining { @@ -62,7 +65,8 @@ mixin _$VideoStore on _VideoStoreBase, Store { }); } - final _$_pausedAtom = Atom(name: '_VideoStoreBase._paused'); + late final _$_pausedAtom = + Atom(name: 'VideoStoreBase._paused', context: context); bool get paused { _$_pausedAtom.reportRead(); @@ -79,7 +83,8 @@ mixin _$VideoStore on _VideoStoreBase, Store { }); } - final _$_overlayVisibleAtom = Atom(name: '_VideoStoreBase._overlayVisible'); + late final _$_overlayVisibleAtom = + Atom(name: 'VideoStoreBase._overlayVisible', context: context); bool get overlayVisible { _$_overlayVisibleAtom.reportRead(); @@ -96,7 +101,8 @@ mixin _$VideoStore on _VideoStoreBase, Store { }); } - final _$_streamInfoAtom = Atom(name: '_VideoStoreBase._streamInfo'); + late final _$_streamInfoAtom = + Atom(name: 'VideoStoreBase._streamInfo', context: context); StreamTwitch? get streamInfo { _$_streamInfoAtom.reportRead(); @@ -113,16 +119,16 @@ mixin _$VideoStore on _VideoStoreBase, Store { }); } - final _$updateStreamInfoAsyncAction = - AsyncAction('_VideoStoreBase.updateStreamInfo'); + late final _$updateStreamInfoAsyncAction = + AsyncAction('VideoStoreBase.updateStreamInfo', context: context); @override Future updateStreamInfo() { return _$updateStreamInfoAsyncAction.run(() => super.updateStreamInfo()); } - final _$handleToggleOverlayAsyncAction = - AsyncAction('_VideoStoreBase.handleToggleOverlay'); + late final _$handleToggleOverlayAsyncAction = + AsyncAction('VideoStoreBase.handleToggleOverlay', context: context); @override Future handleToggleOverlay() { @@ -130,39 +136,39 @@ mixin _$VideoStore on _VideoStoreBase, Store { .run(() => super.handleToggleOverlay()); } - final _$_VideoStoreBaseActionController = - ActionController(name: '_VideoStoreBase'); + late final _$VideoStoreBaseActionController = + ActionController(name: 'VideoStoreBase', context: context); @override void handlePausePlay() { - final _$actionInfo = _$_VideoStoreBaseActionController.startAction( - name: '_VideoStoreBase.handlePausePlay'); + final _$actionInfo = _$VideoStoreBaseActionController.startAction( + name: 'VideoStoreBase.handlePausePlay'); try { return super.handlePausePlay(); } finally { - _$_VideoStoreBaseActionController.endAction(_$actionInfo); + _$VideoStoreBaseActionController.endAction(_$actionInfo); } } @override void handleVideoTap() { - final _$actionInfo = _$_VideoStoreBaseActionController.startAction( - name: '_VideoStoreBase.handleVideoTap'); + final _$actionInfo = _$VideoStoreBaseActionController.startAction( + name: 'VideoStoreBase.handleVideoTap'); try { return super.handleVideoTap(); } finally { - _$_VideoStoreBaseActionController.endAction(_$actionInfo); + _$VideoStoreBaseActionController.endAction(_$actionInfo); } } @override void handleExpand() { - final _$actionInfo = _$_VideoStoreBaseActionController.startAction( - name: '_VideoStoreBase.handleExpand'); + final _$actionInfo = _$VideoStoreBaseActionController.startAction( + name: 'VideoStoreBase.handleExpand'); try { return super.handleExpand(); } finally { - _$_VideoStoreBaseActionController.endAction(_$actionInfo); + _$VideoStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/screens/channel/video/video_overlay.dart b/lib/screens/channel/video/video_overlay.dart index 2fe003be..4249d176 100644 --- a/lib/screens/channel/video/video_overlay.dart +++ b/lib/screens/channel/video/video_overlay.dart @@ -7,6 +7,7 @@ import 'package:frosty/constants/constants.dart'; import 'package:frosty/main.dart'; import 'package:frosty/screens/channel/stores/video_store.dart'; import 'package:frosty/screens/settings/settings.dart'; +import 'package:frosty/widgets/profile_picture.dart'; import 'package:intl/intl.dart'; class VideoOverlay extends StatelessWidget { @@ -66,8 +67,8 @@ class VideoOverlay extends StatelessWidget { actions: [ TextButton( onPressed: Navigator.of(context).pop, - child: const Text('Dismiss'), style: TextButton.styleFrom(primary: Colors.red), + child: const Text('Dismiss'), ), Observer( builder: (context) => ElevatedButton( @@ -175,13 +176,31 @@ class VideoOverlay extends StatelessWidget { ); } - final streamer = Text( - regexEnglish.hasMatch(streamInfo.userName) ? streamInfo.userName : streamInfo.userName + ' (${streamInfo.userLogin})', - style: const TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), + final streamerName = regexEnglish.hasMatch(streamInfo.userName) ? streamInfo.userName : '${streamInfo.userName} (${streamInfo.userLogin})'; + + final streamer = Row( + children: [ + ProfilePicture( + userLogin: streamInfo.userLogin, + radius: 10.0, + ), + const SizedBox(width: 5.0), + Flexible( + child: Tooltip( + message: streamerName, + preferBelow: false, + child: Text( + streamerName, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], ); return Observer( @@ -262,6 +281,7 @@ class VideoOverlay extends StatelessWidget { Text( '${videoStore.streamInfo?.gameName} \u2022 ${NumberFormat().format(videoStore.streamInfo?.viewerCount)} viewers', style: const TextStyle( + fontSize: 12.0, color: Colors.white, fontWeight: FontWeight.w300, ), diff --git a/lib/screens/channel/video_chat.dart b/lib/screens/channel/video_chat.dart index 667fdccf..ec7c9bd4 100644 --- a/lib/screens/channel/video_chat.dart +++ b/lib/screens/channel/video_chat.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:frosty/api/bttv_api.dart'; @@ -32,7 +31,7 @@ class VideoChat extends StatefulWidget { }) : super(key: key); @override - _VideoChatState createState() => _VideoChatState(); + State createState() => _VideoChatState(); } class _VideoChatState extends State { @@ -124,7 +123,7 @@ class _VideoChatState extends State { final appBar = AppBar( title: Text( - regexEnglish.hasMatch(_chatStore.displayName) ? _chatStore.displayName : _chatStore.displayName + ' (${_chatStore.channelName})', + regexEnglish.hasMatch(_chatStore.displayName) ? _chatStore.displayName : '${_chatStore.displayName} (${_chatStore.channelName})', style: const TextStyle(fontSize: 20), ), actions: [ @@ -147,7 +146,7 @@ class _VideoChatState extends State { body: OrientationBuilder( builder: (context, orientation) { // Scroll to bottom when summoning keyboard or rotating. - SchedulerBinding.instance?.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { if (_chatStore.scrollController.hasClients) _chatStore.scrollController.jumpTo(_chatStore.scrollController.position.maxScrollExtent); }); diff --git a/lib/screens/home/search/search.dart b/lib/screens/home/search/search.dart index 69729e24..f92e488a 100644 --- a/lib/screens/home/search/search.dart +++ b/lib/screens/home/search/search.dart @@ -13,7 +13,7 @@ class Search extends StatefulWidget { const Search({Key? key}) : super(key: key); @override - _SearchState createState() => _SearchState(); + State createState() => _SearchState(); } class _SearchState extends State { diff --git a/lib/screens/home/search/search_results_channels.dart b/lib/screens/home/search/search_results_channels.dart index c09263ce..63a44546 100644 --- a/lib/screens/home/search/search_results_channels.dart +++ b/lib/screens/home/search/search_results_channels.dart @@ -9,7 +9,7 @@ import 'package:frosty/widgets/loading_indicator.dart'; import 'package:frosty/widgets/profile_picture.dart'; import 'package:mobx/mobx.dart'; -class SearchResultsChannels extends StatelessWidget { +class SearchResultsChannels extends StatefulWidget { final SearchStore searchStore; final String query; @@ -19,9 +19,16 @@ class SearchResultsChannels extends StatelessWidget { required this.query, }) : super(key: key); + @override + State createState() => _SearchResultsChannelsState(); +} + +class _SearchResultsChannelsState extends State { Future _handleSearch(BuildContext context, String search) async { try { - final channelInfo = await searchStore.searchChannel(search); + final channelInfo = await widget.searchStore.searchChannel(search); + + if (!mounted) return; Navigator.push( context, MaterialPageRoute( @@ -45,7 +52,7 @@ class SearchResultsChannels extends StatelessWidget { Widget build(BuildContext context) { return Observer( builder: (context) { - final future = searchStore.channelFuture; + final future = widget.searchStore.channelFuture; switch (future!.status) { case FutureStatus.pending: @@ -62,14 +69,14 @@ class SearchResultsChannels extends StatelessWidget { ); case FutureStatus.fulfilled: final results = (future.result as List) - .where((channel) => !searchStore.authStore.user.blockedUsers.map((blockedUser) => blockedUser.userId).contains(channel.id)); + .where((channel) => !widget.searchStore.authStore.user.blockedUsers.map((blockedUser) => blockedUser.userId).contains(channel.id)); return SliverList( delegate: SliverChildListDelegate.fixed([ ...results.map( (channel) { final displayName = - regexEnglish.hasMatch(channel.displayName) ? channel.displayName : channel.displayName + ' (${channel.broadcasterLogin})'; + regexEnglish.hasMatch(channel.displayName) ? channel.displayName : '${channel.displayName} (${channel.broadcasterLogin})'; return ListTile( title: Text(displayName), @@ -106,7 +113,7 @@ class SearchResultsChannels extends StatelessWidget { onLongPress: () => showModalBottomSheet( context: context, builder: (context) => BlockReportModal( - authStore: searchStore.authStore, + authStore: widget.searchStore.authStore, name: displayName, userLogin: channel.broadcasterLogin, userId: channel.id, @@ -116,8 +123,8 @@ class SearchResultsChannels extends StatelessWidget { }, ), ListTile( - title: Text('Go to channel "$query"'), - onTap: () => _handleSearch(context, query), + title: Text('Go to channel "${widget.query}"'), + onTap: () => _handleSearch(context, widget.query), trailing: Icon(Icons.adaptive.arrow_forward), ) ]), diff --git a/lib/screens/home/stores/categories_store.dart b/lib/screens/home/stores/categories_store.dart index e00100af..7767e24a 100644 --- a/lib/screens/home/stores/categories_store.dart +++ b/lib/screens/home/stores/categories_store.dart @@ -8,9 +8,9 @@ import 'package:mobx/mobx.dart'; part 'categories_store.g.dart'; -class CategoriesStore = _CategoriesStoreBase with _$CategoriesStore; +class CategoriesStore = CategoriesStoreBase with _$CategoriesStore; -abstract class _CategoriesStoreBase with Store { +abstract class CategoriesStoreBase with Store { /// The authentication store. final AuthStore authStore; @@ -42,7 +42,7 @@ abstract class _CategoriesStoreBase with Store { @readonly String? _error; - _CategoriesStoreBase({required this.authStore, required this.twitchApi}) { + CategoriesStoreBase({required this.authStore, required this.twitchApi}) { scrollController.addListener(() { if (scrollController.position.atEdge || scrollController.position.outOfRange) { showJumpButton = false; diff --git a/lib/screens/home/stores/categories_store.g.dart b/lib/screens/home/stores/categories_store.g.dart index 5828f747..ef0c9bd6 100644 --- a/lib/screens/home/stores/categories_store.g.dart +++ b/lib/screens/home/stores/categories_store.g.dart @@ -6,11 +6,11 @@ part of 'categories_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$CategoriesStore on _CategoriesStoreBase, Store { - final _$showJumpButtonAtom = - Atom(name: '_CategoriesStoreBase.showJumpButton'); +mixin _$CategoriesStore on CategoriesStoreBase, Store { + late final _$showJumpButtonAtom = + Atom(name: 'CategoriesStoreBase.showJumpButton', context: context); @override bool get showJumpButton { @@ -25,7 +25,8 @@ mixin _$CategoriesStore on _CategoriesStoreBase, Store { }); } - final _$_categoriesAtom = Atom(name: '_CategoriesStoreBase._categories'); + late final _$_categoriesAtom = + Atom(name: 'CategoriesStoreBase._categories', context: context); ObservableList get categories { _$_categoriesAtom.reportRead(); @@ -42,7 +43,8 @@ mixin _$CategoriesStore on _CategoriesStoreBase, Store { }); } - final _$_errorAtom = Atom(name: '_CategoriesStoreBase._error'); + late final _$_errorAtom = + Atom(name: 'CategoriesStoreBase._error', context: context); String? get error { _$_errorAtom.reportRead(); @@ -59,25 +61,25 @@ mixin _$CategoriesStore on _CategoriesStoreBase, Store { }); } - final _$getCategoriesAsyncAction = - AsyncAction('_CategoriesStoreBase.getCategories'); + late final _$getCategoriesAsyncAction = + AsyncAction('CategoriesStoreBase.getCategories', context: context); @override Future getCategories() { return _$getCategoriesAsyncAction.run(() => super.getCategories()); } - final _$_CategoriesStoreBaseActionController = - ActionController(name: '_CategoriesStoreBase'); + late final _$CategoriesStoreBaseActionController = + ActionController(name: 'CategoriesStoreBase', context: context); @override Future refreshCategories() { - final _$actionInfo = _$_CategoriesStoreBaseActionController.startAction( - name: '_CategoriesStoreBase.refreshCategories'); + final _$actionInfo = _$CategoriesStoreBaseActionController.startAction( + name: 'CategoriesStoreBase.refreshCategories'); try { return super.refreshCategories(); } finally { - _$_CategoriesStoreBaseActionController.endAction(_$actionInfo); + _$CategoriesStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/screens/home/stores/home_store.dart b/lib/screens/home/stores/home_store.dart index 7b88eaee..d3054a6b 100644 --- a/lib/screens/home/stores/home_store.dart +++ b/lib/screens/home/stores/home_store.dart @@ -1,15 +1,16 @@ import 'package:frosty/core/auth/auth_store.dart'; import 'package:mobx/mobx.dart'; + part 'home_store.g.dart'; -class HomeStore = _HomeStoreBase with _$HomeStore; +class HomeStore = HomeStoreBase with _$HomeStore; -abstract class _HomeStoreBase with Store { +abstract class HomeStoreBase with Store { final AuthStore authStore; late final ReactionDisposer _disposeReaction; - _HomeStoreBase({required this.authStore}) { + HomeStoreBase({required this.authStore}) { _disposeReaction = reaction( (_) => authStore.isLoggedIn, (_) => _selectedIndex = 0, diff --git a/lib/screens/home/stores/home_store.g.dart b/lib/screens/home/stores/home_store.g.dart index 19e23bce..954275f9 100644 --- a/lib/screens/home/stores/home_store.g.dart +++ b/lib/screens/home/stores/home_store.g.dart @@ -6,10 +6,11 @@ part of 'home_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$HomeStore on _HomeStoreBase, Store { - final _$_selectedIndexAtom = Atom(name: '_HomeStoreBase._selectedIndex'); +mixin _$HomeStore on HomeStoreBase, Store { + late final _$_selectedIndexAtom = + Atom(name: 'HomeStoreBase._selectedIndex', context: context); int get selectedIndex { _$_selectedIndexAtom.reportRead(); @@ -26,17 +27,17 @@ mixin _$HomeStore on _HomeStoreBase, Store { }); } - final _$_HomeStoreBaseActionController = - ActionController(name: '_HomeStoreBase'); + late final _$HomeStoreBaseActionController = + ActionController(name: 'HomeStoreBase', context: context); @override void handleTap(int index) { - final _$actionInfo = _$_HomeStoreBaseActionController.startAction( - name: '_HomeStoreBase.handleTap'); + final _$actionInfo = _$HomeStoreBaseActionController.startAction( + name: 'HomeStoreBase.handleTap'); try { return super.handleTap(index); } finally { - _$_HomeStoreBaseActionController.endAction(_$actionInfo); + _$HomeStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/screens/home/stores/list_store.dart b/lib/screens/home/stores/list_store.dart index 0588b4d3..e8e0c361 100644 --- a/lib/screens/home/stores/list_store.dart +++ b/lib/screens/home/stores/list_store.dart @@ -9,9 +9,9 @@ import 'package:mobx/mobx.dart'; part 'list_store.g.dart'; -class ListStore = _ListStoreBase with _$ListStore; +class ListStore = ListStoreBase with _$ListStore; -abstract class _ListStoreBase with Store { +abstract class ListStoreBase with Store { /// The authentication store. final AuthStore authStore; @@ -55,7 +55,7 @@ abstract class _ListStoreBase with Store { @readonly String? _error; - _ListStoreBase({ + ListStoreBase({ required this.authStore, required this.twitchApi, required this.listType, diff --git a/lib/screens/home/stores/list_store.g.dart b/lib/screens/home/stores/list_store.g.dart index 301ab9c8..7275b890 100644 --- a/lib/screens/home/stores/list_store.g.dart +++ b/lib/screens/home/stores/list_store.g.dart @@ -6,18 +6,19 @@ part of 'list_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$ListStore on _ListStoreBase, Store { +mixin _$ListStore on ListStoreBase, Store { Computed>? _$streamsComputed; @override ObservableList get streams => (_$streamsComputed ??= Computed>(() => super.streams, - name: '_ListStoreBase.streams')) + name: 'ListStoreBase.streams')) .value; - final _$showJumpButtonAtom = Atom(name: '_ListStoreBase.showJumpButton'); + late final _$showJumpButtonAtom = + Atom(name: 'ListStoreBase.showJumpButton', context: context); @override bool get showJumpButton { @@ -32,7 +33,8 @@ mixin _$ListStore on _ListStoreBase, Store { }); } - final _$_allStreamsAtom = Atom(name: '_ListStoreBase._allStreams'); + late final _$_allStreamsAtom = + Atom(name: 'ListStoreBase._allStreams', context: context); ObservableList get allStreams { _$_allStreamsAtom.reportRead(); @@ -49,7 +51,8 @@ mixin _$ListStore on _ListStoreBase, Store { }); } - final _$_errorAtom = Atom(name: '_ListStoreBase._error'); + late final _$_errorAtom = + Atom(name: 'ListStoreBase._error', context: context); String? get error { _$_errorAtom.reportRead(); @@ -66,24 +69,25 @@ mixin _$ListStore on _ListStoreBase, Store { }); } - final _$getStreamsAsyncAction = AsyncAction('_ListStoreBase.getStreams'); + late final _$getStreamsAsyncAction = + AsyncAction('ListStoreBase.getStreams', context: context); @override Future getStreams() { return _$getStreamsAsyncAction.run(() => super.getStreams()); } - final _$_ListStoreBaseActionController = - ActionController(name: '_ListStoreBase'); + late final _$ListStoreBaseActionController = + ActionController(name: 'ListStoreBase', context: context); @override Future refreshStreams() { - final _$actionInfo = _$_ListStoreBaseActionController.startAction( - name: '_ListStoreBase.refreshStreams'); + final _$actionInfo = _$ListStoreBaseActionController.startAction( + name: 'ListStoreBase.refreshStreams'); try { return super.refreshStreams(); } finally { - _$_ListStoreBaseActionController.endAction(_$actionInfo); + _$ListStoreBaseActionController.endAction(_$actionInfo); } } diff --git a/lib/screens/home/stores/search_store.dart b/lib/screens/home/stores/search_store.dart index 8b26ac85..f5a3a9ff 100644 --- a/lib/screens/home/stores/search_store.dart +++ b/lib/screens/home/stores/search_store.dart @@ -7,9 +7,9 @@ import 'package:shared_preferences/shared_preferences.dart'; part 'search_store.g.dart'; -class SearchStore = _SearchStoreBase with _$SearchStore; +class SearchStore = SearchStoreBase with _$SearchStore; -abstract class _SearchStoreBase with Store { +abstract class SearchStoreBase with Store { final AuthStore authStore; final TwitchApi twitchApi; @@ -23,7 +23,7 @@ abstract class _SearchStoreBase with Store { @readonly ObservableFuture? _categoryFuture; - _SearchStoreBase({required this.authStore, required this.twitchApi}) { + SearchStoreBase({required this.authStore, required this.twitchApi}) { init(); } diff --git a/lib/screens/home/stores/search_store.g.dart b/lib/screens/home/stores/search_store.g.dart index f3ed38bc..4a239c56 100644 --- a/lib/screens/home/stores/search_store.g.dart +++ b/lib/screens/home/stores/search_store.g.dart @@ -6,10 +6,11 @@ part of 'search_store.dart'; // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers -mixin _$SearchStore on _SearchStoreBase, Store { - final _$_searchHistoryAtom = Atom(name: '_SearchStoreBase._searchHistory'); +mixin _$SearchStore on SearchStoreBase, Store { + late final _$_searchHistoryAtom = + Atom(name: 'SearchStoreBase._searchHistory', context: context); ObservableList get searchHistory { _$_searchHistoryAtom.reportRead(); @@ -26,7 +27,8 @@ mixin _$SearchStore on _SearchStoreBase, Store { }); } - final _$_channelFutureAtom = Atom(name: '_SearchStoreBase._channelFuture'); + late final _$_channelFutureAtom = + Atom(name: 'SearchStoreBase._channelFuture', context: context); ObservableFuture>? get channelFuture { _$_channelFutureAtom.reportRead(); @@ -43,7 +45,8 @@ mixin _$SearchStore on _SearchStoreBase, Store { }); } - final _$_categoryFutureAtom = Atom(name: '_SearchStoreBase._categoryFuture'); + late final _$_categoryFutureAtom = + Atom(name: 'SearchStoreBase._categoryFuture', context: context); ObservableFuture? get categoryFuture { _$_categoryFutureAtom.reportRead(); @@ -60,14 +63,16 @@ mixin _$SearchStore on _SearchStoreBase, Store { }); } - final _$initAsyncAction = AsyncAction('_SearchStoreBase.init'); + late final _$initAsyncAction = + AsyncAction('SearchStoreBase.init', context: context); @override Future init() { return _$initAsyncAction.run(() => super.init()); } - final _$handleQueryAsyncAction = AsyncAction('_SearchStoreBase.handleQuery'); + late final _$handleQueryAsyncAction = + AsyncAction('SearchStoreBase.handleQuery', context: context); @override Future handleQuery(String query) { diff --git a/lib/screens/home/top/categories.dart b/lib/screens/home/top/categories.dart index de1a55be..ceb5c549 100644 --- a/lib/screens/home/top/categories.dart +++ b/lib/screens/home/top/categories.dart @@ -13,7 +13,7 @@ class Categories extends StatefulWidget { const Categories({Key? key}) : super(key: key); @override - _CategoriesState createState() => _CategoriesState(); + State createState() => _CategoriesState(); } class _CategoriesState extends State with AutomaticKeepAliveClientMixin { @@ -42,6 +42,8 @@ class _CategoriesState extends State with AutomaticKeepAliveClientMi content: Text(_categoriesStore.error!), behavior: SnackBarBehavior.floating, ); + + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(snackBar); } }, diff --git a/lib/screens/home/top/category_streams.dart b/lib/screens/home/top/category_streams.dart index 2efe098e..a70da5bc 100644 --- a/lib/screens/home/top/category_streams.dart +++ b/lib/screens/home/top/category_streams.dart @@ -9,11 +9,16 @@ import 'package:frosty/widgets/loading_indicator.dart'; import 'package:frosty/widgets/scroll_to_top_button.dart'; import 'package:provider/provider.dart'; -class CategoryStreams extends StatelessWidget { +class CategoryStreams extends StatefulWidget { final ListStore listStore; const CategoryStreams({Key? key, required this.listStore}) : super(key: key); + @override + State createState() => _CategoryStreamsState(); +} + +class _CategoryStreamsState extends State { @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; @@ -29,19 +34,21 @@ class CategoryStreams extends StatelessWidget { body: RefreshIndicator( onRefresh: () async { HapticFeedback.lightImpact(); - await listStore.refreshStreams(); + await widget.listStore.refreshStreams(); - if (listStore.error != null) { + if (widget.listStore.error != null) { final snackBar = SnackBar( - content: Text(listStore.error!), + content: Text(widget.listStore.error!), behavior: SnackBarBehavior.floating, ); + + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(snackBar); } }, child: Observer( builder: (context) { - if (listStore.streams.isEmpty && listStore.isLoading && listStore.error == null) { + if (widget.listStore.streams.isEmpty && widget.listStore.isLoading && widget.listStore.error == null) { return const LoadingIndicator(subtitle: Text('Loading streams...')); } return Stack( @@ -49,7 +56,7 @@ class CategoryStreams extends StatelessWidget { children: [ CustomScrollView( physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), - controller: listStore.scrollController, + controller: widget.listStore.scrollController, slivers: [ SliverAppBar( stretch: true, @@ -62,14 +69,14 @@ class CategoryStreams extends StatelessWidget { ], centerTitle: true, title: Text( - listStore.categoryInfo!.name, + widget.listStore.categoryInfo!.name, style: Theme.of(context).textTheme.headline6?.copyWith(fontWeight: FontWeight.w800), maxLines: 1, overflow: TextOverflow.ellipsis, ), background: CachedNetworkImage( - imageUrl: listStore.categoryInfo!.boxArtUrl.replaceRange( - listStore.categoryInfo!.boxArtUrl.lastIndexOf('-') + 1, + imageUrl: widget.listStore.categoryInfo!.boxArtUrl.replaceRange( + widget.listStore.categoryInfo!.boxArtUrl.lastIndexOf('-') + 1, null, '${artWidth}x$artHeight.jpg', ), @@ -85,13 +92,13 @@ class CategoryStreams extends StatelessWidget { sliver: SliverList( delegate: SliverChildBuilderDelegate( (context, index) { - if (index > listStore.streams.length / 2 && listStore.hasMore) { - listStore.getStreams(); + if (index > widget.listStore.streams.length / 2 && widget.listStore.hasMore) { + widget.listStore.getStreams(); } return Observer( builder: (context) => StreamCard( - listStore: listStore, - streamInfo: listStore.streams[index], + listStore: widget.listStore, + streamInfo: widget.listStore.streams[index], width: thumbnailWidth, height: thumbnailHeight, showUptime: context.read().showThumbnailUptime, @@ -100,7 +107,7 @@ class CategoryStreams extends StatelessWidget { ), ); }, - childCount: listStore.streams.length, + childCount: widget.listStore.streams.length, ), ), ), @@ -110,7 +117,7 @@ class CategoryStreams extends StatelessWidget { child: Observer( builder: (context) => AnimatedSwitcher( duration: const Duration(milliseconds: 200), - child: listStore.showJumpButton ? ScrollToTopButton(scrollController: listStore.scrollController) : null, + child: widget.listStore.showJumpButton ? ScrollToTopButton(scrollController: widget.listStore.scrollController) : null, ), ), ), diff --git a/lib/screens/home/widgets/stream_card.dart b/lib/screens/home/widgets/stream_card.dart index 8189d932..ee528144 100644 --- a/lib/screens/home/widgets/stream_card.dart +++ b/lib/screens/home/widgets/stream_card.dart @@ -14,7 +14,7 @@ import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; /// A tappable card widget that displays a stream's thumbnail and details. -class StreamCard extends StatelessWidget { +class StreamCard extends StatefulWidget { final ListStore listStore; final StreamTwitch streamInfo; final int width; @@ -34,6 +34,11 @@ class StreamCard extends StatelessWidget { this.showCategory = true, }) : super(key: key); + @override + State createState() => _StreamCardState(); +} + +class _StreamCardState extends State { @override Widget build(BuildContext context) { final time = DateTime.now(); @@ -42,42 +47,44 @@ class StreamCard extends StatelessWidget { final thumbnail = AspectRatio( aspectRatio: 16 / 9, child: CachedNetworkImage( - imageUrl: streamInfo.thumbnailUrl.replaceFirst('-{width}x{height}', '-${width}x$height') + cacheUrlExtension, + imageUrl: widget.streamInfo.thumbnailUrl.replaceFirst('-{width}x{height}', '-${widget.width}x${widget.height}') + cacheUrlExtension, placeholder: (context, url) => const LoadingIndicator(), useOldImageOnUrlChange: true, ), ); - final streamerName = regexEnglish.hasMatch(streamInfo.userName) ? streamInfo.userName : streamInfo.userName + ' (${streamInfo.userLogin})'; + final streamerName = regexEnglish.hasMatch(widget.streamInfo.userName) + ? widget.streamInfo.userName + : '${widget.streamInfo.userName} (${widget.streamInfo.userLogin})'; return InkWell( onTap: () => Navigator.push( context, MaterialPageRoute( builder: (context) => VideoChat( - userId: streamInfo.userId, - userName: streamInfo.userName, - userLogin: streamInfo.userLogin, + userId: widget.streamInfo.userId, + userName: widget.streamInfo.userName, + userLogin: widget.streamInfo.userLogin, ), ), ), onLongPress: () => showModalBottomSheet( context: context, builder: (context) => BlockReportModal( - authStore: listStore.authStore, + authStore: widget.listStore.authStore, name: streamerName, - userLogin: streamInfo.userLogin, - userId: streamInfo.userId, + userLogin: widget.streamInfo.userLogin, + userId: widget.streamInfo.userId, ), ), child: Padding( - padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: showThumbnail ? 15.0 : 5.0), + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: widget.showThumbnail ? 15.0 : 5.0), child: Row( children: [ - if (showThumbnail) + if (widget.showThumbnail) Flexible( flex: 1, - child: showUptime + child: widget.showUptime ? Stack( alignment: AlignmentDirectional.bottomEnd, children: [ @@ -86,7 +93,7 @@ class StreamCard extends StatelessWidget { color: const Color.fromRGBO(0, 0, 0, 0.5), padding: const EdgeInsets.symmetric(horizontal: 2.0), child: Text( - DateTime.now().difference(DateTime.parse(streamInfo.startedAt)).toString().split('.')[0], + DateTime.now().difference(DateTime.parse(widget.streamInfo.startedAt)).toString().split('.')[0], style: const TextStyle(fontSize: 12, color: Colors.white), ), ) @@ -104,7 +111,7 @@ class StreamCard extends StatelessWidget { Row( children: [ ProfilePicture( - userLogin: streamInfo.userLogin, + userLogin: widget.streamInfo.userLogin, radius: 10.0, ), const SizedBox(width: 5.0), @@ -126,25 +133,26 @@ class StreamCard extends StatelessWidget { ), const SizedBox(height: 5.0), Tooltip( - message: streamInfo.title.trim(), + message: widget.streamInfo.title.trim(), preferBelow: false, padding: const EdgeInsets.all(10.0), child: Text( - streamInfo.title.trim(), + widget.streamInfo.title.trim(), overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w500), ), ), const SizedBox(height: 5.0), - if (showCategory) ...[ + if (widget.showCategory) ...[ InkWell( child: Tooltip( - message: streamInfo.gameName, + message: widget.streamInfo.gameName, preferBelow: false, child: Text( - streamInfo.gameName, + widget.streamInfo.gameName, overflow: TextOverflow.ellipsis, style: TextStyle( + fontSize: 12.0, fontWeight: FontWeight.w300, color: DefaultTextStyle.of(context).style.color?.withOpacity(0.8), ), @@ -153,8 +161,9 @@ class StreamCard extends StatelessWidget { onTap: () async { final category = await context .read() - .getCategory(headers: context.read().headersTwitch, gameId: streamInfo.gameId); + .getCategory(headers: context.read().headersTwitch, gameId: widget.streamInfo.gameId); + if (!mounted) return; Navigator.push( context, MaterialPageRoute( @@ -173,7 +182,7 @@ class StreamCard extends StatelessWidget { const SizedBox(height: 5.0), ], Text( - '${NumberFormat().format(streamInfo.viewerCount)} viewers', + '${NumberFormat().format(widget.streamInfo.viewerCount)} viewers', style: TextStyle( fontSize: 12.0, fontWeight: FontWeight.w300, diff --git a/lib/screens/home/widgets/streams_list.dart b/lib/screens/home/widgets/streams_list.dart index 7b9382aa..ff41e64d 100644 --- a/lib/screens/home/widgets/streams_list.dart +++ b/lib/screens/home/widgets/streams_list.dart @@ -22,7 +22,7 @@ class StreamsList extends StatefulWidget { }) : super(key: key); @override - _StreamsListState createState() => _StreamsListState(); + State createState() => _StreamsListState(); } class _StreamsListState extends State with AutomaticKeepAliveClientMixin { @@ -52,6 +52,8 @@ class _StreamsListState extends State with AutomaticKeepAliveClient content: Text(_listStore.error!), behavior: SnackBarBehavior.floating, ); + + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(snackBar); } }, diff --git a/lib/screens/settings/sections/account_settings.dart b/lib/screens/settings/sections/account_settings.dart index 1a11442f..eb8029ae 100644 --- a/lib/screens/settings/sections/account_settings.dart +++ b/lib/screens/settings/sections/account_settings.dart @@ -146,8 +146,8 @@ class ProfileCard extends StatelessWidget { actions: [ TextButton( onPressed: Navigator.of(context).pop, - child: const Text('Cancel'), style: TextButton.styleFrom(primary: Colors.red), + child: const Text('Cancel'), ), ElevatedButton( onPressed: () { @@ -241,7 +241,7 @@ class BlockedUsers extends StatelessWidget { return ListView( children: authStore.user.blockedUsers.map( (user) { - final displayName = regexEnglish.hasMatch(user.displayName) ? user.displayName : user.displayName + ' (${user.userLogin})'; + final displayName = regexEnglish.hasMatch(user.displayName) ? user.displayName : '${user.displayName} (${user.userLogin})'; return ListTile( title: Text(displayName), trailing: BlockButton( diff --git a/lib/screens/settings/sections/chat_settings.dart b/lib/screens/settings/sections/chat_settings.dart index 7bfc2c16..4723b70f 100644 --- a/lib/screens/settings/sections/chat_settings.dart +++ b/lib/screens/settings/sections/chat_settings.dart @@ -11,7 +11,7 @@ class ChatSettings extends StatefulWidget { const ChatSettings({Key? key, required this.settingsStore}) : super(key: key); @override - _ChatSettingsState createState() => _ChatSettingsState(); + State createState() => _ChatSettingsState(); } class _ChatSettingsState extends State { diff --git a/lib/screens/settings/sections/general_settings.dart b/lib/screens/settings/sections/general_settings.dart index bcac6cc5..3e487434 100644 --- a/lib/screens/settings/sections/general_settings.dart +++ b/lib/screens/settings/sections/general_settings.dart @@ -47,6 +47,13 @@ class GeneralSettings extends StatelessWidget { value: settingsStore.showThumbnailUptime, onChanged: settingsStore.showThumbnails ? (newValue) => settingsStore.showThumbnailUptime = newValue : null, ), + SwitchListTile.adaptive( + isThreeLine: true, + title: const Text('Launch URLs in External Browser'), + subtitle: const Text('Opens links in the default external browser.'), + value: settingsStore.launchUrlExternal, + onChanged: (newValue) => settingsStore.launchUrlExternal = newValue, + ), ], ), ); diff --git a/lib/screens/settings/sections/other_settings.dart b/lib/screens/settings/sections/other_settings.dart index 7d8278b2..326da5e1 100644 --- a/lib/screens/settings/sections/other_settings.dart +++ b/lib/screens/settings/sections/other_settings.dart @@ -8,13 +8,19 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; -class OtherSettings extends StatelessWidget { +class OtherSettings extends StatefulWidget { final SettingsStore settingsStore; + const OtherSettings({ Key? key, required this.settingsStore, }) : super(key: key); + @override + State createState() => _OtherSettingsState(); +} + +class _OtherSettingsState extends State { Future _showConfirmDialog(BuildContext context) { return showDialog( context: context, @@ -24,12 +30,12 @@ class OtherSettings extends StatelessWidget { actions: [ TextButton( onPressed: Navigator.of(context).pop, - child: const Text('Cancel'), style: TextButton.styleFrom(primary: Colors.red), + child: const Text('Cancel'), ), ElevatedButton( onPressed: () { - settingsStore.reset(); + widget.settingsStore.reset(); Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( @@ -78,19 +84,20 @@ class OtherSettings extends StatelessWidget { ListTile( leading: const Icon(Icons.launch), title: const Text('FAQ'), - onTap: () => launch('https://github.com/tommyxchow/frosty#faq'), + onTap: () => launchUrl(Uri.parse('https://github.com/tommyxchow/frosty#faq'), + mode: widget.settingsStore.launchUrlExternal ? LaunchMode.externalApplication : LaunchMode.inAppWebView), ), Observer( builder: (_) => SwitchListTile.adaptive( title: const Text('Send Anonymous Crash Logs'), - value: settingsStore.sendCrashLogs, + value: widget.settingsStore.sendCrashLogs, onChanged: (newValue) { if (newValue == true) { SentryFlutter.init((options) => options.tracesSampleRate = sampleRate); } else { Sentry.close(); } - settingsStore.sendCrashLogs = newValue; + widget.settingsStore.sendCrashLogs = newValue; }, ), ), @@ -102,6 +109,8 @@ class OtherSettings extends StatelessWidget { label: const Text('Clear Image Cache'), onPressed: () async { await DefaultCacheManager().emptyCache(); + + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Image cache cleared!'), diff --git a/lib/screens/settings/settings.dart b/lib/screens/settings/settings.dart index cb595322..936fd6f0 100644 --- a/lib/screens/settings/settings.dart +++ b/lib/screens/settings/settings.dart @@ -26,12 +26,14 @@ class Settings extends StatelessWidget { if (Platform.isAndroid) IconButton( tooltip: 'Support the App', - onPressed: () => launch('https://www.buymeacoffee.com/tommychow'), + onPressed: () => launchUrl(Uri.parse('https://www.buymeacoffee.com/tommychow'), + mode: settingsStore.launchUrlExternal ? LaunchMode.externalApplication : LaunchMode.inAppWebView), icon: const FaIcon(FontAwesomeIcons.circleDollarToSlot), ), IconButton( tooltip: 'View Source on GitHub', - onPressed: () => launch('https://github.com/tommyxchow/frosty'), + onPressed: () => launchUrl(Uri.parse('https://github.com/tommyxchow/frosty'), + mode: settingsStore.launchUrlExternal ? LaunchMode.externalApplication : LaunchMode.inAppWebView), icon: const FaIcon(FontAwesomeIcons.github), ), ], diff --git a/lib/screens/settings/stores/settings_store.dart b/lib/screens/settings/stores/settings_store.dart index f26d76dd..10aa31d4 100644 --- a/lib/screens/settings/stores/settings_store.dart +++ b/lib/screens/settings/stores/settings_store.dart @@ -19,6 +19,8 @@ abstract class _SettingsStoreBase with Store { static const defaultShowThumbnails = true; + static const defaultLaunchUrlExternal = false; + @JsonKey(defaultValue: defaultThemeType, unknownEnumValue: ThemeType.system) @observable var themeType = defaultThemeType; @@ -31,6 +33,10 @@ abstract class _SettingsStoreBase with Store { @observable var showThumbnails = defaultShowThumbnails; + @JsonKey(defaultValue: defaultLaunchUrlExternal) + @observable + var launchUrlExternal = defaultLaunchUrlExternal; + // * Video Settings static const defaultShowVideo = true; @@ -155,6 +161,7 @@ abstract class _SettingsStoreBase with Store { themeType = defaultThemeType; showThumbnailUptime = defaultShowThumbnailUptime; showThumbnails = defaultShowThumbnails; + launchUrlExternal = defaultLaunchUrlExternal; // * Video Settings showVideo = defaultShowVideo; diff --git a/lib/screens/settings/stores/settings_store.g.dart b/lib/screens/settings/stores/settings_store.g.dart index 06fcbc08..74d81b66 100644 --- a/lib/screens/settings/stores/settings_store.g.dart +++ b/lib/screens/settings/stores/settings_store.g.dart @@ -13,6 +13,7 @@ SettingsStore _$SettingsStoreFromJson(Map json) => ThemeType.system ..showThumbnailUptime = json['showThumbnailUptime'] as bool? ?? false ..showThumbnails = json['showThumbnails'] as bool? ?? true + ..launchUrlExternal = json['launchUrlExternal'] as bool? ?? false ..showVideo = json['showVideo'] as bool? ?? true ..showOverlay = json['showOverlay'] as bool? ?? true ..toggleableOverlay = json['toggleableOverlay'] as bool? ?? false @@ -42,6 +43,7 @@ Map _$SettingsStoreToJson(SettingsStore instance) => 'themeType': _$ThemeTypeEnumMap[instance.themeType], 'showThumbnailUptime': instance.showThumbnailUptime, 'showThumbnails': instance.showThumbnails, + 'launchUrlExternal': instance.launchUrlExternal, 'showVideo': instance.showVideo, 'showOverlay': instance.showOverlay, 'toggleableOverlay': instance.toggleableOverlay, @@ -80,10 +82,11 @@ const _$TimestampTypeEnumMap = { // StoreGenerator // ************************************************************************** -// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers mixin _$SettingsStore on _SettingsStoreBase, Store { - final _$themeTypeAtom = Atom(name: '_SettingsStoreBase.themeType'); + late final _$themeTypeAtom = + Atom(name: '_SettingsStoreBase.themeType', context: context); @override ThemeType get themeType { @@ -98,8 +101,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showThumbnailUptimeAtom = - Atom(name: '_SettingsStoreBase.showThumbnailUptime'); + late final _$showThumbnailUptimeAtom = + Atom(name: '_SettingsStoreBase.showThumbnailUptime', context: context); @override bool get showThumbnailUptime { @@ -114,7 +117,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showThumbnailsAtom = Atom(name: '_SettingsStoreBase.showThumbnails'); + late final _$showThumbnailsAtom = + Atom(name: '_SettingsStoreBase.showThumbnails', context: context); @override bool get showThumbnails { @@ -129,7 +133,24 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showVideoAtom = Atom(name: '_SettingsStoreBase.showVideo'); + late final _$launchUrlExternalAtom = + Atom(name: '_SettingsStoreBase.launchUrlExternal', context: context); + + @override + bool get launchUrlExternal { + _$launchUrlExternalAtom.reportRead(); + return super.launchUrlExternal; + } + + @override + set launchUrlExternal(bool value) { + _$launchUrlExternalAtom.reportWrite(value, super.launchUrlExternal, () { + super.launchUrlExternal = value; + }); + } + + late final _$showVideoAtom = + Atom(name: '_SettingsStoreBase.showVideo', context: context); @override bool get showVideo { @@ -144,7 +165,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showOverlayAtom = Atom(name: '_SettingsStoreBase.showOverlay'); + late final _$showOverlayAtom = + Atom(name: '_SettingsStoreBase.showOverlay', context: context); @override bool get showOverlay { @@ -159,8 +181,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$toggleableOverlayAtom = - Atom(name: '_SettingsStoreBase.toggleableOverlay'); + late final _$toggleableOverlayAtom = + Atom(name: '_SettingsStoreBase.toggleableOverlay', context: context); @override bool get toggleableOverlay { @@ -175,8 +197,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$pictureInPictureAtom = - Atom(name: '_SettingsStoreBase.pictureInPicture'); + late final _$pictureInPictureAtom = + Atom(name: '_SettingsStoreBase.pictureInPicture', context: context); @override bool get pictureInPicture { @@ -191,7 +213,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showBottomBarAtom = Atom(name: '_SettingsStoreBase.showBottomBar'); + late final _$showBottomBarAtom = + Atom(name: '_SettingsStoreBase.showBottomBar', context: context); @override bool get showBottomBar { @@ -206,8 +229,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showDeletedMessagesAtom = - Atom(name: '_SettingsStoreBase.showDeletedMessages'); + late final _$showDeletedMessagesAtom = + Atom(name: '_SettingsStoreBase.showDeletedMessages', context: context); @override bool get showDeletedMessages { @@ -222,7 +245,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showZeroWidthAtom = Atom(name: '_SettingsStoreBase.showZeroWidth'); + late final _$showZeroWidthAtom = + Atom(name: '_SettingsStoreBase.showZeroWidth', context: context); @override bool get showZeroWidth { @@ -237,8 +261,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$showChatMessageDividersAtom = - Atom(name: '_SettingsStoreBase.showChatMessageDividers'); + late final _$showChatMessageDividersAtom = Atom( + name: '_SettingsStoreBase.showChatMessageDividers', context: context); @override bool get showChatMessageDividers { @@ -254,7 +278,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$timestampTypeAtom = Atom(name: '_SettingsStoreBase.timestampType'); + late final _$timestampTypeAtom = + Atom(name: '_SettingsStoreBase.timestampType', context: context); @override TimestampType get timestampType { @@ -269,8 +294,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$useReadableColorsAtom = - Atom(name: '_SettingsStoreBase.useReadableColors'); + late final _$useReadableColorsAtom = + Atom(name: '_SettingsStoreBase.useReadableColors', context: context); @override bool get useReadableColors { @@ -285,7 +310,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$fontSizeAtom = Atom(name: '_SettingsStoreBase.fontSize'); + late final _$fontSizeAtom = + Atom(name: '_SettingsStoreBase.fontSize', context: context); @override double get fontSize { @@ -300,7 +326,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$messageSpacingAtom = Atom(name: '_SettingsStoreBase.messageSpacing'); + late final _$messageSpacingAtom = + Atom(name: '_SettingsStoreBase.messageSpacing', context: context); @override double get messageSpacing { @@ -315,7 +342,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$messageScaleAtom = Atom(name: '_SettingsStoreBase.messageScale'); + late final _$messageScaleAtom = + Atom(name: '_SettingsStoreBase.messageScale', context: context); @override double get messageScale { @@ -330,7 +358,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$badgeScaleAtom = Atom(name: '_SettingsStoreBase.badgeScale'); + late final _$badgeScaleAtom = + Atom(name: '_SettingsStoreBase.badgeScale', context: context); @override double get badgeScale { @@ -345,7 +374,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$emoteScaleAtom = Atom(name: '_SettingsStoreBase.emoteScale'); + late final _$emoteScaleAtom = + Atom(name: '_SettingsStoreBase.emoteScale', context: context); @override double get emoteScale { @@ -360,8 +390,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$emoteAutocompleteAtom = - Atom(name: '_SettingsStoreBase.emoteAutocomplete'); + late final _$emoteAutocompleteAtom = + Atom(name: '_SettingsStoreBase.emoteAutocomplete', context: context); @override bool get emoteAutocomplete { @@ -376,7 +406,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$sendCrashLogsAtom = Atom(name: '_SettingsStoreBase.sendCrashLogs'); + late final _$sendCrashLogsAtom = + Atom(name: '_SettingsStoreBase.sendCrashLogs', context: context); @override bool get sendCrashLogs { @@ -391,7 +422,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$fullScreenAtom = Atom(name: '_SettingsStoreBase.fullScreen'); + late final _$fullScreenAtom = + Atom(name: '_SettingsStoreBase.fullScreen', context: context); @override bool get fullScreen { @@ -406,7 +438,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$expandInfoAtom = Atom(name: '_SettingsStoreBase.expandInfo'); + late final _$expandInfoAtom = + Atom(name: '_SettingsStoreBase.expandInfo', context: context); @override bool get expandInfo { @@ -421,8 +454,8 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - final _$_SettingsStoreBaseActionController = - ActionController(name: '_SettingsStoreBase'); + late final _$_SettingsStoreBaseActionController = + ActionController(name: '_SettingsStoreBase', context: context); @override void reset() { @@ -441,6 +474,7 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { themeType: ${themeType}, showThumbnailUptime: ${showThumbnailUptime}, showThumbnails: ${showThumbnails}, +launchUrlExternal: ${launchUrlExternal}, showVideo: ${showVideo}, showOverlay: ${showOverlay}, toggleableOverlay: ${toggleableOverlay}, diff --git a/lib/widgets/block_button.dart b/lib/widgets/block_button.dart index 7b727feb..6b4ee7a5 100644 --- a/lib/widgets/block_button.dart +++ b/lib/widgets/block_button.dart @@ -31,8 +31,8 @@ class BlockButton extends StatelessWidget { actions: [ TextButton( onPressed: Navigator.of(context).pop, - child: const Text('Cancel'), style: TextButton.styleFrom(primary: Colors.red), + child: const Text('Cancel'), ), ElevatedButton( onPressed: () { diff --git a/lib/widgets/scroll_to_top_button.dart b/lib/widgets/scroll_to_top_button.dart index 13a34721..026f57ca 100644 --- a/lib/widgets/scroll_to_top_button.dart +++ b/lib/widgets/scroll_to_top_button.dart @@ -20,9 +20,9 @@ class ScrollToTopButton extends StatelessWidget { duration: const Duration(milliseconds: 500), ); }, - child: const Icon(Icons.keyboard_arrow_up), mini: true, heroTag: null, + child: const Icon(Icons.keyboard_arrow_up), ), ); } diff --git a/pubspec.lock b/pubspec.lock index c41c83c1..eb5371cc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "38.0.0" + version: "40.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "3.4.1" + version: "4.1.0" archive: dependency: transitive description: @@ -28,7 +28,7 @@ packages: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" async: dependency: transitive description: @@ -49,7 +49,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.3.0" build_config: dependency: transitive description: @@ -63,21 +63,21 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.6" + version: "2.0.8" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.8" + version: "2.1.11" build_runner_core: dependency: transitive description: @@ -98,14 +98,14 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.1.4" + version: "8.3.0" cached_network_image: dependency: "direct main" description: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: @@ -156,12 +156,12 @@ packages: source: hosted version: "4.1.0" collection: - dependency: transitive + dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" convert: dependency: transitive description: @@ -175,7 +175,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" cupertino_icons: dependency: "direct main" description: @@ -189,21 +189,21 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "2.2.3" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.2.1" file: dependency: transitive description: @@ -217,7 +217,7 @@ packages: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" flutter: dependency: "direct main" description: flutter @@ -229,9 +229,9 @@ packages: name: flutter_blurhash url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.7.0" flutter_cache_manager: - dependency: transitive + dependency: "direct main" description: name: flutter_cache_manager url: "https://pub.dartlang.org" @@ -250,21 +250,21 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_mobx: dependency: "direct main" description: name: flutter_mobx url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.6+1" flutter_native_splash: dependency: "direct dev" description: name: flutter_native_splash url: "https://pub.dartlang.org" source: hosted - version: "2.1.3+1" + version: "2.2.0+1" flutter_secure_storage: dependency: "direct main" description: @@ -344,7 +344,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" glob: dependency: transitive description: @@ -379,7 +379,7 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" image: dependency: transitive description: @@ -407,28 +407,35 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: "direct main" description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.5.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.1.5" + version: "6.2.0" + lint: + dependency: transitive + description: + name: lint + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.2" lints: dependency: transitive description: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" logging: dependency: transitive description: @@ -449,7 +456,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -463,21 +470,21 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" mobx: dependency: "direct main" description: name: mobx url: "https://pub.dartlang.org" source: hosted - version: "2.0.6+1" + version: "2.0.7+2" mobx_codegen: dependency: "direct dev" description: name: mobx_codegen url: "https://pub.dartlang.org" source: hosted - version: "2.0.5+2" + version: "2.0.7" nested: dependency: transitive description: @@ -491,7 +498,7 @@ packages: name: octo_image url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" package_config: dependency: transitive description: @@ -547,7 +554,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_drawing: dependency: transitive description: @@ -568,49 +575,49 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" path_provider_android: dependency: transitive description: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.12" + version: "2.0.14" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.9" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "2.1.6" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" pedantic: dependency: transitive description: @@ -624,7 +631,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "5.0.0" platform: dependency: transitive description: @@ -659,7 +666,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.2" + version: "6.0.3" pub_semver: dependency: transitive description: @@ -680,7 +687,7 @@ packages: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "3.0.1+1" + version: "3.1.0" rxdart: dependency: transitive description: @@ -694,49 +701,49 @@ packages: name: sentry url: "https://pub.dartlang.org" source: hosted - version: "6.4.0" + version: "6.5.1" sentry_flutter: dependency: "direct main" description: name: sentry_flutter url: "https://pub.dartlang.org" source: hosted - version: "6.4.0" + version: "6.5.1" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "2.0.15" shared_preferences_android: dependency: transitive description: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: @@ -750,14 +757,14 @@ packages: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" shelf: dependency: transitive description: @@ -783,35 +790,35 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.2" source_helper: dependency: transitive description: name: source_helper url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.2" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" sqflite: dependency: transitive description: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.2+1" sqflite_common: dependency: transitive description: name: sqflite_common url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.2.1+1" stack_trace: dependency: transitive description: @@ -860,7 +867,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" timing: dependency: transitive description: @@ -881,7 +888,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" universal_io: dependency: transitive description: @@ -895,35 +902,35 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.0.20" + version: "6.1.2" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.15" + version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.15" + version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: @@ -937,14 +944,14 @@ packages: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.11" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" uuid: dependency: transitive description: @@ -958,7 +965,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" watcher: dependency: transitive description: @@ -972,42 +979,42 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" webview_flutter: dependency: "direct main" description: name: webview_flutter url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.0.4" webview_flutter_android: dependency: transitive description: name: webview_flutter_android url: "https://pub.dartlang.org" source: hosted - version: "2.8.5" + version: "2.8.8" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.9.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview url: "https://pub.dartlang.org" source: hosted - version: "2.7.2" + version: "2.7.5" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.5.1" + version: "2.6.1" xdg_directories: dependency: transitive description: @@ -1021,14 +1028,14 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.3.1" + version: "5.4.1" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.16.0 <3.0.0" - flutter: ">=2.10.0" + dart: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index ec753df3..d8da18c6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,7 +29,7 @@ environment: dependencies: flutter: sdk: flutter - json_annotation: ^4.4.0 + json_annotation: ^4.5.0 # The following adds the Cupertino Icons font to your application. @@ -52,6 +52,8 @@ dependencies: url_launcher: ^6.0.17 font_awesome_flutter: ^10.0.0 package_info_plus: ^1.3.0 + collection: ^1.16.0 + flutter_cache_manager: ^3.3.0 dev_dependencies: flutter_test: @@ -62,10 +64,10 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.1 build_runner: ^2.1.1 json_serializable: ^6.0.0 - mobx_codegen: ^2.0.0 + mobx_codegen: ^2.0.6 flutter_native_splash: ^2.0.5 flutter_launcher_icons: "^0.9.2" diff --git a/web/favicon.png b/web/favicon.png deleted file mode 100644 index 8aaa46ac..00000000 Binary files a/web/favicon.png and /dev/null differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png deleted file mode 100644 index b749bfef..00000000 Binary files a/web/icons/Icon-192.png and /dev/null differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48d..00000000 Binary files a/web/icons/Icon-512.png and /dev/null differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76..00000000 Binary files a/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c5669..00000000 Binary files a/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/web/index.html b/web/index.html deleted file mode 100644 index 571372ef..00000000 --- a/web/index.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - frosty - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/web/manifest.json b/web/manifest.json deleted file mode 100644 index ee44ff5c..00000000 --- a/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "frosty", - "short_name": "frosty", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/web/splash/img/dark-1x.png b/web/splash/img/dark-1x.png deleted file mode 100644 index 65e45c48..00000000 Binary files a/web/splash/img/dark-1x.png and /dev/null differ diff --git a/web/splash/img/dark-2x.png b/web/splash/img/dark-2x.png deleted file mode 100644 index b45507c1..00000000 Binary files a/web/splash/img/dark-2x.png and /dev/null differ diff --git a/web/splash/img/dark-3x.png b/web/splash/img/dark-3x.png deleted file mode 100644 index d56cc8fd..00000000 Binary files a/web/splash/img/dark-3x.png and /dev/null differ diff --git a/web/splash/img/dark-4x.png b/web/splash/img/dark-4x.png deleted file mode 100644 index b65f0d82..00000000 Binary files a/web/splash/img/dark-4x.png and /dev/null differ diff --git a/web/splash/img/light-1x.png b/web/splash/img/light-1x.png deleted file mode 100644 index 65e45c48..00000000 Binary files a/web/splash/img/light-1x.png and /dev/null differ diff --git a/web/splash/img/light-2x.png b/web/splash/img/light-2x.png deleted file mode 100644 index b45507c1..00000000 Binary files a/web/splash/img/light-2x.png and /dev/null differ diff --git a/web/splash/img/light-3x.png b/web/splash/img/light-3x.png deleted file mode 100644 index d56cc8fd..00000000 Binary files a/web/splash/img/light-3x.png and /dev/null differ diff --git a/web/splash/img/light-4x.png b/web/splash/img/light-4x.png deleted file mode 100644 index b65f0d82..00000000 Binary files a/web/splash/img/light-4x.png and /dev/null differ diff --git a/web/splash/img/light-background.png b/web/splash/img/light-background.png deleted file mode 100644 index ca2302e0..00000000 Binary files a/web/splash/img/light-background.png and /dev/null differ diff --git a/web/splash/splash.js b/web/splash/splash.js deleted file mode 100644 index 898c454f..00000000 --- a/web/splash/splash.js +++ /dev/null @@ -1,7 +0,0 @@ -function removeSplashFromWeb() { - const elem = document.getElementById("splash"); - if (elem) { - elem.remove(); - } - document.body.style.background = "transparent"; -} diff --git a/web/splash/style.css b/web/splash/style.css deleted file mode 100644 index deae8fc0..00000000 --- a/web/splash/style.css +++ /dev/null @@ -1,43 +0,0 @@ -body { - margin:0; - height:100%; - background: #000000; - background-image: url("img/light-background.png"); - background-size: 100% 100%; -} - -.center { - margin: 0; - position: absolute; - top: 50%; - left: 50%; - -ms-transform: translate(-50%, -50%); - transform: translate(-50%, -50%); -} - -.contain { - display:block; - width:100%; height:100%; - object-fit: contain; -} - -.stretch { - display:block; - width:100%; height:100%; -} - -.cover { - display:block; - width:100%; height:100%; - object-fit: cover; -} - -@media (prefers-color-scheme: dark) { - body { - margin:0; - height:100%; - background: #000000; - background-image: url("img/dark-background.png"); - background-size: 100% 100%; - } -}