From d19fa0ccd0fd44d0580252faeae6dc303a248fbb Mon Sep 17 00:00:00 2001 From: PartyDonut Date: Sun, 6 Oct 2024 19:01:46 +0200 Subject: [PATCH] [Fixed] Use browser navigation --- lib/providers/library_search_provider.dart | 25 ++++--- lib/routes/auto_router.dart | 13 ++-- lib/routes/nested_details_screen.dart | 22 +++++- .../details_screens/book_detail_screen.dart | 12 ++-- .../episode_detail_screen.dart | 20 +++--- .../details_screens/movie_detail_screen.dart | 16 +++-- .../details_screens/season_detail_screen.dart | 10 ++- .../details_screens/series_detail_screen.dart | 23 +++--- .../library_search/library_search_screen.dart | 46 ++++++++---- .../widgets/library_filter_chips.dart | 10 +-- lib/screens/login/login_screen.dart | 2 +- lib/screens/metadata/identifty_screen.dart | 8 ++- lib/screens/metadata/info_screen.dart | 10 +-- .../settings/client_settings_page.dart | 6 +- lib/screens/settings/settings_scaffold.dart | 3 + lib/screens/settings/settings_screen.dart | 5 +- lib/screens/shared/detail_scaffold.dart | 70 ++----------------- lib/screens/splash_screen.dart | 23 ++++-- lib/util/router_extension.dart | 30 ++++++++ .../components/navigation_drawer.dart | 3 +- .../navigation_scaffold.dart | 6 +- lib/widgets/shared/trickplay_image.dart | 3 +- 22 files changed, 210 insertions(+), 156 deletions(-) create mode 100644 lib/util/router_extension.dart diff --git a/lib/providers/library_search_provider.dart b/lib/providers/library_search_provider.dart index 5130073..764f08d 100644 --- a/lib/providers/library_search_provider.dart +++ b/lib/providers/library_search_provider.dart @@ -1,31 +1,32 @@ import 'dart:developer'; +import 'package:flutter/material.dart'; + import 'package:chopper/chopper.dart'; import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:page_transition/page_transition.dart'; + +import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; import 'package:fladder/models/collection_types.dart'; +import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/models/items/folder_model.dart'; import 'package:fladder/models/items/item_shared_models.dart'; import 'package:fladder/models/items/photos_model.dart'; +import 'package:fladder/models/library_search/library_search_model.dart'; import 'package:fladder/models/library_search/library_search_options.dart'; import 'package:fladder/models/playlist_model.dart'; +import 'package:fladder/models/view_model.dart'; +import 'package:fladder/providers/api_provider.dart'; import 'package:fladder/providers/service_provider.dart'; import 'package:fladder/providers/settings/client_settings_provider.dart'; +import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/screens/photo_viewer/photo_viewer_screen.dart'; import 'package:fladder/screens/shared/fladder_snackbar.dart'; import 'package:fladder/util/item_base_model/play_item_helpers.dart'; import 'package:fladder/util/list_extensions.dart'; import 'package:fladder/util/localization_helper.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart'; -import 'package:fladder/models/item_base_model.dart'; -import 'package:fladder/models/library_search/library_search_model.dart'; -import 'package:fladder/models/view_model.dart'; -import 'package:fladder/providers/api_provider.dart'; -import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/util/map_bool_helper.dart'; -import 'package:page_transition/page_transition.dart'; final librarySearchProvider = StateNotifierProvider.family.autoDispose((ref, id) { @@ -652,6 +653,10 @@ class LibrarySearchNotifier extends StateNotifier { items.firstOrNull?.navigateTo(context); } } + + void updateEverything() { + state = state.copyWith(); + } } extension SimpleSorter on List { diff --git a/lib/routes/auto_router.dart b/lib/routes/auto_router.dart index 9770c28..ad0dc76 100644 --- a/lib/routes/auto_router.dart +++ b/lib/routes/auto_router.dart @@ -10,7 +10,10 @@ import 'package:fladder/util/adaptive_layout.dart'; @AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route') class AutoRouter extends RootStackRouter { - AutoRouter({required this.layout, required this.ref}); + AutoRouter({ + required this.layout, + required this.ref, + }); final WidgetRef ref; final ScreenLayout layout; @@ -35,8 +38,8 @@ class AutoRouter extends RootStackRouter { _syncedRoute, ], ), - AutoRoute(page: DetailsRoute.page, path: '/details'), - AutoRoute(page: LibrarySearchRoute.page, path: '/library'), + AutoRoute(page: DetailsRoute.page, path: '/details', usesPathAsKey: true), + AutoRoute(page: LibrarySearchRoute.page, path: '/library', usesPathAsKey: true), AutoRoute(page: SettingsRoute.page, path: '/settings'), ..._settingsChildren.map( (e) => e.copyWith(path: "/$e", initial: false), @@ -49,8 +52,8 @@ class AutoRouter extends RootStackRouter { _dashboardRoute, _favouritesRoute, _syncedRoute, - AutoRoute(page: DetailsRoute.page, path: 'details'), - AutoRoute(page: LibrarySearchRoute.page, path: 'library'), + AutoRoute(page: DetailsRoute.page, path: 'details', usesPathAsKey: true), + AutoRoute(page: LibrarySearchRoute.page, path: 'library', usesPathAsKey: true), AutoRoute( page: SettingsRoute.page, path: 'settings', diff --git a/lib/routes/nested_details_screen.dart b/lib/routes/nested_details_screen.dart index 8e95c99..e545855 100644 --- a/lib/routes/nested_details_screen.dart +++ b/lib/routes/nested_details_screen.dart @@ -1,10 +1,13 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + import 'package:auto_route/auto_route.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/providers/items/item_details_provider.dart'; import 'package:fladder/routes/auto_router.gr.dart'; import 'package:fladder/util/fladder_image.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; @RoutePage() class DetailsScreen extends ConsumerStatefulWidget { @@ -22,9 +25,21 @@ class _DetailsScreenState extends ConsumerState { child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), ); + @override + void didUpdateWidget(covariant DetailsScreen oldWidget) { + super.didUpdateWidget(oldWidget); + if (kIsWeb) { + updateWidget(); + } + } + @override void initState() { super.initState(); + updateWidget(); + } + + Future updateWidget() async { Future.microtask(() async { if (widget.item != null) { setState(() { @@ -38,7 +53,7 @@ class _DetailsScreenState extends ConsumerState { currentWidget = response.detailScreenWidget; }); } else { - const DashboardRoute().navigate(context); + const DashboardRoute().navigate(context); } } } @@ -48,6 +63,7 @@ class _DetailsScreenState extends ConsumerState { @override Widget build(BuildContext context) { return Stack( + key: Key(widget.id), children: [ Hero( tag: widget.id, diff --git a/lib/screens/details_screens/book_detail_screen.dart b/lib/screens/details_screens/book_detail_screen.dart index b77f703..2288566 100644 --- a/lib/screens/details_screens/book_detail_screen.dart +++ b/lib/screens/details_screens/book_detail_screen.dart @@ -1,5 +1,9 @@ +import 'package:flutter/material.dart'; + import 'package:auto_route/auto_route.dart'; import 'package:ficonsax/ficonsax.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/book_model.dart'; import 'package:fladder/providers/items/book_details_provider.dart'; import 'package:fladder/providers/user_provider.dart'; @@ -13,12 +17,11 @@ import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; import 'package:fladder/util/item_base_model/play_item_helpers.dart'; import 'package:fladder/util/list_padding.dart'; import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/router_extension.dart'; import 'package:fladder/util/widget_extensions.dart'; import 'package:fladder/widgets/shared/item_actions.dart'; import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; import 'package:fladder/widgets/shared/selectable_icon_button.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; class BookDetailScreen extends ConsumerStatefulWidget { final BookModel item; @@ -29,7 +32,8 @@ class BookDetailScreen extends ConsumerStatefulWidget { } class _BookDetailScreenState extends ConsumerState { - late final provider = bookDetailsProvider(widget.item.id); + AutoDisposeStateNotifierProvider get provider => + bookDetailsProvider(widget.item.id); @override Widget build(BuildContext context) { @@ -47,7 +51,7 @@ class _BookDetailScreenState extends ConsumerState { }, onDeleteSuccesFully: (item) { if (context.mounted) { - context.router.maybePop(); + context.router.popBack(); } }, ), diff --git a/lib/screens/details_screens/episode_detail_screen.dart b/lib/screens/details_screens/episode_detail_screen.dart index 9b88e6e..17d0792 100644 --- a/lib/screens/details_screens/episode_detail_screen.dart +++ b/lib/screens/details_screens/episode_detail_screen.dart @@ -1,25 +1,26 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:ficonsax/ficonsax.dart'; -import 'package:fladder/screens/details_screens/components/overview_header.dart'; -import 'package:fladder/screens/shared/media/components/media_play_button.dart'; -import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; -import 'package:fladder/util/item_base_model/play_item_helpers.dart'; -import 'package:fladder/util/localization_helper.dart'; import 'package:flutter/material.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:ficonsax/ficonsax.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/providers/items/episode_details_provider.dart'; import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/screens/details_screens/components/media_stream_information.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; import 'package:fladder/screens/shared/detail_scaffold.dart'; import 'package:fladder/screens/shared/fladder_snackbar.dart'; import 'package:fladder/screens/shared/media/chapter_row.dart'; import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; import 'package:fladder/screens/shared/media/episode_posters.dart'; import 'package:fladder/screens/shared/media/expanding_overview.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/router_extension.dart'; import 'package:fladder/util/widget_extensions.dart'; import 'package:fladder/widgets/shared/selectable_icon_button.dart'; @@ -32,7 +33,8 @@ class EpisodeDetailScreen extends ConsumerStatefulWidget { } class _ItemDetailScreenState extends ConsumerState { - late final providerInstance = episodeDetailsProvider(widget.item.id); + AutoDisposeStateNotifierProvider get providerInstance => + episodeDetailsProvider(widget.item.id); @override Widget build(BuildContext context) { @@ -52,7 +54,7 @@ class _ItemDetailScreenState extends ConsumerState { }, onDeleteSuccesFully: (item) { if (context.mounted) { - context.router.maybePop(); + context.router.popBack(); } }, ), diff --git a/lib/screens/details_screens/movie_detail_screen.dart b/lib/screens/details_screens/movie_detail_screen.dart index a235d78..bb87805 100644 --- a/lib/screens/details_screens/movie_detail_screen.dart +++ b/lib/screens/details_screens/movie_detail_screen.dart @@ -1,25 +1,27 @@ +import 'package:fladder/util/router_extension.dart'; +import 'package:flutter/material.dart'; + import 'package:auto_route/auto_route.dart'; import 'package:ficonsax/ficonsax.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/providers/items/movies_details_provider.dart'; import 'package:fladder/providers/user_provider.dart'; -import 'package:fladder/screens/details_screens/components/overview_header.dart'; import 'package:fladder/screens/details_screens/components/media_stream_information.dart'; -import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; import 'package:fladder/screens/shared/detail_scaffold.dart'; import 'package:fladder/screens/shared/media/chapter_row.dart'; +import 'package:fladder/screens/shared/media/components/media_header.dart'; import 'package:fladder/screens/shared/media/components/media_play_button.dart'; import 'package:fladder/screens/shared/media/expanding_overview.dart'; import 'package:fladder/screens/shared/media/people_row.dart'; import 'package:fladder/screens/shared/media/poster_row.dart'; import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; import 'package:fladder/util/item_base_model/play_item_helpers.dart'; - import 'package:fladder/util/list_padding.dart'; import 'package:fladder/util/widget_extensions.dart'; import 'package:fladder/widgets/shared/selectable_icon_button.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; class MovieDetailScreen extends ConsumerStatefulWidget { final ItemBaseModel item; @@ -30,7 +32,7 @@ class MovieDetailScreen extends ConsumerStatefulWidget { } class _ItemDetailScreenState extends ConsumerState { - late final providerInstance = movieDetailsProvider(widget.item.id); + MovieDetailsProvider get providerInstance => movieDetailsProvider(widget.item.id); @override Widget build(BuildContext context) { @@ -49,7 +51,7 @@ class _ItemDetailScreenState extends ConsumerState { }, onDeleteSuccesFully: (item) { if (context.mounted) { - context.router.maybePop(); + context.router.popBack(); } }, ), diff --git a/lib/screens/details_screens/season_detail_screen.dart b/lib/screens/details_screens/season_detail_screen.dart index e34be27..ec2874f 100644 --- a/lib/screens/details_screens/season_detail_screen.dart +++ b/lib/screens/details_screens/season_detail_screen.dart @@ -1,5 +1,10 @@ +import 'package:flutter/material.dart'; + import 'package:ficonsax/ficonsax.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/season_model.dart'; import 'package:fladder/providers/items/season_details_provider.dart'; import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/screens/details_screens/components/overview_header.dart'; @@ -16,8 +21,6 @@ import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/string_extensions.dart'; import 'package:fladder/util/widget_extensions.dart'; import 'package:fladder/widgets/shared/selectable_icon_button.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; class SeasonDetailScreen extends ConsumerStatefulWidget { final ItemBaseModel item; @@ -29,7 +32,8 @@ class SeasonDetailScreen extends ConsumerStatefulWidget { class _SeasonDetailScreenState extends ConsumerState { Set viewOptions = {EpisodeDetailsViewType.grid}; - late final providerId = seasonDetailsProvider(widget.item.id); + AutoDisposeStateNotifierProvider get providerId => + seasonDetailsProvider(widget.item.id); @override Widget build(BuildContext context) { diff --git a/lib/screens/details_screens/series_detail_screen.dart b/lib/screens/details_screens/series_detail_screen.dart index 9278da9..33a5d7f 100644 --- a/lib/screens/details_screens/series_detail_screen.dart +++ b/lib/screens/details_screens/series_detail_screen.dart @@ -1,26 +1,28 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:ficonsax/ficonsax.dart'; -import 'package:fladder/screens/details_screens/components/overview_header.dart'; -import 'package:fladder/screens/shared/media/components/media_play_button.dart'; -import 'package:fladder/screens/shared/media/components/next_up_episode.dart'; -import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; -import 'package:fladder/util/item_base_model/play_item_helpers.dart'; -import 'package:fladder/util/localization_helper.dart'; import 'package:flutter/material.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:ficonsax/ficonsax.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/models/item_base_model.dart'; +import 'package:fladder/models/items/series_model.dart'; import 'package:fladder/providers/items/series_details_provider.dart'; import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/screens/details_screens/components/overview_header.dart'; import 'package:fladder/screens/shared/detail_scaffold.dart'; import 'package:fladder/screens/shared/media/components/media_header.dart'; +import 'package:fladder/screens/shared/media/components/media_play_button.dart'; +import 'package:fladder/screens/shared/media/components/next_up_episode.dart'; import 'package:fladder/screens/shared/media/episode_posters.dart'; import 'package:fladder/screens/shared/media/expanding_overview.dart'; import 'package:fladder/screens/shared/media/people_row.dart'; import 'package:fladder/screens/shared/media/poster_row.dart'; import 'package:fladder/screens/shared/media/season_row.dart'; +import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; +import 'package:fladder/util/item_base_model/play_item_helpers.dart'; import 'package:fladder/util/list_padding.dart'; +import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/router_extension.dart'; import 'package:fladder/util/widget_extensions.dart'; import 'package:fladder/widgets/shared/selectable_icon_button.dart'; @@ -33,7 +35,8 @@ class SeriesDetailScreen extends ConsumerStatefulWidget { } class _SeriesDetailScreenState extends ConsumerState { - late final providerId = seriesDetailsProvider(widget.item.id); + AutoDisposeStateNotifierProvider get providerId => + seriesDetailsProvider(widget.item.id); @override Widget build(BuildContext context) { @@ -51,7 +54,7 @@ class _SeriesDetailScreenState extends ConsumerState { }, onDeleteSuccesFully: (item) { if (context.mounted) { - context.router.maybePop(); + context.router.popBack(); } }, ), diff --git a/lib/screens/library_search/library_search_screen.dart b/lib/screens/library_search/library_search_screen.dart index 6141910..2ea5060 100644 --- a/lib/screens/library_search/library_search_screen.dart +++ b/lib/screens/library_search/library_search_screen.dart @@ -1,3 +1,7 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + import 'package:auto_route/auto_route.dart'; import 'package:ficonsax/ficonsax.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -28,6 +32,7 @@ import 'package:fladder/util/item_base_model/item_base_model_extensions.dart'; import 'package:fladder/util/list_padding.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/util/router_extension.dart'; import 'package:fladder/util/sliver_list_padding.dart'; import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart'; import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; @@ -41,9 +46,6 @@ import 'package:fladder/widgets/shared/pull_to_refresh.dart'; import 'package:fladder/widgets/shared/scroll_position.dart'; import 'package:fladder/widgets/shared/shapes.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - @RoutePage() class LibrarySearchScreen extends ConsumerStatefulWidget { final String? viewModelId; @@ -67,9 +69,6 @@ class LibrarySearchScreen extends ConsumerStatefulWidget { } class _LibrarySearchScreenState extends ConsumerState { - late final Key uniqueKey = Key(widget.folderId?.join(',').toString() ?? widget.viewModelId ?? UniqueKey().toString()); - late final providerKey = librarySearchProvider(uniqueKey); - late final libraryProvider = ref.read(providerKey.notifier); final SearchController searchController = SearchController(); final Debouncer debouncer = Debouncer(const Duration(seconds: 1)); final GlobalKey refreshKey = GlobalKey(); @@ -78,9 +77,26 @@ class _LibrarySearchScreenState extends ConsumerState { bool loadOnStart = false; + Key get uniqueKey => Key(widget.folderId?.join(',').toString() ?? widget.viewModelId ?? "EmptySearch"); + AutoDisposeStateNotifierProvider get providerKey => + librarySearchProvider(uniqueKey); + LibrarySearchNotifier get libraryProvider => ref.read(librarySearchProvider(uniqueKey).notifier); + + @override + void didUpdateWidget(covariant LibrarySearchScreen oldWidget) { + super.didUpdateWidget(oldWidget); + if (kIsWeb && ref.read(librarySearchProvider(uniqueKey)).posters.isEmpty) { + initLibrary(); + } + } + @override void initState() { super.initState(); + initLibrary(); + } + + void initLibrary() { searchController.addListener(() { debouncer.run(() { ref.read(providerKey.notifier).setSearch(searchController.text); @@ -89,7 +105,9 @@ class _LibrarySearchScreenState extends ConsumerState { Future.microtask( () async { - libraryProvider.setDefaultOptions(widget.sortOrder, widget.sortingOptions); + if (libraryProvider.mounted) { + libraryProvider.setDefaultOptions(widget.sortOrder, widget.sortingOptions); + } await refreshKey.currentState?.show(); SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, @@ -115,10 +133,8 @@ class _LibrarySearchScreenState extends ConsumerState { Widget build(BuildContext context) { final isEmptySearchScreen = widget.viewModelId == null && widget.favourites == null && widget.folderId == null; final librarySearchResults = ref.watch(providerKey); - final libraryProvider = ref.read(providerKey.notifier); final postersList = librarySearchResults.posters.hideEmptyChildren(librarySearchResults.hideEmtpyShows); final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state)); - final libraryViewType = ref.watch(libraryViewTypeProvider); ref.listen( @@ -132,6 +148,7 @@ class _LibrarySearchScreenState extends ConsumerState { ); return PopScope( + key: uniqueKey, canPop: !librarySearchResults.selecteMode, onPopInvokedWithResult: (didPop, result) { if (librarySearchResults.selecteMode) { @@ -210,8 +227,12 @@ class _LibrarySearchScreenState extends ConsumerState { refreshKey: refreshKey, autoFocus: false, contextRefresh: false, - onRefresh: () async => - libraryProvider.initRefresh(widget.folderId, widget.viewModelId, widget.favourites), + onRefresh: () async { + if (libraryProvider.mounted) { + return libraryProvider.initRefresh( + widget.folderId, widget.viewModelId, widget.favourites); + } + }, refreshOnStart: false, child: CustomScrollView( physics: const AlwaysScrollableNoImplicitScrollPhysics(), @@ -220,10 +241,11 @@ class _LibrarySearchScreenState extends ConsumerState { SliverAppBar( floating: !AdaptiveLayout.of(context).isDesktop, collapsedHeight: 80, - automaticallyImplyLeading: true, + automaticallyImplyLeading: false, pinned: AdaptiveLayout.of(context).isDesktop, primary: true, elevation: 5, + leading: context.router.backButton(), surfaceTintColor: Colors.transparent, shadowColor: Colors.transparent, backgroundColor: Theme.of(context).colorScheme.surface, diff --git a/lib/screens/library_search/widgets/library_filter_chips.dart b/lib/screens/library_search/widgets/library_filter_chips.dart index 9e72b6f..92d9ae9 100644 --- a/lib/screens/library_search/widgets/library_filter_chips.dart +++ b/lib/screens/library_search/widgets/library_filter_chips.dart @@ -1,4 +1,8 @@ +import 'package:flutter/material.dart'; + import 'package:ficonsax/ficonsax.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart'; import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/models/items/item_shared_models.dart'; @@ -12,8 +16,6 @@ import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/map_bool_helper.dart'; import 'package:fladder/util/refresh_state.dart'; import 'package:fladder/widgets/shared/scroll_position.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; class LibraryFilterChips extends ConsumerWidget { final Key uniqueKey; @@ -188,12 +190,12 @@ List libraryFilterChips( if (librarySearchResults.types[FladderItemType.series] == true) FilterChip( avatar: Icon( - librarySearchResults.hideEmtpyShows ? Icons.visibility_rounded : Icons.visibility_off_rounded, + librarySearchResults.hideEmtpyShows ? Icons.visibility_off_rounded : Icons.visibility_rounded, color: Theme.of(context).colorScheme.onSurface, ), selected: librarySearchResults.hideEmtpyShows, showCheckmark: false, - label: Text(librarySearchResults.hideEmtpyShows ? context.localized.showEmpty : context.localized.hideEmpty), + label: Text(context.localized.hideEmpty), onSelected: libraryProvider.setHideEmpty, ), if (librarySearchResults.officialRatings.isNotEmpty) diff --git a/lib/screens/login/login_screen.dart b/lib/screens/login/login_screen.dart index 181898f..c54b734 100644 --- a/lib/screens/login/login_screen.dart +++ b/lib/screens/login/login_screen.dart @@ -164,7 +164,7 @@ class _LoginPageState extends ConsumerState { serverTextController.text = value; startAddingNewUser(); }); - context.router.maybePop(); + Navigator.of(context).pop(); }, ), ); diff --git a/lib/screens/metadata/identifty_screen.dart b/lib/screens/metadata/identifty_screen.dart index f0f4ca1..127508e 100644 --- a/lib/screens/metadata/identifty_screen.dart +++ b/lib/screens/metadata/identifty_screen.dart @@ -1,6 +1,10 @@ +import 'package:flutter/material.dart'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:collection/collection.dart'; import 'package:ficonsax/ficonsax.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/providers/items/identify_provider.dart'; import 'package:fladder/screens/shared/adaptive_dialog.dart'; @@ -9,8 +13,6 @@ import 'package:fladder/screens/shared/focused_outlined_text_field.dart'; import 'package:fladder/screens/shared/media/external_urls.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/string_extensions.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; Future showIdentifyScreen(BuildContext context, ItemBaseModel item) async { return showDialogAdaptive( @@ -30,7 +32,7 @@ class IdentifyScreen extends ConsumerStatefulWidget { } class _IdentifyScreenState extends ConsumerState with TickerProviderStateMixin { - late AutoDisposeStateNotifierProvider provider = identifyProvider(widget.item.id); + AutoDisposeStateNotifierProvider get provider => identifyProvider(widget.item.id); late final TabController tabController = TabController(length: 2, vsync: this); TextEditingController? currentController; diff --git a/lib/screens/metadata/info_screen.dart b/lib/screens/metadata/info_screen.dart index 00e2262..9243675 100644 --- a/lib/screens/metadata/info_screen.dart +++ b/lib/screens/metadata/info_screen.dart @@ -1,13 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + import 'package:ficonsax/ficonsax.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/information_model.dart'; import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/providers/items/information_provider.dart'; import 'package:fladder/screens/shared/fladder_snackbar.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/widgets/shared/clickable_text.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter/services.dart'; Future showInfoScreen(BuildContext context, ItemBaseModel item) async { return showDialog( @@ -27,7 +29,7 @@ class ItemInfoScreen extends ConsumerStatefulWidget { } class ItemInfoScreenState extends ConsumerState { - late AutoDisposeStateNotifierProvider provider = + AutoDisposeStateNotifierProvider get provider => informationProvider(widget.item.id); @override diff --git a/lib/screens/settings/client_settings_page.dart b/lib/screens/settings/client_settings_page.dart index d913c6a..3560601 100644 --- a/lib/screens/settings/client_settings_page.dart +++ b/lib/screens/settings/client_settings_page.dart @@ -133,10 +133,10 @@ class _ClientSettingsPageState extends ConsumerState { (context) async { await ref.read(syncProvider.notifier).clear(); setState(() {}); - context.router.maybePop(); + Navigator.of(context).pop(); }, context.localized.clear, - (context) => context.router.maybePop(), + (context) => Navigator.of(context).pop(), context.localized.cancel, ); }, @@ -451,7 +451,7 @@ class _ClientSettingsPageState extends ConsumerState { mainAxisSize: MainAxisSize.min, children: [ FilledButton( - onPressed: () => context.router.maybePop(), + onPressed: () => Navigator.of(context).pop(), child: Text(context.localized.cancel), ), const SizedBox(width: 8), diff --git a/lib/screens/settings/settings_scaffold.dart b/lib/screens/settings/settings_scaffold.dart index f6b37df..ee811ad 100644 --- a/lib/screens/settings/settings_scaffold.dart +++ b/lib/screens/settings/settings_scaffold.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/screens/shared/user_icon.dart'; import 'package:fladder/util/adaptive_layout.dart'; +import 'package:fladder/util/router_extension.dart'; class SettingsScaffold extends ConsumerWidget { final String label; @@ -39,6 +41,7 @@ class SettingsScaffold extends ConsumerWidget { if (AdaptiveLayout.of(context).size == ScreenLayout.single) SliverAppBar.large( backgroundColor: Theme.of(context).scaffoldBackgroundColor, + leading: context.router.backButton(), flexibleSpace: FlexibleSpaceBar( titlePadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16) .add(EdgeInsets.only(left: padding.left, right: padding.right)), diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart index 1dfb0e5..d776fe1 100644 --- a/lib/screens/settings/settings_screen.dart +++ b/lib/screens/settings/settings_screen.dart @@ -15,6 +15,7 @@ import 'package:fladder/screens/shared/fladder_icon.dart'; import 'package:fladder/util/adaptive_layout.dart'; import 'package:fladder/util/application_info.dart'; import 'package:fladder/util/localization_helper.dart'; +import 'package:fladder/util/router_extension.dart'; import 'package:fladder/util/theme_extensions.dart'; import 'package:fladder/widgets/shared/hide_on_scroll.dart'; @@ -90,7 +91,7 @@ class _SettingsScreenState extends ConsumerState { scrollController: scrollController, showUserIcon: true, items: [ - if (context.router.canPop() && AdaptiveLayout.of(context).size == ScreenLayout.dual) + if (context.router.canNavigateBack && AdaptiveLayout.of(context).size == ScreenLayout.dual) Align( alignment: Alignment.centerLeft, child: Padding( @@ -99,7 +100,7 @@ class _SettingsScreenState extends ConsumerState { style: IconButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.8), ), - onPressed: () => context.router.maybePop(), + onPressed: () => context.router.popBack(), icon: Padding( padding: EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4), child: const Icon(IconsaxOutline.arrow_left_2), diff --git a/lib/screens/shared/detail_scaffold.dart b/lib/screens/shared/detail_scaffold.dart index 0f0e50b..f33f18d 100644 --- a/lib/screens/shared/detail_scaffold.dart +++ b/lib/screens/shared/detail_scaffold.dart @@ -7,7 +7,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/models/items/images_models.dart'; import 'package:fladder/models/media_playback_model.dart'; -import 'package:fladder/providers/items/item_details_provider.dart'; import 'package:fladder/providers/video_player_provider.dart'; import 'package:fladder/routes/auto_router.gr.dart'; import 'package:fladder/theme.dart'; @@ -15,74 +14,13 @@ import 'package:fladder/util/adaptive_layout.dart'; import 'package:fladder/util/fladder_image.dart'; import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/refresh_state.dart'; +import 'package:fladder/util/router_extension.dart'; import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart'; import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart'; import 'package:fladder/widgets/shared/item_actions.dart'; import 'package:fladder/widgets/shared/modal_bottom_sheet.dart'; import 'package:fladder/widgets/shared/pull_to_refresh.dart'; -class DetailScreen extends ConsumerStatefulWidget { - final String id; - final ItemBaseModel? item; - const DetailScreen({required this.id, this.item, super.key}); - - @override - ConsumerState createState() => _DetailScreenState(); -} - -class _DetailScreenState extends ConsumerState { - late Widget currentWidget = const Center( - key: Key("progress-indicator"), - child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round), - ); - - @override - void initState() { - super.initState(); - Future.microtask(() async { - if (widget.item != null) { - setState(() { - currentWidget = widget.item!.detailScreenWidget; - }); - } else { - final response = await ref.read(itemDetailsProvider.notifier).fetchDetails(widget.id); - if (context.mounted) { - if (response != null) { - setState(() { - currentWidget = response.detailScreenWidget; - }); - } else { - context.router.navigate(const DashboardRoute()); - } - } - } - }); - } - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - Hero( - tag: widget.id, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface.withOpacity(1.0), - ), - //Small offset to match detailscaffold - child: Transform.translate( - offset: const Offset(0, -5), child: FladderImage(image: widget.item?.getPosters?.primary)), - ), - ), - AnimatedSwitcher( - duration: const Duration(seconds: 1), - child: currentWidget, - ) - ], - ); - } -} - class DetailScaffold extends ConsumerStatefulWidget { final String label; final ItemBaseModel? item; @@ -212,7 +150,7 @@ class _DetailScaffoldState extends ConsumerState { style: IconButton.styleFrom( backgroundColor: backGroundColor, ), - onPressed: () => context.router.maybePop(), + onPressed: () => context.router.popBack(), icon: Padding( padding: EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4), @@ -269,8 +207,8 @@ class _DetailScaffoldState extends ConsumerState { icon: const Icon(IconsaxOutline.refresh), ), ), - ) - else + ), + if (AdaptiveLayout.of(context).size == ScreenLayout.single) const SizedBox(height: 30, width: 30, child: SettingsUserIcon()), Tooltip( message: context.localized.home, diff --git a/lib/screens/splash_screen.dart b/lib/screens/splash_screen.dart index 0849160..efa5301 100644 --- a/lib/screens/splash_screen.dart +++ b/lib/screens/splash_screen.dart @@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/models/account_model.dart'; import 'package:fladder/providers/shared_provider.dart'; import 'package:fladder/providers/user_provider.dart'; +import 'package:fladder/routes/auto_router.gr.dart'; import 'package:fladder/screens/shared/fladder_logo.dart'; @RoutePage() @@ -28,19 +29,16 @@ class _SplashScreenState extends ConsumerState { if (context.mounted) { if (lastUsedAccount == null) { - widget.loggedIn?.call(false); - context.router.maybePop(false); + callBackOrNavigate(false); } else { switch (lastUsedAccount.authMethod) { case Authentication.autoLogin: - widget.loggedIn?.call(true); - context.router.maybePop(true); + callBackOrNavigate(true); break; case Authentication.biometrics: case Authentication.none: case Authentication.passcode: - widget.loggedIn?.call(false); - context.router.maybePop(false); + callBackOrNavigate(false); break; } } @@ -48,6 +46,19 @@ class _SplashScreenState extends ConsumerState { }); } + void callBackOrNavigate(bool loggedIn) { + if (widget.loggedIn == null) { + if (loggedIn) { + context.router.replace(const DashboardRoute()); + } else { + context.router.replace(const LoginRoute()); + } + } else { + widget.loggedIn?.call(loggedIn); + context.router.maybePop(loggedIn); + } + } + @override Widget build(BuildContext context) { return const Scaffold( diff --git a/lib/util/router_extension.dart b/lib/util/router_extension.dart new file mode 100644 index 0000000..7b13b7a --- /dev/null +++ b/lib/util/router_extension.dart @@ -0,0 +1,30 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import 'package:auto_route/auto_route.dart'; + +extension RouterExtension on StackRouter { + Future popBack() async { + if (kIsWeb) { + back(); + return canNavigateBack; + } else { + return maybePop(); + } + } + + Widget? backButton() { + if (kIsWeb && canNavigateBack) { + return IconButton( + onPressed: back, + icon: const BackButtonIcon(), + ); + } else if (canPop()) { + return IconButton( + onPressed: maybePop, + icon: const BackButtonIcon(), + ); + } + return null; + } +} diff --git a/lib/widgets/navigation_scaffold/components/navigation_drawer.dart b/lib/widgets/navigation_scaffold/components/navigation_drawer.dart index a2f47c5..1f1c0a7 100644 --- a/lib/widgets/navigation_scaffold/components/navigation_drawer.dart +++ b/lib/widgets/navigation_scaffold/components/navigation_drawer.dart @@ -154,7 +154,8 @@ class NestedNavigationDrawer extends ConsumerWidget { bool checkLibrary(BuildContext context, String id) { try { - return context.routeData.queryParams.isNotEmpty && context.routeData.queryParams.getString('parentId') == id; + return context.router.current.name == LibrarySearchRoute().routeName && + (context.routeData.queryParams.isNotEmpty && context.routeData.queryParams.getString('parentId') == id); } catch (e) { return false; } diff --git a/lib/widgets/navigation_scaffold/navigation_scaffold.dart b/lib/widgets/navigation_scaffold/navigation_scaffold.dart index 3d7b960..bb0ef94 100644 --- a/lib/widgets/navigation_scaffold/navigation_scaffold.dart +++ b/lib/widgets/navigation_scaffold/navigation_scaffold.dart @@ -1,3 +1,7 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'package:fladder/models/media_playback_model.dart'; import 'package:fladder/providers/video_player_provider.dart'; import 'package:fladder/providers/views_provider.dart'; @@ -9,8 +13,6 @@ import 'package:fladder/widgets/navigation_scaffold/components/floating_player_b import 'package:fladder/widgets/navigation_scaffold/components/navigation_body.dart'; import 'package:fladder/widgets/navigation_scaffold/components/navigation_drawer.dart'; import 'package:fladder/widgets/shared/hide_on_scroll.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; class NavigationScaffold extends ConsumerStatefulWidget { final String? currentRouteName; diff --git a/lib/widgets/shared/trickplay_image.dart b/lib/widgets/shared/trickplay_image.dart index 2a8b40f..48d18d0 100644 --- a/lib/widgets/shared/trickplay_image.dart +++ b/lib/widgets/shared/trickplay_image.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; + import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart' as http; @@ -34,12 +35,12 @@ class _TrickplayImageState extends ConsumerState { @override void didUpdateWidget(covariant TrickplayImage oldWidget) { + super.didUpdateWidget(oldWidget); if (oldWidget.position?.inMilliseconds != widget.position?.inMilliseconds) { time = widget.position ?? Duration.zero; model = widget.trickplay; loadImage(); } - super.didUpdateWidget(oldWidget); } @override