mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
[Fixed] Use browser navigation
This commit is contained in:
parent
69b3a77d17
commit
d19fa0ccd0
22 changed files with 210 additions and 156 deletions
|
|
@ -1,31 +1,32 @@
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:chopper/chopper.dart';
|
import 'package:chopper/chopper.dart';
|
||||||
import 'package:collection/collection.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/collection_types.dart';
|
||||||
|
import 'package:fladder/models/item_base_model.dart';
|
||||||
import 'package:fladder/models/items/folder_model.dart';
|
import 'package:fladder/models/items/folder_model.dart';
|
||||||
import 'package:fladder/models/items/item_shared_models.dart';
|
import 'package:fladder/models/items/item_shared_models.dart';
|
||||||
import 'package:fladder/models/items/photos_model.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/library_search/library_search_options.dart';
|
||||||
import 'package:fladder/models/playlist_model.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/service_provider.dart';
|
||||||
import 'package:fladder/providers/settings/client_settings_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/photo_viewer/photo_viewer_screen.dart';
|
||||||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||||
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
||||||
import 'package:fladder/util/list_extensions.dart';
|
import 'package:fladder/util/list_extensions.dart';
|
||||||
import 'package:fladder/util/localization_helper.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:fladder/util/map_bool_helper.dart';
|
||||||
import 'package:page_transition/page_transition.dart';
|
|
||||||
|
|
||||||
final librarySearchProvider =
|
final librarySearchProvider =
|
||||||
StateNotifierProvider.family.autoDispose<LibrarySearchNotifier, LibrarySearchModel, Key>((ref, id) {
|
StateNotifierProvider.family.autoDispose<LibrarySearchNotifier, LibrarySearchModel, Key>((ref, id) {
|
||||||
|
|
@ -652,6 +653,10 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
||||||
items.firstOrNull?.navigateTo(context);
|
items.firstOrNull?.navigateTo(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateEverything() {
|
||||||
|
state = state.copyWith();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SimpleSorter on List<ItemBaseModel> {
|
extension SimpleSorter on List<ItemBaseModel> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@ import 'package:fladder/util/adaptive_layout.dart';
|
||||||
|
|
||||||
@AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route')
|
@AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route')
|
||||||
class AutoRouter extends RootStackRouter {
|
class AutoRouter extends RootStackRouter {
|
||||||
AutoRouter({required this.layout, required this.ref});
|
AutoRouter({
|
||||||
|
required this.layout,
|
||||||
|
required this.ref,
|
||||||
|
});
|
||||||
|
|
||||||
final WidgetRef ref;
|
final WidgetRef ref;
|
||||||
final ScreenLayout layout;
|
final ScreenLayout layout;
|
||||||
|
|
@ -35,8 +38,8 @@ class AutoRouter extends RootStackRouter {
|
||||||
_syncedRoute,
|
_syncedRoute,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
AutoRoute(page: DetailsRoute.page, path: '/details'),
|
AutoRoute(page: DetailsRoute.page, path: '/details', usesPathAsKey: true),
|
||||||
AutoRoute(page: LibrarySearchRoute.page, path: '/library'),
|
AutoRoute(page: LibrarySearchRoute.page, path: '/library', usesPathAsKey: true),
|
||||||
AutoRoute(page: SettingsRoute.page, path: '/settings'),
|
AutoRoute(page: SettingsRoute.page, path: '/settings'),
|
||||||
..._settingsChildren.map(
|
..._settingsChildren.map(
|
||||||
(e) => e.copyWith(path: "/$e", initial: false),
|
(e) => e.copyWith(path: "/$e", initial: false),
|
||||||
|
|
@ -49,8 +52,8 @@ class AutoRouter extends RootStackRouter {
|
||||||
_dashboardRoute,
|
_dashboardRoute,
|
||||||
_favouritesRoute,
|
_favouritesRoute,
|
||||||
_syncedRoute,
|
_syncedRoute,
|
||||||
AutoRoute(page: DetailsRoute.page, path: 'details'),
|
AutoRoute(page: DetailsRoute.page, path: 'details', usesPathAsKey: true),
|
||||||
AutoRoute(page: LibrarySearchRoute.page, path: 'library'),
|
AutoRoute(page: LibrarySearchRoute.page, path: 'library', usesPathAsKey: true),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
page: SettingsRoute.page,
|
page: SettingsRoute.page,
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.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/models/item_base_model.dart';
|
||||||
import 'package:fladder/providers/items/item_details_provider.dart';
|
import 'package:fladder/providers/items/item_details_provider.dart';
|
||||||
import 'package:fladder/routes/auto_router.gr.dart';
|
import 'package:fladder/routes/auto_router.gr.dart';
|
||||||
import 'package:fladder/util/fladder_image.dart';
|
import 'package:fladder/util/fladder_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class DetailsScreen extends ConsumerStatefulWidget {
|
class DetailsScreen extends ConsumerStatefulWidget {
|
||||||
|
|
@ -22,9 +25,21 @@ class _DetailsScreenState extends ConsumerState<DetailsScreen> {
|
||||||
child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round),
|
child: CircularProgressIndicator.adaptive(strokeCap: StrokeCap.round),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant DetailsScreen oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (kIsWeb) {
|
||||||
|
updateWidget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
updateWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateWidget() async {
|
||||||
Future.microtask(() async {
|
Future.microtask(() async {
|
||||||
if (widget.item != null) {
|
if (widget.item != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -38,7 +53,7 @@ class _DetailsScreenState extends ConsumerState<DetailsScreen> {
|
||||||
currentWidget = response.detailScreenWidget;
|
currentWidget = response.detailScreenWidget;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const DashboardRoute().navigate(context);
|
const DashboardRoute().navigate(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +63,7 @@ class _DetailsScreenState extends ConsumerState<DetailsScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
|
key: Key(widget.id),
|
||||||
children: [
|
children: [
|
||||||
Hero(
|
Hero(
|
||||||
tag: widget.id,
|
tag: widget.id,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:ficonsax/ficonsax.dart';
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/book_model.dart';
|
import 'package:fladder/models/book_model.dart';
|
||||||
import 'package:fladder/providers/items/book_details_provider.dart';
|
import 'package:fladder/providers/items/book_details_provider.dart';
|
||||||
import 'package:fladder/providers/user_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/item_base_model/play_item_helpers.dart';
|
||||||
import 'package:fladder/util/list_padding.dart';
|
import 'package:fladder/util/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.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/util/widget_extensions.dart';
|
||||||
import 'package:fladder/widgets/shared/item_actions.dart';
|
import 'package:fladder/widgets/shared/item_actions.dart';
|
||||||
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
|
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
|
||||||
import 'package:fladder/widgets/shared/selectable_icon_button.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 {
|
class BookDetailScreen extends ConsumerStatefulWidget {
|
||||||
final BookModel item;
|
final BookModel item;
|
||||||
|
|
@ -29,7 +32,8 @@ class BookDetailScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
|
class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
|
||||||
late final provider = bookDetailsProvider(widget.item.id);
|
AutoDisposeStateNotifierProvider<BookDetailsProviderNotifier, BookProviderModel> get provider =>
|
||||||
|
bookDetailsProvider(widget.item.id);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -47,7 +51,7 @@ class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
|
||||||
},
|
},
|
||||||
onDeleteSuccesFully: (item) {
|
onDeleteSuccesFully: (item) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.router.maybePop();
|
context.router.popBack();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/item_base_model.dart';
|
import 'package:fladder/models/item_base_model.dart';
|
||||||
import 'package:fladder/providers/items/episode_details_provider.dart';
|
import 'package:fladder/providers/items/episode_details_provider.dart';
|
||||||
import 'package:fladder/providers/user_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/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/detail_scaffold.dart';
|
||||||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||||
import 'package:fladder/screens/shared/media/chapter_row.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_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/episode_posters.dart';
|
||||||
import 'package:fladder/screens/shared/media/expanding_overview.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/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/util/widget_extensions.dart';
|
||||||
import 'package:fladder/widgets/shared/selectable_icon_button.dart';
|
import 'package:fladder/widgets/shared/selectable_icon_button.dart';
|
||||||
|
|
||||||
|
|
@ -32,7 +33,8 @@ class EpisodeDetailScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
||||||
late final providerInstance = episodeDetailsProvider(widget.item.id);
|
AutoDisposeStateNotifierProvider<EpisodeDetailsProvider, EpisodeDetailModel> get providerInstance =>
|
||||||
|
episodeDetailsProvider(widget.item.id);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -52,7 +54,7 @@ class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
||||||
},
|
},
|
||||||
onDeleteSuccesFully: (item) {
|
onDeleteSuccesFully: (item) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.router.maybePop();
|
context.router.popBack();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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:auto_route/auto_route.dart';
|
||||||
import 'package:ficonsax/ficonsax.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/item_base_model.dart';
|
||||||
import 'package:fladder/providers/items/movies_details_provider.dart';
|
import 'package:fladder/providers/items/movies_details_provider.dart';
|
||||||
import 'package:fladder/providers/user_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/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/detail_scaffold.dart';
|
||||||
import 'package:fladder/screens/shared/media/chapter_row.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/components/media_play_button.dart';
|
||||||
import 'package:fladder/screens/shared/media/expanding_overview.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/people_row.dart';
|
||||||
import 'package:fladder/screens/shared/media/poster_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/item_base_model_extensions.dart';
|
||||||
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
||||||
|
|
||||||
import 'package:fladder/util/list_padding.dart';
|
import 'package:fladder/util/list_padding.dart';
|
||||||
import 'package:fladder/util/widget_extensions.dart';
|
import 'package:fladder/util/widget_extensions.dart';
|
||||||
import 'package:fladder/widgets/shared/selectable_icon_button.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 {
|
class MovieDetailScreen extends ConsumerStatefulWidget {
|
||||||
final ItemBaseModel item;
|
final ItemBaseModel item;
|
||||||
|
|
@ -30,7 +32,7 @@ class MovieDetailScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
||||||
late final providerInstance = movieDetailsProvider(widget.item.id);
|
MovieDetailsProvider get providerInstance => movieDetailsProvider(widget.item.id);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -49,7 +51,7 @@ class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
||||||
},
|
},
|
||||||
onDeleteSuccesFully: (item) {
|
onDeleteSuccesFully: (item) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.router.maybePop();
|
context.router.popBack();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:ficonsax/ficonsax.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/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/items/season_details_provider.dart';
|
||||||
import 'package:fladder/providers/user_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/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/string_extensions.dart';
|
||||||
import 'package:fladder/util/widget_extensions.dart';
|
import 'package:fladder/util/widget_extensions.dart';
|
||||||
import 'package:fladder/widgets/shared/selectable_icon_button.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 {
|
class SeasonDetailScreen extends ConsumerStatefulWidget {
|
||||||
final ItemBaseModel item;
|
final ItemBaseModel item;
|
||||||
|
|
@ -29,7 +32,8 @@ class SeasonDetailScreen extends ConsumerStatefulWidget {
|
||||||
|
|
||||||
class _SeasonDetailScreenState extends ConsumerState<SeasonDetailScreen> {
|
class _SeasonDetailScreenState extends ConsumerState<SeasonDetailScreen> {
|
||||||
Set<EpisodeDetailsViewType> viewOptions = {EpisodeDetailsViewType.grid};
|
Set<EpisodeDetailsViewType> viewOptions = {EpisodeDetailsViewType.grid};
|
||||||
late final providerId = seasonDetailsProvider(widget.item.id);
|
AutoDisposeStateNotifierProvider<SeasonDetailsNotifier, SeasonModel?> get providerId =>
|
||||||
|
seasonDetailsProvider(widget.item.id);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
||||||
|
|
@ -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:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/item_base_model.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/items/series_details_provider.dart';
|
||||||
import 'package:fladder/providers/user_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/detail_scaffold.dart';
|
||||||
import 'package:fladder/screens/shared/media/components/media_header.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/episode_posters.dart';
|
||||||
import 'package:fladder/screens/shared/media/expanding_overview.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/people_row.dart';
|
||||||
import 'package:fladder/screens/shared/media/poster_row.dart';
|
import 'package:fladder/screens/shared/media/poster_row.dart';
|
||||||
import 'package:fladder/screens/shared/media/season_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/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/util/widget_extensions.dart';
|
||||||
import 'package:fladder/widgets/shared/selectable_icon_button.dart';
|
import 'package:fladder/widgets/shared/selectable_icon_button.dart';
|
||||||
|
|
||||||
|
|
@ -33,7 +35,8 @@ class SeriesDetailScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||||
late final providerId = seriesDetailsProvider(widget.item.id);
|
AutoDisposeStateNotifierProvider<SeriesDetailViewNotifier, SeriesModel?> get providerId =>
|
||||||
|
seriesDetailsProvider(widget.item.id);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -51,7 +54,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||||
},
|
},
|
||||||
onDeleteSuccesFully: (item) {
|
onDeleteSuccesFully: (item) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.router.maybePop();
|
context.router.popBack();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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:auto_route/auto_route.dart';
|
||||||
import 'package:ficonsax/ficonsax.dart';
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.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/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/refresh_state.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/util/sliver_list_padding.dart';
|
||||||
import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.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/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/scroll_position.dart';
|
||||||
import 'package:fladder/widgets/shared/shapes.dart';
|
import 'package:fladder/widgets/shared/shapes.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class LibrarySearchScreen extends ConsumerStatefulWidget {
|
class LibrarySearchScreen extends ConsumerStatefulWidget {
|
||||||
final String? viewModelId;
|
final String? viewModelId;
|
||||||
|
|
@ -67,9 +69,6 @@ class LibrarySearchScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
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 SearchController searchController = SearchController();
|
||||||
final Debouncer debouncer = Debouncer(const Duration(seconds: 1));
|
final Debouncer debouncer = Debouncer(const Duration(seconds: 1));
|
||||||
final GlobalKey<RefreshIndicatorState> refreshKey = GlobalKey<RefreshIndicatorState>();
|
final GlobalKey<RefreshIndicatorState> refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||||
|
|
@ -78,9 +77,26 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
||||||
|
|
||||||
bool loadOnStart = false;
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
initLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initLibrary() {
|
||||||
searchController.addListener(() {
|
searchController.addListener(() {
|
||||||
debouncer.run(() {
|
debouncer.run(() {
|
||||||
ref.read(providerKey.notifier).setSearch(searchController.text);
|
ref.read(providerKey.notifier).setSearch(searchController.text);
|
||||||
|
|
@ -89,7 +105,9 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
||||||
|
|
||||||
Future.microtask(
|
Future.microtask(
|
||||||
() async {
|
() async {
|
||||||
libraryProvider.setDefaultOptions(widget.sortOrder, widget.sortingOptions);
|
if (libraryProvider.mounted) {
|
||||||
|
libraryProvider.setDefaultOptions(widget.sortOrder, widget.sortingOptions);
|
||||||
|
}
|
||||||
await refreshKey.currentState?.show();
|
await refreshKey.currentState?.show();
|
||||||
SystemChrome.setEnabledSystemUIMode(
|
SystemChrome.setEnabledSystemUIMode(
|
||||||
SystemUiMode.edgeToEdge,
|
SystemUiMode.edgeToEdge,
|
||||||
|
|
@ -115,10 +133,8 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isEmptySearchScreen = widget.viewModelId == null && widget.favourites == null && widget.folderId == null;
|
final isEmptySearchScreen = widget.viewModelId == null && widget.favourites == null && widget.folderId == null;
|
||||||
final librarySearchResults = ref.watch(providerKey);
|
final librarySearchResults = ref.watch(providerKey);
|
||||||
final libraryProvider = ref.read(providerKey.notifier);
|
|
||||||
final postersList = librarySearchResults.posters.hideEmptyChildren(librarySearchResults.hideEmtpyShows);
|
final postersList = librarySearchResults.posters.hideEmptyChildren(librarySearchResults.hideEmtpyShows);
|
||||||
final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state));
|
final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state));
|
||||||
|
|
||||||
final libraryViewType = ref.watch(libraryViewTypeProvider);
|
final libraryViewType = ref.watch(libraryViewTypeProvider);
|
||||||
|
|
||||||
ref.listen(
|
ref.listen(
|
||||||
|
|
@ -132,6 +148,7 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
||||||
);
|
);
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
|
key: uniqueKey,
|
||||||
canPop: !librarySearchResults.selecteMode,
|
canPop: !librarySearchResults.selecteMode,
|
||||||
onPopInvokedWithResult: (didPop, result) {
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
if (librarySearchResults.selecteMode) {
|
if (librarySearchResults.selecteMode) {
|
||||||
|
|
@ -210,8 +227,12 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
||||||
refreshKey: refreshKey,
|
refreshKey: refreshKey,
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
contextRefresh: false,
|
contextRefresh: false,
|
||||||
onRefresh: () async =>
|
onRefresh: () async {
|
||||||
libraryProvider.initRefresh(widget.folderId, widget.viewModelId, widget.favourites),
|
if (libraryProvider.mounted) {
|
||||||
|
return libraryProvider.initRefresh(
|
||||||
|
widget.folderId, widget.viewModelId, widget.favourites);
|
||||||
|
}
|
||||||
|
},
|
||||||
refreshOnStart: false,
|
refreshOnStart: false,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
physics: const AlwaysScrollableNoImplicitScrollPhysics(),
|
physics: const AlwaysScrollableNoImplicitScrollPhysics(),
|
||||||
|
|
@ -220,10 +241,11 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
floating: !AdaptiveLayout.of(context).isDesktop,
|
floating: !AdaptiveLayout.of(context).isDesktop,
|
||||||
collapsedHeight: 80,
|
collapsedHeight: 80,
|
||||||
automaticallyImplyLeading: true,
|
automaticallyImplyLeading: false,
|
||||||
pinned: AdaptiveLayout.of(context).isDesktop,
|
pinned: AdaptiveLayout.of(context).isDesktop,
|
||||||
primary: true,
|
primary: true,
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
|
leading: context.router.backButton(),
|
||||||
surfaceTintColor: Colors.transparent,
|
surfaceTintColor: Colors.transparent,
|
||||||
shadowColor: Colors.transparent,
|
shadowColor: Colors.transparent,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:ficonsax/ficonsax.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/jellyfin/jellyfin_open_api.enums.swagger.dart';
|
||||||
import 'package:fladder/models/item_base_model.dart';
|
import 'package:fladder/models/item_base_model.dart';
|
||||||
import 'package:fladder/models/items/item_shared_models.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/map_bool_helper.dart';
|
||||||
import 'package:fladder/util/refresh_state.dart';
|
import 'package:fladder/util/refresh_state.dart';
|
||||||
import 'package:fladder/widgets/shared/scroll_position.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 {
|
class LibraryFilterChips extends ConsumerWidget {
|
||||||
final Key uniqueKey;
|
final Key uniqueKey;
|
||||||
|
|
@ -188,12 +190,12 @@ List<Widget> libraryFilterChips(
|
||||||
if (librarySearchResults.types[FladderItemType.series] == true)
|
if (librarySearchResults.types[FladderItemType.series] == true)
|
||||||
FilterChip(
|
FilterChip(
|
||||||
avatar: Icon(
|
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,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
selected: librarySearchResults.hideEmtpyShows,
|
selected: librarySearchResults.hideEmtpyShows,
|
||||||
showCheckmark: false,
|
showCheckmark: false,
|
||||||
label: Text(librarySearchResults.hideEmtpyShows ? context.localized.showEmpty : context.localized.hideEmpty),
|
label: Text(context.localized.hideEmpty),
|
||||||
onSelected: libraryProvider.setHideEmpty,
|
onSelected: libraryProvider.setHideEmpty,
|
||||||
),
|
),
|
||||||
if (librarySearchResults.officialRatings.isNotEmpty)
|
if (librarySearchResults.officialRatings.isNotEmpty)
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ class _LoginPageState extends ConsumerState<LoginScreen> {
|
||||||
serverTextController.text = value;
|
serverTextController.text = value;
|
||||||
startAddingNewUser();
|
startAddingNewUser();
|
||||||
});
|
});
|
||||||
context.router.maybePop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:ficonsax/ficonsax.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/item_base_model.dart';
|
||||||
import 'package:fladder/providers/items/identify_provider.dart';
|
import 'package:fladder/providers/items/identify_provider.dart';
|
||||||
import 'package:fladder/screens/shared/adaptive_dialog.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/screens/shared/media/external_urls.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/string_extensions.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 {
|
Future<void> showIdentifyScreen(BuildContext context, ItemBaseModel item) async {
|
||||||
return showDialogAdaptive(
|
return showDialogAdaptive(
|
||||||
|
|
@ -30,7 +32,7 @@ class IdentifyScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _IdentifyScreenState extends ConsumerState<IdentifyScreen> with TickerProviderStateMixin {
|
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);
|
late final TabController tabController = TabController(length: 2, vsync: this);
|
||||||
|
|
||||||
TextEditingController? currentController;
|
TextEditingController? currentController;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:ficonsax/ficonsax.dart';
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/information_model.dart';
|
import 'package:fladder/models/information_model.dart';
|
||||||
import 'package:fladder/models/item_base_model.dart';
|
import 'package:fladder/models/item_base_model.dart';
|
||||||
import 'package:fladder/providers/items/information_provider.dart';
|
import 'package:fladder/providers/items/information_provider.dart';
|
||||||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/widgets/shared/clickable_text.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 {
|
Future<void> showInfoScreen(BuildContext context, ItemBaseModel item) async {
|
||||||
return showDialog(
|
return showDialog(
|
||||||
|
|
@ -27,7 +29,7 @@ class ItemInfoScreen extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemInfoScreenState extends ConsumerState<ItemInfoScreen> {
|
class ItemInfoScreenState extends ConsumerState<ItemInfoScreen> {
|
||||||
late AutoDisposeStateNotifierProvider<InformationNotifier, InformationProviderModel> provider =
|
AutoDisposeStateNotifierProvider<InformationNotifier, InformationProviderModel> get provider =>
|
||||||
informationProvider(widget.item.id);
|
informationProvider(widget.item.id);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -133,10 +133,10 @@ class _ClientSettingsPageState extends ConsumerState<ClientSettingsPage> {
|
||||||
(context) async {
|
(context) async {
|
||||||
await ref.read(syncProvider.notifier).clear();
|
await ref.read(syncProvider.notifier).clear();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
context.router.maybePop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
context.localized.clear,
|
context.localized.clear,
|
||||||
(context) => context.router.maybePop(),
|
(context) => Navigator.of(context).pop(),
|
||||||
context.localized.cancel,
|
context.localized.cancel,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -451,7 +451,7 @@ class _ClientSettingsPageState extends ConsumerState<ClientSettingsPage> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: () => context.router.maybePop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(context.localized.cancel),
|
child: Text(context.localized.cancel),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/providers/user_provider.dart';
|
import 'package:fladder/providers/user_provider.dart';
|
||||||
import 'package:fladder/screens/shared/user_icon.dart';
|
import 'package:fladder/screens/shared/user_icon.dart';
|
||||||
import 'package:fladder/util/adaptive_layout.dart';
|
import 'package:fladder/util/adaptive_layout.dart';
|
||||||
|
import 'package:fladder/util/router_extension.dart';
|
||||||
|
|
||||||
class SettingsScaffold extends ConsumerWidget {
|
class SettingsScaffold extends ConsumerWidget {
|
||||||
final String label;
|
final String label;
|
||||||
|
|
@ -39,6 +41,7 @@ class SettingsScaffold extends ConsumerWidget {
|
||||||
if (AdaptiveLayout.of(context).size == ScreenLayout.single)
|
if (AdaptiveLayout.of(context).size == ScreenLayout.single)
|
||||||
SliverAppBar.large(
|
SliverAppBar.large(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
|
leading: context.router.backButton(),
|
||||||
flexibleSpace: FlexibleSpaceBar(
|
flexibleSpace: FlexibleSpaceBar(
|
||||||
titlePadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16)
|
titlePadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16)
|
||||||
.add(EdgeInsets.only(left: padding.left, right: padding.right)),
|
.add(EdgeInsets.only(left: padding.left, right: padding.right)),
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import 'package:fladder/screens/shared/fladder_icon.dart';
|
||||||
import 'package:fladder/util/adaptive_layout.dart';
|
import 'package:fladder/util/adaptive_layout.dart';
|
||||||
import 'package:fladder/util/application_info.dart';
|
import 'package:fladder/util/application_info.dart';
|
||||||
import 'package:fladder/util/localization_helper.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/util/theme_extensions.dart';
|
||||||
import 'package:fladder/widgets/shared/hide_on_scroll.dart';
|
import 'package:fladder/widgets/shared/hide_on_scroll.dart';
|
||||||
|
|
||||||
|
|
@ -90,7 +91,7 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
showUserIcon: true,
|
showUserIcon: true,
|
||||||
items: [
|
items: [
|
||||||
if (context.router.canPop() && AdaptiveLayout.of(context).size == ScreenLayout.dual)
|
if (context.router.canNavigateBack && AdaptiveLayout.of(context).size == ScreenLayout.dual)
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
@ -99,7 +100,7 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
|
||||||
style: IconButton.styleFrom(
|
style: IconButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
|
backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.8),
|
||||||
),
|
),
|
||||||
onPressed: () => context.router.maybePop(),
|
onPressed: () => context.router.popBack(),
|
||||||
icon: Padding(
|
icon: Padding(
|
||||||
padding: EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4),
|
padding: EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4),
|
||||||
child: const Icon(IconsaxOutline.arrow_left_2),
|
child: const Icon(IconsaxOutline.arrow_left_2),
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:fladder/models/item_base_model.dart';
|
import 'package:fladder/models/item_base_model.dart';
|
||||||
import 'package:fladder/models/items/images_models.dart';
|
import 'package:fladder/models/items/images_models.dart';
|
||||||
import 'package:fladder/models/media_playback_model.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/providers/video_player_provider.dart';
|
||||||
import 'package:fladder/routes/auto_router.gr.dart';
|
import 'package:fladder/routes/auto_router.gr.dart';
|
||||||
import 'package:fladder/theme.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/fladder_image.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/refresh_state.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/floating_player_bar.dart';
|
||||||
import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.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/item_actions.dart';
|
||||||
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
|
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
|
||||||
import 'package:fladder/widgets/shared/pull_to_refresh.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 {
|
class DetailScaffold extends ConsumerStatefulWidget {
|
||||||
final String label;
|
final String label;
|
||||||
final ItemBaseModel? item;
|
final ItemBaseModel? item;
|
||||||
|
|
@ -212,7 +150,7 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
|
||||||
style: IconButton.styleFrom(
|
style: IconButton.styleFrom(
|
||||||
backgroundColor: backGroundColor,
|
backgroundColor: backGroundColor,
|
||||||
),
|
),
|
||||||
onPressed: () => context.router.maybePop(),
|
onPressed: () => context.router.popBack(),
|
||||||
icon: Padding(
|
icon: Padding(
|
||||||
padding:
|
padding:
|
||||||
EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4),
|
EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4),
|
||||||
|
|
@ -269,8 +207,8 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
|
||||||
icon: const Icon(IconsaxOutline.refresh),
|
icon: const Icon(IconsaxOutline.refresh),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
else
|
if (AdaptiveLayout.of(context).size == ScreenLayout.single)
|
||||||
const SizedBox(height: 30, width: 30, child: SettingsUserIcon()),
|
const SizedBox(height: 30, width: 30, child: SettingsUserIcon()),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: context.localized.home,
|
message: context.localized.home,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:fladder/models/account_model.dart';
|
import 'package:fladder/models/account_model.dart';
|
||||||
import 'package:fladder/providers/shared_provider.dart';
|
import 'package:fladder/providers/shared_provider.dart';
|
||||||
import 'package:fladder/providers/user_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';
|
import 'package:fladder/screens/shared/fladder_logo.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
|
@ -28,19 +29,16 @@ class _SplashScreenState extends ConsumerState<SplashScreen> {
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
if (lastUsedAccount == null) {
|
if (lastUsedAccount == null) {
|
||||||
widget.loggedIn?.call(false);
|
callBackOrNavigate(false);
|
||||||
context.router.maybePop(false);
|
|
||||||
} else {
|
} else {
|
||||||
switch (lastUsedAccount.authMethod) {
|
switch (lastUsedAccount.authMethod) {
|
||||||
case Authentication.autoLogin:
|
case Authentication.autoLogin:
|
||||||
widget.loggedIn?.call(true);
|
callBackOrNavigate(true);
|
||||||
context.router.maybePop(true);
|
|
||||||
break;
|
break;
|
||||||
case Authentication.biometrics:
|
case Authentication.biometrics:
|
||||||
case Authentication.none:
|
case Authentication.none:
|
||||||
case Authentication.passcode:
|
case Authentication.passcode:
|
||||||
widget.loggedIn?.call(false);
|
callBackOrNavigate(false);
|
||||||
context.router.maybePop(false);
|
|
||||||
break;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Scaffold(
|
return const Scaffold(
|
||||||
|
|
|
||||||
30
lib/util/router_extension.dart
Normal file
30
lib/util/router_extension.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -154,7 +154,8 @@ class NestedNavigationDrawer extends ConsumerWidget {
|
||||||
|
|
||||||
bool checkLibrary(BuildContext context, String id) {
|
bool checkLibrary(BuildContext context, String id) {
|
||||||
try {
|
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) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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/models/media_playback_model.dart';
|
||||||
import 'package:fladder/providers/video_player_provider.dart';
|
import 'package:fladder/providers/video_player_provider.dart';
|
||||||
import 'package:fladder/providers/views_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_body.dart';
|
||||||
import 'package:fladder/widgets/navigation_scaffold/components/navigation_drawer.dart';
|
import 'package:fladder/widgets/navigation_scaffold/components/navigation_drawer.dart';
|
||||||
import 'package:fladder/widgets/shared/hide_on_scroll.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 {
|
class NavigationScaffold extends ConsumerStatefulWidget {
|
||||||
final String? currentRouteName;
|
final String? currentRouteName;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
|
@ -34,12 +35,12 @@ class _TrickplayImageState extends ConsumerState<TrickplayImage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant TrickplayImage oldWidget) {
|
void didUpdateWidget(covariant TrickplayImage oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
if (oldWidget.position?.inMilliseconds != widget.position?.inMilliseconds) {
|
if (oldWidget.position?.inMilliseconds != widget.position?.inMilliseconds) {
|
||||||
time = widget.position ?? Duration.zero;
|
time = widget.position ?? Duration.zero;
|
||||||
model = widget.trickplay;
|
model = widget.trickplay;
|
||||||
loadImage();
|
loadImage();
|
||||||
}
|
}
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue