mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-08 23:18:16 -07:00
chore: Lots of bug fixes and navigation improvements
This commit is contained in:
parent
9bb5e81812
commit
92d5391b93
35 changed files with 513 additions and 455 deletions
|
|
@ -18,6 +18,7 @@ import 'package:fladder/providers/user_provider.dart';
|
|||
import 'package:fladder/providers/views_provider.dart';
|
||||
import 'package:fladder/routes/auto_router.gr.dart';
|
||||
import 'package:fladder/screens/dashboard/home_banner_widget.dart';
|
||||
import 'package:fladder/screens/home_screen.dart';
|
||||
import 'package:fladder/screens/shared/media/poster_row.dart';
|
||||
import 'package:fladder/screens/shared/nested_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/nested_sliver_appbar.dart';
|
||||
|
|
@ -97,7 +98,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
|||
child: PinchPosterZoom(
|
||||
scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference),
|
||||
child: CustomScrollView(
|
||||
controller: AdaptiveLayout.scrollOf(context),
|
||||
controller: AdaptiveLayout.scrollOf(context, HomeTabs.dashboard),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
const DefaultSliverTopBadding(),
|
||||
|
|
@ -196,6 +197,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
|||
_ => SortingOptions.dateAdded,
|
||||
},
|
||||
sortOrder: SortingOrder.descending,
|
||||
recursive: true,
|
||||
),
|
||||
),
|
||||
posters: view.recentlyAdded,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class FolderDetailScreen extends ConsumerWidget {
|
|||
switch (item) {
|
||||
case PhotoModel photoModel:
|
||||
final photoItems = details?.items.whereType<PhotoModel>().toList();
|
||||
await context.navigateTo(PhotoViewerRoute(
|
||||
await context.pushRoute(PhotoViewerRoute(
|
||||
items: photoItems,
|
||||
selected: photoModel.id,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:fladder/models/library_filter_model.dart';
|
|||
import 'package:fladder/providers/favourites_provider.dart';
|
||||
import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||
import 'package:fladder/routes/auto_router.gr.dart';
|
||||
import 'package:fladder/screens/home_screen.dart';
|
||||
import 'package:fladder/screens/shared/media/poster_row.dart';
|
||||
import 'package:fladder/screens/shared/nested_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/nested_sliver_appbar.dart';
|
||||
|
|
@ -35,7 +36,7 @@ class FavouritesScreen extends ConsumerWidget {
|
|||
scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference / 2),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: AdaptiveLayout.scrollOf(context),
|
||||
controller: AdaptiveLayout.scrollOf(context, HomeTabs.favorites),
|
||||
slivers: [
|
||||
if (AdaptiveLayout.viewSizeOf(context) == ViewSize.phone)
|
||||
NestedSliverAppBar(
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ enum HomeTabs {
|
|||
HomeTabs.dashboard => context.router.navigate(const DashboardRoute()),
|
||||
HomeTabs.library => context.router.navigate(const LibraryRoute()),
|
||||
HomeTabs.favorites => context.router.navigate(const FavouritesRoute()),
|
||||
HomeTabs.sync => context.router.navigate(SyncedRoute()),
|
||||
HomeTabs.sync => context.router.navigate(const SyncedRoute()),
|
||||
};
|
||||
|
||||
String label(BuildContext context) => switch (this) {
|
||||
|
|
@ -101,7 +101,7 @@ class HomeScreen extends ConsumerWidget {
|
|||
label: context.localized.navigationSync,
|
||||
icon: Icon(e.icon),
|
||||
selectedIcon: Icon(e.selectedIcon),
|
||||
route: SyncedRoute(),
|
||||
route: const SyncedRoute(),
|
||||
action: () => e.navigate(context),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import 'package:fladder/models/recommended_model.dart';
|
|||
import 'package:fladder/models/view_model.dart';
|
||||
import 'package:fladder/providers/library_screen_provider.dart';
|
||||
import 'package:fladder/routes/auto_router.gr.dart';
|
||||
import 'package:fladder/screens/home_screen.dart';
|
||||
import 'package:fladder/screens/metadata/refresh_metadata.dart';
|
||||
import 'package:fladder/screens/shared/flat_button.dart';
|
||||
import 'package:fladder/screens/shared/media/poster_row.dart';
|
||||
|
|
@ -62,7 +63,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTicker
|
|||
onRefresh: () => ref.read(libraryScreenProvider.notifier).fetchAllLibraries(),
|
||||
child: SizedBox.expand(
|
||||
child: CustomScrollView(
|
||||
controller: AdaptiveLayout.scrollOf(context),
|
||||
controller: AdaptiveLayout.scrollOf(context, HomeTabs.library),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
const DefaultSliverTopBadding(),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import 'package:iconsax_plus/iconsax_plus.dart';
|
|||
|
||||
import 'package:fladder/models/boxset_model.dart';
|
||||
import 'package:fladder/models/item_base_model.dart';
|
||||
import 'package:fladder/models/items/photos_model.dart';
|
||||
import 'package:fladder/models/library_filter_model.dart';
|
||||
import 'package:fladder/models/library_search/library_search_model.dart';
|
||||
import 'package:fladder/models/library_search/library_search_options.dart';
|
||||
|
|
@ -55,8 +54,7 @@ class LibrarySearchScreen extends ConsumerStatefulWidget {
|
|||
final SortingOptions? sortingOptions;
|
||||
final Map<FladderItemType, bool>? types;
|
||||
final Map<String, bool>? genres;
|
||||
final bool recursive;
|
||||
final PhotoModel? photoToView;
|
||||
final bool? recursive;
|
||||
const LibrarySearchScreen({
|
||||
@QueryParam("parentId") this.viewModelId,
|
||||
@QueryParam("folderId") this.folderId,
|
||||
|
|
@ -65,8 +63,7 @@ class LibrarySearchScreen extends ConsumerStatefulWidget {
|
|||
@QueryParam("sortOptions") this.sortingOptions,
|
||||
@QueryParam("itemTypes") this.types,
|
||||
@QueryParam("genres") this.genres,
|
||||
@QueryParam("recursive") this.recursive = true,
|
||||
this.photoToView,
|
||||
@QueryParam("recursive") this.recursive,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -109,10 +106,6 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
SystemUiMode.edgeToEdge,
|
||||
overlays: [],
|
||||
);
|
||||
|
||||
if (context.mounted && widget.photoToView != null) {
|
||||
libraryProvider.viewGallery(context, selected: widget.photoToView);
|
||||
}
|
||||
scrollController.addListener(() {
|
||||
scrollPosition();
|
||||
});
|
||||
|
|
@ -227,7 +220,7 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
widget.folderId,
|
||||
widget.viewModelId,
|
||||
defaultFilter.copyWith(
|
||||
favourites: widget.favourites ?? defaultFilter.favourites,
|
||||
favourites: widget.favourites,
|
||||
sortOrder: widget.sortOrder ?? defaultFilter.sortOrder,
|
||||
sortingOption: widget.sortingOptions ?? defaultFilter.sortingOption,
|
||||
types: widget.types ?? {},
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ class _LibraryFilterChipsState extends ConsumerState<LibraryFilterChips> {
|
|||
onClear: () => libraryProvider.setTypes(librarySearchResults.filters.types.setAll(false)),
|
||||
),
|
||||
ExpressiveButton(
|
||||
isSelected: favourites,
|
||||
icon: favourites ? const Icon(IconsaxPlusBold.heart) : null,
|
||||
isSelected: favourites == true,
|
||||
icon: favourites == true ? const Icon(IconsaxPlusBold.heart) : null,
|
||||
label: Text(context.localized.favorites),
|
||||
onPressed: () {
|
||||
libraryProvider.toggleFavourite();
|
||||
|
|
@ -68,8 +68,8 @@ class _LibraryFilterChipsState extends ConsumerState<LibraryFilterChips> {
|
|||
},
|
||||
),
|
||||
ExpressiveButton(
|
||||
isSelected: recursive,
|
||||
icon: recursive ? const Icon(IconsaxPlusBold.tick_circle) : null,
|
||||
isSelected: recursive == true,
|
||||
icon: recursive == true ? const Icon(IconsaxPlusBold.tick_circle) : null,
|
||||
label: Text(context.localized.recursive),
|
||||
onPressed: () {
|
||||
libraryProvider.toggleRecursive();
|
||||
|
|
|
|||
|
|
@ -61,18 +61,23 @@ class ItemInfoScreenState extends ConsumerState<ItemInfoScreen> {
|
|||
Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
spacing: 6,
|
||||
spacing: 12,
|
||||
children: [
|
||||
Text(
|
||||
widget.item.name,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.item.name,
|
||||
softWrap: false,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
onPressed: () => context.copyToClipboard(info.model.toString()),
|
||||
icon: const Icon(Icons.copy_all_rounded)),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:extended_image/extended_image.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
|
@ -23,6 +24,7 @@ import 'package:fladder/util/throttler.dart';
|
|||
import 'package:fladder/widgets/full_screen_helpers/full_screen_wrapper.dart';
|
||||
import 'package:fladder/widgets/shared/elevated_icon.dart';
|
||||
import 'package:fladder/widgets/shared/progress_floating_button.dart';
|
||||
import 'package:fladder/widgets/shared/selectable_icon_button.dart';
|
||||
|
||||
class PhotoViewerControls extends ConsumerStatefulWidget {
|
||||
final EdgeInsets padding;
|
||||
|
|
@ -309,13 +311,19 @@ class _PhotoViewerControllsState extends ConsumerState<PhotoViewerControls> with
|
|||
children: [
|
||||
ElevatedIconButton(
|
||||
onPressed: widget.openOptions,
|
||||
icon: IconsaxPlusLinear.more_2,
|
||||
icon: IconsaxPlusLinear.more_square,
|
||||
),
|
||||
const Spacer(),
|
||||
ElevatedIconButton(
|
||||
SelectableIconButton(
|
||||
onPressed: markAsFavourite,
|
||||
color: widget.photo.userData.isFavourite ? Colors.red : null,
|
||||
selected: false,
|
||||
icon: widget.photo.userData.isFavourite ? IconsaxPlusBold.heart : IconsaxPlusLinear.heart,
|
||||
backgroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimary
|
||||
.harmonizeWith(Colors.red)
|
||||
.withValues(alpha: 0.25),
|
||||
iconColor: widget.photo.userData.isFavourite ? Colors.red : null,
|
||||
),
|
||||
ProgressFloatingButton(
|
||||
controller: timerController,
|
||||
|
|
@ -341,8 +349,11 @@ class _PhotoViewerControllsState extends ConsumerState<PhotoViewerControls> with
|
|||
);
|
||||
}
|
||||
|
||||
void markAsFavourite() {
|
||||
ref.read(userProvider.notifier).setAsFavorite(!widget.photo.userData.isFavourite, widget.photo.id);
|
||||
Future<void> markAsFavourite() async {
|
||||
final response =
|
||||
await ref.read(userProvider.notifier).setAsFavorite(!widget.photo.userData.isFavourite, widget.photo.id);
|
||||
|
||||
if (response?.isSuccessful == false) return;
|
||||
|
||||
widget.onPhotoChanged(widget.photo
|
||||
.copyWith(userData: widget.photo.userData.copyWith(isFavourite: !widget.photo.userData.isFavourite)));
|
||||
|
|
|
|||
|
|
@ -90,7 +90,13 @@ class _PhotoViewerScreenState extends ConsumerState<PhotoViewerScreen> with Widg
|
|||
|
||||
if (context.mounted) {
|
||||
setState(() {
|
||||
photos = {...photos, ...newItems}.toList();
|
||||
if (photos.length == 1 && newItems.contains(photos.first)) {
|
||||
photos = newItems;
|
||||
currentPage = photos.indexWhere((value) => value.id == widget.selected).clamp(0, photos.length - 1);
|
||||
controller.jumpToPage(currentPage);
|
||||
} else {
|
||||
photos = {...photos, ...newItems}.toList();
|
||||
}
|
||||
loadingItems = false;
|
||||
});
|
||||
}
|
||||
|
|
@ -165,14 +171,14 @@ class _PhotoViewerScreenState extends ConsumerState<PhotoViewerScreen> with Widg
|
|||
? Center(
|
||||
child: Text(context.localized.noItemsToShow),
|
||||
)
|
||||
: buildViewer(),
|
||||
: buildViewer(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildViewer() {
|
||||
Widget buildViewer(BuildContext context) {
|
||||
final currentPhoto = photos[currentPage];
|
||||
final imageHash = currentPhoto.images?.primary?.hash;
|
||||
return Stack(
|
||||
|
|
@ -498,8 +504,8 @@ class _PhotoViewerScreenState extends ConsumerState<PhotoViewerScreen> with Widg
|
|||
},
|
||||
);
|
||||
|
||||
void markAsFavourite(PhotoModel photo, {bool? value}) {
|
||||
ref.read(userProvider.notifier).setAsFavorite(value ?? !photo.userData.isFavourite, photo.id);
|
||||
Future<void> markAsFavourite(PhotoModel photo, {bool? value}) async {
|
||||
await ref.read(userProvider.notifier).setAsFavorite(value ?? !photo.userData.isFavourite, photo.id);
|
||||
|
||||
setState(() {
|
||||
int index = photos.indexOf(photo);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class ItemLogo extends StatelessWidget {
|
|||
child: Text(
|
||||
item.parentBaseModel.name,
|
||||
textAlign: TextAlign.start,
|
||||
maxLines: 3,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.fade,
|
||||
style: textStyle ??
|
||||
Theme.of(context).textTheme.headlineLarge?.copyWith(
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
}
|
||||
|
||||
Future<void> navigateToDetails() async {
|
||||
await widget.poster.navigateTo(context);
|
||||
await widget.poster.navigateTo(context, ref: ref);
|
||||
}
|
||||
|
||||
final posterRadius = FladderTheme.smallShape.borderRadius;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class _PosterRowState extends ConsumerState<PosterRow> {
|
|||
contentPadding: widget.contentPadding,
|
||||
label: widget.label,
|
||||
onLabelClick: widget.onLabelClick,
|
||||
dominantRatio: dominantRatio,
|
||||
items: widget.posters,
|
||||
itemBuilder: (context, index) {
|
||||
final poster = widget.posters[index];
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import 'package:iconsax_plus/iconsax_plus.dart';
|
|||
import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||
import 'package:fladder/providers/sync_provider.dart';
|
||||
import 'package:fladder/routes/auto_router.gr.dart';
|
||||
import 'package:fladder/screens/home_screen.dart';
|
||||
import 'package:fladder/screens/shared/nested_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/nested_sliver_appbar.dart';
|
||||
import 'package:fladder/screens/syncing/sync_list_item.dart';
|
||||
|
|
@ -20,9 +21,7 @@ import 'package:fladder/widgets/shared/pull_to_refresh.dart';
|
|||
|
||||
@RoutePage()
|
||||
class SyncedScreen extends ConsumerStatefulWidget {
|
||||
final ScrollController? navigationScrollController;
|
||||
|
||||
const SyncedScreen({this.navigationScrollController, super.key});
|
||||
const SyncedScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() => _SyncedScreenState();
|
||||
|
|
@ -43,7 +42,7 @@ class _SyncedScreenState extends ConsumerState<SyncedScreen> {
|
|||
scaleDifference: (difference) => ref.read(clientSettingsProvider.notifier).addPosterSize(difference / 2),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: widget.navigationScrollController,
|
||||
controller: AdaptiveLayout.scrollOf(context, HomeTabs.sync),
|
||||
slivers: [
|
||||
if (AdaptiveLayout.viewSizeOf(context) == ViewSize.phone)
|
||||
NestedSliverAppBar(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue