[Fixed] Use browser navigation

This commit is contained in:
PartyDonut 2024-10-06 19:01:46 +02:00
parent 69b3a77d17
commit d19fa0ccd0
22 changed files with 210 additions and 156 deletions

View file

@ -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<LibrarySearchNotifier, LibrarySearchModel, Key>((ref, id) {
@ -652,6 +653,10 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
items.firstOrNull?.navigateTo(context);
}
}
void updateEverything() {
state = state.copyWith();
}
}
extension SimpleSorter on List<ItemBaseModel> {

View file

@ -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',

View file

@ -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<DetailsScreen> {
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<void> updateWidget() async {
Future.microtask(() async {
if (widget.item != null) {
setState(() {
@ -48,6 +63,7 @@ class _DetailsScreenState extends ConsumerState<DetailsScreen> {
@override
Widget build(BuildContext context) {
return Stack(
key: Key(widget.id),
children: [
Hero(
tag: widget.id,

View file

@ -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<BookDetailScreen> {
late final provider = bookDetailsProvider(widget.item.id);
AutoDisposeStateNotifierProvider<BookDetailsProviderNotifier, BookProviderModel> get provider =>
bookDetailsProvider(widget.item.id);
@override
Widget build(BuildContext context) {
@ -47,7 +51,7 @@ class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
},
onDeleteSuccesFully: (item) {
if (context.mounted) {
context.router.maybePop();
context.router.popBack();
}
},
),

View file

@ -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<EpisodeDetailScreen> {
late final providerInstance = episodeDetailsProvider(widget.item.id);
AutoDisposeStateNotifierProvider<EpisodeDetailsProvider, EpisodeDetailModel> get providerInstance =>
episodeDetailsProvider(widget.item.id);
@override
Widget build(BuildContext context) {
@ -52,7 +54,7 @@ class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
},
onDeleteSuccesFully: (item) {
if (context.mounted) {
context.router.maybePop();
context.router.popBack();
}
},
),

View file

@ -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<MovieDetailScreen> {
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<MovieDetailScreen> {
},
onDeleteSuccesFully: (item) {
if (context.mounted) {
context.router.maybePop();
context.router.popBack();
}
},
),

View file

@ -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<SeasonDetailScreen> {
Set<EpisodeDetailsViewType> viewOptions = {EpisodeDetailsViewType.grid};
late final providerId = seasonDetailsProvider(widget.item.id);
AutoDisposeStateNotifierProvider<SeasonDetailsNotifier, SeasonModel?> get providerId =>
seasonDetailsProvider(widget.item.id);
@override
Widget build(BuildContext context) {

View file

@ -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<SeriesDetailScreen> {
late final providerId = seriesDetailsProvider(widget.item.id);
AutoDisposeStateNotifierProvider<SeriesDetailViewNotifier, SeriesModel?> get providerId =>
seriesDetailsProvider(widget.item.id);
@override
Widget build(BuildContext context) {
@ -51,7 +54,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
},
onDeleteSuccesFully: (item) {
if (context.mounted) {
context.router.maybePop();
context.router.popBack();
}
},
),

View file

@ -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<LibrarySearchScreen> {
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<RefreshIndicatorState> refreshKey = GlobalKey<RefreshIndicatorState>();
@ -78,9 +77,26 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
bool loadOnStart = false;
Key get uniqueKey => Key(widget.folderId?.join(',').toString() ?? widget.viewModelId ?? "EmptySearch");
AutoDisposeStateNotifierProvider<LibrarySearchNotifier, LibrarySearchModel> 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<LibrarySearchScreen> {
Future.microtask(
() async {
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<LibrarySearchScreen> {
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<LibrarySearchScreen> {
);
return PopScope(
key: uniqueKey,
canPop: !librarySearchResults.selecteMode,
onPopInvokedWithResult: (didPop, result) {
if (librarySearchResults.selecteMode) {
@ -210,8 +227,12 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
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<LibrarySearchScreen> {
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,

View file

@ -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<Widget> 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)

View file

@ -164,7 +164,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
serverTextController.text = value;
startAddingNewUser();
});
context.router.maybePop();
Navigator.of(context).pop();
},
),
);

View file

@ -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<void> showIdentifyScreen(BuildContext context, ItemBaseModel item) async {
return showDialogAdaptive(
@ -30,7 +32,7 @@ class IdentifyScreen extends ConsumerStatefulWidget {
}
class _IdentifyScreenState extends ConsumerState<IdentifyScreen> with TickerProviderStateMixin {
late AutoDisposeStateNotifierProvider<IdentifyNotifier, IdentifyModel> provider = identifyProvider(widget.item.id);
AutoDisposeStateNotifierProvider<IdentifyNotifier, IdentifyModel> get provider => identifyProvider(widget.item.id);
late final TabController tabController = TabController(length: 2, vsync: this);
TextEditingController? currentController;

View file

@ -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<void> showInfoScreen(BuildContext context, ItemBaseModel item) async {
return showDialog(
@ -27,7 +29,7 @@ class ItemInfoScreen extends ConsumerStatefulWidget {
}
class ItemInfoScreenState extends ConsumerState<ItemInfoScreen> {
late AutoDisposeStateNotifierProvider<InformationNotifier, InformationProviderModel> provider =
AutoDisposeStateNotifierProvider<InformationNotifier, InformationProviderModel> get provider =>
informationProvider(widget.item.id);
@override

View file

@ -133,10 +133,10 @@ class _ClientSettingsPageState extends ConsumerState<ClientSettingsPage> {
(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<ClientSettingsPage> {
mainAxisSize: MainAxisSize.min,
children: [
FilledButton(
onPressed: () => context.router.maybePop(),
onPressed: () => Navigator.of(context).pop(),
child: Text(context.localized.cancel),
),
const SizedBox(width: 8),

View file

@ -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)),

View file

@ -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<SettingsScreen> {
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<SettingsScreen> {
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),

View file

@ -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<ConsumerStatefulWidget> createState() => _DetailScreenState();
}
class _DetailScreenState extends ConsumerState<DetailScreen> {
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<DetailScaffold> {
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<DetailScaffold> {
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,

View file

@ -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<SplashScreen> {
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<SplashScreen> {
});
}
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(

View file

@ -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<bool> 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;
}
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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<TrickplayImage> {
@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