diff --git a/android/app/build.gradle b/android/app/build.gradle index 87a6244..6c91c85 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 + compileSdkVersion 34 ndkVersion flutter.ndkVersion compileOptions { diff --git a/android/build.gradle b/android/build.gradle index 3cdaac9..f475bc5 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.9.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.2' + classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 4601702..981076a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -157,7 +157,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a..a6b826d 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ {}; -final _useVideoPlayer = kIsWeb; +const _useVideoPlayer = kIsWeb; final _useMediaKit = Platform.isAndroid || Platform.isIOS || Platform.isWindows || diff --git a/lib/controls/audio_video/media_kit_av_control.dart b/lib/controls/audio_video/media_kit_av_control.dart index 2907bf9..73d868b 100644 --- a/lib/controls/audio_video/media_kit_av_control.dart +++ b/lib/controls/audio_video/media_kit_av_control.dart @@ -29,26 +29,17 @@ class _MediaKitAvControlState extends State { ), ); VideoController? controller; - var needToOpen = true; - var playing = false; @override void initState() { super.initState(); - Future.microtask(() async { - _logger.info('initializing'); - controller = await VideoController.create(player); - _logger.info('initialized'); - if (context.mounted) { - setState(() {}); - } - }); + controller = VideoController(player); + player.open(Media(widget.videoUrl), play: false); } @override void dispose() { Future.microtask(() async { - await controller?.dispose(); await player.dispose(); }); super.dispose(); @@ -57,50 +48,16 @@ class _MediaKitAvControlState extends State { @override void deactivate() { player.pause(); - playing = false; super.deactivate(); } - Future toggleVideoPlay() async { - _logger.fine('Toggling play on: ${widget.videoUrl}'); - if (needToOpen) { - await player.open(Media(widget.videoUrl), play: false); - needToOpen = false; - } - if (playing) { - await player.pause(); - playing = false; - } else { - await player.play(); - playing = true; - } - setState(() {}); - } - - void resetPlay() async { - if (playing) { - await player.pause(); - } - - await player.seek(Duration.zero); - - if (playing) { - playing = false; - await player.play(); - playing = true; - } - - setState(() {}); - } - double? get height => widget.height == null ? null : widget.height! - 50; double? get width => widget.width; @override Widget build(BuildContext context) { - _logger.finer( - 'Building MediaKit Control playing? $playing for ${widget.videoUrl}'); + _logger.finer('Building MediaKit Control for ${widget.videoUrl}'); if (controller == null) { return Container( width: widget.width, @@ -117,39 +74,16 @@ class _MediaKitAvControlState extends State { } return GestureDetector( - onTap: toggleVideoPlay, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Video( - controller: controller, + controller: controller!, width: width, height: height, ), ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - icon: playing - ? const Icon(Icons.pause) - : const Icon(Icons.play_arrow), - onPressed: toggleVideoPlay, - ), - IconButton(onPressed: resetPlay, icon: const Icon(Icons.replay)), - if (widget.onGoFullScreen != null) - IconButton( - onPressed: () async { - if (playing) { - await toggleVideoPlay(); - } - await widget.onGoFullScreen!(); - }, - icon: const Icon(Icons.fullscreen), - ) - ], - ) ], ), ); diff --git a/lib/controls/autocomplete/hashtag_autocomplete_options.dart b/lib/controls/autocomplete/hashtag_autocomplete_options.dart index e06d1b4..b45dc0b 100644 --- a/lib/controls/autocomplete/hashtag_autocomplete_options.dart +++ b/lib/controls/autocomplete/hashtag_autocomplete_options.dart @@ -5,10 +5,10 @@ import '../../services/hashtag_service.dart'; class HashtagAutocompleteOptions extends StatelessWidget { const HashtagAutocompleteOptions({ - Key? key, + super.key, required this.query, required this.onHashtagTap, - }) : super(key: key); + }); final String query; final ValueSetter onHashtagTap; diff --git a/lib/controls/autocomplete/mention_autocomplete_options.dart b/lib/controls/autocomplete/mention_autocomplete_options.dart index 7c404d2..d7f83d4 100644 --- a/lib/controls/autocomplete/mention_autocomplete_options.dart +++ b/lib/controls/autocomplete/mention_autocomplete_options.dart @@ -11,10 +11,10 @@ class MentionAutocompleteOptions extends StatelessWidget { static final _logger = Logger('$MentionAutocompleteOptions'); const MentionAutocompleteOptions({ - Key? key, + super.key, required this.query, required this.onMentionUserTap, - }) : super(key: key); + }); final String query; final ValueSetter onMentionUserTap; diff --git a/lib/controls/entry_media_attachments/media_upload_editor_control.dart b/lib/controls/entry_media_attachments/media_upload_editor_control.dart index 6cd54c1..acd5dbc 100644 --- a/lib/controls/entry_media_attachments/media_upload_editor_control.dart +++ b/lib/controls/entry_media_attachments/media_upload_editor_control.dart @@ -46,7 +46,7 @@ class _MediaUploadEditorControlState extends State { alignLabelWithHint: true, border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -56,7 +56,7 @@ class _MediaUploadEditorControlState extends State { )), IconButton( onPressed: widget.onDelete, - icon: Icon(Icons.cancel), + icon: const Icon(Icons.cancel), ), ], ), @@ -72,7 +72,7 @@ class _MediaUploadEditorControlState extends State { alignLabelWithHint: true, border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, ), borderRadius: BorderRadius.circular(5.0), ), diff --git a/lib/controls/notifications_control.dart b/lib/controls/notifications_control.dart index 416749d..7a11eb5 100644 --- a/lib/controls/notifications_control.dart +++ b/lib/controls/notifications_control.dart @@ -69,13 +69,13 @@ class NotificationControl extends StatelessWidget { height: iconSize, onTap: () async { context.pushNamed(ScreenPaths.userProfile, - params: {'id': notification.fromId}); + pathParameters: {'id': notification.fromId}); }, ), onError: (error) => GestureDetector( onTap: () async { context.pushNamed(ScreenPaths.userProfile, - params: {'id': notification.fromId}); + pathParameters: {'id': notification.fromId}); }, child: const SizedBox( width: iconSize, @@ -90,7 +90,7 @@ class NotificationControl extends StatelessWidget { case NotificationType.follow: onTap = () { context.pushNamed(ScreenPaths.userProfile, - params: {'id': notification.fromId}); + pathParameters: {'id': notification.fromId}); }; break; case NotificationType.follow_request: @@ -113,7 +113,7 @@ class NotificationControl extends StatelessWidget { case NotificationType.direct_message: onTap = () => context.pushNamed( ScreenPaths.thread, - queryParams: {'uri': notification.iid}, + queryParameters: {'uri': notification.iid}, ); break; } @@ -147,7 +147,7 @@ class NotificationControl extends StatelessWidget { logError(error, _logger); }); }, - icon: Icon(Icons.close_rounded)), + icon: const Icon(Icons.close_rounded)), ); } } diff --git a/lib/controls/search_result_status_control.dart b/lib/controls/search_result_status_control.dart index f379bde..6540f86 100644 --- a/lib/controls/search_result_status_control.dart +++ b/lib/controls/search_result_status_control.dart @@ -31,6 +31,7 @@ class _SearchResultStatusControlState extends State { @override void initState() { + super.initState(); showContent = widget.status.spoilerText.isEmpty; } @@ -48,7 +49,7 @@ class _SearchResultStatusControlState extends State { BoxShadow( color: Theme.of(context).dividerColor, blurRadius: 2, - offset: Offset(4, 4), + offset: const Offset(4, 4), spreadRadius: 0.1, blurStyle: BlurStyle.normal, ) @@ -137,7 +138,7 @@ class _SearchResultStatusControlState extends State { ); }, separatorBuilder: (context, index) { - return HorizontalPadding(); + return const HorizontalPadding(); }, itemCount: items.length)); } diff --git a/lib/controls/standard_app_drawer.dart b/lib/controls/standard_app_drawer.dart index 4c57eb4..16277aa 100644 --- a/lib/controls/standard_app_drawer.dart +++ b/lib/controls/standard_app_drawer.dart @@ -46,13 +46,13 @@ class StandardAppDrawer extends StatelessWidget { title: Text( p.username, style: p == getIt().currentProfile - ? TextStyle(fontWeight: FontWeight.bold) + ? const TextStyle(fontWeight: FontWeight.bold) : null, ), subtitle: Text( p.serverName, style: p == getIt().currentProfile - ? TextStyle(fontWeight: FontWeight.bold) + ? const TextStyle(fontWeight: FontWeight.bold) : null, ), ), diff --git a/lib/controls/timeline/flattened_tree_entry_control.dart b/lib/controls/timeline/flattened_tree_entry_control.dart index c4aa066..e22d46b 100644 --- a/lib/controls/timeline/flattened_tree_entry_control.dart +++ b/lib/controls/timeline/flattened_tree_entry_control.dart @@ -237,7 +237,7 @@ class _StatusControlState extends State { ); }, separatorBuilder: (context, index) { - return HorizontalPadding(); + return const HorizontalPadding(); }, itemCount: items.length)); } diff --git a/lib/controls/timeline/interactions_bar_control.dart b/lib/controls/timeline/interactions_bar_control.dart index 0b963b0..1688a94 100644 --- a/lib/controls/timeline/interactions_bar_control.dart +++ b/lib/controls/timeline/interactions_bar_control.dart @@ -186,7 +186,7 @@ class _InteractionsBarControlState extends State { Icons.thumb_up, semanticLabel: 'Like', ) - : Icon(Icons.thumb_up_outlined)), + : const Icon(Icons.thumb_up_outlined)), if (isPost) IconButton( onPressed: widget.isMine && !widget.entry.youReshared @@ -200,7 +200,7 @@ class _InteractionsBarControlState extends State { youReshared ? Icons.repeat_on_outlined : Icons.repeat)), IconButton( onPressed: isProcessing ? null : addComment, - icon: Icon(Icons.add_comment)), + icon: const Icon(Icons.add_comment)), ]), ], ); diff --git a/lib/controls/timeline/link_preview_control.dart b/lib/controls/timeline/link_preview_control.dart index d1838af..c00de62 100644 --- a/lib/controls/timeline/link_preview_control.dart +++ b/lib/controls/timeline/link_preview_control.dart @@ -25,7 +25,7 @@ class LinkPreviewControl extends StatelessWidget { }, child: Row( children: [ - Container( + SizedBox( width: width, child: CachedNetworkImage(imageUrl: preview.selectedImageUrl), ), diff --git a/lib/controls/timeline/status_header_control.dart b/lib/controls/timeline/status_header_control.dart index 4a70f5f..e512c28 100644 --- a/lib/controls/timeline/status_header_control.dart +++ b/lib/controls/timeline/status_header_control.dart @@ -27,7 +27,7 @@ class StatusHeaderControl extends StatelessWidget { }); void goToProfile(BuildContext context, String id) { - context.pushNamed(ScreenPaths.userProfile, params: {'id': id}); + context.pushNamed(ScreenPaths.userProfile, pathParameters: {'id': id}); } @override @@ -66,7 +66,7 @@ class StatusHeaderControl extends StatelessWidget { children: [ ImageControl( imageUrl: author.avatarUrl.toString(), - iconOverride: Icon(Icons.person), + iconOverride: const Icon(Icons.person), width: 32.0, onTap: () => goToProfile(context, author.id), ), @@ -79,7 +79,7 @@ class StatusHeaderControl extends StatelessWidget { onTap: () => goToProfile(context, author.id), child: Text( author.name, - style: Theme.of(context).textTheme.bodyText1, + style: Theme.of(context).textTheme.bodyLarge, ), ), ], @@ -94,7 +94,7 @@ class StatusHeaderControl extends StatelessWidget { children: [ ImageControl( imageUrl: reshareAuthor.avatarUrl.toString(), - iconOverride: Icon(Icons.person), + iconOverride: const Icon(Icons.person), width: 32.0, onTap: () => goToProfile(context, reshareAuthor.id), ), @@ -103,7 +103,7 @@ class StatusHeaderControl extends StatelessWidget { onTap: () => goToProfile(context, reshareAuthor.id), child: Text( reshareAuthor.name, - style: Theme.of(context).textTheme.bodyText1, + style: Theme.of(context).textTheme.bodyLarge, ), ), ], @@ -112,7 +112,7 @@ class StatusHeaderControl extends StatelessWidget { if (showIsCommentText && entry.parentId.isNotEmpty) Text( ' ...made a comment:', - style: Theme.of(context).textTheme.bodyText1, + style: Theme.of(context).textTheme.bodyLarge, ), ], ), @@ -120,7 +120,7 @@ class StatusHeaderControl extends StatelessWidget { children: [ Text( ElapsedDateUtils.epochSecondsToString(entry.backdatedTimestamp), - style: Theme.of(context).textTheme.caption, + style: Theme.of(context).textTheme.bodySmall, ), const HorizontalPadding(), Icon( @@ -128,7 +128,7 @@ class StatusHeaderControl extends StatelessWidget { ? Icons.public : Icons.lock, color: Theme.of(context).hintColor, - size: Theme.of(context).textTheme.caption?.fontSize, + size: Theme.of(context).textTheme.bodySmall?.fontSize, ), ], ), diff --git a/lib/friendica_client/friendica_client.dart b/lib/friendica_client/friendica_client.dart index c585bc1..dec4487 100644 --- a/lib/friendica_client/friendica_client.dart +++ b/lib/friendica_client/friendica_client.dart @@ -327,7 +327,7 @@ class InteractionsClient extends FriendicaClient { _networkStatusService.startInteractionsLoading(); final result = (await runCatchingAsync(() async { final url = 'https://$serverName/api/v1/statuses/$id/favourited_by'; - final request = Uri.parse('$url'); + final request = Uri.parse(url); _logger.finest(() => 'Getting favorites for status $id'); return (await _getApiListRequest(request) .andThenSuccessAsync((jsonArray) async { @@ -346,7 +346,7 @@ class InteractionsClient extends FriendicaClient { _networkStatusService.startInteractionsLoading(); final result = (await runCatchingAsync(() async { final url = 'https://$serverName/api/v1/statuses/$id/reblogged_by'; - final request = Uri.parse('$url'); + final request = Uri.parse(url); _logger.finest(() => 'Getting rebloggers for status $id'); return (await _getApiListRequest(request) .andThenSuccessAsync((jsonArray) async { diff --git a/lib/friendica_client/paged_response.dart b/lib/friendica_client/paged_response.dart index 6a13f68..6b29912 100644 --- a/lib/friendica_client/paged_response.dart +++ b/lib/friendica_client/paged_response.dart @@ -14,7 +14,7 @@ class PagedResponse { T data; PagedResponse(this.data, {String? id, this.previous, this.next}) - : id = id ?? Uuid().v4(); + : id = id ?? const Uuid().v4(); bool get hasMorePages => previous != null || next != null; diff --git a/lib/main.dart b/lib/main.dart index 481ff5d..0348e9c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,9 +29,8 @@ import 'utils/old_android_letsencrypte_cert.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - if (kReleaseMode) { - MediaKit.ensureInitialized(); - } + MediaKit.ensureInitialized(); + // await dotenv.load(fileName: '.env'); const enablePreview = false; Logger.root.level = Level.FINER; @@ -123,7 +122,6 @@ class App extends StatelessWidget { ), ], child: MaterialApp.router( - useInheritedMediaQuery: true, locale: DevicePreview.locale(context), builder: DevicePreview.appBuilder, theme: buildTheme( diff --git a/lib/models/auth/basic_credentials.dart b/lib/models/auth/basic_credentials.dart index 92614fd..700d74e 100644 --- a/lib/models/auth/basic_credentials.dart +++ b/lib/models/auth/basic_credentials.dart @@ -7,9 +7,11 @@ import '../exec_error.dart'; import 'credentials_intf.dart'; class BasicCredentials implements ICredentials { + @override late final String id; final String username; final String password; + @override final String serverName; late final String _authHeaderValue; diff --git a/lib/models/auth/oauth_credentials.dart b/lib/models/auth/oauth_credentials.dart index 5103490..a0b5d1d 100644 --- a/lib/models/auth/oauth_credentials.dart +++ b/lib/models/auth/oauth_credentials.dart @@ -94,7 +94,7 @@ class OAuthCredentials implements ICredentials { final idEndpoint = Uri.parse('https://$serverName/api/v1/apps'); final response = await http.post(idEndpoint, body: { 'client_name': 'Relatica', - 'redirect_uris': '$redirectUrl', + 'redirect_uris': redirectUrl, 'scopes': 'read write follow push', 'website': 'https://myportal.social', }); diff --git a/lib/models/timeline.dart b/lib/models/timeline.dart index 7aae68c..2cd4def 100644 --- a/lib/models/timeline.dart +++ b/lib/models/timeline.dart @@ -59,8 +59,8 @@ class Timeline { void removeTimelineEntry(String id) { if (_postsById.containsKey(id)) { - final _post = _postsById.remove(id); - _posts.remove(_post); + final post = _postsById.remove(id); + _posts.remove(post); return; } diff --git a/lib/models/timeline_entry.dart b/lib/models/timeline_entry.dart index 78aaa63..cfa8b94 100644 --- a/lib/models/timeline_entry.dart +++ b/lib/models/timeline_entry.dart @@ -146,7 +146,7 @@ class TimelineEntry { modificationTimestamp: modificationTimestamp ?? this.modificationTimestamp, id: id ?? this.id, - youReshared: isReshare ?? this.youReshared, + youReshared: isReshare ?? youReshared, visibility: visibility ?? this.visibility, parentId: parentId ?? this.parentId, externalLink: externalLink ?? this.externalLink, diff --git a/lib/routes.dart b/lib/routes.dart index e71d5b7..a7280b3 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -72,11 +72,11 @@ final appRouter = GoRouter( return ScreenPaths.splash; } - if (!loggedIn && !allowedLoggedOut.contains(state.location)) { + if (!loggedIn && !allowedLoggedOut.contains(state.uri.toString())) { return ScreenPaths.signin; } - if (loggedIn && allowedLoggedOut.contains(state.location)) { + if (loggedIn && allowedLoggedOut.contains(state.uri.toString())) { return ScreenPaths.timelines; } @@ -102,46 +102,46 @@ final appRouter = GoRouter( GoRoute( path: 'edit/:id', pageBuilder: (context, state) => NoTransitionPage( - child: FilterEditorScreen(id: state.params['id']!)), + child: FilterEditorScreen(id: state.pathParameters['id']!)), ) ], ), GoRoute( path: ScreenPaths.signin, name: ScreenPaths.signin, - builder: (context, state) => SignInScreen(), + builder: (context, state) => const SignInScreen(), ), GoRoute( path: ScreenPaths.manageProfiles, name: ScreenPaths.manageProfiles, - builder: (context, state) => SignInScreen(), + builder: (context, state) => const SignInScreen(), ), GoRoute( path: ScreenPaths.contacts, name: ScreenPaths.contacts, pageBuilder: (context, state) => NoTransitionPage( name: ScreenPaths.contacts, - child: ContactsScreen(), + child: const ContactsScreen(), ), ), GoRoute( path: '/connect/:id', name: ScreenPaths.connectHandle, builder: (context, state) => - FollowRequestAdjudicationScreen(userId: state.params['id']!), + FollowRequestAdjudicationScreen(userId: state.pathParameters['id']!), ), GoRoute( path: ScreenPaths.timelines, name: ScreenPaths.timelines, pageBuilder: (context, state) => NoTransitionPage( name: ScreenPaths.timelines, - child: HomeScreen(), + child: const HomeScreen(), ), ), GoRoute( path: ScreenPaths.messages, name: ScreenPaths.messages, - pageBuilder: (context, state) => NoTransitionPage( + pageBuilder: (context, state) => const NoTransitionPage( child: MessagesScreen(), ), routes: [ @@ -157,7 +157,7 @@ final appRouter = GoRouter( name: ScreenPaths.thread, path: ScreenPaths.thread, builder: (context, state) => - MessageThreadScreen(parentThreadId: state.queryParams['uri']!), + MessageThreadScreen(parentThreadId: state.uri.queryParameters['uri']!), ), GoRoute( name: ScreenPaths.groupManagement, @@ -167,31 +167,31 @@ final appRouter = GoRouter( GoRoute( path: 'show/:id', builder: (context, state) => GroupEditorScreen( - groupId: state.params['id']!, + groupId: state.pathParameters['id']!, ), ), GoRoute( path: 'new', - builder: (context, state) => GroupCreateScreen(), + builder: (context, state) => const GroupCreateScreen(), ), GoRoute( path: 'add_users/:id', builder: (context, state) => - GroupAddUsersScreen(groupId: state.params['id']!), + GroupAddUsersScreen(groupId: state.pathParameters['id']!), ), ], ), GoRoute( path: ScreenPaths.settings, name: ScreenPaths.settings, - pageBuilder: (context, state) => NoTransitionPage( + pageBuilder: (context, state) => const NoTransitionPage( child: SettingsScreen(), ), ), GoRoute( path: ScreenPaths.gallery, name: ScreenPaths.gallery, - pageBuilder: (context, state) => NoTransitionPage( + pageBuilder: (context, state) => const NoTransitionPage( child: GalleryBrowsersScreen(), ), routes: [ @@ -204,8 +204,8 @@ final appRouter = GoRouter( GoRoute( path: 'edit/:name/image/:id', builder: (context, state) => ImageEditorScreen( - galleryName: state.params['name']!, - imageId: state.params['id']!, + galleryName: state.pathParameters['name']!, + imageId: state.pathParameters['id']!, ), ), ], @@ -213,19 +213,19 @@ final appRouter = GoRouter( GoRoute( path: ScreenPaths.notifications, name: ScreenPaths.notifications, - pageBuilder: (context, state) => NoTransitionPage( + pageBuilder: (context, state) => const NoTransitionPage( child: NotificationsScreen(), ), ), GoRoute( path: ScreenPaths.splash, name: ScreenPaths.splash, - builder: (context, state) => SplashScreen(), + builder: (context, state) => const SplashScreen(), ), GoRoute( path: '/post', redirect: (context, state) { - if (state.location == '/post') { + if (state.uri.toString() == '/post') { return '/post/new'; } @@ -234,29 +234,29 @@ final appRouter = GoRouter( routes: [ GoRoute( path: 'new', - builder: (context, state) => EditorScreen( + builder: (context, state) => const EditorScreen( forEditing: false, ), ), GoRoute( path: 'edit/:id', builder: (context, state) => EditorScreen( - id: state.params['id'] ?? 'Not Found', + id: state.pathParameters['id'] ?? 'Not Found', forEditing: true, ), ), GoRoute( path: 'view/:id/:goto_id', builder: (context, state) => PostScreen( - id: state.params['id'] ?? 'Not Found', - goToId: state.params['goto_id'] ?? 'Not Found', + id: state.pathParameters['id'] ?? 'Not Found', + goToId: state.pathParameters['goto_id'] ?? 'Not Found', ), ), ]), GoRoute( path: '/comment', redirect: (context, state) { - if (state.location == '/comment') { + if (state.uri.toString() == '/comment') { return '/comment/new'; } @@ -266,14 +266,14 @@ final appRouter = GoRouter( GoRoute( path: 'new', builder: (context, state) => EditorScreen( - parentId: state.queryParams['parent_id'] ?? '', + parentId: state.uri.queryParameters['parent_id'] ?? '', forEditing: false, ), ), GoRoute( path: 'edit/:id', builder: (context, state) => EditorScreen( - id: state.params['id'] ?? 'Not Found', + id: state.pathParameters['id'] ?? 'Not Found', forEditing: true, ), ), @@ -282,13 +282,13 @@ final appRouter = GoRouter( path: '/user_posts/:id', name: ScreenPaths.userPosts, builder: (context, state) => - UserPostsScreen(userId: state.params['id']!), + UserPostsScreen(userId: state.pathParameters['id']!), ), GoRoute( path: '/likes/:id', name: ScreenPaths.likes, builder: (context, state) => InteractionsViewerScreen( - statusId: state.params['id']!, + statusId: state.pathParameters['id']!, type: InteractionType.like, ), ), @@ -296,7 +296,7 @@ final appRouter = GoRouter( path: '/reshares/:id', name: ScreenPaths.reshares, builder: (context, state) => InteractionsViewerScreen( - statusId: state.params['id']!, + statusId: state.pathParameters['id']!, type: InteractionType.reshare, ), ), @@ -304,14 +304,14 @@ final appRouter = GoRouter( path: '/user_profile/:id', name: ScreenPaths.userProfile, builder: (context, state) => - UserProfileScreen(userId: state.params['id']!), + UserProfileScreen(userId: state.pathParameters['id']!), ), GoRoute( path: ScreenPaths.search, name: ScreenPaths.search, pageBuilder: (context, state) => NoTransitionPage( name: ScreenPaths.search, - child: SearchScreen(), + child: const SearchScreen(), ), ), ]); diff --git a/lib/screens/blocks_screen.dart b/lib/screens/blocks_screen.dart index 0d6465f..1cdd664 100644 --- a/lib/screens/blocks_screen.dart +++ b/lib/screens/blocks_screen.dart @@ -27,7 +27,7 @@ class BlocksScreen extends StatelessWidget { return ListTile( onTap: () async { context.pushNamed(ScreenPaths.userProfile, - params: {'id': contact.id}); + pathParameters: {'id': contact.id}); }, leading: ImageControl( imageUrl: contact.avatarUrl.toString(), diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index 5572f9b..f3d8848 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -13,12 +13,13 @@ import '../controls/status_and_refresh_button.dart'; import '../globals.dart'; import '../models/connection.dart'; import '../routes.dart'; -import '../services/auth_service.dart'; import '../services/connections_manager.dart'; import '../services/network_status_service.dart'; import '../utils/active_profile_selector.dart'; class ContactsScreen extends StatefulWidget { + const ContactsScreen({super.key}); + @override State createState() => _ContactsScreenState(); } @@ -30,7 +31,6 @@ class _ContactsScreenState extends State { @override Widget build(BuildContext context) { final nss = getIt(); - final activeProfile = context.watch(); final manager = context .watch>() .activeEntry @@ -63,7 +63,7 @@ class _ContactsScreenState extends State { return ListTile( onTap: () { context.pushNamed(ScreenPaths.userProfile, - params: {'id': contact.id}); + pathParameters: {'id': contact.id}); }, leading: ImageControl( imageUrl: contact.avatarUrl.toString(), @@ -142,7 +142,7 @@ class _ContactsScreenState extends State { ), ), ), - bottomNavigationBar: AppBottomNavBar( + bottomNavigationBar: const AppBottomNavBar( currentButton: NavBarButtons.contacts, ), ); diff --git a/lib/screens/editor.dart b/lib/screens/editor.dart index df84dcb..347b8e9 100644 --- a/lib/screens/editor.dart +++ b/lib/screens/editor.dart @@ -71,6 +71,7 @@ class _EditorScreenState extends State { @override void initState() { + super.initState(); if (isComment) { final manager = context .read>() @@ -97,7 +98,7 @@ class _EditorScreenState extends State { loaded = false; final result = await getIt>() .activeEntry - .andThenAsync((manager) async => await manager.getEntryById(widget.id)); + .andThenAsync((manager) async => manager.getEntryById(widget.id)); result.match(onSuccess: (entry) { _logger.fine('Loading status ${widget.id} information into fields'); contentController.text = htmlToSimpleText(entry.body); @@ -227,7 +228,7 @@ class _EditorScreenState extends State { final canSpoilerText = vc.canUseFeature(RelaticaFeatures.postSpoilerText) || widget.parentId.isNotEmpty; - late final body; + late final Widget body; if (widget.forEditing && !canEdit) { body = Center( @@ -479,7 +480,7 @@ class _EditorScreenState extends State { } }); }, - icon: Icon(Icons.refresh), + icon: const Icon(Icons.refresh), ), ], ), @@ -504,7 +505,7 @@ class _EditorScreenState extends State { linkPreviewData = null; }); }, - icon: Icon(Icons.delete), + icon: const Icon(Icons.delete), ), ), ), @@ -524,7 +525,7 @@ class _EditorScreenState extends State { ); } - final currentImage = Container( + final currentImage = SizedBox( width: width, height: height, child: diff --git a/lib/screens/existing_image_selector_screen.dart b/lib/screens/existing_image_selector_screen.dart index c0222d6..73499d7 100644 --- a/lib/screens/existing_image_selector_screen.dart +++ b/lib/screens/existing_image_selector_screen.dart @@ -50,7 +50,7 @@ class _ExistingImageSelectorScreenState Navigator.of(context).pop(selectedImages); }, tooltip: 'Attach selected files', - icon: Icon(Icons.attach_file), + icon: const Icon(Icons.attach_file), ), IconButton( onPressed: selectedImages.isEmpty @@ -61,7 +61,7 @@ class _ExistingImageSelectorScreenState }); }, tooltip: 'Clear Selection', - icon: Icon(Icons.remove_circle_outline), + icon: const Icon(Icons.remove_circle_outline), ), ], ), @@ -89,11 +89,11 @@ class _ExistingImageSelectorScreenState } Widget buildInfoBody() { - return Center( + return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, - children: const [Text('Select a gallery')], + children: [Text('Select a gallery')], ), ); } diff --git a/lib/screens/follow_request_adjudication_screen.dart b/lib/screens/follow_request_adjudication_screen.dart index 0e07ce8..52a51d4 100644 --- a/lib/screens/follow_request_adjudication_screen.dart +++ b/lib/screens/follow_request_adjudication_screen.dart @@ -169,7 +169,7 @@ class _FollowRequestAdjudicationScreenState ElevatedButton( onPressed: () => context.pushNamed( ScreenPaths.userPosts, - params: {'id': contact.id}, + pathParameters: {'id': contact.id}, ), child: const Text('Posts')), ElevatedButton( diff --git a/lib/screens/gallery_browsers_screen.dart b/lib/screens/gallery_browsers_screen.dart index 74ad999..2b85628 100644 --- a/lib/screens/gallery_browsers_screen.dart +++ b/lib/screens/gallery_browsers_screen.dart @@ -15,6 +15,8 @@ import '../utils/active_profile_selector.dart'; class GalleryBrowsersScreen extends StatelessWidget { static final _logger = Logger('$GalleryBrowsersScreen'); + const GalleryBrowsersScreen({super.key}); + String? validNameChecker(String? text) { final newName = text ?? ''; if (newName.isEmpty) { @@ -117,11 +119,11 @@ class GalleryBrowsersScreen extends StatelessWidget { } if (galleries.isEmpty) { - return Center( + return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, - children: const [ + children: [ Text('Loading galleries'), VerticalPadding(), CircularProgressIndicator(), diff --git a/lib/screens/gallery_screen.dart b/lib/screens/gallery_screen.dart index 9b38cff..d002f2f 100644 --- a/lib/screens/gallery_screen.dart +++ b/lib/screens/gallery_screen.dart @@ -96,11 +96,11 @@ class _GalleryScreenBody extends StatelessWidget { final images = imageResult.value; final attachments = images.map((i) => i.toMediaAttachment()).toList(); if (images.isEmpty && service.loaded) { - return Center( + return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, - children: const [ + children: [ Text('No images'), ], ), @@ -108,11 +108,11 @@ class _GalleryScreenBody extends StatelessWidget { } if (images.isEmpty) { - return Center( + return const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, - children: const [ + children: [ Text('Loading images'), ], ), diff --git a/lib/screens/group_add_users_screen.dart b/lib/screens/group_add_users_screen.dart index 6a73143..9b0f9b4 100644 --- a/lib/screens/group_add_users_screen.dart +++ b/lib/screens/group_add_users_screen.dart @@ -12,7 +12,6 @@ import '../models/connection.dart'; import '../models/exec_error.dart'; import '../models/group_data.dart'; import '../routes.dart'; -import '../services/auth_service.dart'; import '../services/connections_manager.dart'; import '../services/network_status_service.dart'; import '../utils/active_profile_selector.dart'; @@ -63,7 +62,6 @@ class _GroupAddUsersScreenState extends State { Widget build(BuildContext context) { _logger.finer('Build'); final nss = getIt(); - final activeProfile = context.watch(); final manager = context .watch>() .activeEntry @@ -102,7 +100,7 @@ class _GroupAddUsersScreenState extends State { return ListTile( onTap: () { context.pushNamed(ScreenPaths.userProfile, - params: {'id': contact.id}); + pathParameters: {'id': contact.id}); }, title: Text( '${contact.name} (${contact.handle})', diff --git a/lib/screens/group_create_screen.dart b/lib/screens/group_create_screen.dart index 6797111..423ae60 100644 --- a/lib/screens/group_create_screen.dart +++ b/lib/screens/group_create_screen.dart @@ -9,7 +9,7 @@ import '../utils/active_profile_selector.dart'; import '../utils/snackbar_builder.dart'; class GroupCreateScreen extends StatefulWidget { - GroupCreateScreen({super.key}); + const GroupCreateScreen({super.key}); @override State createState() => _GroupCreateScreenState(); diff --git a/lib/screens/group_editor_screen.dart b/lib/screens/group_editor_screen.dart index 6efeed8..9ada179 100644 --- a/lib/screens/group_editor_screen.dart +++ b/lib/screens/group_editor_screen.dart @@ -243,7 +243,7 @@ class _GroupEditorScreenState extends State { return ListTile( onTap: () { context.pushNamed(ScreenPaths.userProfile, - params: {'id': m.id}); + pathParameters: {'id': m.id}); }, title: Text( '${m.name} (${m.handle})', diff --git a/lib/screens/home.dart b/lib/screens/home.dart index c80a5a6..19f70dc 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -168,7 +168,7 @@ class _HomeScreenState extends State { onPressed: () { context.push('/post/new'); }, - child: Icon(Icons.add), + child: const Icon(Icons.add), )); } } diff --git a/lib/screens/interactions_viewer_screen.dart b/lib/screens/interactions_viewer_screen.dart index e656c63..e3474c6 100644 --- a/lib/screens/interactions_viewer_screen.dart +++ b/lib/screens/interactions_viewer_screen.dart @@ -80,7 +80,7 @@ class InteractionsViewerScreen extends StatelessWidget { }); if (context.mounted) { context.pushNamed(ScreenPaths.userProfile, - params: {'id': connection.id}); + pathParameters: {'id': connection.id}); } }, leading: ImageControl( @@ -88,7 +88,7 @@ class InteractionsViewerScreen extends StatelessWidget { iconOverride: const Icon(Icons.person), width: 32.0, onTap: () => context.pushNamed(ScreenPaths.userProfile, - params: {'id': connection.id}), + pathParameters: {'id': connection.id}), ), title: Text('${connection.name} (${connection.handle})'), ); diff --git a/lib/screens/media_viewer_screen.dart b/lib/screens/media_viewer_screen.dart index 28c3cbb..97f39b0 100644 --- a/lib/screens/media_viewer_screen.dart +++ b/lib/screens/media_viewer_screen.dart @@ -221,7 +221,7 @@ class _MediaViewerScreenState extends State { text: attachment.description, message: 'Image description copied to clipboard'); }, - icon: Icon(Icons.copy), + icon: const Icon(Icons.copy), ), ], ), diff --git a/lib/screens/message_threads_browser_screen.dart b/lib/screens/message_threads_browser_screen.dart index 9f52726..9d6e226 100644 --- a/lib/screens/message_threads_browser_screen.dart +++ b/lib/screens/message_threads_browser_screen.dart @@ -14,6 +14,8 @@ import '../utils/active_profile_selector.dart'; import '../utils/dateutils.dart'; class MessagesScreen extends StatelessWidget { + const MessagesScreen({super.key}); + @override Widget build(BuildContext context) { final service = context @@ -32,7 +34,7 @@ class MessagesScreen extends StatelessWidget { onPressed: () { context.push('/messages/new_thread'); }, - icon: Icon(Icons.add), + icon: const Icon(Icons.add), ) ]), body: RefreshIndicator( @@ -61,7 +63,7 @@ class MessagesScreen extends StatelessWidget { return ListTile( onTap: () => context.pushNamed( ScreenPaths.thread, - queryParams: {'uri': thread.parentUri}, + queryParameters: {'uri': thread.parentUri}, ), leading: ImageControl( imageUrl: thread.participants.first.avatarUrl.toString(), diff --git a/lib/screens/messages_new_thread.dart b/lib/screens/messages_new_thread.dart index c54302b..1df3cb2 100644 --- a/lib/screens/messages_new_thread.dart +++ b/lib/screens/messages_new_thread.dart @@ -16,6 +16,8 @@ class MessagesNewThread extends StatelessWidget { final replyController = TextEditingController(); final focusNode = FocusNode(); + MessagesNewThread({super.key}); + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/screens/notifications_screen.dart b/lib/screens/notifications_screen.dart index a047f6f..9bb5b05 100644 --- a/lib/screens/notifications_screen.dart +++ b/lib/screens/notifications_screen.dart @@ -52,9 +52,9 @@ class NotificationsScreen extends StatelessWidget { update(manager); return; }, - child: Center( + child: const Center( child: Column( - children: const [ + children: [ Center(child: Text('No notifications')), ], )), @@ -114,9 +114,9 @@ class NotificationsScreen extends StatelessWidget { }, onError: (error) { title = 'Notifications'; actions = []; - body = Center( + body = const Center( child: Column( - children: const [ + children: [ Center(child: Text('Error getting notifications')), ], )); @@ -130,7 +130,7 @@ class NotificationsScreen extends StatelessWidget { withDrawer: true, actions: actions, ), - drawer: StandardAppDrawer(), + drawer: const StandardAppDrawer(), body: body, bottomNavigationBar: const AppBottomNavBar( currentButton: NavBarButtons.notifications, diff --git a/lib/screens/search_screen.dart b/lib/screens/search_screen.dart index 707c4a1..a83bd0d 100644 --- a/lib/screens/search_screen.dart +++ b/lib/screens/search_screen.dart @@ -26,6 +26,8 @@ import '../utils/active_profile_selector.dart'; import '../utils/snackbar_builder.dart'; class SearchScreen extends StatefulWidget { + const SearchScreen({super.key}); + @override State createState() => _SearchScreenState(); } @@ -40,7 +42,7 @@ class _SearchScreenState extends State { var searchResult = SearchResults.empty(); PagingData genNextPageData() { - late final offset; + late final int offset; switch (searchType) { case SearchTypes.hashTag: offset = searchResult.hashtags.length; @@ -110,7 +112,7 @@ class _SearchScreenState extends State { } return Scaffold( - drawer: StandardAppDrawer(skipPopDismiss: true), + drawer: const StandardAppDrawer(skipPopDismiss: true), body: SafeArea( child: RefreshIndicator( onRefresh: () async { @@ -147,7 +149,7 @@ class _SearchScreenState extends State { alignLabelWithHint: true, border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -312,15 +314,15 @@ class _SearchScreenState extends State { }); if (context.mounted) { context.pushNamed(ScreenPaths.userProfile, - params: {'id': connection.id}); + pathParameters: {'id': connection.id}); } }, leading: ImageControl( imageUrl: connection.avatarUrl.toString(), iconOverride: const Icon(Icons.person), width: 32.0, - onTap: () => context - .pushNamed(ScreenPaths.userProfile, params: {'id': connection.id}), + onTap: () => context.pushNamed(ScreenPaths.userProfile, + pathParameters: {'id': connection.id}), ), title: Text('${connection.name} (${connection.handle})'), ); diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 100372e..e3c93d1 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -11,6 +11,8 @@ import '../services/setting_service.dart'; import '../utils/theme_mode_extensions.dart'; class SettingsScreen extends StatelessWidget { + const SettingsScreen({super.key}); + @override Widget build(BuildContext context) { final settings = context.watch(); diff --git a/lib/screens/sign_in.dart b/lib/screens/sign_in.dart index 088a34f..e1b9261 100644 --- a/lib/screens/sign_in.dart +++ b/lib/screens/sign_in.dart @@ -14,6 +14,8 @@ import '../services/auth_service.dart'; import '../utils/snackbar_builder.dart'; class SignInScreen extends StatefulWidget { + const SignInScreen({super.key}); + @override State createState() => _SignInScreenState(); } @@ -146,7 +148,7 @@ class _SignInScreenState extends State { hintText: 'Server Name (friendica.example.com)', border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -180,7 +182,7 @@ class _SignInScreenState extends State { hintText: 'Username (user@example.com)', border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -207,7 +209,7 @@ class _SignInScreenState extends State { hintText: 'Password', border: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, ), borderRadius: BorderRadius.circular(5.0), ), @@ -368,6 +370,8 @@ class _SignInScreenState extends State { return; } + print('Sign in credentials: ${creds.toJson()}'); + final result = await getIt().signIn(creds); if (mounted && result.isFailure) { buildSnackbar(context, 'Error signing in: ${result.error}'); diff --git a/lib/screens/splash.dart b/lib/screens/splash.dart index a39eb41..a62adb5 100644 --- a/lib/screens/splash.dart +++ b/lib/screens/splash.dart @@ -6,6 +6,8 @@ import '../globals.dart'; import '../services/auth_service.dart'; class SplashScreen extends StatelessWidget { + const SplashScreen({super.key}); + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/screens/user_profile_screen.dart b/lib/screens/user_profile_screen.dart index f3d0374..723cc9c 100644 --- a/lib/screens/user_profile_screen.dart +++ b/lib/screens/user_profile_screen.dart @@ -63,7 +63,7 @@ class _UserProfileScreenState extends State { children: [ LoginAwareCachedNetworkImage( imageUrl: profile.avatarUrl.toString()), - Row( + const Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [], @@ -91,7 +91,7 @@ class _UserProfileScreenState extends State { ElevatedButton( onPressed: () => context.pushNamed( ScreenPaths.userPosts, - params: {'id': profile.id}, + pathParameters: {'id': profile.id}, ), child: const Text('Posts')), ElevatedButton( @@ -127,7 +127,7 @@ class _UserProfileScreenState extends State { }); return Scaffold( appBar: AppBar( - title: Text('Profile'), + title: const Text('Profile'), ), body: Padding( padding: const EdgeInsets.all(8.0), diff --git a/lib/serializers/friendica/timeline_entry_friendica_extensions.dart b/lib/serializers/friendica/timeline_entry_friendica_extensions.dart index 81e9097..3fa4664 100644 --- a/lib/serializers/friendica/timeline_entry_friendica_extensions.dart +++ b/lib/serializers/friendica/timeline_entry_friendica_extensions.dart @@ -33,7 +33,7 @@ extension TimelineEntryFriendicaExtensions on TimelineEntry { final authorId = json['user']['id_str']; final title = json['friendica_title'] ?? ''; final externalLink = json['external_url'] ?? ''; - final actualLocationData = LocationData(); + const actualLocationData = LocationData(); final modificationTimestamp = timestamp; final backdatedTimestamp = timestamp; final mediaAttachments = (json['attachments'] as List? ?? []) diff --git a/lib/serializers/mastodon/follow_request_mastodon_extensions.dart b/lib/serializers/mastodon/follow_request_mastodon_extensions.dart index 58c54d2..31132cd 100644 --- a/lib/serializers/mastodon/follow_request_mastodon_extensions.dart +++ b/lib/serializers/mastodon/follow_request_mastodon_extensions.dart @@ -8,7 +8,7 @@ import 'connection_mastodon_extensions.dart'; extension FollowRequestMastodonExtension on FollowRequest { static FollowRequest fromJson(Map json) { final connection = ConnectionMastodonExtensions.fromJson(json); - final id = json['id'] ?? Uuid().v4(); + final id = json['id'] ?? const Uuid().v4(); final int timestamp = json.containsKey('created_at') ? OffsetDateTimeUtils.epochSecTimeFromTimeZoneString(json['created_at']) .fold( diff --git a/lib/services/entry_manager_service.dart b/lib/services/entry_manager_service.dart index 14478b4..743d641 100644 --- a/lib/services/entry_manager_service.dart +++ b/lib/services/entry_manager_service.dart @@ -144,11 +144,11 @@ class EntryManagerService extends ChangeNotifier { return item; }).andThenSuccessAsync((item) async { if (inReplyToId.isNotEmpty) { - late final rootPostId; + late final String rootPostId; if (_postNodes.containsKey(inReplyToId)) { rootPostId = inReplyToId; } else { - rootPostId = _parentPostIds[inReplyToId]; + rootPostId = _parentPostIds[inReplyToId]!; } await refreshStatusChain(rootPostId); } @@ -234,11 +234,11 @@ class EntryManagerService extends ChangeNotifier { }).andThenSuccessAsync((item) async { final inReplyToId = item.parentId; if (inReplyToId.isNotEmpty) { - late final rootPostId; + late final String rootPostId; if (_postNodes.containsKey(inReplyToId)) { rootPostId = inReplyToId; } else { - rootPostId = _parentPostIds[inReplyToId]; + rootPostId = _parentPostIds[inReplyToId]!; } await refreshStatusChain(rootPostId); } diff --git a/lib/services/notifications_manager.dart b/lib/services/notifications_manager.dart index 820ccc3..13063e2 100644 --- a/lib/services/notifications_manager.dart +++ b/lib/services/notifications_manager.dart @@ -103,7 +103,7 @@ class NotificationsManager extends ChangeNotifier { }) async { final (_, highestId) = unread.isNotEmpty ? calcLowHigh(unread) : calcLowHigh(read); - final pm = await _buildPageManager( + final pm = _buildPageManager( profile, true, initialPages: [ diff --git a/lib/utils/active_profile_selector.dart b/lib/utils/active_profile_selector.dart index d4ab971..007c861 100644 --- a/lib/utils/active_profile_selector.dart +++ b/lib/utils/active_profile_selector.dart @@ -11,7 +11,7 @@ class ActiveProfileSelector extends ChangeNotifier { final T Function(Profile p)? _entryBuilder; - bool _subscribeAdded = false; + final bool _subscribeAdded = false; ActiveProfileSelector(T Function(Profile p)? entryBuilder) : _entryBuilder = entryBuilder; diff --git a/lib/utils/json_printer.dart b/lib/utils/json_printer.dart index c5a4661..2160397 100644 --- a/lib/utils/json_printer.dart +++ b/lib/utils/json_printer.dart @@ -4,7 +4,7 @@ class PrettyJsonEncoder { late JsonEncoder encoder; PrettyJsonEncoder() { - encoder = JsonEncoder.withIndent('\t'); + encoder = const JsonEncoder.withIndent('\t'); } String convert(Object json) => encoder.convert(json); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 6249bac..340847e 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -18,6 +19,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) desktop_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWindowPlugin"); desktop_window_plugin_register_with_registrar(desktop_window_registrar); + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index dd5f438..0306caa 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_window + file_selector_linux flutter_secure_storage_linux media_kit_libs_linux media_kit_video diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 571c08e..f0bc79e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,28 +7,38 @@ import Foundation import desktop_window import device_info_plus +import file_selector_macos import flutter_secure_storage_macos import flutter_web_auth_2 import media_kit_libs_macos_video import media_kit_video import objectbox_flutter_libs +import package_info_plus import path_provider_foundation +import screen_brightness_macos import shared_preferences_foundation import sqflite import url_launcher_macos +import video_player_avfoundation +import wakelock_plus import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) ObjectboxFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "ObjectboxFlutterLibsPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) } diff --git a/macos/Podfile b/macos/Podfile index f9ebb8d..a1cf8ff 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '11.0' +platform :osx, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/macos/Podfile.lock b/macos/Podfile.lock index e5f504d..b9c6608 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -3,9 +3,11 @@ PODS: - FlutterMacOS - device_info_plus (0.0.1): - FlutterMacOS + - file_selector_macos (0.0.1): + - FlutterMacOS - flutter_secure_storage_macos (6.1.1): - FlutterMacOS - - flutter_web_auth_2 (1.1.1): + - flutter_web_auth_2 (3.0.0): - FlutterMacOS - FlutterMacOS (1.0.0) - FMDB (2.7.5): @@ -17,13 +19,17 @@ PODS: - FlutterMacOS - media_kit_video (0.0.1): - FlutterMacOS - - ObjectBox (1.8.1) + - ObjectBox (1.9.0) - objectbox_flutter_libs (0.0.1): - FlutterMacOS - - ObjectBox (= 1.8.1) + - ObjectBox (= 1.9.0) + - package_info_plus (0.0.1): + - FlutterMacOS - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - screen_brightness_macos (0.1.0): + - FlutterMacOS - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -32,12 +38,18 @@ PODS: - FMDB (>= 2.7.5) - url_launcher_macos (0.0.1): - FlutterMacOS + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS - window_to_front (0.0.1): - FlutterMacOS DEPENDENCIES: - desktop_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_window/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - flutter_web_auth_2 (from `Flutter/ephemeral/.symlinks/plugins/flutter_web_auth_2/macos`) - FlutterMacOS (from `Flutter/ephemeral`) @@ -45,10 +57,14 @@ DEPENDENCIES: - media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`) - media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`) - objectbox_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/objectbox_flutter_libs/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) - window_to_front (from `Flutter/ephemeral/.symlinks/plugins/window_to_front/macos`) SPEC REPOS: @@ -61,6 +77,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/desktop_window/macos device_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + file_selector_macos: + :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos flutter_secure_storage_macos: :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos flutter_web_auth_2: @@ -75,35 +93,48 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos objectbox_flutter_libs: :path: Flutter/ephemeral/.symlinks/plugins/objectbox_flutter_libs/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + screen_brightness_macos: + :path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite: :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + video_player_avfoundation: + :path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos window_to_front: :path: Flutter/ephemeral/.symlinks/plugins/window_to_front/macos SPEC CHECKSUMS: desktop_window: fb7c4f12c1129f947ac482296b6f14059d57a3c3 device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f + file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea - flutter_web_auth_2: 6695649132b6c71ea17700703761c0d18fdb8cf6 + flutter_web_auth_2: 2e1dc2d2139973e4723c5286ce247dd590390d70 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - media_kit_libs_macos_video: 0a4a5bf21533cba968c0833f1b59e9af8b5847f1 - media_kit_native_event_loop: 9a1b256cfb11adcaebd13a2969c617720c3187e0 - media_kit_video: 1e311a3dfe41f276935f95518b51a0c3ff72114f - ObjectBox: a7900d5335218cd437cbc080b7ccc38a5211f7b4 - objectbox_flutter_libs: f89ab4878f0f764a49077cfaa59030be69ae1d7e - path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 - shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 + media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82 + media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5 + media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5 + ObjectBox: e7ff611291a0663380e0736b46786bcd077294ff + objectbox_flutter_libs: 32997857c213cbcc6f9b25ffc73e1e3c34ea3c8e + package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + screen_brightness_macos: 2d6d3af2165592d9a55ffcd95b7550970e41ebda + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea - url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451 + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + video_player_avfoundation: 8563f13d8fc8b2c29dc2d09e60b660e4e8128837 + wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 window_to_front: 4cdc24ddd8461ad1a55fa06286d6a79d8b29e8d8 -PODFILE CHECKSUM: 8d40c19d3cbdb380d870685c3a564c989f1efa52 +PODFILE CHECKSUM: 137ddf7b4dbe5a83427ebf04ae8dea674cfd87fa -COCOAPODS: 1.12.0 +COCOAPODS: 1.14.2 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 373d6ab..f5e63bd 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -204,7 +204,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -407,7 +407,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -436,7 +436,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -497,7 +497,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -545,7 +545,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -574,7 +574,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -602,7 +602,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 33da272..84aa87e 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ =3.0.0 <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index e3e182d..0c78ea4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,34 +15,29 @@ dependencies: cupertino_icons: ^1.0.2 carousel_slider: ^4.2.1 desktop_window: ^0.4.0 - device_info_plus: ^8.0.0 + device_info_plus: ^9.1.0 device_preview: ^1.1.0 - file_picker: ^5.2.4 + file_picker: ^6.0.0 flutter_dotenv: ^5.0.2 flutter_file_dialog: ^3.0.0 - flutter_secure_storage: ^8.0.0 - flutter_web_auth_2: ^2.1.2 - flutter_widget_from_html_core: ^0.10.0 + flutter_secure_storage: ^9.0.0 + flutter_web_auth_2: ^3.0.3 + flutter_widget_from_html_core: ^0.14.6 get_it: ^7.2.0 get_it_mixin: ^4.1.1 - go_router: ^6.5.0 + go_router: ^12.0.1 html: ^0.15.2 image: ^4.0.15 - image_picker: ^0.8.6 + image_picker: ^1.0.4 logging: ^1.1.0 markdown: ^7.0.1 - media_kit: ^0.0.5 # Primary package. - media_kit_video: ^0.0.6 # For video rendering. - media_kit_native_event_loop: ^1.0.3 # Support for higher number of concurrent instances & better performance. - media_kit_libs_windows_video: ^1.0.2 # Windows package for video native libraries. - media_kit_libs_android_video: ^1.0.0 # Android package for video native libraries. - media_kit_libs_macos_video: ^1.0.4 # macOS package for video native libraries. - media_kit_libs_ios_video: ^1.0.4 # iOS package for video native libraries. - media_kit_libs_linux: ^1.0.2 # GNU/Linux dependency package. metadata_fetch: ^0.4.1 - multi_trigger_autocomplete: ^0.1.1 + media_kit: ^1.1.10 # Primary package. + media_kit_libs_video: ^1.0.4 # Native video dependencies. + media_kit_video: ^1.2.4 # For video rendering. + multi_trigger_autocomplete: ^1.0.0 network_to_file_image: ^4.0.1 - objectbox: ^2.0.0 - objectbox_flutter_libs: ^2.0.0 + objectbox: ^2.3.1 + objectbox_flutter_libs: ^2.3.1 path: ^1.8.2 path_provider: ^2.0.11 provider: ^6.0.4 @@ -51,12 +46,12 @@ dependencies: url: https://gitlab.com/HankG/dart-result-monad.git scrollable_positioned_list: ^0.3.5 shared_preferences: ^2.0.15 - sqlite3: ^1.9.1 + sqlite3: ^2.1.0 stack_trace: ^1.11.0 - string_validator: ^0.3.0 + string_validator: ^1.0.2 time_machine: ^0.9.17 url_launcher: ^6.1.6 - uuid: ^3.0.6 + uuid: ^4.1.0 video_player: ^2.4.10 flutter_svg: ^2.0.5 @@ -64,7 +59,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^3.0.0 build_runner: ^2.3.3 objectbox_generator: ^2.0.0 diff --git a/test/pages_manager_test.dart b/test/pages_manager_test.dart index 0cc7222..1bbfa30 100644 --- a/test/pages_manager_test.dart +++ b/test/pages_manager_test.dart @@ -14,19 +14,25 @@ void main() async { final pm = _buildPagesManager(); final numbers = []; final initial = await pm.initialize(10); - initial.value.data.forEach((e) => numbers.add(e.id)); + for (var e in initial.value.data) { + numbers.add(e.id); + } var current = initial.value; while (current.next != null) { final result = await pm.nextWithResult(current); current = result.value; - result.value.data.forEach((e) => numbers.add(e.id)); + for (var e in result.value.data) { + numbers.add(e.id); + } } current = initial.value; while (current.previous != null) { final result = await pm.previousWithResult(current); current = result.value; - result.value.data.forEach((e) => numbers.add(e.id)); + for (var e in result.value.data) { + numbers.add(e.id); + } } numbers.sort(); final expected = elements.map((e) => e.id).toList(); @@ -40,7 +46,9 @@ void main() async { final pm = _buildPagesManager(); final numbers = []; final initial = await pm.initialize(10); - initial.value.data.reversed.forEach((e) => numbers.add(e.id)); + for (var e in initial.value.data.reversed) { + numbers.add(e.id); + } var moreWork = true; while (moreWork) { final nextFromEnd = await pm.nextFromEnd(); diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 6b3d3e0..6dc2888 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,16 +7,20 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include #include +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { DesktopWindowPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DesktopWindowPlugin")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( @@ -25,6 +29,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); ObjectboxFlutterLibsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ObjectboxFlutterLibsPlugin")); + ScreenBrightnessWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowToFrontPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index f4d8ce9..65ba3a4 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,10 +4,12 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_window + file_selector_windows flutter_secure_storage_windows media_kit_libs_windows_video media_kit_video objectbox_flutter_libs + screen_brightness_windows url_launcher_windows window_to_front )