Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions lib/models/items/images_models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ import 'package:fladder/util/custom_cache_manager.dart';

class ImagesData {
final ImageData? primary;
final ImageData? thumb;
final List<ImageData>? backDrop;
final ImageData? logo;
ImagesData({
this.primary,
this.thumb,
this.backDrop,
this.logo,
});

bool get isEmpty {
if (primary == null && backDrop == null) return true;
if (primary == null && thumb == null && backDrop == null) return true;
return false;
}

ImageData? get firstOrNull {
return primary ?? backDrop?.firstOrNull;
return primary ?? thumb ?? backDrop?.firstOrNull;
}

ImageData? get randomBackDrop => (backDrop?..shuffle())?.firstOrNull ?? primary;
Expand All @@ -38,6 +40,7 @@ class ImagesData {
dto.BaseItemDto item,
Ref ref, {
Size backDrop = const Size(2000, 2000),
Size thumb = const Size(1200, 1200),
Size logo = const Size(500, 500),
Size primary = const Size(600, 600),
bool getOriginalSize = false,
Expand All @@ -64,6 +67,23 @@ class ImagesData {
hash: item.imageBlurHashes?.primary?[item.imageTags?['Primary']] ?? "",
)
: null,
thumb: item.imageTags?['Thumb'] != null
? ImageData(
path: getOriginalSize
? imageProvider.getItemsOrigImageUrl(
itemid,
type: enums.ImageType.thumb,
)
: imageProvider.getItemsImageUrl(
itemid,
type: enums.ImageType.thumb,
maxHeight: thumb.height.toInt(),
maxWidth: thumb.width.toInt(),
),
key: "${itemid}_thumb_${item.imageTags?['Thumb']}",
hash: item.imageBlurHashes?.thumb?[item.imageTags?['Thumb']] ?? "",
)
: null,
logo: ImageData(
path: getOriginalSize
? imageProvider.getItemsOrigImageUrl(
Expand Down Expand Up @@ -111,6 +131,7 @@ class ImagesData {
dto.BaseItemDto item,
Ref ref, {
Size backDrop = const Size(2000, 2000),
Size thumb = const Size(1200, 1200),
Size logo = const Size(500, 500),
Size primary = const Size(600, 600),
}) {
Expand All @@ -130,6 +151,19 @@ class ImagesData {
key: "${item.seriesId}_primary_${item.seriesPrimaryImageTag ?? ""}",
hash: item.imageBlurHashes?.primary?[item.seriesPrimaryImageTag] ?? "")
: null,
thumb: ((item.seriesThumbImageTag ?? item.parentThumbImageTag) != null)
? ImageData(
path: imageProvider.getItemsImageUrl(
item.parentThumbItemId ?? item.seriesId ?? item.parentId,
type: enums.ImageType.thumb,
maxHeight: thumb.height.toInt(),
maxWidth: thumb.width.toInt(),
),
key:
"${item.parentThumbItemId ?? item.seriesId ?? item.parentId}_thumb_${item.seriesThumbImageTag ?? item.parentThumbImageTag ?? ""}",
hash: item.imageBlurHashes?.thumb?[item.seriesThumbImageTag ?? item.parentThumbImageTag] ?? "",
)
: null,
logo: ImageData(
path: imageProvider.getItemsImageUrl(
item.seriesId,
Expand Down Expand Up @@ -183,21 +217,24 @@ class ImagesData {
key: "${item.id ?? ""}_primary_${item.primaryImageTag ?? ''}",
hash: item.imageBlurHashes?.primary?[item.primaryImageTag] ?? '')
: null,
thumb: null,
logo: null,
backDrop: null,
);
}

@override
String toString() => 'ImagesData(primary: $primary, backDrop: $backDrop, logo: $logo)';
String toString() => 'ImagesData(primary: $primary, thumb: $thumb, backDrop: $backDrop, logo: $logo)';

ImagesData copyWith({
ValueGetter<ImageData?>? primary,
ValueGetter<ImageData?>? thumb,
ValueGetter<List<ImageData>?>? backDrop,
ValueGetter<ImageData?>? logo,
}) {
return ImagesData(
primary: primary != null ? primary() : this.primary,
thumb: thumb != null ? thumb() : this.thumb,
backDrop: backDrop != null ? backDrop() : this.backDrop,
logo: logo != null ? logo() : this.logo,
);
Expand All @@ -206,6 +243,7 @@ class ImagesData {
Map<String, dynamic> toMap() {
return {
'primary': primary?.toMap(),
'thumb': thumb?.toMap(),
'backDrop': backDrop?.map((x) => x.toMap()).toList(),
'logo': logo?.toMap(),
};
Expand All @@ -214,6 +252,7 @@ class ImagesData {
factory ImagesData.fromMap(Map<String, dynamic> map) {
return ImagesData(
primary: map['primary'] != null ? ImageData.fromMap(map['primary']) : null,
thumb: map['thumb'] != null ? ImageData.fromMap(map['thumb']) : null,
backDrop:
map['backDrop'] != null ? List<ImageData>.from(map['backDrop']?.map((x) => ImageData.fromMap(x))) : null,
logo: map['logo'] != null ? ImageData.fromMap(map['logo']) : null,
Expand Down
3 changes: 3 additions & 0 deletions lib/providers/dashboard_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class DashboardNotifier extends StateNotifier<HomeModel> {

final imagesToFetch = {
ImageType.logo,
ImageType.thumb,
ImageType.primary,
ImageType.backdrop,
ImageType.banner,
Expand Down Expand Up @@ -117,6 +118,8 @@ class DashboardNotifier extends StateNotifier<HomeModel> {
nextUpDateCutoff: DateTime.now().subtract(
ref.read(clientSettingsProvider.select((value) => value.nextUpDateCutoff ?? const Duration(days: 28)))),
fields: fieldsToFetch.toList(),
enableImageTypes: imagesToFetch,
imageTypeLimit: 1,
);

final next = nextResponse.body?.items
Expand Down
2 changes: 1 addition & 1 deletion lib/screens/library/library_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen> with SingleTicker
tvMode: useTVExpandedLayout,
contentPadding: padding,
posters: element.posters,
primaryPosters: element.name is Continue,
collectionAspectRatio: element.name is Continue ? 1.2 : null,
label: element.type != null
? "${element.type?.label(context.localized)} - ${element.name.label(context.localized)}"
: element.name.label(context.localized),
Expand Down
31 changes: 26 additions & 5 deletions lib/screens/shared/media/components/poster_image.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as jelly;
import 'package:flutter/material.dart';

import 'package:dynamic_color/dynamic_color.dart';
Expand Down Expand Up @@ -35,7 +37,7 @@ class PosterImage extends ConsumerWidget {
final Function(ItemBaseModel newItem)? onItemUpdated;
final Function(ItemBaseModel oldItem)? onItemRemoved;
final Function(Function() action, ItemBaseModel item)? onPressed;
final bool primaryPosters;
final List<jelly.ImageType>? imagePriority;
final Function(bool focus)? onFocusChanged;
final bool showSyncStatus;

Expand All @@ -50,12 +52,33 @@ class PosterImage extends ConsumerWidget {
this.otherActions = const [],
this.onPressed,
this.onUserDataChanged,
this.primaryPosters = false,
this.imagePriority,
this.onFocusChanged,
this.showSyncStatus = false,
super.key,
});

ImageData? _resolveImage() {
final source = poster.getPosters;
final fallback = poster.images;

final effectivePriority =
imagePriority ?? const [jelly.ImageType.primary, jelly.ImageType.thumb, jelly.ImageType.backdrop];

for (final type in effectivePriority) {
final image = switch (type) {
jelly.ImageType.primary => source?.primary ?? fallback?.primary,
jelly.ImageType.thumb => source?.thumb ?? fallback?.thumb,
jelly.ImageType.backdrop => source?.backDrop?.lastOrNull ?? fallback?.backDrop?.lastOrNull,
_ => null,
};

if (image != null) return image;
}

return null;
}

@override
Widget build(BuildContext context, WidgetRef ref) {
final radius = FladderTheme.smallShape.borderRadius;
Expand Down Expand Up @@ -95,9 +118,7 @@ class PosterImage extends ConsumerWidget {
border: Border.all(width: 1, color: Colors.white.withAlpha(45)),
),
child: FladderImage(
image: primaryPosters
? poster.images?.primary
: poster.getPosters?.primary ?? poster.getPosters?.backDrop?.lastOrNull,
image: _resolveImage(),
placeHolder: PosterPlaceholder(item: poster),
),
),
Expand Down
7 changes: 6 additions & 1 deletion lib/screens/shared/media/detailed_banner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';

import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as jelly;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/screens/details_screens/components/overview_header.dart';
import 'package:fladder/screens/shared/media/poster_row.dart';
Expand Down Expand Up @@ -110,7 +111,11 @@ class _DetailedBannerState extends ConsumerState<DetailedBanner> {
return FocusProvider(
autoFocus: true,
child: PosterRow(
primaryPosters: true,
imagePriority: const [
jelly.ImageType.thumb,
jelly.ImageType.backdrop,
jelly.ImageType.primary,
],
label: context.localized.nextUp,
posters: widget.posters,
onFocused: (poster) {
Expand Down
10 changes: 5 additions & 5 deletions lib/screens/shared/media/poster_row.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';

import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as jelly;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/providers/arguments_provider.dart';
import 'package:fladder/screens/shared/media/poster_widget.dart';
Expand All @@ -18,7 +19,7 @@ class PosterRow extends ConsumerWidget {
final Function()? onLabelClick;
final EdgeInsets contentPadding;
final Function(ItemBaseModel focused)? onFocused;
final bool primaryPosters;
final List<jelly.ImageType>? imagePriority;
final bool tvMode;
final bool showSyncStatus;
const PosterRow({
Expand All @@ -28,15 +29,15 @@ class PosterRow extends ConsumerWidget {
this.collectionAspectRatio,
this.onLabelClick,
this.onFocused,
this.primaryPosters = false,
this.imagePriority,
this.tvMode = false,
this.showSyncStatus = false,
super.key,
});

@override
Widget build(BuildContext context, WidgetRef ref) {
final dominantRatio = primaryPosters ? 1.2 : collectionAspectRatio ?? posters.getMostCommonType.aspectRatio;
final dominantRatio = collectionAspectRatio ?? posters.getMostCommonType.aspectRatio;
if (tvMode) {
return TVPosterRow(
posters: posters,
Expand All @@ -45,7 +46,6 @@ class PosterRow extends ConsumerWidget {
contentPadding: contentPadding,
onLabelClick: onLabelClick,
onFocused: onFocused,
primaryPosters: primaryPosters,
autoFocus: ref.read(argumentsStateProvider).htpcMode ? FocusProvider.autoFocusOf(context) : false,
);
}
Expand All @@ -69,8 +69,8 @@ class PosterRow extends ConsumerWidget {
key: Key(poster.id),
poster: poster,
aspectRatio: dominantRatio,
primaryPosters: primaryPosters,
showSyncStatus: showSyncStatus,
imagePriority: imagePriority,
);
},
);
Expand Down
7 changes: 4 additions & 3 deletions lib/screens/shared/media/poster_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';

import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as jelly;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/album_model.dart';
import 'package:fladder/models/items/item_shared_models.dart';
Expand Down Expand Up @@ -30,7 +31,7 @@ class PosterWidget extends ConsumerWidget {
final Function(ItemBaseModel newItem)? onItemUpdated;
final Function(ItemBaseModel oldItem)? onItemRemoved;
final Function(VoidCallback action, ItemBaseModel item)? onPressed;
final bool primaryPosters;
final List<jelly.ImageType>? imagePriority;
final Function(bool focus)? onFocusChanged;
final bool showSyncStatus;

Expand All @@ -48,7 +49,7 @@ class PosterWidget extends ConsumerWidget {
this.onItemUpdated,
this.onItemRemoved,
this.onPressed,
this.primaryPosters = false,
this.imagePriority,
this.onFocusChanged,
this.showSyncStatus = false,
super.key,
Expand Down Expand Up @@ -80,7 +81,7 @@ class PosterWidget extends ConsumerWidget {
onItemRemoved: onItemRemoved,
onItemUpdated: onItemUpdated,
onPressed: onPressed,
primaryPosters: primaryPosters,
imagePriority: imagePriority,
onFocusChanged: onFocusChanged,
showSyncStatus: showSyncStatus,
),
Expand Down
5 changes: 0 additions & 5 deletions lib/screens/shared/media/tv_poster_row.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class TVPosterRow extends ConsumerStatefulWidget {
final EdgeInsets contentPadding;
final Function()? onLabelClick;
final Function(ItemBaseModel focused)? onFocused;
final bool primaryPosters;
final bool autoFocus;

const TVPosterRow({
Expand All @@ -45,7 +44,6 @@ class TVPosterRow extends ConsumerStatefulWidget {
this.primaryRatio = 0.67,
this.onLabelClick,
this.onFocused,
this.primaryPosters = false,
this.autoFocus = false,
super.key,
});
Expand Down Expand Up @@ -143,7 +141,6 @@ class _TVPosterRowState extends ConsumerState<TVPosterRow> {
widget.onFocused?.call(poster);
}
},
primaryPosters: isFocused || widget.primaryPosters,
onTap: () => poster.navigateTo(context, ref: ref),
);
},
Expand Down Expand Up @@ -172,7 +169,6 @@ class _TVPosterItem extends ConsumerWidget {
final bool selected;
final bool focused;
final Function(bool focused)? onFocusChanged;
final bool primaryPosters;
final VoidCallback onTap;

const _TVPosterItem({
Expand All @@ -182,7 +178,6 @@ class _TVPosterItem extends ConsumerWidget {
required this.selected,
required this.focused,
this.onFocusChanged,
required this.primaryPosters,
required this.onTap,
});

Expand Down
Loading