Merge pull request #117 from tommyxchow/113-flutter-3
Upgrade to Flutter 3
1
.gitignore
vendored
|
|
@ -8,6 +8,7 @@
|
|||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath 'com.android.tools.build:gradle:7.1.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ PODS:
|
|||
- Flutter
|
||||
- path_provider_ios (0.0.1):
|
||||
- Flutter
|
||||
- Sentry (7.10.2):
|
||||
- Sentry/Core (= 7.10.2)
|
||||
- Sentry/Core (7.10.2)
|
||||
- Sentry (7.11.0):
|
||||
- Sentry/Core (= 7.11.0)
|
||||
- Sentry/Core (7.11.0)
|
||||
- sentry_flutter (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Sentry (~> 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
|
||||
|
|
|
|||
|
|
@ -52,5 +52,7 @@
|
|||
<true/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Map<String, String>>? _$headersTwitchComputed;
|
||||
|
||||
@override
|
||||
Map<String, String> get headersTwitch => (_$headersTwitchComputed ??=
|
||||
Computed<Map<String, String>>(() => 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<void> init() {
|
||||
return _$initAsyncAction.run(() => super.init());
|
||||
}
|
||||
|
||||
final _$loginAsyncAction = AsyncAction('_AuthBase.login');
|
||||
late final _$loginAsyncAction =
|
||||
AsyncAction('AuthBase.login', context: context);
|
||||
|
||||
@override
|
||||
Future<void> 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<void> logout() {
|
||||
|
|
|
|||
|
|
@ -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<void> init({required Map<String, String> headers}) async {
|
||||
|
|
|
|||
|
|
@ -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<UserBlockedTwitch> 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<void> init({required Map<String, String> headers}) {
|
||||
return _$initAsyncAction.run(() => super.init(headers: headers));
|
||||
}
|
||||
|
||||
final _$blockAsyncAction = AsyncAction('_UserStoreBase.block');
|
||||
late final _$blockAsyncAction =
|
||||
AsyncAction('UserStoreBase.block', context: context);
|
||||
|
||||
@override
|
||||
Future<void> 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<void> 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<void> refreshBlockedUsers({required Map<String, String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class ChattersList extends StatefulWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ChattersListState createState() => _ChattersListState();
|
||||
State<ChattersList> createState() => _ChattersListState();
|
||||
}
|
||||
|
||||
class _ChattersListState extends State<ChattersList> {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ class _RecentEmotesPanelState extends State<RecentEmotesPanel> {
|
|||
actions: [
|
||||
TextButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
child: const Text('Cancel'),
|
||||
style: TextButton.styleFrom(primary: Colors.red),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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<ChatUserModal> createState() => _ChatUserModalState();
|
||||
}
|
||||
|
||||
class _ChatUserModalState extends State<ChatUserModal> {
|
||||
@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,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<List<Emote>>? _$bttvEmotesComputed;
|
||||
|
||||
@override
|
||||
List<Emote> get bttvEmotes =>
|
||||
(_$bttvEmotesComputed ??= Computed<List<Emote>>(() => super.bttvEmotes,
|
||||
name: '_ChatAssetsStoreBase.bttvEmotes'))
|
||||
name: 'ChatAssetsStoreBase.bttvEmotes'))
|
||||
.value;
|
||||
Computed<List<Emote>>? _$ffzEmotesComputed;
|
||||
|
||||
@override
|
||||
List<Emote> get ffzEmotes =>
|
||||
(_$ffzEmotesComputed ??= Computed<List<Emote>>(() => super.ffzEmotes,
|
||||
name: '_ChatAssetsStoreBase.ffzEmotes'))
|
||||
name: 'ChatAssetsStoreBase.ffzEmotes'))
|
||||
.value;
|
||||
Computed<List<Emote>>? _$sevenTVEmotesComputed;
|
||||
|
||||
@override
|
||||
List<Emote> get sevenTVEmotes => (_$sevenTVEmotesComputed ??=
|
||||
Computed<List<Emote>>(() => 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<Emote> 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<String, Emote> 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<String, Emote> 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<String, List<Badge>> 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<String, List<Badge>> 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<String, Badge> 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,15 +171,16 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
final _$initAsyncAction = AsyncAction('_ChatAssetsStoreBase.init');
|
||||
late final _$initAsyncAction =
|
||||
AsyncAction('ChatAssetsStoreBase.init', context: context);
|
||||
|
||||
@override
|
||||
Future<void> init() {
|
||||
return _$initAsyncAction.run(() => super.init());
|
||||
}
|
||||
|
||||
final _$_ChatAssetsStoreBaseActionController =
|
||||
ActionController(name: '_ChatAssetsStoreBase');
|
||||
late final _$ChatAssetsStoreBaseActionController =
|
||||
ActionController(name: 'ChatAssetsStoreBase', context: context);
|
||||
|
||||
@override
|
||||
Future<void> assetsFuture(
|
||||
|
|
@ -186,8 +189,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
required Map<String, String> 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,
|
||||
|
|
@ -196,7 +199,7 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
onEmoteError: onEmoteError,
|
||||
onBadgeError: onBadgeError);
|
||||
} finally {
|
||||
_$_ChatAssetsStoreBaseActionController.endAction(_$actionInfo);
|
||||
_$ChatAssetsStoreBaseActionController.endAction(_$actionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,8 +209,8 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
required String channelName,
|
||||
required Map<String, String> headers,
|
||||
required Function onError}) {
|
||||
final _$actionInfo = _$_ChatAssetsStoreBaseActionController.startAction(
|
||||
name: '_ChatAssetsStoreBase.emotesFuture');
|
||||
final _$actionInfo = _$ChatAssetsStoreBaseActionController.startAction(
|
||||
name: 'ChatAssetsStoreBase.emotesFuture');
|
||||
try {
|
||||
return super.emotesFuture(
|
||||
channelId: channelId,
|
||||
|
|
@ -215,7 +218,7 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
headers: headers,
|
||||
onError: onError);
|
||||
} finally {
|
||||
_$_ChatAssetsStoreBaseActionController.endAction(_$actionInfo);
|
||||
_$ChatAssetsStoreBaseActionController.endAction(_$actionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,13 +227,13 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
{required String channelId,
|
||||
required Map<String, String> 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 +242,13 @@ mixin _$ChatAssetsStore on _ChatAssetsStoreBase, Store {
|
|||
{required List<String> emoteSets,
|
||||
required Map<String, String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<void> updateChatters(String userLogin) async {
|
||||
|
|
|
|||
|
|
@ -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<Iterable<List<String>>>? _$filteredUsersComputed;
|
||||
|
||||
@override
|
||||
Iterable<List<String>> get filteredUsers => (_$filteredUsersComputed ??=
|
||||
Computed<Iterable<List<String>>>(() => 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<void> updateChatters(String userLogin) {
|
||||
|
|
|
|||
|
|
@ -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 = <ReactionDisposer>[];
|
||||
|
||||
_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);
|
||||
});
|
||||
}
|
||||
|
|
@ -237,7 +236,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 +309,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 +323,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 +332,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
|
||||
|
|
|
|||
|
|
@ -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<IRCMessage> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<String>? _$videoUrlComputed;
|
||||
|
||||
@override
|
||||
String get videoUrl =>
|
||||
(_$videoUrlComputed ??= Computed<String>(() => 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<void> updateStreamInfo() {
|
||||
return _$updateStreamInfoAsyncAction.run(() => super.updateStreamInfo());
|
||||
}
|
||||
|
||||
final _$handleToggleOverlayAsyncAction =
|
||||
AsyncAction('_VideoStoreBase.handleToggleOverlay');
|
||||
late final _$handleToggleOverlayAsyncAction =
|
||||
AsyncAction('VideoStoreBase.handleToggleOverlay', context: context);
|
||||
|
||||
@override
|
||||
Future<void> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,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(
|
||||
|
|
@ -176,7 +176,7 @@ class VideoOverlay extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
final streamerName = regexEnglish.hasMatch(streamInfo.userName) ? streamInfo.userName : streamInfo.userName + ' (${streamInfo.userLogin})';
|
||||
final streamerName = regexEnglish.hasMatch(streamInfo.userName) ? streamInfo.userName : '${streamInfo.userName} (${streamInfo.userLogin})';
|
||||
|
||||
final streamer = Row(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -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<VideoChat> createState() => _VideoChatState();
|
||||
}
|
||||
|
||||
class _VideoChatState extends State<VideoChat> {
|
||||
|
|
@ -124,7 +123,7 @@ class _VideoChatState extends State<VideoChat> {
|
|||
|
||||
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<VideoChat> {
|
|||
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);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Search extends StatefulWidget {
|
|||
const Search({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_SearchState createState() => _SearchState();
|
||||
State<Search> createState() => _SearchState();
|
||||
}
|
||||
|
||||
class _SearchState extends State<Search> {
|
||||
|
|
|
|||
|
|
@ -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<SearchResultsChannels> createState() => _SearchResultsChannelsState();
|
||||
}
|
||||
|
||||
class _SearchResultsChannelsState extends State<SearchResultsChannels> {
|
||||
Future<void> _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<ChannelQuery>)
|
||||
.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),
|
||||
)
|
||||
]),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<CategoryTwitch> 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<void> getCategories() {
|
||||
return _$getCategoriesAsyncAction.run(() => super.getCategories());
|
||||
}
|
||||
|
||||
final _$_CategoriesStoreBaseActionController =
|
||||
ActionController(name: '_CategoriesStoreBase');
|
||||
late final _$CategoriesStoreBaseActionController =
|
||||
ActionController(name: 'CategoriesStoreBase', context: context);
|
||||
|
||||
@override
|
||||
Future<void> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<ObservableList<StreamTwitch>>? _$streamsComputed;
|
||||
|
||||
@override
|
||||
ObservableList<StreamTwitch> get streams => (_$streamsComputed ??=
|
||||
Computed<ObservableList<StreamTwitch>>(() => 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<StreamTwitch> 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<void> getStreams() {
|
||||
return _$getStreamsAsyncAction.run(() => super.getStreams());
|
||||
}
|
||||
|
||||
final _$_ListStoreBaseActionController =
|
||||
ActionController(name: '_ListStoreBase');
|
||||
late final _$ListStoreBaseActionController =
|
||||
ActionController(name: 'ListStoreBase', context: context);
|
||||
|
||||
@override
|
||||
Future<void> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<CategoriesTwitch?>? _categoryFuture;
|
||||
|
||||
_SearchStoreBase({required this.authStore, required this.twitchApi}) {
|
||||
SearchStoreBase({required this.authStore, required this.twitchApi}) {
|
||||
init();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String> 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<List<ChannelQuery>>? 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<CategoriesTwitch?>? 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<void> init() {
|
||||
return _$initAsyncAction.run(() => super.init());
|
||||
}
|
||||
|
||||
final _$handleQueryAsyncAction = AsyncAction('_SearchStoreBase.handleQuery');
|
||||
late final _$handleQueryAsyncAction =
|
||||
AsyncAction('SearchStoreBase.handleQuery', context: context);
|
||||
|
||||
@override
|
||||
Future<void> handleQuery(String query) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Categories extends StatefulWidget {
|
|||
const Categories({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_CategoriesState createState() => _CategoriesState();
|
||||
State<Categories> createState() => _CategoriesState();
|
||||
}
|
||||
|
||||
class _CategoriesState extends State<Categories> with AutomaticKeepAliveClientMixin {
|
||||
|
|
@ -42,6 +42,8 @@ class _CategoriesState extends State<Categories> with AutomaticKeepAliveClientMi
|
|||
content: Text(_categoriesStore.error!),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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<CategoryStreams> createState() => _CategoryStreamsState();
|
||||
}
|
||||
|
||||
class _CategoryStreamsState extends State<CategoryStreams> {
|
||||
@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<SettingsStore>().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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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<StreamCard> createState() => _StreamCardState();
|
||||
}
|
||||
|
||||
class _StreamCardState extends State<StreamCard> {
|
||||
@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,23 +133,23 @@ 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,
|
||||
|
|
@ -154,8 +161,9 @@ class StreamCard extends StatelessWidget {
|
|||
onTap: () async {
|
||||
final category = await context
|
||||
.read<TwitchApi>()
|
||||
.getCategory(headers: context.read<AuthStore>().headersTwitch, gameId: streamInfo.gameId);
|
||||
.getCategory(headers: context.read<AuthStore>().headersTwitch, gameId: widget.streamInfo.gameId);
|
||||
|
||||
if (!mounted) return;
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
|
|
@ -174,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,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class StreamsList extends StatefulWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_StreamsListState createState() => _StreamsListState();
|
||||
State<StreamsList> createState() => _StreamsListState();
|
||||
}
|
||||
|
||||
class _StreamsListState extends State<StreamsList> with AutomaticKeepAliveClientMixin {
|
||||
|
|
@ -52,6 +52,8 @@ class _StreamsListState extends State<StreamsList> with AutomaticKeepAliveClient
|
|||
content: Text(_listStore.error!),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class ChatSettings extends StatefulWidget {
|
|||
const ChatSettings({Key? key, required this.settingsStore}) : super(key: key);
|
||||
|
||||
@override
|
||||
_ChatSettingsState createState() => _ChatSettingsState();
|
||||
State<ChatSettings> createState() => _ChatSettingsState();
|
||||
}
|
||||
|
||||
class _ChatSettingsState extends State<ChatSettings> {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,13 @@ class GeneralSettings extends StatelessWidget {
|
|||
.toList(),
|
||||
),
|
||||
),
|
||||
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,
|
||||
),
|
||||
SwitchListTile.adaptive(
|
||||
title: const Text('Stream Card Thumbnails'),
|
||||
value: settingsStore.showThumbnails,
|
||||
|
|
|
|||
|
|
@ -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<OtherSettings> createState() => _OtherSettingsState();
|
||||
}
|
||||
|
||||
class _OtherSettingsState extends State<OtherSettings> {
|
||||
Future<void> _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!'),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ SettingsStore _$SettingsStoreFromJson(Map<String, dynamic> 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<String, dynamic> _$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},
|
||||
|
|
|
|||
|
|
@ -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: () {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
161
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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
BIN
web/favicon.png
|
Before Width: | Height: | Size: 917 B |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 20 KiB |
112
web/index.html
|
|
@ -1,112 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
|
||||
The path provided below has to start and end with a slash "/" in order for
|
||||
it to work correctly.
|
||||
|
||||
For more details:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||
|
||||
This is a placeholder for base href that will be replaced by the value of
|
||||
the `--base-href` argument provided to `flutter build`.
|
||||
-->
|
||||
<base href="$FLUTTER_BASE_HREF">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="A new Flutter project.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="frosty">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>frosty</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" type="text/css" href="splash/style.css">
|
||||
<script src="splash/splash.js"></script>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||
</head>
|
||||
<body>
|
||||
<picture id="splash">
|
||||
<source srcset="splash/img/light-1x.png 1x, splash/img/light-2x.png 2x, splash/img/light-3x.png 3x, splash/img/light-4x.png 4x" media="(prefers-color-scheme: light)">
|
||||
<source srcset="splash/img/dark-1x.png 1x, splash/img/dark-2x.png 2x, splash/img/dark-3x.png 3x, splash/img/dark-4x.png 4x" media="(prefers-color-scheme: dark)">
|
||||
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" />
|
||||
</picture>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
var serviceWorkerVersion = null;
|
||||
var scriptLoaded = false;
|
||||
function loadMainDartJs() {
|
||||
if (scriptLoaded) {
|
||||
return;
|
||||
}
|
||||
scriptLoaded = true;
|
||||
var scriptTag = document.createElement('script');
|
||||
scriptTag.src = 'main.dart.js';
|
||||
scriptTag.type = 'application/javascript';
|
||||
document.body.append(scriptTag);
|
||||
}
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
// Service workers are supported. Use them.
|
||||
window.addEventListener('load', function () {
|
||||
// Wait for registration to finish before dropping the <script> tag.
|
||||
// Otherwise, the browser will load the script multiple times,
|
||||
// potentially different versions.
|
||||
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
|
||||
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||
.then((reg) => {
|
||||
function waitForActivation(serviceWorker) {
|
||||
serviceWorker.addEventListener('statechange', () => {
|
||||
if (serviceWorker.state == 'activated') {
|
||||
console.log('Installed new service worker.');
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||
// No active web worker and we have installed or are installing
|
||||
// one for the first time. Simply wait for it to activate.
|
||||
waitForActivation(reg.installing || reg.waiting);
|
||||
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||
// When the app updates the serviceWorkerVersion changes, so we
|
||||
// need to ask the service worker to update.
|
||||
console.log('New service worker available.');
|
||||
reg.update();
|
||||
waitForActivation(reg.installing);
|
||||
} else {
|
||||
// Existing service worker is still good.
|
||||
console.log('Loading app from service worker.');
|
||||
loadMainDartJs();
|
||||
}
|
||||
});
|
||||
|
||||
// If service worker doesn't succeed in a reasonable amount of time,
|
||||
// fallback to plaint <script> tag.
|
||||
setTimeout(() => {
|
||||
if (!scriptLoaded) {
|
||||
console.warn(
|
||||
'Failed to load app from service worker. Falling back to plain <script> tag.',
|
||||
);
|
||||
loadMainDartJs();
|
||||
}
|
||||
}, 4000);
|
||||
});
|
||||
} else {
|
||||
// Service workers not supported. Just drop the <script> tag.
|
||||
loadMainDartJs();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
|
@ -1,7 +0,0 @@
|
|||
function removeSplashFromWeb() {
|
||||
const elem = document.getElementById("splash");
|
||||
if (elem) {
|
||||
elem.remove();
|
||||
}
|
||||
document.body.style.background = "transparent";
|
||||
}
|
||||
|
|
@ -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%;
|
||||
}
|
||||
}
|
||||