fix: Small improvement to library screen

This commit is contained in:
PartyDonut 2025-10-28 21:44:36 +01:00
parent b2657f6408
commit 16bf5e8a32
3 changed files with 204 additions and 136 deletions

View file

@ -12,6 +12,13 @@ sealed class NameSwitch {
String label(BuildContext context);
}
class Resume extends NameSwitch {
const Resume();
@override
String label(BuildContext context) => context.localized.dashboardContinue;
}
class NextUp extends NameSwitch {
const NextUp();

View file

@ -90,23 +90,32 @@ class LibraryScreen extends _$LibraryScreen {
return null;
}
Future<void> loadResume(ViewModel viewModel) async {}
Future<void> loadRecommendations(ViewModel viewModel) async {
List<RecommendedModel> newRecommendations = [];
final latest = await api.usersUserIdItemsLatestGet(
final resume = await api.usersUserIdItemsResumeGet(
parentId: viewModel.id,
limit: 14,
isPlayed: false,
imageTypeLimit: 1,
includeItemTypes: viewModel.collectionType.itemKinds.map((e) => e.dtoKind).toList(),
enableUserData: true,
enableImageTypes: [
ImageType.primary,
ImageType.banner,
ImageType.screenshot,
],
mediaTypes: [MediaType.video],
enableTotalRecordCount: false,
);
newRecommendations = [
...newRecommendations,
RecommendedModel(
name: const Latest(),
posters: latest.body?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? [],
name: const Resume(),
posters: resume.body?.items?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? [],
type: null,
),
];
if (viewModel.collectionType == CollectionType.movies) {
final response = await api.moviesRecommendationsGet(
parentId: viewModel.id,
@ -146,6 +155,22 @@ class LibraryScreen extends _$LibraryScreen {
];
}
final latest = await api.usersUserIdItemsLatestGet(
parentId: viewModel.id,
limit: 14,
isPlayed: false,
imageTypeLimit: 1,
includeItemTypes: viewModel.collectionType.itemKinds.map((e) => e.dtoKind).toList(),
);
newRecommendations = [
...newRecommendations,
RecommendedModel(
name: const Latest(),
posters: latest.body?.map((e) => ItemBaseModel.fromBaseDto(e, ref)).toList() ?? [],
type: null,
),
];
state = state.copyWith(
recommendations: newRecommendations,
);

View file

@ -40,6 +40,9 @@ class LibraryScreen extends ConsumerStatefulWidget {
class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTickerProviderStateMixin {
final GlobalKey<RefreshIndicatorState>? refreshKey = GlobalKey();
bool refreshing = false;
@override
Widget build(BuildContext context) {
final libraryScreenState = ref.watch(libraryScreenProvider);
@ -60,7 +63,20 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTicker
body: PullToRefresh(
refreshOnStart: true,
refreshKey: refreshKey,
onRefresh: () => ref.read(libraryScreenProvider.notifier).fetchAllLibraries(),
onRefresh: () async {
if (refreshing) return;
setState(() => refreshing = true);
try {
await ref.read(libraryScreenProvider.notifier).fetchAllLibraries();
} finally {
if (mounted) {
setState(() => refreshing = false);
}
}
},
child: AnimatedOpacity(
opacity: refreshing ? 0.75 : 1.0,
duration: const Duration(milliseconds: 175),
child: SizedBox.expand(
child: CustomScrollView(
controller: AdaptiveLayout.scrollOf(context, HomeTabs.library),
@ -79,6 +95,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTicker
views: views,
selectedView: libraryScreenState.selectedViewModel,
onSelected: (view) {
if (refreshing) return;
ref.read(libraryScreenProvider.notifier).selectLibrary(view);
refreshKey?.currentState?.show();
},
@ -141,18 +158,21 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTicker
if (viewTypes.contains(LibraryViewType.recommended)) ...[
if (recommendations.isNotEmpty)
...recommendations.where((element) => element.posters.isNotEmpty).map(
(element) => SliverToBoxAdapter(
(element) {
return SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: PosterRow(
contentPadding: padding,
posters: element.posters,
primaryPosters: element.name is Resume,
label: element.type != null
? "${element.type?.label(context)} - ${element.name.label(context)}"
: element.name.label(context),
),
),
),
);
},
),
],
if (viewTypes.contains(LibraryViewType.favourites))
@ -209,6 +229,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTicker
),
),
),
),
);
}
}
@ -297,6 +318,19 @@ class LibraryRow extends ConsumerWidget {
),
),
),
Row(
spacing: 8,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isSelected)
Container(
height: 12,
width: 12,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.primary,
),
),
Text(
view.name,
style: Theme.of(context).textTheme.titleMedium,
@ -305,6 +339,8 @@ class LibraryRow extends ConsumerWidget {
textAlign: TextAlign.start,
)
],
)
],
);
},
);