Init repo

This commit is contained in:
PartyDonut 2024-09-15 14:12:28 +02:00
commit 764b6034e3
566 changed files with 212335 additions and 0 deletions

View file

@ -0,0 +1,90 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:fladder/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/providers/image_provider.dart';
class Chapter {
final String name;
final String imageUrl;
final Uint8List? imageData;
final Duration startPosition;
Chapter({
required this.name,
required this.imageUrl,
this.imageData,
required this.startPosition,
});
ImageProvider get imageProvider {
if (imageData != null) {
return Image.memory(imageData!).image;
}
if (imageUrl.startsWith("http")) {
return CachedNetworkImageProvider(
cacheKey: name + imageUrl,
cacheManager: CustomCacheManager.instance,
imageUrl,
);
} else {
return Image.file(
key: Key(name + imageUrl),
File(imageUrl),
).image;
}
}
static List<Chapter> chaptersFromInfo(String itemId, List<dto.ChapterInfo> chapters, Ref ref) {
return chapters
.mapIndexed((index, element) => Chapter(
name: element.name ?? "",
imageUrl: ref.read(imageUtilityProvider).getChapterUrl(itemId, index),
startPosition: Duration(milliseconds: (element.startPositionTicks ?? 0) ~/ 10000)))
.toList();
}
Chapter copyWith({
String? name,
String? imageUrl,
Duration? startPosition,
}) {
return Chapter(
name: name ?? this.name,
imageUrl: imageUrl ?? this.imageUrl,
startPosition: startPosition ?? this.startPosition,
);
}
Map<String, dynamic> toMap() {
return {
'name': name,
'imageUrl': imageUrl,
'startPosition': startPosition.inMilliseconds,
};
}
factory Chapter.fromMap(Map<String, dynamic> map) {
return Chapter(
name: map['name'] ?? '',
imageUrl: map['imageUrl'] ?? '',
startPosition: Duration(milliseconds: map['startPosition'] as int),
);
}
String toJson() => json.encode(toMap());
factory Chapter.fromJson(String source) => Chapter.fromMap(json.decode(source));
}
extension ChapterExtension on List<Chapter> {
Chapter? getChapterFromDuration(Duration duration) {
return lastWhereOrNull((element) => element.startPosition < duration);
}
}

View file

@ -0,0 +1,201 @@
import 'package:collection/collection.dart';
import 'package:fladder/jellyfin/enum_models.dart';
import 'package:fladder/models/items/series_model.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/string_extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/models/items/chapters_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/item_stream_model.dart';
import 'package:fladder/models/items/media_streams_model.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'episode_model.mapper.dart';
enum EpisodeStatus { available, unaired, missing }
@MappableClass()
class EpisodeModel extends ItemStreamModel with EpisodeModelMappable {
final String? seriesName;
final int season;
final int episode;
final List<Chapter> chapters;
final ItemLocation? location;
final DateTime? dateAired;
const EpisodeModel({
required this.seriesName,
required this.season,
required this.episode,
this.chapters = const [],
this.location,
this.dateAired,
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
required super.parentImages,
required super.mediaStreams,
super.canDelete,
super.canDownload,
super.jellyType,
});
EpisodeStatus get status {
return switch (location) {
ItemLocation.filesystem => EpisodeStatus.available,
ItemLocation.virtual =>
(dateAired?.isBefore(DateTime.now()) == true) ? EpisodeStatus.missing : EpisodeStatus.unaired,
_ => EpisodeStatus.missing
};
}
@override
String? detailedName(BuildContext context) => "${subTextShort(context)} - $name";
@override
SeriesModel get parentBaseModel => SeriesModel(
originalTitle: '',
sortName: '',
status: "",
name: seriesName ?? "",
id: parentId ?? "",
playlistId: playlistId,
overview: overview,
parentId: parentId,
images: images,
childCount: childCount,
primaryRatio: primaryRatio,
userData: UserData(),
);
@override
String get streamId => parentId ?? "";
@override
String get title => seriesName ?? name;
@override
MediaStreamsModel? get streamModel => mediaStreams;
@override
ImagesData? get getPosters => parentImages;
@override
String? get subText => name.isEmpty ? "TBA" : name;
@override
String? subTextShort(BuildContext context) => seasonEpisodeLabel(context);
@override
String? label(BuildContext context) => "${subTextShort(context)} - $name";
@override
bool get playAble => switch (status) {
EpisodeStatus.available => true,
_ => false,
};
@override
String playButtonLabel(BuildContext context) {
final string = seasonEpisodeLabel(context).maxLength();
return progress != 0 ? context.localized.resume(string) : context.localized.play(string);
}
String seasonAnnotation(BuildContext context) => context.localized.season(1)[0];
String episodeAnnotation(BuildContext context) => context.localized.episode(1)[0];
String seasonEpisodeLabel(BuildContext context) {
return "${seasonAnnotation(context)}$season - ${episodeAnnotation(context)}$episode";
}
String seasonEpisodeLabelFull(BuildContext context) {
return "${context.localized.season(1)} $season - ${context.localized.episode(1)} $episode";
}
String episodeLabel(BuildContext context) {
return "${seasonEpisodeLabel(context)} - $subText";
}
String get fullName {
return "$episode. $subText";
}
@override
bool get syncAble => playAble;
@override
factory EpisodeModel.fromBaseDto(dto.BaseItemDto item, Ref ref) => EpisodeModel(
seriesName: item.seriesName,
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.seriesId,
playlistId: item.playlistItemId,
dateAired: item.premiereDate,
chapters: Chapter.chaptersFromInfo(item.id ?? "", item.chapters ?? [], ref),
images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true),
primaryRatio: item.primaryImageAspectRatio,
season: item.parentIndexNumber ?? 0,
episode: item.indexNumber ?? 0,
location: ItemLocation.fromDto(item.locationType),
parentImages: ImagesData.fromBaseItemParent(item, ref),
canDelete: item.canDelete,
canDownload: item.canDownload,
mediaStreams:
MediaStreamsModel.fromMediaStreamsList(item.mediaSources?.firstOrNull, item.mediaStreams ?? [], ref),
jellyType: item.type,
);
static List<EpisodeModel> episodesFromDto(List<dto.BaseItemDto>? dto, Ref ref) {
return dto?.map((e) => EpisodeModel.fromBaseDto(e, ref)).toList() ?? [];
}
}
extension EpisodeListExtensions on List<EpisodeModel> {
Map<int, List<EpisodeModel>> get episodesBySeason {
Map<int, List<EpisodeModel>> groupedItems = {};
for (int i = 0; i < length; i++) {
int seasonIndex = this[i].season;
if (!groupedItems.containsKey(seasonIndex)) {
groupedItems[seasonIndex] = [this[i]];
} else {
groupedItems[seasonIndex]?.add(this[i]);
}
}
return groupedItems;
}
EpisodeModel? get nextUp {
final lastProgress =
lastIndexWhere((element) => element.userData.progress != 0 && element.status == EpisodeStatus.available);
final lastPlayed =
lastIndexWhere((element) => element.userData.played && element.status == EpisodeStatus.available);
if (lastProgress == -1 && lastPlayed == -1) {
return firstWhereOrNull((element) => element.status == EpisodeStatus.available);
} else {
return getRange(lastProgress > lastPlayed ? lastProgress : lastPlayed + 1, length)
.firstWhereOrNull((element) => element.status == EpisodeStatus.available);
}
}
bool get allPlayed {
for (var element in this) {
if (!element.userData.played) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,301 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'episode_model.dart';
class EpisodeModelMapper extends SubClassMapperBase<EpisodeModel> {
EpisodeModelMapper._();
static EpisodeModelMapper? _instance;
static EpisodeModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = EpisodeModelMapper._());
ItemStreamModelMapper.ensureInitialized().addSubMapper(_instance!);
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'EpisodeModel';
static String? _$seriesName(EpisodeModel v) => v.seriesName;
static const Field<EpisodeModel, String> _f$seriesName =
Field('seriesName', _$seriesName);
static int _$season(EpisodeModel v) => v.season;
static const Field<EpisodeModel, int> _f$season = Field('season', _$season);
static int _$episode(EpisodeModel v) => v.episode;
static const Field<EpisodeModel, int> _f$episode =
Field('episode', _$episode);
static List<Chapter> _$chapters(EpisodeModel v) => v.chapters;
static const Field<EpisodeModel, List<Chapter>> _f$chapters =
Field('chapters', _$chapters, opt: true, def: const []);
static ItemLocation? _$location(EpisodeModel v) => v.location;
static const Field<EpisodeModel, ItemLocation> _f$location =
Field('location', _$location, opt: true);
static DateTime? _$dateAired(EpisodeModel v) => v.dateAired;
static const Field<EpisodeModel, DateTime> _f$dateAired =
Field('dateAired', _$dateAired, opt: true);
static String _$name(EpisodeModel v) => v.name;
static const Field<EpisodeModel, String> _f$name = Field('name', _$name);
static String _$id(EpisodeModel v) => v.id;
static const Field<EpisodeModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(EpisodeModel v) => v.overview;
static const Field<EpisodeModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(EpisodeModel v) => v.parentId;
static const Field<EpisodeModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(EpisodeModel v) => v.playlistId;
static const Field<EpisodeModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(EpisodeModel v) => v.images;
static const Field<EpisodeModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(EpisodeModel v) => v.childCount;
static const Field<EpisodeModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(EpisodeModel v) => v.primaryRatio;
static const Field<EpisodeModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(EpisodeModel v) => v.userData;
static const Field<EpisodeModel, UserData> _f$userData =
Field('userData', _$userData);
static ImagesData? _$parentImages(EpisodeModel v) => v.parentImages;
static const Field<EpisodeModel, ImagesData> _f$parentImages =
Field('parentImages', _$parentImages);
static MediaStreamsModel _$mediaStreams(EpisodeModel v) => v.mediaStreams;
static const Field<EpisodeModel, MediaStreamsModel> _f$mediaStreams =
Field('mediaStreams', _$mediaStreams);
static bool? _$canDelete(EpisodeModel v) => v.canDelete;
static const Field<EpisodeModel, bool> _f$canDelete =
Field('canDelete', _$canDelete, opt: true);
static bool? _$canDownload(EpisodeModel v) => v.canDownload;
static const Field<EpisodeModel, bool> _f$canDownload =
Field('canDownload', _$canDownload, opt: true);
static dto.BaseItemKind? _$jellyType(EpisodeModel v) => v.jellyType;
static const Field<EpisodeModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<EpisodeModel> fields = const {
#seriesName: _f$seriesName,
#season: _f$season,
#episode: _f$episode,
#chapters: _f$chapters,
#location: _f$location,
#dateAired: _f$dateAired,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#parentImages: _f$parentImages,
#mediaStreams: _f$mediaStreams,
#canDelete: _f$canDelete,
#canDownload: _f$canDownload,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'EpisodeModel';
@override
late final ClassMapperBase superMapper =
ItemStreamModelMapper.ensureInitialized();
static EpisodeModel _instantiate(DecodingData data) {
return EpisodeModel(
seriesName: data.dec(_f$seriesName),
season: data.dec(_f$season),
episode: data.dec(_f$episode),
chapters: data.dec(_f$chapters),
location: data.dec(_f$location),
dateAired: data.dec(_f$dateAired),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
parentImages: data.dec(_f$parentImages),
mediaStreams: data.dec(_f$mediaStreams),
canDelete: data.dec(_f$canDelete),
canDownload: data.dec(_f$canDownload),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static EpisodeModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<EpisodeModel>(map);
}
static EpisodeModel fromJson(String json) {
return ensureInitialized().decodeJson<EpisodeModel>(json);
}
}
mixin EpisodeModelMappable {
String toJson() {
return EpisodeModelMapper.ensureInitialized()
.encodeJson<EpisodeModel>(this as EpisodeModel);
}
Map<String, dynamic> toMap() {
return EpisodeModelMapper.ensureInitialized()
.encodeMap<EpisodeModel>(this as EpisodeModel);
}
EpisodeModelCopyWith<EpisodeModel, EpisodeModel, EpisodeModel> get copyWith =>
_EpisodeModelCopyWithImpl(this as EpisodeModel, $identity, $identity);
@override
String toString() {
return EpisodeModelMapper.ensureInitialized()
.stringifyValue(this as EpisodeModel);
}
}
extension EpisodeModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, EpisodeModel, $Out> {
EpisodeModelCopyWith<$R, EpisodeModel, $Out> get $asEpisodeModel =>
$base.as((v, t, t2) => _EpisodeModelCopyWithImpl(v, t, t2));
}
abstract class EpisodeModelCopyWith<$R, $In extends EpisodeModel, $Out>
implements ItemStreamModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>> get chapters;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{String? seriesName,
int? season,
int? episode,
List<Chapter>? chapters,
ItemLocation? location,
DateTime? dateAired,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
ImagesData? parentImages,
MediaStreamsModel? mediaStreams,
bool? canDelete,
bool? canDownload,
dto.BaseItemKind? jellyType});
EpisodeModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _EpisodeModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, EpisodeModel, $Out>
implements EpisodeModelCopyWith<$R, EpisodeModel, $Out> {
_EpisodeModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<EpisodeModel> $mapper =
EpisodeModelMapper.ensureInitialized();
@override
ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>>
get chapters => ListCopyWith($value.chapters,
(v, t) => ObjectCopyWith(v, $identity, t), (v) => call(chapters: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{Object? seriesName = $none,
int? season,
int? episode,
List<Chapter>? chapters,
Object? location = $none,
Object? dateAired = $none,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? parentImages = $none,
MediaStreamsModel? mediaStreams,
Object? canDelete = $none,
Object? canDownload = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (seriesName != $none) #seriesName: seriesName,
if (season != null) #season: season,
if (episode != null) #episode: episode,
if (chapters != null) #chapters: chapters,
if (location != $none) #location: location,
if (dateAired != $none) #dateAired: dateAired,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (parentImages != $none) #parentImages: parentImages,
if (mediaStreams != null) #mediaStreams: mediaStreams,
if (canDelete != $none) #canDelete: canDelete,
if (canDownload != $none) #canDownload: canDownload,
if (jellyType != $none) #jellyType: jellyType
}));
@override
EpisodeModel $make(CopyWithData data) => EpisodeModel(
seriesName: data.get(#seriesName, or: $value.seriesName),
season: data.get(#season, or: $value.season),
episode: data.get(#episode, or: $value.episode),
chapters: data.get(#chapters, or: $value.chapters),
location: data.get(#location, or: $value.location),
dateAired: data.get(#dateAired, or: $value.dateAired),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
parentImages: data.get(#parentImages, or: $value.parentImages),
mediaStreams: data.get(#mediaStreams, or: $value.mediaStreams),
canDelete: data.get(#canDelete, or: $value.canDelete),
canDownload: data.get(#canDownload, or: $value.canDownload),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
EpisodeModelCopyWith<$R2, EpisodeModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_EpisodeModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,50 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
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/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'folder_model.mapper.dart';
@MappableClass()
class FolderModel extends ItemBaseModel with FolderModelMappable {
final List<ItemBaseModel> items;
const FolderModel({
required this.items,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
required super.name,
required super.id,
super.canDownload,
super.canDelete,
super.jellyType,
});
factory FolderModel.fromBaseDto(BaseItemDto item, Ref ref) {
return FolderModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
images: ImagesData.fromBaseItem(item, ref),
primaryRatio: item.primaryImageAspectRatio,
items: [],
canDelete: item.canDelete,
canDownload: item.canDownload,
);
}
}

View file

@ -0,0 +1,242 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'folder_model.dart';
class FolderModelMapper extends SubClassMapperBase<FolderModel> {
FolderModelMapper._();
static FolderModelMapper? _instance;
static FolderModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = FolderModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
ItemBaseModelMapper.ensureInitialized();
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'FolderModel';
static List<ItemBaseModel> _$items(FolderModel v) => v.items;
static const Field<FolderModel, List<ItemBaseModel>> _f$items =
Field('items', _$items);
static OverviewModel _$overview(FolderModel v) => v.overview;
static const Field<FolderModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(FolderModel v) => v.parentId;
static const Field<FolderModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(FolderModel v) => v.playlistId;
static const Field<FolderModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(FolderModel v) => v.images;
static const Field<FolderModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(FolderModel v) => v.childCount;
static const Field<FolderModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(FolderModel v) => v.primaryRatio;
static const Field<FolderModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(FolderModel v) => v.userData;
static const Field<FolderModel, UserData> _f$userData =
Field('userData', _$userData);
static String _$name(FolderModel v) => v.name;
static const Field<FolderModel, String> _f$name = Field('name', _$name);
static String _$id(FolderModel v) => v.id;
static const Field<FolderModel, String> _f$id = Field('id', _$id);
static bool? _$canDownload(FolderModel v) => v.canDownload;
static const Field<FolderModel, bool> _f$canDownload =
Field('canDownload', _$canDownload, opt: true);
static bool? _$canDelete(FolderModel v) => v.canDelete;
static const Field<FolderModel, bool> _f$canDelete =
Field('canDelete', _$canDelete, opt: true);
static BaseItemKind? _$jellyType(FolderModel v) => v.jellyType;
static const Field<FolderModel, BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<FolderModel> fields = const {
#items: _f$items,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#name: _f$name,
#id: _f$id,
#canDownload: _f$canDownload,
#canDelete: _f$canDelete,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'FolderModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static FolderModel _instantiate(DecodingData data) {
return FolderModel(
items: data.dec(_f$items),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
name: data.dec(_f$name),
id: data.dec(_f$id),
canDownload: data.dec(_f$canDownload),
canDelete: data.dec(_f$canDelete),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static FolderModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<FolderModel>(map);
}
static FolderModel fromJson(String json) {
return ensureInitialized().decodeJson<FolderModel>(json);
}
}
mixin FolderModelMappable {
String toJson() {
return FolderModelMapper.ensureInitialized()
.encodeJson<FolderModel>(this as FolderModel);
}
Map<String, dynamic> toMap() {
return FolderModelMapper.ensureInitialized()
.encodeMap<FolderModel>(this as FolderModel);
}
FolderModelCopyWith<FolderModel, FolderModel, FolderModel> get copyWith =>
_FolderModelCopyWithImpl(this as FolderModel, $identity, $identity);
@override
String toString() {
return FolderModelMapper.ensureInitialized()
.stringifyValue(this as FolderModel);
}
}
extension FolderModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, FolderModel, $Out> {
FolderModelCopyWith<$R, FolderModel, $Out> get $asFolderModel =>
$base.as((v, t, t2) => _FolderModelCopyWithImpl(v, t, t2));
}
abstract class FolderModelCopyWith<$R, $In extends FolderModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get items;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{List<ItemBaseModel>? items,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
String? name,
String? id,
bool? canDownload,
bool? canDelete,
BaseItemKind? jellyType});
FolderModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _FolderModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, FolderModel, $Out>
implements FolderModelCopyWith<$R, FolderModel, $Out> {
_FolderModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<FolderModel> $mapper =
FolderModelMapper.ensureInitialized();
@override
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>>
get items => ListCopyWith(
$value.items, (v, t) => v.copyWith.$chain(t), (v) => call(items: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{List<ItemBaseModel>? items,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
String? name,
String? id,
Object? canDownload = $none,
Object? canDelete = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (items != null) #items: items,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (name != null) #name: name,
if (id != null) #id: id,
if (canDownload != $none) #canDownload: canDownload,
if (canDelete != $none) #canDelete: canDelete,
if (jellyType != $none) #jellyType: jellyType
}));
@override
FolderModel $make(CopyWithData data) => FolderModel(
items: data.get(#items, or: $value.items),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
canDownload: data.get(#canDownload, or: $value.canDownload),
canDelete: data.get(#canDelete, or: $value.canDelete),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
FolderModelCopyWith<$R2, FolderModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_FolderModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,286 @@
import 'dart:convert';
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:fladder/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart' as enums;
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/providers/image_provider.dart';
import 'package:fladder/util/jelly_id.dart';
class ImagesData {
final ImageData? primary;
final List<ImageData>? backDrop;
final ImageData? logo;
ImagesData({
this.primary,
this.backDrop,
this.logo,
});
bool get isEmpty {
if (primary == null && backDrop == null) return true;
return false;
}
ImageData? get firstOrNull {
return primary ?? backDrop?[0];
}
ImageData? get randomBackDrop => (backDrop?..shuffle())?.firstOrNull ?? primary;
factory ImagesData.fromBaseItem(
dto.BaseItemDto item,
Ref ref, {
Size backDrop = const Size(2000, 2000),
Size logo = const Size(1000, 1000),
Size primary = const Size(600, 600),
bool getOriginalSize = false,
int quality = 90,
}) {
final newImgesData = ImagesData(
primary: item.imageTags?['Primary'] != null
? ImageData(
path: getOriginalSize
? ref.read(imageUtilityProvider).getItemsOrigImageUrl(
item.id!,
type: enums.ImageType.primary,
)
: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.id!),
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
key: item.imageTags?['Primary'],
hash: item.imageBlurHashes?.primary?[item.imageTags?['Primary']] as String? ?? "",
)
: null,
logo: item.imageTags?['Logo'] != null
? ImageData(
path: getOriginalSize
? ref.read(imageUtilityProvider).getItemsOrigImageUrl(
item.id!,
type: enums.ImageType.logo,
)
: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.id!),
type: enums.ImageType.logo,
maxHeight: logo.height.toInt(),
maxWidth: logo.width.toInt(),
quality: quality,
),
key: item.imageTags?['Logo'],
hash: item.imageBlurHashes?.logo?[item.imageTags?['Logo']] as String? ?? "")
: null,
backDrop: (item.backdropImageTags ?? []).mapIndexed(
(index, backdrop) {
final image = ImageData(
path: getOriginalSize
? ref.read(imageUtilityProvider).getBackdropOrigImage(
item.id!,
index,
backdrop,
)
: ref.read(imageUtilityProvider).getBackdropImage(
(item.id!),
index,
backdrop,
maxHeight: backDrop.height.toInt(),
maxWidth: backDrop.width.toInt(),
quality: quality,
),
key: backdrop,
hash: item.imageBlurHashes?.backdrop?[backdrop] ?? jellyId,
);
return image;
},
).toList(),
);
return newImgesData;
}
static ImagesData? fromBaseItemParent(
dto.BaseItemDto item,
Ref ref, {
Size backDrop = const Size(2000, 2000),
Size logo = const Size(1000, 1000),
Size primary = const Size(600, 600),
int quality = 90,
}) {
if (item.seriesId == null && item.parentId == null) return null;
final newImgesData = ImagesData(
primary: (item.seriesPrimaryImageTag != null)
? ImageData(
path: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.seriesId!),
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
key: item.seriesPrimaryImageTag ?? "",
hash: item.imageBlurHashes?.primary?[item.seriesPrimaryImageTag] as String? ?? "")
: null,
logo: (item.parentLogoImageTag != null)
? ImageData(
path: ref.read(imageUtilityProvider).getItemsImageUrl(
(item.seriesId!),
type: enums.ImageType.logo,
maxHeight: logo.height.toInt(),
maxWidth: logo.width.toInt(),
quality: quality,
),
key: item.parentLogoImageTag ?? "",
hash: item.imageBlurHashes?.logo?[item.parentLogoImageTag] as String? ?? "")
: null,
backDrop: (item.backdropImageTags ?? []).mapIndexed(
(index, backdrop) {
final image = ImageData(
path: ref.read(imageUtilityProvider).getBackdropImage(
((item.seriesId ?? item.parentId)!),
index,
backdrop,
maxHeight: backDrop.height.toInt(),
maxWidth: backDrop.width.toInt(),
quality: quality,
),
key: backdrop,
hash: item.imageBlurHashes?.backdrop?[backdrop],
);
return image;
},
).toList(),
);
return newImgesData;
}
static ImagesData? fromPersonDto(
dto.BaseItemPerson item,
Ref ref, {
Size backDrop = const Size(2000, 2000),
Size logo = const Size(1000, 1000),
Size primary = const Size(2000, 2000),
int quality = 90,
}) {
return ImagesData(
primary: (item.primaryImageTag != null && item.imageBlurHashes != null)
? ImageData(
path: ref.read(imageUtilityProvider).getItemsImageUrl(
item.id ?? "",
type: enums.ImageType.primary,
maxHeight: primary.height.toInt(),
maxWidth: primary.width.toInt(),
quality: quality,
),
key: item.primaryImageTag ?? "",
hash: item.imageBlurHashes?.primary?[item.primaryImageTag] as String? ?? jellyId)
: null,
logo: null,
backDrop: null,
);
}
@override
String toString() => 'ImagesData(primary: $primary, backDrop: $backDrop, logo: $logo)';
ImagesData copyWith({
ValueGetter<ImageData?>? primary,
ValueGetter<List<ImageData>?>? backDrop,
ValueGetter<ImageData?>? logo,
}) {
return ImagesData(
primary: primary != null ? primary() : this.primary,
backDrop: backDrop != null ? backDrop() : this.backDrop,
logo: logo != null ? logo() : this.logo,
);
}
Map<String, dynamic> toMap() {
return {
'primary': primary?.toMap(),
'backDrop': backDrop?.map((x) => x.toMap()).toList(),
'logo': logo?.toMap(),
};
}
factory ImagesData.fromMap(Map<String, dynamic> map) {
return ImagesData(
primary: map['primary'] != null ? ImageData.fromMap(map['primary']) : 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,
);
}
String toJson() => json.encode(toMap());
factory ImagesData.fromJson(String source) => ImagesData.fromMap(json.decode(source));
}
class ImageData {
final String path;
final String hash;
final String key;
ImageData({
this.path = '',
this.hash = '',
this.key = '',
});
ImageProvider get imageProvider {
if (path.startsWith("http")) {
return CachedNetworkImageProvider(
cacheKey: key,
cacheManager: CustomCacheManager.instance,
path,
);
} else {
return Image.file(
key: Key(key),
File(path),
).image;
}
}
@override
String toString() => 'ImageData(path: $path, hash: $hash, key: $key)';
ImageData copyWith({
String? path,
String? hash,
String? key,
}) {
return ImageData(
path: path ?? this.path,
hash: hash ?? this.hash,
key: key ?? this.key,
);
}
Map<String, dynamic> toMap() {
return {
'path': path,
'hash': hash,
'key': key,
};
}
factory ImageData.fromMap(Map<String, dynamic> map) {
return ImageData(
path: map['path'] ?? '',
hash: map['hash'] ?? '',
key: map['key'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory ImageData.fromJson(String source) => ImageData.fromMap(json.decode(source));
}

View file

@ -0,0 +1,47 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first, invalid_annotation_target
import 'package:freezed_annotation/freezed_annotation.dart';
part 'intro_skip_model.freezed.dart';
part 'intro_skip_model.g.dart';
@freezed
class IntroOutSkipModel with _$IntroOutSkipModel {
const IntroOutSkipModel._();
factory IntroOutSkipModel({
IntroSkipModel? intro,
IntroSkipModel? credits,
}) = _IntroOutSkipModel;
factory IntroOutSkipModel.fromJson(Map<String, dynamic> json) => _$IntroOutSkipModelFromJson(json);
bool introInRange(Duration position) {
if (intro == null) return false;
return (position.compareTo(intro!.showTime) >= 0 && position.compareTo(intro!.hideTime) <= 0);
}
bool creditsInRange(Duration position) {
if (credits == null) return false;
return (position.compareTo(credits!.showTime) >= 0 && position.compareTo(credits!.hideTime) <= 0);
}
}
@freezed
class IntroSkipModel with _$IntroSkipModel {
factory IntroSkipModel({
@JsonKey(name: "EpisodeId") required String id,
@JsonKey(name: "Valid") required bool valid,
@JsonKey(name: "IntroStart", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds)
required Duration start,
@JsonKey(name: "IntroEnd", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds)
required Duration end,
@JsonKey(name: "ShowSkipPromptAt", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds)
required Duration showTime,
@JsonKey(name: "HideSkipPromptAt", fromJson: _durationFromMilliseconds, toJson: _durationToMilliseconds)
required Duration hideTime,
}) = _IntroSkipModel;
factory IntroSkipModel.fromJson(Map<String, dynamic> json) => _$IntroSkipModelFromJson(json);
}
Duration _durationFromMilliseconds(num milliseconds) => Duration(milliseconds: (milliseconds * 1000).toInt());
num _durationToMilliseconds(Duration duration) => duration.inMilliseconds.toDouble() / 1000.0;

View file

@ -0,0 +1,565 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'intro_skip_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
IntroOutSkipModel _$IntroOutSkipModelFromJson(Map<String, dynamic> json) {
return _IntroOutSkipModel.fromJson(json);
}
/// @nodoc
mixin _$IntroOutSkipModel {
IntroSkipModel? get intro => throw _privateConstructorUsedError;
IntroSkipModel? get credits => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$IntroOutSkipModelCopyWith<IntroOutSkipModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $IntroOutSkipModelCopyWith<$Res> {
factory $IntroOutSkipModelCopyWith(
IntroOutSkipModel value, $Res Function(IntroOutSkipModel) then) =
_$IntroOutSkipModelCopyWithImpl<$Res, IntroOutSkipModel>;
@useResult
$Res call({IntroSkipModel? intro, IntroSkipModel? credits});
$IntroSkipModelCopyWith<$Res>? get intro;
$IntroSkipModelCopyWith<$Res>? get credits;
}
/// @nodoc
class _$IntroOutSkipModelCopyWithImpl<$Res, $Val extends IntroOutSkipModel>
implements $IntroOutSkipModelCopyWith<$Res> {
_$IntroOutSkipModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? intro = freezed,
Object? credits = freezed,
}) {
return _then(_value.copyWith(
intro: freezed == intro
? _value.intro
: intro // ignore: cast_nullable_to_non_nullable
as IntroSkipModel?,
credits: freezed == credits
? _value.credits
: credits // ignore: cast_nullable_to_non_nullable
as IntroSkipModel?,
) as $Val);
}
@override
@pragma('vm:prefer-inline')
$IntroSkipModelCopyWith<$Res>? get intro {
if (_value.intro == null) {
return null;
}
return $IntroSkipModelCopyWith<$Res>(_value.intro!, (value) {
return _then(_value.copyWith(intro: value) as $Val);
});
}
@override
@pragma('vm:prefer-inline')
$IntroSkipModelCopyWith<$Res>? get credits {
if (_value.credits == null) {
return null;
}
return $IntroSkipModelCopyWith<$Res>(_value.credits!, (value) {
return _then(_value.copyWith(credits: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$IntroOutSkipModelImplCopyWith<$Res>
implements $IntroOutSkipModelCopyWith<$Res> {
factory _$$IntroOutSkipModelImplCopyWith(_$IntroOutSkipModelImpl value,
$Res Function(_$IntroOutSkipModelImpl) then) =
__$$IntroOutSkipModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({IntroSkipModel? intro, IntroSkipModel? credits});
@override
$IntroSkipModelCopyWith<$Res>? get intro;
@override
$IntroSkipModelCopyWith<$Res>? get credits;
}
/// @nodoc
class __$$IntroOutSkipModelImplCopyWithImpl<$Res>
extends _$IntroOutSkipModelCopyWithImpl<$Res, _$IntroOutSkipModelImpl>
implements _$$IntroOutSkipModelImplCopyWith<$Res> {
__$$IntroOutSkipModelImplCopyWithImpl(_$IntroOutSkipModelImpl _value,
$Res Function(_$IntroOutSkipModelImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? intro = freezed,
Object? credits = freezed,
}) {
return _then(_$IntroOutSkipModelImpl(
intro: freezed == intro
? _value.intro
: intro // ignore: cast_nullable_to_non_nullable
as IntroSkipModel?,
credits: freezed == credits
? _value.credits
: credits // ignore: cast_nullable_to_non_nullable
as IntroSkipModel?,
));
}
}
/// @nodoc
@JsonSerializable()
class _$IntroOutSkipModelImpl extends _IntroOutSkipModel {
_$IntroOutSkipModelImpl({this.intro, this.credits}) : super._();
factory _$IntroOutSkipModelImpl.fromJson(Map<String, dynamic> json) =>
_$$IntroOutSkipModelImplFromJson(json);
@override
final IntroSkipModel? intro;
@override
final IntroSkipModel? credits;
@override
String toString() {
return 'IntroOutSkipModel(intro: $intro, credits: $credits)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$IntroOutSkipModelImpl &&
(identical(other.intro, intro) || other.intro == intro) &&
(identical(other.credits, credits) || other.credits == credits));
}
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(runtimeType, intro, credits);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$IntroOutSkipModelImplCopyWith<_$IntroOutSkipModelImpl> get copyWith =>
__$$IntroOutSkipModelImplCopyWithImpl<_$IntroOutSkipModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$IntroOutSkipModelImplToJson(
this,
);
}
}
abstract class _IntroOutSkipModel extends IntroOutSkipModel {
factory _IntroOutSkipModel(
{final IntroSkipModel? intro,
final IntroSkipModel? credits}) = _$IntroOutSkipModelImpl;
_IntroOutSkipModel._() : super._();
factory _IntroOutSkipModel.fromJson(Map<String, dynamic> json) =
_$IntroOutSkipModelImpl.fromJson;
@override
IntroSkipModel? get intro;
@override
IntroSkipModel? get credits;
@override
@JsonKey(ignore: true)
_$$IntroOutSkipModelImplCopyWith<_$IntroOutSkipModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}
IntroSkipModel _$IntroSkipModelFromJson(Map<String, dynamic> json) {
return _IntroSkipModel.fromJson(json);
}
/// @nodoc
mixin _$IntroSkipModel {
@JsonKey(name: "EpisodeId")
String get id => throw _privateConstructorUsedError;
@JsonKey(name: "Valid")
bool get valid => throw _privateConstructorUsedError;
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get start => throw _privateConstructorUsedError;
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get end => throw _privateConstructorUsedError;
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get showTime => throw _privateConstructorUsedError;
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get hideTime => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$IntroSkipModelCopyWith<IntroSkipModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $IntroSkipModelCopyWith<$Res> {
factory $IntroSkipModelCopyWith(
IntroSkipModel value, $Res Function(IntroSkipModel) then) =
_$IntroSkipModelCopyWithImpl<$Res, IntroSkipModel>;
@useResult
$Res call(
{@JsonKey(name: "EpisodeId") String id,
@JsonKey(name: "Valid") bool valid,
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration start,
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration end,
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration showTime,
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration hideTime});
}
/// @nodoc
class _$IntroSkipModelCopyWithImpl<$Res, $Val extends IntroSkipModel>
implements $IntroSkipModelCopyWith<$Res> {
_$IntroSkipModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? valid = null,
Object? start = null,
Object? end = null,
Object? showTime = null,
Object? hideTime = null,
}) {
return _then(_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String,
valid: null == valid
? _value.valid
: valid // ignore: cast_nullable_to_non_nullable
as bool,
start: null == start
? _value.start
: start // ignore: cast_nullable_to_non_nullable
as Duration,
end: null == end
? _value.end
: end // ignore: cast_nullable_to_non_nullable
as Duration,
showTime: null == showTime
? _value.showTime
: showTime // ignore: cast_nullable_to_non_nullable
as Duration,
hideTime: null == hideTime
? _value.hideTime
: hideTime // ignore: cast_nullable_to_non_nullable
as Duration,
) as $Val);
}
}
/// @nodoc
abstract class _$$IntroSkipModelImplCopyWith<$Res>
implements $IntroSkipModelCopyWith<$Res> {
factory _$$IntroSkipModelImplCopyWith(_$IntroSkipModelImpl value,
$Res Function(_$IntroSkipModelImpl) then) =
__$$IntroSkipModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{@JsonKey(name: "EpisodeId") String id,
@JsonKey(name: "Valid") bool valid,
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration start,
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration end,
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration showTime,
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration hideTime});
}
/// @nodoc
class __$$IntroSkipModelImplCopyWithImpl<$Res>
extends _$IntroSkipModelCopyWithImpl<$Res, _$IntroSkipModelImpl>
implements _$$IntroSkipModelImplCopyWith<$Res> {
__$$IntroSkipModelImplCopyWithImpl(
_$IntroSkipModelImpl _value, $Res Function(_$IntroSkipModelImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? valid = null,
Object? start = null,
Object? end = null,
Object? showTime = null,
Object? hideTime = null,
}) {
return _then(_$IntroSkipModelImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String,
valid: null == valid
? _value.valid
: valid // ignore: cast_nullable_to_non_nullable
as bool,
start: null == start
? _value.start
: start // ignore: cast_nullable_to_non_nullable
as Duration,
end: null == end
? _value.end
: end // ignore: cast_nullable_to_non_nullable
as Duration,
showTime: null == showTime
? _value.showTime
: showTime // ignore: cast_nullable_to_non_nullable
as Duration,
hideTime: null == hideTime
? _value.hideTime
: hideTime // ignore: cast_nullable_to_non_nullable
as Duration,
));
}
}
/// @nodoc
@JsonSerializable()
class _$IntroSkipModelImpl implements _IntroSkipModel {
_$IntroSkipModelImpl(
{@JsonKey(name: "EpisodeId") required this.id,
@JsonKey(name: "Valid") required this.valid,
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required this.start,
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required this.end,
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required this.showTime,
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required this.hideTime});
factory _$IntroSkipModelImpl.fromJson(Map<String, dynamic> json) =>
_$$IntroSkipModelImplFromJson(json);
@override
@JsonKey(name: "EpisodeId")
final String id;
@override
@JsonKey(name: "Valid")
final bool valid;
@override
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
final Duration start;
@override
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
final Duration end;
@override
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
final Duration showTime;
@override
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
final Duration hideTime;
@override
String toString() {
return 'IntroSkipModel(id: $id, valid: $valid, start: $start, end: $end, showTime: $showTime, hideTime: $hideTime)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$IntroSkipModelImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.valid, valid) || other.valid == valid) &&
(identical(other.start, start) || other.start == start) &&
(identical(other.end, end) || other.end == end) &&
(identical(other.showTime, showTime) ||
other.showTime == showTime) &&
(identical(other.hideTime, hideTime) ||
other.hideTime == hideTime));
}
@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, id, valid, start, end, showTime, hideTime);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$IntroSkipModelImplCopyWith<_$IntroSkipModelImpl> get copyWith =>
__$$IntroSkipModelImplCopyWithImpl<_$IntroSkipModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$IntroSkipModelImplToJson(
this,
);
}
}
abstract class _IntroSkipModel implements IntroSkipModel {
factory _IntroSkipModel(
{@JsonKey(name: "EpisodeId") required final String id,
@JsonKey(name: "Valid") required final bool valid,
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required final Duration start,
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required final Duration end,
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required final Duration showTime,
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
required final Duration hideTime}) = _$IntroSkipModelImpl;
factory _IntroSkipModel.fromJson(Map<String, dynamic> json) =
_$IntroSkipModelImpl.fromJson;
@override
@JsonKey(name: "EpisodeId")
String get id;
@override
@JsonKey(name: "Valid")
bool get valid;
@override
@JsonKey(
name: "IntroStart",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get start;
@override
@JsonKey(
name: "IntroEnd",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get end;
@override
@JsonKey(
name: "ShowSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get showTime;
@override
@JsonKey(
name: "HideSkipPromptAt",
fromJson: _durationFromMilliseconds,
toJson: _durationToMilliseconds)
Duration get hideTime;
@override
@JsonKey(ignore: true)
_$$IntroSkipModelImplCopyWith<_$IntroSkipModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View file

@ -0,0 +1,46 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'intro_skip_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$IntroOutSkipModelImpl _$$IntroOutSkipModelImplFromJson(
Map<String, dynamic> json) =>
_$IntroOutSkipModelImpl(
intro: json['intro'] == null
? null
: IntroSkipModel.fromJson(json['intro'] as Map<String, dynamic>),
credits: json['credits'] == null
? null
: IntroSkipModel.fromJson(json['credits'] as Map<String, dynamic>),
);
Map<String, dynamic> _$$IntroOutSkipModelImplToJson(
_$IntroOutSkipModelImpl instance) =>
<String, dynamic>{
'intro': instance.intro,
'credits': instance.credits,
};
_$IntroSkipModelImpl _$$IntroSkipModelImplFromJson(Map<String, dynamic> json) =>
_$IntroSkipModelImpl(
id: json['EpisodeId'] as String,
valid: json['Valid'] as bool,
start: _durationFromMilliseconds(json['IntroStart'] as num),
end: _durationFromMilliseconds(json['IntroEnd'] as num),
showTime: _durationFromMilliseconds(json['ShowSkipPromptAt'] as num),
hideTime: _durationFromMilliseconds(json['HideSkipPromptAt'] as num),
);
Map<String, dynamic> _$$IntroSkipModelImplToJson(
_$IntroSkipModelImpl instance) =>
<String, dynamic>{
'EpisodeId': instance.id,
'Valid': instance.valid,
'IntroStart': _durationToMilliseconds(instance.start),
'IntroEnd': _durationToMilliseconds(instance.end),
'ShowSkipPromptAt': _durationToMilliseconds(instance.showTime),
'HideSkipPromptAt': _durationToMilliseconds(instance.hideTime),
};

View file

@ -0,0 +1,21 @@
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:freezed_annotation/freezed_annotation.dart';
part 'item_properties_model.freezed.dart';
@Freezed(fromJson: false, toJson: false)
class ItemPropertiesModel with _$ItemPropertiesModel {
const ItemPropertiesModel._();
factory ItemPropertiesModel._internal({
required bool canDelete,
required bool canDownload,
}) = _ItemPropertiesModel;
factory ItemPropertiesModel.fromBaseDto(dto.BaseItemDto dtoItem) {
return ItemPropertiesModel._internal(
canDelete: dtoItem.canDelete ?? false,
canDownload: dtoItem.canDownload ?? false,
);
}
}

View file

@ -0,0 +1,156 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'item_properties_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$ItemPropertiesModel {
bool get canDelete => throw _privateConstructorUsedError;
bool get canDownload => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ItemPropertiesModelCopyWith<ItemPropertiesModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ItemPropertiesModelCopyWith<$Res> {
factory $ItemPropertiesModelCopyWith(
ItemPropertiesModel value, $Res Function(ItemPropertiesModel) then) =
_$ItemPropertiesModelCopyWithImpl<$Res, ItemPropertiesModel>;
@useResult
$Res call({bool canDelete, bool canDownload});
}
/// @nodoc
class _$ItemPropertiesModelCopyWithImpl<$Res, $Val extends ItemPropertiesModel>
implements $ItemPropertiesModelCopyWith<$Res> {
_$ItemPropertiesModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? canDelete = null,
Object? canDownload = null,
}) {
return _then(_value.copyWith(
canDelete: null == canDelete
? _value.canDelete
: canDelete // ignore: cast_nullable_to_non_nullable
as bool,
canDownload: null == canDownload
? _value.canDownload
: canDownload // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val);
}
}
/// @nodoc
abstract class _$$ItemPropertiesModelImplCopyWith<$Res>
implements $ItemPropertiesModelCopyWith<$Res> {
factory _$$ItemPropertiesModelImplCopyWith(_$ItemPropertiesModelImpl value,
$Res Function(_$ItemPropertiesModelImpl) then) =
__$$ItemPropertiesModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({bool canDelete, bool canDownload});
}
/// @nodoc
class __$$ItemPropertiesModelImplCopyWithImpl<$Res>
extends _$ItemPropertiesModelCopyWithImpl<$Res, _$ItemPropertiesModelImpl>
implements _$$ItemPropertiesModelImplCopyWith<$Res> {
__$$ItemPropertiesModelImplCopyWithImpl(_$ItemPropertiesModelImpl _value,
$Res Function(_$ItemPropertiesModelImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? canDelete = null,
Object? canDownload = null,
}) {
return _then(_$ItemPropertiesModelImpl(
canDelete: null == canDelete
? _value.canDelete
: canDelete // ignore: cast_nullable_to_non_nullable
as bool,
canDownload: null == canDownload
? _value.canDownload
: canDownload // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// @nodoc
class _$ItemPropertiesModelImpl extends _ItemPropertiesModel {
_$ItemPropertiesModelImpl(
{required this.canDelete, required this.canDownload})
: super._();
@override
final bool canDelete;
@override
final bool canDownload;
@override
String toString() {
return 'ItemPropertiesModel._internal(canDelete: $canDelete, canDownload: $canDownload)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ItemPropertiesModelImpl &&
(identical(other.canDelete, canDelete) ||
other.canDelete == canDelete) &&
(identical(other.canDownload, canDownload) ||
other.canDownload == canDownload));
}
@override
int get hashCode => Object.hash(runtimeType, canDelete, canDownload);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ItemPropertiesModelImplCopyWith<_$ItemPropertiesModelImpl> get copyWith =>
__$$ItemPropertiesModelImplCopyWithImpl<_$ItemPropertiesModelImpl>(
this, _$identity);
}
abstract class _ItemPropertiesModel extends ItemPropertiesModel {
factory _ItemPropertiesModel(
{required final bool canDelete,
required final bool canDownload}) = _$ItemPropertiesModelImpl;
_ItemPropertiesModel._() : super._();
@override
bool get canDelete;
@override
bool get canDownload;
@override
@JsonKey(ignore: true)
_$$ItemPropertiesModelImplCopyWith<_$ItemPropertiesModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View file

@ -0,0 +1,380 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/models/items/images_models.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:json_annotation/json_annotation.dart';
part 'item_shared_models.mapper.dart';
@MappableClass()
class UserData with UserDataMappable {
final bool isFavourite;
final int playCount;
final int? unPlayedItemCount;
final int playbackPositionTicks;
final double progress;
final bool played;
final DateTime? lastPlayed;
const UserData({
this.isFavourite = false,
this.playCount = 0,
this.unPlayedItemCount,
this.playbackPositionTicks = 0,
this.progress = 0,
this.lastPlayed,
this.played = false,
});
factory UserData.fromDto(dto.UserItemDataDto? dto) {
if (dto == null) {
return UserData();
}
return UserData(
isFavourite: dto.isFavorite ?? false,
playCount: dto.playCount ?? 0,
playbackPositionTicks: dto.playbackPositionTicks ?? 0,
played: dto.played ?? false,
unPlayedItemCount: dto.unplayedItemCount ?? 0,
lastPlayed: dto.lastPlayedDate,
progress: dto.playedPercentage ?? 0,
);
}
Duration get playBackPosition => Duration(milliseconds: playbackPositionTicks ~/ 10000);
factory UserData.fromMap(Map<String, dynamic> map) => UserDataMapper.fromMap(map);
factory UserData.fromJson(String json) => UserDataMapper.fromJson(json);
}
class UserDataJsonSerializer extends JsonConverter<UserData, String> {
const UserDataJsonSerializer();
@override
UserData fromJson(String json) {
return UserData.fromJson(json);
}
@override
String toJson(UserData object) {
return object.toJson();
}
}
enum EditorLockedFields {
name("Name"),
overView("Overview"),
genres("Genres"),
officialRating("OfficialRating"),
cast("Cast"),
productionLocations("ProductionLocations"),
runTime("Runtime"),
studios("Studios"),
tags("Tags"),
;
const EditorLockedFields(this.value);
static Map<EditorLockedFields, bool> enabled(List<String> fromStrings) => Map.fromEntries(
EditorLockedFields.values.map(
(e) => MapEntry(e, fromStrings.contains(e.value)),
),
);
final String value;
}
enum DisplayOrder {
empty(""),
aired("aired"),
originalAirDate("originalAirDate"),
absolute("absolute"),
dvd("dvd"),
digital("digital"),
storyArc("storyArc"),
production("production"),
tv("tv"),
;
const DisplayOrder(this.value);
static DisplayOrder? fromMap(String? value) {
return DisplayOrder.values.firstWhereOrNull((element) => element.value == value) ?? DisplayOrder.empty;
}
final String value;
}
enum ShowStatus {
empty(""),
ended("Ended"),
continuing("Continuing");
const ShowStatus(this.value);
static ShowStatus? fromMap(String? value) {
return ShowStatus.values.firstWhereOrNull((element) => element.value == value) ?? ShowStatus.empty;
}
final String value;
}
class ExternalUrls {
final String name;
final String url;
ExternalUrls({
required this.name,
required this.url,
});
static List<ExternalUrls> fromDto(List<dto.ExternalUrl> dto) {
return dto.map((e) => ExternalUrls(name: e.name ?? "", url: e.url ?? "")).toList();
}
Map<String, dynamic> toMap() {
return {
'Name': name,
'Url': url,
};
}
factory ExternalUrls.fromMap(Map<String, dynamic> map) {
return ExternalUrls(
name: map['Name'] ?? '',
url: map['Url'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory ExternalUrls.fromJson(String source) => ExternalUrls.fromMap(json.decode(source));
}
class GenreItems {
final String id;
final String name;
GenreItems({
required this.id,
required this.name,
});
@override
String toString() => 'GenreItems(id: $id, name: $name)';
}
class Person {
final String id;
final String name;
final ImageData? image;
final String role;
final PersonKind? type;
Person({
required this.id,
this.name = "",
this.image,
this.role = "",
this.type,
});
static Person fromBaseDto(dto.BaseItemDto item, Ref ref) {
return Person(
id: item.id ?? "",
name: item.name ?? "",
image: ImagesData.fromBaseItem(item, ref).primary,
);
}
static Person fromBasePerson(dto.BaseItemPerson person, Ref ref) {
return Person(
id: person.id ?? "",
name: person.name ?? "",
image: ImagesData.fromPersonDto(person, ref)?.primary,
role: person.role ?? "",
type: person.type);
}
dto.BaseItemPerson toPerson() {
return dto.BaseItemPerson(
id: id,
name: name,
type: type,
role: role,
);
}
static List<Person> peopleFromDto(List<dto.BaseItemPerson>? people, Ref ref) {
return people
?.mapIndexed(
(index, person) => fromBasePerson(person, ref),
)
.toList() ??
[];
}
@override
String toString() {
return 'People(id: $id, name: $name, imageUrl: $image, role: $role, type: $type)';
}
}
class Studio {
final String id;
final String name;
Studio({
required this.id,
required this.name,
});
Studio copyWith({
String? id,
String? name,
ValueGetter<String?>? image,
}) {
return Studio(
id: id ?? this.id,
name: name ?? this.name,
);
}
@override
String toString() => 'Studio(name: $name, id: $id)';
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
};
}
factory Studio.fromMap(Map<String, dynamic> map) {
return Studio(
id: map['id'] ?? map['Id'] ?? '',
name: map['name'] ?? map['Name'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory Studio.fromJson(String source) => Studio.fromMap(json.decode(source));
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Studio && other.id == id && other.name == name;
}
@override
int get hashCode => id.hashCode ^ name.hashCode;
}
// class UserData {
// final bool isFavourite;
// final int playCount;
// final int? unPlayedItemCount;
// final int playbackPositionTicks;
// final double progress;
// final bool played;
// UserData({
// this.isFavourite = false,
// this.playCount = 0,
// this.unPlayedItemCount,
// this.playbackPositionTicks = 0,
// this.progress = 0,
// this.played = false,
// });
// factory UserData.fromDto(dto.UserItemDataDto? dto) {
// if (dto == null) {
// return UserData();
// }
// return UserData(
// isFavourite: dto.isFavorite ?? false,
// playCount: dto.playCount ?? 0,
// playbackPositionTicks: dto.playbackPositionTicks ?? 0,
// played: dto.played ?? false,
// unPlayedItemCount: dto.unplayedItemCount ?? 0,
// progress: dto.playedPercentage ?? 0,
// );
// }
// Duration get playBackPosition => Duration(milliseconds: playbackPositionTicks ~/ 10000);
// @override
// String toString() {
// return 'UserData(isFavourite: $isFavourite, playCount: $playCount, unPlayedItemCount: $unPlayedItemCount, playbackPositionTicks: $playbackPositionTicks, progress: $progress, played: $played)';
// }
// UserData copyWith({
// bool? isFavourite,
// int? playCount,
// int? unPlayedItemCount,
// int? playbackPositionTicks,
// double? progress,
// bool? played,
// }) {
// return UserData(
// isFavourite: isFavourite ?? this.isFavourite,
// playCount: playCount ?? this.playCount,
// unPlayedItemCount: unPlayedItemCount ?? this.unPlayedItemCount,
// playbackPositionTicks: playbackPositionTicks ?? this.playbackPositionTicks,
// progress: progress ?? this.progress,
// played: played ?? this.played,
// );
// }
// Map<String, dynamic> toMap() {
// return <String, dynamic>{
// 'isFavourite': isFavourite,
// 'playCount': playCount,
// 'unPlayedItemCount': unPlayedItemCount,
// 'playbackPositionTicks': playbackPositionTicks,
// 'progress': progress,
// 'played': played,
// };
// }
// factory UserData.fromMap(Map<String, dynamic> map) {
// return UserData(
// isFavourite: (map['isFavourite'] ?? false) as bool,
// playCount: (map['playCount'] ?? 0) as int,
// unPlayedItemCount: (map['unPlayedItemCount'] ?? 0) as int,
// playbackPositionTicks: (map['playbackPositionTicks'] ?? 0) as int,
// progress: (map['progress'] ?? 0.0) as double,
// played: (map['played'] ?? false) as bool,
// );
// }
// String toJson() => json.encode(toMap());
// factory UserData.fromJson(String source) => UserData.fromMap(json.decode(source) as Map<String, dynamic>);
// @override
// bool operator ==(covariant UserData other) {
// if (identical(this, other)) return true;
// return other.isFavourite == isFavourite &&
// other.playCount == playCount &&
// other.unPlayedItemCount == unPlayedItemCount &&
// other.playbackPositionTicks == playbackPositionTicks &&
// other.progress == progress &&
// other.played == played;
// }
// @override
// int get hashCode {
// return isFavourite.hashCode ^
// playCount.hashCode ^
// unPlayedItemCount.hashCode ^
// playbackPositionTicks.hashCode ^
// progress.hashCode ^
// played.hashCode;
// }
// }

View file

@ -0,0 +1,162 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'item_shared_models.dart';
class UserDataMapper extends ClassMapperBase<UserData> {
UserDataMapper._();
static UserDataMapper? _instance;
static UserDataMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = UserDataMapper._());
}
return _instance!;
}
@override
final String id = 'UserData';
static bool _$isFavourite(UserData v) => v.isFavourite;
static const Field<UserData, bool> _f$isFavourite =
Field('isFavourite', _$isFavourite, opt: true, def: false);
static int _$playCount(UserData v) => v.playCount;
static const Field<UserData, int> _f$playCount =
Field('playCount', _$playCount, opt: true, def: 0);
static int? _$unPlayedItemCount(UserData v) => v.unPlayedItemCount;
static const Field<UserData, int> _f$unPlayedItemCount =
Field('unPlayedItemCount', _$unPlayedItemCount, opt: true);
static int _$playbackPositionTicks(UserData v) => v.playbackPositionTicks;
static const Field<UserData, int> _f$playbackPositionTicks = Field(
'playbackPositionTicks', _$playbackPositionTicks,
opt: true, def: 0);
static double _$progress(UserData v) => v.progress;
static const Field<UserData, double> _f$progress =
Field('progress', _$progress, opt: true, def: 0);
static DateTime? _$lastPlayed(UserData v) => v.lastPlayed;
static const Field<UserData, DateTime> _f$lastPlayed =
Field('lastPlayed', _$lastPlayed, opt: true);
static bool _$played(UserData v) => v.played;
static const Field<UserData, bool> _f$played =
Field('played', _$played, opt: true, def: false);
@override
final MappableFields<UserData> fields = const {
#isFavourite: _f$isFavourite,
#playCount: _f$playCount,
#unPlayedItemCount: _f$unPlayedItemCount,
#playbackPositionTicks: _f$playbackPositionTicks,
#progress: _f$progress,
#lastPlayed: _f$lastPlayed,
#played: _f$played,
};
@override
final bool ignoreNull = true;
static UserData _instantiate(DecodingData data) {
return UserData(
isFavourite: data.dec(_f$isFavourite),
playCount: data.dec(_f$playCount),
unPlayedItemCount: data.dec(_f$unPlayedItemCount),
playbackPositionTicks: data.dec(_f$playbackPositionTicks),
progress: data.dec(_f$progress),
lastPlayed: data.dec(_f$lastPlayed),
played: data.dec(_f$played));
}
@override
final Function instantiate = _instantiate;
static UserData fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<UserData>(map);
}
static UserData fromJson(String json) {
return ensureInitialized().decodeJson<UserData>(json);
}
}
mixin UserDataMappable {
String toJson() {
return UserDataMapper.ensureInitialized()
.encodeJson<UserData>(this as UserData);
}
Map<String, dynamic> toMap() {
return UserDataMapper.ensureInitialized()
.encodeMap<UserData>(this as UserData);
}
UserDataCopyWith<UserData, UserData, UserData> get copyWith =>
_UserDataCopyWithImpl(this as UserData, $identity, $identity);
@override
String toString() {
return UserDataMapper.ensureInitialized().stringifyValue(this as UserData);
}
}
extension UserDataValueCopy<$R, $Out> on ObjectCopyWith<$R, UserData, $Out> {
UserDataCopyWith<$R, UserData, $Out> get $asUserData =>
$base.as((v, t, t2) => _UserDataCopyWithImpl(v, t, t2));
}
abstract class UserDataCopyWith<$R, $In extends UserData, $Out>
implements ClassCopyWith<$R, $In, $Out> {
$R call(
{bool? isFavourite,
int? playCount,
int? unPlayedItemCount,
int? playbackPositionTicks,
double? progress,
DateTime? lastPlayed,
bool? played});
UserDataCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _UserDataCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, UserData, $Out>
implements UserDataCopyWith<$R, UserData, $Out> {
_UserDataCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<UserData> $mapper =
UserDataMapper.ensureInitialized();
@override
$R call(
{bool? isFavourite,
int? playCount,
Object? unPlayedItemCount = $none,
int? playbackPositionTicks,
double? progress,
Object? lastPlayed = $none,
bool? played}) =>
$apply(FieldCopyWithData({
if (isFavourite != null) #isFavourite: isFavourite,
if (playCount != null) #playCount: playCount,
if (unPlayedItemCount != $none) #unPlayedItemCount: unPlayedItemCount,
if (playbackPositionTicks != null)
#playbackPositionTicks: playbackPositionTicks,
if (progress != null) #progress: progress,
if (lastPlayed != $none) #lastPlayed: lastPlayed,
if (played != null) #played: played
}));
@override
UserData $make(CopyWithData data) => UserData(
isFavourite: data.get(#isFavourite, or: $value.isFavourite),
playCount: data.get(#playCount, or: $value.playCount),
unPlayedItemCount:
data.get(#unPlayedItemCount, or: $value.unPlayedItemCount),
playbackPositionTicks:
data.get(#playbackPositionTicks, or: $value.playbackPositionTicks),
progress: data.get(#progress, or: $value.progress),
lastPlayed: data.get(#lastPlayed, or: $value.lastPlayed),
played: data.get(#played, or: $value.played));
@override
UserDataCopyWith<$R2, UserData, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_UserDataCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,67 @@
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/episode_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/media_streams_model.dart';
import 'package:fladder/models/items/movie_model.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'item_stream_model.mapper.dart';
@MappableClass()
class ItemStreamModel extends ItemBaseModel with ItemStreamModelMappable {
final ImagesData? parentImages;
final MediaStreamsModel mediaStreams;
const ItemStreamModel({
required this.parentImages,
required this.mediaStreams,
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
required super.canDelete,
required super.canDownload,
super.jellyType,
});
factory ItemStreamModel.fromBaseDto(dto.BaseItemDto item, Ref ref) {
return switch (item.type) {
BaseItemKind.episode => EpisodeModel.fromBaseDto(item, ref),
BaseItemKind.movie => MovieModel.fromBaseDto(item, ref),
_ => ItemStreamModel._fromBaseDto(item, ref)
};
}
factory ItemStreamModel._fromBaseDto(dto.BaseItemDto item, Ref ref) {
return ItemStreamModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
images: ImagesData.fromBaseItem(item, ref),
primaryRatio: item.primaryImageAspectRatio,
parentImages: ImagesData.fromBaseItemParent(item, ref),
canDelete: item.canDelete,
canDownload: item.canDownload,
mediaStreams:
MediaStreamsModel.fromMediaStreamsList(item.mediaSources?.firstOrNull, item.mediaStreams ?? [], ref),
);
}
String? get videoPropertiesLabel {
if (mediaStreams.displayProfile == null && mediaStreams.resolution == null) return null;
return "${mediaStreams.displayProfile?.value}";
}
}

View file

@ -0,0 +1,245 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'item_stream_model.dart';
class ItemStreamModelMapper extends SubClassMapperBase<ItemStreamModel> {
ItemStreamModelMapper._();
static ItemStreamModelMapper? _instance;
static ItemStreamModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = ItemStreamModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'ItemStreamModel';
static ImagesData? _$parentImages(ItemStreamModel v) => v.parentImages;
static const Field<ItemStreamModel, ImagesData> _f$parentImages =
Field('parentImages', _$parentImages);
static MediaStreamsModel _$mediaStreams(ItemStreamModel v) => v.mediaStreams;
static const Field<ItemStreamModel, MediaStreamsModel> _f$mediaStreams =
Field('mediaStreams', _$mediaStreams);
static String _$name(ItemStreamModel v) => v.name;
static const Field<ItemStreamModel, String> _f$name = Field('name', _$name);
static String _$id(ItemStreamModel v) => v.id;
static const Field<ItemStreamModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(ItemStreamModel v) => v.overview;
static const Field<ItemStreamModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(ItemStreamModel v) => v.parentId;
static const Field<ItemStreamModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(ItemStreamModel v) => v.playlistId;
static const Field<ItemStreamModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(ItemStreamModel v) => v.images;
static const Field<ItemStreamModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(ItemStreamModel v) => v.childCount;
static const Field<ItemStreamModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(ItemStreamModel v) => v.primaryRatio;
static const Field<ItemStreamModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(ItemStreamModel v) => v.userData;
static const Field<ItemStreamModel, UserData> _f$userData =
Field('userData', _$userData);
static bool? _$canDelete(ItemStreamModel v) => v.canDelete;
static const Field<ItemStreamModel, bool> _f$canDelete =
Field('canDelete', _$canDelete);
static bool? _$canDownload(ItemStreamModel v) => v.canDownload;
static const Field<ItemStreamModel, bool> _f$canDownload =
Field('canDownload', _$canDownload);
static dto.BaseItemKind? _$jellyType(ItemStreamModel v) => v.jellyType;
static const Field<ItemStreamModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<ItemStreamModel> fields = const {
#parentImages: _f$parentImages,
#mediaStreams: _f$mediaStreams,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#canDelete: _f$canDelete,
#canDownload: _f$canDownload,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'ItemStreamModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static ItemStreamModel _instantiate(DecodingData data) {
return ItemStreamModel(
parentImages: data.dec(_f$parentImages),
mediaStreams: data.dec(_f$mediaStreams),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
canDelete: data.dec(_f$canDelete),
canDownload: data.dec(_f$canDownload),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static ItemStreamModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<ItemStreamModel>(map);
}
static ItemStreamModel fromJson(String json) {
return ensureInitialized().decodeJson<ItemStreamModel>(json);
}
}
mixin ItemStreamModelMappable {
String toJson() {
return ItemStreamModelMapper.ensureInitialized()
.encodeJson<ItemStreamModel>(this as ItemStreamModel);
}
Map<String, dynamic> toMap() {
return ItemStreamModelMapper.ensureInitialized()
.encodeMap<ItemStreamModel>(this as ItemStreamModel);
}
ItemStreamModelCopyWith<ItemStreamModel, ItemStreamModel, ItemStreamModel>
get copyWith => _ItemStreamModelCopyWithImpl(
this as ItemStreamModel, $identity, $identity);
@override
String toString() {
return ItemStreamModelMapper.ensureInitialized()
.stringifyValue(this as ItemStreamModel);
}
}
extension ItemStreamModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, ItemStreamModel, $Out> {
ItemStreamModelCopyWith<$R, ItemStreamModel, $Out> get $asItemStreamModel =>
$base.as((v, t, t2) => _ItemStreamModelCopyWithImpl(v, t, t2));
}
abstract class ItemStreamModelCopyWith<$R, $In extends ItemStreamModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{ImagesData? parentImages,
MediaStreamsModel? mediaStreams,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
bool? canDelete,
bool? canDownload,
dto.BaseItemKind? jellyType});
ItemStreamModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _ItemStreamModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, ItemStreamModel, $Out>
implements ItemStreamModelCopyWith<$R, ItemStreamModel, $Out> {
_ItemStreamModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<ItemStreamModel> $mapper =
ItemStreamModelMapper.ensureInitialized();
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{Object? parentImages = $none,
MediaStreamsModel? mediaStreams,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? canDelete = $none,
Object? canDownload = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (parentImages != $none) #parentImages: parentImages,
if (mediaStreams != null) #mediaStreams: mediaStreams,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (canDelete != $none) #canDelete: canDelete,
if (canDownload != $none) #canDownload: canDownload,
if (jellyType != $none) #jellyType: jellyType
}));
@override
ItemStreamModel $make(CopyWithData data) => ItemStreamModel(
parentImages: data.get(#parentImages, or: $value.parentImages),
mediaStreams: data.get(#mediaStreams, or: $value.mediaStreams),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
canDelete: data.get(#canDelete, or: $value.canDelete),
canDownload: data.get(#canDownload, or: $value.canDownload),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
ItemStreamModelCopyWith<$R2, ItemStreamModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_ItemStreamModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,372 @@
import 'dart:convert';
import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart';
import 'package:flutter/material.dart';
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:collection/collection.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/providers/user_provider.dart';
import 'package:fladder/util/video_properties.dart';
class MediaStreamsModel {
final int? defaultAudioStreamIndex;
final int? defaultSubStreamIndex;
final List<VideoStreamModel> videoStreams;
final List<AudioStreamModel> audioStreams;
final List<SubStreamModel> subStreams;
MediaStreamsModel({
this.defaultAudioStreamIndex,
this.defaultSubStreamIndex,
required this.videoStreams,
required this.audioStreams,
required this.subStreams,
});
bool get isNull {
return defaultAudioStreamIndex == null ||
defaultSubStreamIndex == null ||
audioStreams.isEmpty ||
subStreams.isEmpty;
}
bool get isNotEmpty {
return audioStreams.isNotEmpty && subStreams.isNotEmpty;
}
AudioStreamModel? get currentAudioStream {
if (defaultAudioStreamIndex == -1) {
return AudioStreamModel.no();
}
return audioStreams.firstWhereOrNull((element) => element.index == defaultAudioStreamIndex) ??
audioStreams.firstOrNull;
}
SubStreamModel? get currentSubStream {
if (defaultSubStreamIndex == -1) {
return SubStreamModel.no();
}
return subStreams.firstWhereOrNull((element) => element.index == defaultSubStreamIndex) ?? subStreams.firstOrNull;
}
DisplayProfile? get displayProfile {
return DisplayProfile.fromVideoStreams(videoStreams);
}
Resolution? get resolution {
return Resolution.fromVideoStream(videoStreams.firstOrNull);
}
String? get resolutionText {
final stream = videoStreams.firstOrNull;
if (stream == null) return null;
return "${stream.width}x${stream.height}";
}
Widget? audioIcon(
BuildContext context,
Function()? onTap,
) {
final audioStream = audioStreams.firstWhereOrNull((element) => element.isDefault) ?? audioStreams.firstOrNull;
if (audioStream == null) return null;
return DefaultVideoInformationBox(
onTap: onTap,
child: Text(
audioStream.title,
),
);
}
Widget subtitleIcon(
BuildContext context,
Function()? onTap,
) {
return DefaultVideoInformationBox(
onTap: onTap,
child: Icon(
subStreams.isNotEmpty ? Icons.subtitles_rounded : Icons.subtitles_off_outlined,
),
);
}
static MediaStreamsModel fromMediaStreamsList(
dto.MediaSourceInfo? mediaSource, List<dto.MediaStream> streams, Ref ref) {
return MediaStreamsModel(
defaultAudioStreamIndex: mediaSource?.defaultAudioStreamIndex,
defaultSubStreamIndex: mediaSource?.defaultSubtitleStreamIndex,
videoStreams: streams
.where((element) => element.type == dto.MediaStreamType.video)
.map(
(e) => VideoStreamModel.fromMediaStream(e),
)
.sortByExternal(),
audioStreams: streams
.where((element) => element.type == dto.MediaStreamType.audio)
.map(
(e) => AudioStreamModel.fromMediaStream(e),
)
.sortByExternal(),
subStreams: streams
.where((element) => element.type == dto.MediaStreamType.subtitle)
.map(
(sub) => SubStreamModel.fromMediaStream(sub, ref),
)
.sortByExternal(),
);
}
MediaStreamsModel copyWith({
int? defaultAudioStreamIndex,
int? defaultSubStreamIndex,
List<VideoStreamModel>? videoStreams,
List<AudioStreamModel>? audioStreams,
List<SubStreamModel>? subStreams,
}) {
return MediaStreamsModel(
defaultAudioStreamIndex: defaultAudioStreamIndex ?? this.defaultAudioStreamIndex,
defaultSubStreamIndex: defaultSubStreamIndex ?? this.defaultSubStreamIndex,
videoStreams: videoStreams ?? this.videoStreams,
audioStreams: audioStreams ?? this.audioStreams,
subStreams: subStreams ?? this.subStreams,
);
}
@override
String toString() {
return 'MediaStreamsModel(defaultAudioStreamIndex: $defaultAudioStreamIndex, defaultSubStreamIndex: $defaultSubStreamIndex, videoStreams: $videoStreams, audioStreams: $audioStreams, subStreams: $subStreams)';
}
}
class StreamModel {
final String name;
final String codec;
final bool isDefault;
final bool isExternal;
final int index;
StreamModel({
required this.name,
required this.codec,
required this.isDefault,
required this.isExternal,
required this.index,
});
}
class VideoStreamModel extends StreamModel {
final int width;
final int height;
final double frameRate;
final String? videoDoViTitle;
final VideoRangeType? videoRangeType;
VideoStreamModel({
required super.name,
required super.codec,
required super.isDefault,
required super.isExternal,
required super.index,
required this.videoDoViTitle,
required this.videoRangeType,
required this.width,
required this.height,
required this.frameRate,
});
factory VideoStreamModel.fromMediaStream(dto.MediaStream stream) {
return VideoStreamModel(
name: stream.title ?? "",
isDefault: stream.isDefault ?? false,
codec: stream.codec ?? "",
videoDoViTitle: stream.videoDoViTitle,
videoRangeType: stream.videoRangeType,
width: stream.width ?? 0,
height: stream.height ?? 0,
frameRate: stream.realFrameRate ?? 24,
isExternal: stream.isExternal ?? false,
index: stream.index ?? -1,
);
}
String get prettyName {
return "${Resolution.fromVideoStream(this)?.value} - ${DisplayProfile.fromVideoStream(this).value} - (${codec.toUpperCase()})";
}
@override
String toString() {
return 'VideoStreamModel(width: $width, height: $height, frameRate: $frameRate, videoDoViTitle: $videoDoViTitle, videoRangeType: $videoRangeType)';
}
}
//Instead of using sortBy(a.isExternal etc..) this one seems to be more consistent for some reason
extension SortByExternalExtension<T extends StreamModel> on Iterable<T> {
List<T> sortByExternal() {
return [...where((element) => !element.isExternal), ...where((element) => element.isExternal)];
}
}
class AudioStreamModel extends StreamModel {
final String displayTitle;
final String language;
final String channelLayout;
AudioStreamModel({
required this.displayTitle,
required super.name,
required super.codec,
required super.isDefault,
required super.isExternal,
required super.index,
required this.language,
required this.channelLayout,
});
factory AudioStreamModel.fromMediaStream(dto.MediaStream stream) {
return AudioStreamModel(
displayTitle: stream.displayTitle ?? "",
name: stream.title ?? "",
isDefault: stream.isDefault ?? false,
codec: stream.codec ?? "",
language: stream.language ?? "Unknown",
channelLayout: stream.channelLayout ?? "",
isExternal: stream.isExternal ?? false,
index: stream.index ?? -1,
);
}
String get title =>
[name, language, codec, channelLayout].whereNotNull().where((element) => element.isNotEmpty).join(' - ');
AudioStreamModel.no({
super.name = 'Off',
this.displayTitle = 'Off',
this.language = '',
super.codec = '',
this.channelLayout = '',
super.isDefault = false,
super.isExternal = false,
super.index = -1,
});
}
class SubStreamModel extends StreamModel {
String id;
String title;
String displayTitle;
String language;
String? url;
bool supportsExternalStream;
SubStreamModel({
required super.name,
required this.id,
required this.title,
required this.displayTitle,
required this.language,
this.url,
required super.codec,
required super.isDefault,
required super.isExternal,
required super.index,
this.supportsExternalStream = false,
});
SubStreamModel.no({
super.name = 'Off',
this.id = 'Off',
this.title = 'Off',
this.displayTitle = 'Off',
this.language = '',
this.url = '',
super.codec = '',
super.isDefault = false,
super.isExternal = false,
super.index = -1,
this.supportsExternalStream = false,
});
factory SubStreamModel.fromMediaStream(dto.MediaStream stream, Ref ref) {
return SubStreamModel(
name: stream.title ?? "",
title: stream.title ?? "",
displayTitle: stream.displayTitle ?? "",
language: stream.language ?? "Unknown",
isDefault: stream.isDefault ?? false,
codec: stream.codec ?? "",
id: stream.hashCode.toString(),
supportsExternalStream: stream.supportsExternalStream ?? false,
url: stream.deliveryUrl != null
? "${ref.read(userProvider)?.server ?? ""}${stream.deliveryUrl}}".replaceAll(".vtt", ".srt")
: null,
isExternal: stream.isExternal ?? false,
index: stream.index ?? -1,
);
}
SubStreamModel copyWith({
String? name,
String? id,
String? title,
String? displayTitle,
String? language,
ValueGetter<String?>? url,
String? codec,
bool? isDefault,
bool? isExternal,
int? index,
bool? supportsExternalStream,
}) {
return SubStreamModel(
name: name ?? this.name,
id: id ?? this.id,
title: title ?? this.title,
displayTitle: displayTitle ?? this.displayTitle,
language: language ?? this.language,
url: url != null ? url() : this.url,
supportsExternalStream: supportsExternalStream ?? this.supportsExternalStream,
codec: codec ?? this.codec,
isDefault: isDefault ?? this.isDefault,
isExternal: isExternal ?? this.isExternal,
index: index ?? this.index,
);
}
Map<String, dynamic> toMap() {
return {
'name': name,
'id': id,
'title': title,
'displayTitle': displayTitle,
'language': language,
'url': url,
'supportsExternalStream': supportsExternalStream,
'codec': codec,
'isExternal': isExternal,
'isDefault': isDefault,
'index': index,
};
}
factory SubStreamModel.fromMap(Map<String, dynamic> map) {
return SubStreamModel(
name: map['name'] ?? '',
id: map['id'] ?? '',
title: map['title'] ?? '',
displayTitle: map['displayTitle'] ?? '',
language: map['language'] ?? '',
url: map['url'],
supportsExternalStream: map['supportsExternalStream'] ?? false,
codec: map['codec'] ?? '',
isDefault: map['isDefault'] ?? false,
isExternal: map['isExternal'] ?? false,
index: map['index'] ?? -1,
);
}
String toJson() => json.encode(toMap());
factory SubStreamModel.fromJson(String source) => SubStreamModel.fromMap(json.decode(source));
@override
String toString() {
return 'SubFile(title: $title, displayTitle: $displayTitle, language: $language, url: $url, isExternal: $isExternal)';
}
}

View file

@ -0,0 +1,107 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:fladder/util/humanize_duration.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/chapters_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/item_stream_model.dart';
import 'package:fladder/models/items/media_streams_model.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:fladder/screens/details_screens/movie_detail_screen.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'movie_model.mapper.dart';
@MappableClass()
class MovieModel extends ItemStreamModel with MovieModelMappable {
final String originalTitle;
final String? path;
final DateTime premiereDate;
final String sortName;
final String status;
final List<ItemBaseModel> related;
final List<Chapter> chapters;
const MovieModel({
required this.originalTitle,
this.path,
this.chapters = const [],
required this.premiereDate,
required this.sortName,
required this.status,
this.related = const [],
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
required super.parentImages,
required super.mediaStreams,
required super.canDownload,
required super.canDelete,
super.jellyType,
});
@override
String? detailedName(BuildContext context) => "$name${overview.yearAired != null ? " (${overview.yearAired})" : ""}";
@override
Widget get detailScreenWidget => MovieDetailScreen(item: this);
@override
ItemBaseModel get parentBaseModel => this;
@override
String? get subText => overview.yearAired?.toString() ?? overview.runTime.humanize;
@override
bool get playAble => true;
@override
bool get identifiable => true;
@override
String? label(BuildContext context) =>
overview.yearAired == null ? overview.runTime.humanize : "$name (${overview.yearAired})";
@override
ImageData? get bannerImage => images?.backDrop?.firstOrNull ?? images?.primary ?? getPosters?.primary;
@override
MediaStreamsModel? get streamModel => mediaStreams;
@override
bool get syncAble => true;
factory MovieModel.fromBaseDto(dto.BaseItemDto item, Ref ref) {
return MovieModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
sortName: item.sortName ?? "",
status: item.status ?? "",
originalTitle: item.originalTitle ?? "",
images: ImagesData.fromBaseItem(item, ref),
primaryRatio: item.primaryImageAspectRatio,
chapters: Chapter.chaptersFromInfo(item.id ?? "", item.chapters ?? [], ref),
premiereDate: item.premiereDate ?? DateTime.now(),
parentImages: ImagesData.fromBaseItemParent(item, ref),
canDelete: item.canDelete,
canDownload: item.canDownload,
mediaStreams:
MediaStreamsModel.fromMediaStreamsList(item.mediaSources?.firstOrNull, item.mediaStreams ?? [], ref),
);
}
}

View file

@ -0,0 +1,318 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'movie_model.dart';
class MovieModelMapper extends SubClassMapperBase<MovieModel> {
MovieModelMapper._();
static MovieModelMapper? _instance;
static MovieModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = MovieModelMapper._());
ItemStreamModelMapper.ensureInitialized().addSubMapper(_instance!);
ItemBaseModelMapper.ensureInitialized();
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'MovieModel';
static String _$originalTitle(MovieModel v) => v.originalTitle;
static const Field<MovieModel, String> _f$originalTitle =
Field('originalTitle', _$originalTitle);
static String? _$path(MovieModel v) => v.path;
static const Field<MovieModel, String> _f$path =
Field('path', _$path, opt: true);
static List<Chapter> _$chapters(MovieModel v) => v.chapters;
static const Field<MovieModel, List<Chapter>> _f$chapters =
Field('chapters', _$chapters, opt: true, def: const []);
static DateTime _$premiereDate(MovieModel v) => v.premiereDate;
static const Field<MovieModel, DateTime> _f$premiereDate =
Field('premiereDate', _$premiereDate);
static String _$sortName(MovieModel v) => v.sortName;
static const Field<MovieModel, String> _f$sortName =
Field('sortName', _$sortName);
static String _$status(MovieModel v) => v.status;
static const Field<MovieModel, String> _f$status = Field('status', _$status);
static List<ItemBaseModel> _$related(MovieModel v) => v.related;
static const Field<MovieModel, List<ItemBaseModel>> _f$related =
Field('related', _$related, opt: true, def: const []);
static String _$name(MovieModel v) => v.name;
static const Field<MovieModel, String> _f$name = Field('name', _$name);
static String _$id(MovieModel v) => v.id;
static const Field<MovieModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(MovieModel v) => v.overview;
static const Field<MovieModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(MovieModel v) => v.parentId;
static const Field<MovieModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(MovieModel v) => v.playlistId;
static const Field<MovieModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(MovieModel v) => v.images;
static const Field<MovieModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(MovieModel v) => v.childCount;
static const Field<MovieModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(MovieModel v) => v.primaryRatio;
static const Field<MovieModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(MovieModel v) => v.userData;
static const Field<MovieModel, UserData> _f$userData =
Field('userData', _$userData);
static ImagesData? _$parentImages(MovieModel v) => v.parentImages;
static const Field<MovieModel, ImagesData> _f$parentImages =
Field('parentImages', _$parentImages);
static MediaStreamsModel _$mediaStreams(MovieModel v) => v.mediaStreams;
static const Field<MovieModel, MediaStreamsModel> _f$mediaStreams =
Field('mediaStreams', _$mediaStreams);
static bool? _$canDownload(MovieModel v) => v.canDownload;
static const Field<MovieModel, bool> _f$canDownload =
Field('canDownload', _$canDownload);
static bool? _$canDelete(MovieModel v) => v.canDelete;
static const Field<MovieModel, bool> _f$canDelete =
Field('canDelete', _$canDelete);
static dto.BaseItemKind? _$jellyType(MovieModel v) => v.jellyType;
static const Field<MovieModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<MovieModel> fields = const {
#originalTitle: _f$originalTitle,
#path: _f$path,
#chapters: _f$chapters,
#premiereDate: _f$premiereDate,
#sortName: _f$sortName,
#status: _f$status,
#related: _f$related,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#parentImages: _f$parentImages,
#mediaStreams: _f$mediaStreams,
#canDownload: _f$canDownload,
#canDelete: _f$canDelete,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'MovieModel';
@override
late final ClassMapperBase superMapper =
ItemStreamModelMapper.ensureInitialized();
static MovieModel _instantiate(DecodingData data) {
return MovieModel(
originalTitle: data.dec(_f$originalTitle),
path: data.dec(_f$path),
chapters: data.dec(_f$chapters),
premiereDate: data.dec(_f$premiereDate),
sortName: data.dec(_f$sortName),
status: data.dec(_f$status),
related: data.dec(_f$related),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
parentImages: data.dec(_f$parentImages),
mediaStreams: data.dec(_f$mediaStreams),
canDownload: data.dec(_f$canDownload),
canDelete: data.dec(_f$canDelete),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static MovieModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<MovieModel>(map);
}
static MovieModel fromJson(String json) {
return ensureInitialized().decodeJson<MovieModel>(json);
}
}
mixin MovieModelMappable {
String toJson() {
return MovieModelMapper.ensureInitialized()
.encodeJson<MovieModel>(this as MovieModel);
}
Map<String, dynamic> toMap() {
return MovieModelMapper.ensureInitialized()
.encodeMap<MovieModel>(this as MovieModel);
}
MovieModelCopyWith<MovieModel, MovieModel, MovieModel> get copyWith =>
_MovieModelCopyWithImpl(this as MovieModel, $identity, $identity);
@override
String toString() {
return MovieModelMapper.ensureInitialized()
.stringifyValue(this as MovieModel);
}
}
extension MovieModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, MovieModel, $Out> {
MovieModelCopyWith<$R, MovieModel, $Out> get $asMovieModel =>
$base.as((v, t, t2) => _MovieModelCopyWithImpl(v, t, t2));
}
abstract class MovieModelCopyWith<$R, $In extends MovieModel, $Out>
implements ItemStreamModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>> get chapters;
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get related;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{String? originalTitle,
String? path,
List<Chapter>? chapters,
DateTime? premiereDate,
String? sortName,
String? status,
List<ItemBaseModel>? related,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
ImagesData? parentImages,
MediaStreamsModel? mediaStreams,
bool? canDownload,
bool? canDelete,
dto.BaseItemKind? jellyType});
MovieModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _MovieModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, MovieModel, $Out>
implements MovieModelCopyWith<$R, MovieModel, $Out> {
_MovieModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<MovieModel> $mapper =
MovieModelMapper.ensureInitialized();
@override
ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>>
get chapters => ListCopyWith($value.chapters,
(v, t) => ObjectCopyWith(v, $identity, t), (v) => call(chapters: v));
@override
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>>
get related => ListCopyWith($value.related,
(v, t) => v.copyWith.$chain(t), (v) => call(related: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{String? originalTitle,
Object? path = $none,
List<Chapter>? chapters,
DateTime? premiereDate,
String? sortName,
String? status,
List<ItemBaseModel>? related,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? parentImages = $none,
MediaStreamsModel? mediaStreams,
Object? canDownload = $none,
Object? canDelete = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (originalTitle != null) #originalTitle: originalTitle,
if (path != $none) #path: path,
if (chapters != null) #chapters: chapters,
if (premiereDate != null) #premiereDate: premiereDate,
if (sortName != null) #sortName: sortName,
if (status != null) #status: status,
if (related != null) #related: related,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (parentImages != $none) #parentImages: parentImages,
if (mediaStreams != null) #mediaStreams: mediaStreams,
if (canDownload != $none) #canDownload: canDownload,
if (canDelete != $none) #canDelete: canDelete,
if (jellyType != $none) #jellyType: jellyType
}));
@override
MovieModel $make(CopyWithData data) => MovieModel(
originalTitle: data.get(#originalTitle, or: $value.originalTitle),
path: data.get(#path, or: $value.path),
chapters: data.get(#chapters, or: $value.chapters),
premiereDate: data.get(#premiereDate, or: $value.premiereDate),
sortName: data.get(#sortName, or: $value.sortName),
status: data.get(#status, or: $value.status),
related: data.get(#related, or: $value.related),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
parentImages: data.get(#parentImages, or: $value.parentImages),
mediaStreams: data.get(#mediaStreams, or: $value.mediaStreams),
canDownload: data.get(#canDownload, or: $value.canDownload),
canDelete: data.get(#canDelete, or: $value.canDelete),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
MovieModelCopyWith<$R2, MovieModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_MovieModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,82 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
import 'package:fladder/models/items/chapters_model.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/trick_play_model.dart';
import 'package:fladder/util/duration_extensions.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'overview_model.mapper.dart';
@MappableClass()
class OverviewModel with OverviewModelMappable {
final Duration? runTime;
final String summary;
final int? yearAired;
final DateTime? dateAdded;
final String? parentalRating;
final int? productionYear;
final double? criticRating;
final double? communityRating;
final Map<String, TrickPlayModel>? trickPlayInfo;
final List<Chapter>? chapters;
final List<ExternalUrls>? externalUrls;
final List<Studio> studios;
final List<String> genres;
final List<GenreItems> genreItems;
final List<String> tags;
final List<Person> people;
const OverviewModel({
this.runTime,
this.summary = "",
this.yearAired,
this.dateAdded,
this.parentalRating,
this.productionYear,
this.criticRating,
this.communityRating,
this.trickPlayInfo,
this.chapters,
this.externalUrls,
this.studios = const [],
this.genres = const [],
this.genreItems = const [],
this.tags = const [],
this.people = const [],
});
List<Person> get directors {
return people.where((element) => element.type == PersonKind.director).toList();
}
List<Person> get writers {
return people.where((element) => element.type == PersonKind.writer).toList();
}
factory OverviewModel.fromBaseItemDto(BaseItemDto item, Ref ref) {
final trickPlayItem = item.trickplay;
return OverviewModel(
runTime: item.runTimeDuration,
yearAired: item.productionYear,
parentalRating: item.officialRating,
summary: item.overview ?? "",
genres: item.genres ?? [],
criticRating: item.criticRating,
communityRating: item.communityRating,
tags: item.tags ?? [],
dateAdded: item.dateCreated,
trickPlayInfo:
trickPlayItem != null && trickPlayItem.isNotEmpty ? TrickPlayModel.toTrickPlayMap(trickPlayItem) : null,
chapters: item.id != null ? Chapter.chaptersFromInfo(item.id ?? "", item.chapters ?? [], ref) : null,
studios: item.studios?.map((e) => Studio(id: e.id ?? "", name: e.name ?? "")).toList() ?? [],
genreItems: item.genreItems?.map((e) => GenreItems(id: e.id ?? "", name: e.name ?? "")).toList() ?? [],
externalUrls: ExternalUrls.fromDto(item.externalUrls ?? []),
people: Person.peopleFromDto(item.people ?? [], ref),
);
}
factory OverviewModel.fromMap(Map<String, dynamic> map) => OverviewModelMapper.fromMap(map);
factory OverviewModel.fromJson(String json) => OverviewModelMapper.fromJson(json);
}

View file

@ -0,0 +1,302 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'overview_model.dart';
class OverviewModelMapper extends ClassMapperBase<OverviewModel> {
OverviewModelMapper._();
static OverviewModelMapper? _instance;
static OverviewModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = OverviewModelMapper._());
}
return _instance!;
}
@override
final String id = 'OverviewModel';
static Duration? _$runTime(OverviewModel v) => v.runTime;
static const Field<OverviewModel, Duration> _f$runTime =
Field('runTime', _$runTime, opt: true);
static String _$summary(OverviewModel v) => v.summary;
static const Field<OverviewModel, String> _f$summary =
Field('summary', _$summary, opt: true, def: "");
static int? _$yearAired(OverviewModel v) => v.yearAired;
static const Field<OverviewModel, int> _f$yearAired =
Field('yearAired', _$yearAired, opt: true);
static DateTime? _$dateAdded(OverviewModel v) => v.dateAdded;
static const Field<OverviewModel, DateTime> _f$dateAdded =
Field('dateAdded', _$dateAdded, opt: true);
static String? _$parentalRating(OverviewModel v) => v.parentalRating;
static const Field<OverviewModel, String> _f$parentalRating =
Field('parentalRating', _$parentalRating, opt: true);
static int? _$productionYear(OverviewModel v) => v.productionYear;
static const Field<OverviewModel, int> _f$productionYear =
Field('productionYear', _$productionYear, opt: true);
static double? _$criticRating(OverviewModel v) => v.criticRating;
static const Field<OverviewModel, double> _f$criticRating =
Field('criticRating', _$criticRating, opt: true);
static double? _$communityRating(OverviewModel v) => v.communityRating;
static const Field<OverviewModel, double> _f$communityRating =
Field('communityRating', _$communityRating, opt: true);
static Map<String, TrickPlayModel>? _$trickPlayInfo(OverviewModel v) =>
v.trickPlayInfo;
static const Field<OverviewModel, Map<String, TrickPlayModel>>
_f$trickPlayInfo = Field('trickPlayInfo', _$trickPlayInfo, opt: true);
static List<Chapter>? _$chapters(OverviewModel v) => v.chapters;
static const Field<OverviewModel, List<Chapter>> _f$chapters =
Field('chapters', _$chapters, opt: true);
static List<ExternalUrls>? _$externalUrls(OverviewModel v) => v.externalUrls;
static const Field<OverviewModel, List<ExternalUrls>> _f$externalUrls =
Field('externalUrls', _$externalUrls, opt: true);
static List<Studio> _$studios(OverviewModel v) => v.studios;
static const Field<OverviewModel, List<Studio>> _f$studios =
Field('studios', _$studios, opt: true, def: const []);
static List<String> _$genres(OverviewModel v) => v.genres;
static const Field<OverviewModel, List<String>> _f$genres =
Field('genres', _$genres, opt: true, def: const []);
static List<GenreItems> _$genreItems(OverviewModel v) => v.genreItems;
static const Field<OverviewModel, List<GenreItems>> _f$genreItems =
Field('genreItems', _$genreItems, opt: true, def: const []);
static List<String> _$tags(OverviewModel v) => v.tags;
static const Field<OverviewModel, List<String>> _f$tags =
Field('tags', _$tags, opt: true, def: const []);
static List<Person> _$people(OverviewModel v) => v.people;
static const Field<OverviewModel, List<Person>> _f$people =
Field('people', _$people, opt: true, def: const []);
@override
final MappableFields<OverviewModel> fields = const {
#runTime: _f$runTime,
#summary: _f$summary,
#yearAired: _f$yearAired,
#dateAdded: _f$dateAdded,
#parentalRating: _f$parentalRating,
#productionYear: _f$productionYear,
#criticRating: _f$criticRating,
#communityRating: _f$communityRating,
#trickPlayInfo: _f$trickPlayInfo,
#chapters: _f$chapters,
#externalUrls: _f$externalUrls,
#studios: _f$studios,
#genres: _f$genres,
#genreItems: _f$genreItems,
#tags: _f$tags,
#people: _f$people,
};
@override
final bool ignoreNull = true;
static OverviewModel _instantiate(DecodingData data) {
return OverviewModel(
runTime: data.dec(_f$runTime),
summary: data.dec(_f$summary),
yearAired: data.dec(_f$yearAired),
dateAdded: data.dec(_f$dateAdded),
parentalRating: data.dec(_f$parentalRating),
productionYear: data.dec(_f$productionYear),
criticRating: data.dec(_f$criticRating),
communityRating: data.dec(_f$communityRating),
trickPlayInfo: data.dec(_f$trickPlayInfo),
chapters: data.dec(_f$chapters),
externalUrls: data.dec(_f$externalUrls),
studios: data.dec(_f$studios),
genres: data.dec(_f$genres),
genreItems: data.dec(_f$genreItems),
tags: data.dec(_f$tags),
people: data.dec(_f$people));
}
@override
final Function instantiate = _instantiate;
static OverviewModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<OverviewModel>(map);
}
static OverviewModel fromJson(String json) {
return ensureInitialized().decodeJson<OverviewModel>(json);
}
}
mixin OverviewModelMappable {
String toJson() {
return OverviewModelMapper.ensureInitialized()
.encodeJson<OverviewModel>(this as OverviewModel);
}
Map<String, dynamic> toMap() {
return OverviewModelMapper.ensureInitialized()
.encodeMap<OverviewModel>(this as OverviewModel);
}
OverviewModelCopyWith<OverviewModel, OverviewModel, OverviewModel>
get copyWith => _OverviewModelCopyWithImpl(
this as OverviewModel, $identity, $identity);
@override
String toString() {
return OverviewModelMapper.ensureInitialized()
.stringifyValue(this as OverviewModel);
}
}
extension OverviewModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, OverviewModel, $Out> {
OverviewModelCopyWith<$R, OverviewModel, $Out> get $asOverviewModel =>
$base.as((v, t, t2) => _OverviewModelCopyWithImpl(v, t, t2));
}
abstract class OverviewModelCopyWith<$R, $In extends OverviewModel, $Out>
implements ClassCopyWith<$R, $In, $Out> {
MapCopyWith<$R, String, TrickPlayModel,
ObjectCopyWith<$R, TrickPlayModel, TrickPlayModel>>? get trickPlayInfo;
ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>>? get chapters;
ListCopyWith<$R, ExternalUrls,
ObjectCopyWith<$R, ExternalUrls, ExternalUrls>>? get externalUrls;
ListCopyWith<$R, Studio, ObjectCopyWith<$R, Studio, Studio>> get studios;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get genres;
ListCopyWith<$R, GenreItems, ObjectCopyWith<$R, GenreItems, GenreItems>>
get genreItems;
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get tags;
ListCopyWith<$R, Person, ObjectCopyWith<$R, Person, Person>> get people;
$R call(
{Duration? runTime,
String? summary,
int? yearAired,
DateTime? dateAdded,
String? parentalRating,
int? productionYear,
double? criticRating,
double? communityRating,
Map<String, TrickPlayModel>? trickPlayInfo,
List<Chapter>? chapters,
List<ExternalUrls>? externalUrls,
List<Studio>? studios,
List<String>? genres,
List<GenreItems>? genreItems,
List<String>? tags,
List<Person>? people});
OverviewModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _OverviewModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, OverviewModel, $Out>
implements OverviewModelCopyWith<$R, OverviewModel, $Out> {
_OverviewModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<OverviewModel> $mapper =
OverviewModelMapper.ensureInitialized();
@override
MapCopyWith<$R, String, TrickPlayModel,
ObjectCopyWith<$R, TrickPlayModel, TrickPlayModel>>?
get trickPlayInfo => $value.trickPlayInfo != null
? MapCopyWith(
$value.trickPlayInfo!,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(trickPlayInfo: v))
: null;
@override
ListCopyWith<$R, Chapter, ObjectCopyWith<$R, Chapter, Chapter>>?
get chapters => $value.chapters != null
? ListCopyWith(
$value.chapters!,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(chapters: v))
: null;
@override
ListCopyWith<$R, ExternalUrls,
ObjectCopyWith<$R, ExternalUrls, ExternalUrls>>?
get externalUrls => $value.externalUrls != null
? ListCopyWith(
$value.externalUrls!,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(externalUrls: v))
: null;
@override
ListCopyWith<$R, Studio, ObjectCopyWith<$R, Studio, Studio>> get studios =>
ListCopyWith($value.studios, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(studios: v));
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get genres =>
ListCopyWith($value.genres, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(genres: v));
@override
ListCopyWith<$R, GenreItems, ObjectCopyWith<$R, GenreItems, GenreItems>>
get genreItems => ListCopyWith(
$value.genreItems,
(v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(genreItems: v));
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get tags =>
ListCopyWith($value.tags, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(tags: v));
@override
ListCopyWith<$R, Person, ObjectCopyWith<$R, Person, Person>> get people =>
ListCopyWith($value.people, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(people: v));
@override
$R call(
{Object? runTime = $none,
String? summary,
Object? yearAired = $none,
Object? dateAdded = $none,
Object? parentalRating = $none,
Object? productionYear = $none,
Object? criticRating = $none,
Object? communityRating = $none,
Object? trickPlayInfo = $none,
Object? chapters = $none,
Object? externalUrls = $none,
List<Studio>? studios,
List<String>? genres,
List<GenreItems>? genreItems,
List<String>? tags,
List<Person>? people}) =>
$apply(FieldCopyWithData({
if (runTime != $none) #runTime: runTime,
if (summary != null) #summary: summary,
if (yearAired != $none) #yearAired: yearAired,
if (dateAdded != $none) #dateAdded: dateAdded,
if (parentalRating != $none) #parentalRating: parentalRating,
if (productionYear != $none) #productionYear: productionYear,
if (criticRating != $none) #criticRating: criticRating,
if (communityRating != $none) #communityRating: communityRating,
if (trickPlayInfo != $none) #trickPlayInfo: trickPlayInfo,
if (chapters != $none) #chapters: chapters,
if (externalUrls != $none) #externalUrls: externalUrls,
if (studios != null) #studios: studios,
if (genres != null) #genres: genres,
if (genreItems != null) #genreItems: genreItems,
if (tags != null) #tags: tags,
if (people != null) #people: people
}));
@override
OverviewModel $make(CopyWithData data) => OverviewModel(
runTime: data.get(#runTime, or: $value.runTime),
summary: data.get(#summary, or: $value.summary),
yearAired: data.get(#yearAired, or: $value.yearAired),
dateAdded: data.get(#dateAdded, or: $value.dateAdded),
parentalRating: data.get(#parentalRating, or: $value.parentalRating),
productionYear: data.get(#productionYear, or: $value.productionYear),
criticRating: data.get(#criticRating, or: $value.criticRating),
communityRating: data.get(#communityRating, or: $value.communityRating),
trickPlayInfo: data.get(#trickPlayInfo, or: $value.trickPlayInfo),
chapters: data.get(#chapters, or: $value.chapters),
externalUrls: data.get(#externalUrls, or: $value.externalUrls),
studios: data.get(#studios, or: $value.studios),
genres: data.get(#genres, or: $value.genres),
genreItems: data.get(#genreItems, or: $value.genreItems),
tags: data.get(#tags, or: $value.tags),
people: data.get(#people, or: $value.people));
@override
OverviewModelCopyWith<$R2, OverviewModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_OverviewModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,68 @@
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/movie_model.dart';
import 'package:fladder/models/items/series_model.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'person_model.mapper.dart';
@MappableClass()
class PersonModel extends ItemBaseModel with PersonModelMappable {
final DateTime? dateOfBirth;
final List<String> birthPlace;
final List<MovieModel> movies;
final List<SeriesModel> series;
const PersonModel({
this.dateOfBirth,
required this.birthPlace,
required this.movies,
required this.series,
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
super.canDownload,
super.canDelete,
super.jellyType,
});
static PersonModel fromBaseDto(BaseItemDto item, Ref ref) {
return PersonModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true),
primaryRatio: item.primaryImageAspectRatio,
dateOfBirth: item.premiereDate,
birthPlace: item.productionLocations ?? [],
movies: [],
series: [],
);
}
int? get age {
if (dateOfBirth == null) return null;
final today = DateTime.now();
final months = today.month - dateOfBirth!.month;
if (months < 0) {
return (dateOfBirth!.year - (DateTime.now().year - 1)).abs();
} else {
return (dateOfBirth!.year - DateTime.now().year).abs();
}
}
}

View file

@ -0,0 +1,281 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'person_model.dart';
class PersonModelMapper extends SubClassMapperBase<PersonModel> {
PersonModelMapper._();
static PersonModelMapper? _instance;
static PersonModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = PersonModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
MovieModelMapper.ensureInitialized();
SeriesModelMapper.ensureInitialized();
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'PersonModel';
static DateTime? _$dateOfBirth(PersonModel v) => v.dateOfBirth;
static const Field<PersonModel, DateTime> _f$dateOfBirth =
Field('dateOfBirth', _$dateOfBirth, opt: true);
static List<String> _$birthPlace(PersonModel v) => v.birthPlace;
static const Field<PersonModel, List<String>> _f$birthPlace =
Field('birthPlace', _$birthPlace);
static List<MovieModel> _$movies(PersonModel v) => v.movies;
static const Field<PersonModel, List<MovieModel>> _f$movies =
Field('movies', _$movies);
static List<SeriesModel> _$series(PersonModel v) => v.series;
static const Field<PersonModel, List<SeriesModel>> _f$series =
Field('series', _$series);
static String _$name(PersonModel v) => v.name;
static const Field<PersonModel, String> _f$name = Field('name', _$name);
static String _$id(PersonModel v) => v.id;
static const Field<PersonModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(PersonModel v) => v.overview;
static const Field<PersonModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(PersonModel v) => v.parentId;
static const Field<PersonModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(PersonModel v) => v.playlistId;
static const Field<PersonModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(PersonModel v) => v.images;
static const Field<PersonModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(PersonModel v) => v.childCount;
static const Field<PersonModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(PersonModel v) => v.primaryRatio;
static const Field<PersonModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(PersonModel v) => v.userData;
static const Field<PersonModel, UserData> _f$userData =
Field('userData', _$userData);
static bool? _$canDownload(PersonModel v) => v.canDownload;
static const Field<PersonModel, bool> _f$canDownload =
Field('canDownload', _$canDownload, opt: true);
static bool? _$canDelete(PersonModel v) => v.canDelete;
static const Field<PersonModel, bool> _f$canDelete =
Field('canDelete', _$canDelete, opt: true);
static BaseItemKind? _$jellyType(PersonModel v) => v.jellyType;
static const Field<PersonModel, BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<PersonModel> fields = const {
#dateOfBirth: _f$dateOfBirth,
#birthPlace: _f$birthPlace,
#movies: _f$movies,
#series: _f$series,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#canDownload: _f$canDownload,
#canDelete: _f$canDelete,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'PersonModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static PersonModel _instantiate(DecodingData data) {
return PersonModel(
dateOfBirth: data.dec(_f$dateOfBirth),
birthPlace: data.dec(_f$birthPlace),
movies: data.dec(_f$movies),
series: data.dec(_f$series),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
canDownload: data.dec(_f$canDownload),
canDelete: data.dec(_f$canDelete),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static PersonModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<PersonModel>(map);
}
static PersonModel fromJson(String json) {
return ensureInitialized().decodeJson<PersonModel>(json);
}
}
mixin PersonModelMappable {
String toJson() {
return PersonModelMapper.ensureInitialized()
.encodeJson<PersonModel>(this as PersonModel);
}
Map<String, dynamic> toMap() {
return PersonModelMapper.ensureInitialized()
.encodeMap<PersonModel>(this as PersonModel);
}
PersonModelCopyWith<PersonModel, PersonModel, PersonModel> get copyWith =>
_PersonModelCopyWithImpl(this as PersonModel, $identity, $identity);
@override
String toString() {
return PersonModelMapper.ensureInitialized()
.stringifyValue(this as PersonModel);
}
}
extension PersonModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, PersonModel, $Out> {
PersonModelCopyWith<$R, PersonModel, $Out> get $asPersonModel =>
$base.as((v, t, t2) => _PersonModelCopyWithImpl(v, t, t2));
}
abstract class PersonModelCopyWith<$R, $In extends PersonModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get birthPlace;
ListCopyWith<$R, MovieModel, MovieModelCopyWith<$R, MovieModel, MovieModel>>
get movies;
ListCopyWith<$R, SeriesModel,
SeriesModelCopyWith<$R, SeriesModel, SeriesModel>> get series;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{DateTime? dateOfBirth,
List<String>? birthPlace,
List<MovieModel>? movies,
List<SeriesModel>? series,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
bool? canDownload,
bool? canDelete,
BaseItemKind? jellyType});
PersonModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _PersonModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, PersonModel, $Out>
implements PersonModelCopyWith<$R, PersonModel, $Out> {
_PersonModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<PersonModel> $mapper =
PersonModelMapper.ensureInitialized();
@override
ListCopyWith<$R, String, ObjectCopyWith<$R, String, String>> get birthPlace =>
ListCopyWith($value.birthPlace, (v, t) => ObjectCopyWith(v, $identity, t),
(v) => call(birthPlace: v));
@override
ListCopyWith<$R, MovieModel, MovieModelCopyWith<$R, MovieModel, MovieModel>>
get movies => ListCopyWith($value.movies, (v, t) => v.copyWith.$chain(t),
(v) => call(movies: v));
@override
ListCopyWith<$R, SeriesModel,
SeriesModelCopyWith<$R, SeriesModel, SeriesModel>>
get series => ListCopyWith($value.series, (v, t) => v.copyWith.$chain(t),
(v) => call(series: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{Object? dateOfBirth = $none,
List<String>? birthPlace,
List<MovieModel>? movies,
List<SeriesModel>? series,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? canDownload = $none,
Object? canDelete = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (dateOfBirth != $none) #dateOfBirth: dateOfBirth,
if (birthPlace != null) #birthPlace: birthPlace,
if (movies != null) #movies: movies,
if (series != null) #series: series,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (canDownload != $none) #canDownload: canDownload,
if (canDelete != $none) #canDelete: canDelete,
if (jellyType != $none) #jellyType: jellyType
}));
@override
PersonModel $make(CopyWithData data) => PersonModel(
dateOfBirth: data.get(#dateOfBirth, or: $value.dateOfBirth),
birthPlace: data.get(#birthPlace, or: $value.birthPlace),
movies: data.get(#movies, or: $value.movies),
series: data.get(#series, or: $value.series),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
canDownload: data.get(#canDownload, or: $value.canDownload),
canDelete: data.get(#canDelete, or: $value.canDelete),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
PersonModelCopyWith<$R2, PersonModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_PersonModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,154 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.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' as dto;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:fladder/providers/user_provider.dart';
import 'package:fladder/screens/shared/fladder_snackbar.dart';
import 'package:fladder/util/refresh_state.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'photos_model.mapper.dart';
@MappableClass()
class PhotoAlbumModel extends ItemBaseModel with PhotoAlbumModelMappable {
final List<ItemBaseModel> photos;
const PhotoAlbumModel({
required this.photos,
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
super.canDelete,
super.canDownload,
super.jellyType,
});
@override
bool get unWatched => userData.unPlayedItemCount != 0;
@override
bool get playAble => true;
@override
ItemBaseModel get parentBaseModel => copyWith(id: parentId);
factory PhotoAlbumModel.fromBaseDto(dto.BaseItemDto item, Ref ref) {
return PhotoAlbumModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
images: ImagesData.fromBaseItem(item, ref),
primaryRatio: item.primaryImageAspectRatio,
canDelete: item.canDelete,
canDownload: item.canDownload,
photos: [],
);
}
}
@MappableClass()
class PhotoModel extends ItemBaseModel with PhotoModelMappable {
final String? albumId;
final DateTime? dateTaken;
final ImagesData? thumbnail;
final FladderItemType internalType;
const PhotoModel({
required this.albumId,
required this.dateTaken,
required this.thumbnail,
required this.internalType,
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
required super.canDownload,
required super.canDelete,
super.jellyType,
});
@override
PhotoAlbumModel get parentBaseModel => PhotoAlbumModel(
photos: [],
name: "",
id: parentId ?? "",
overview: overview,
parentId: parentId,
playlistId: playlistId,
images: images,
childCount: childCount,
primaryRatio: primaryRatio,
userData: userData,
);
@override
ImagesData? get getPosters => thumbnail;
@override
bool get galleryItem => switch (internalType) {
FladderItemType.photo => albumId?.isNotEmpty == true,
FladderItemType.video => parentId?.isNotEmpty == true,
_ => false,
};
@override
bool get unWatched => false;
factory PhotoModel.fromBaseDto(dto.BaseItemDto item, Ref ref) {
return PhotoModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
primaryRatio: double.tryParse(item.aspectRatio ?? "") ?? item.primaryImageAspectRatio ?? 1.0,
dateTaken: item.dateCreated,
albumId: item.albumId,
thumbnail: ImagesData.fromBaseItem(item, ref),
images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true),
canDelete: item.canDelete,
canDownload: item.canDownload,
internalType: switch (item.type) {
BaseItemKind.video => FladderItemType.video,
_ => FladderItemType.photo,
},
);
}
String downloadPath(WidgetRef ref) {
return "${ref.read(userProvider)?.server}/Items/$id/Download?api_key=${ref.read(userProvider)?.credentials.token}";
}
Future<void> navigateToAlbum(BuildContext context) async {
if ((albumId ?? parentId) == null) {
fladderSnackbar(context, title: context.localized.notPartOfAlbum);
return;
}
await parentBaseModel.navigateTo(context);
if (context.mounted) context.refreshData();
}
}

View file

@ -0,0 +1,498 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'photos_model.dart';
class PhotoAlbumModelMapper extends SubClassMapperBase<PhotoAlbumModel> {
PhotoAlbumModelMapper._();
static PhotoAlbumModelMapper? _instance;
static PhotoAlbumModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = PhotoAlbumModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
ItemBaseModelMapper.ensureInitialized();
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'PhotoAlbumModel';
static List<ItemBaseModel> _$photos(PhotoAlbumModel v) => v.photos;
static const Field<PhotoAlbumModel, List<ItemBaseModel>> _f$photos =
Field('photos', _$photos);
static String _$name(PhotoAlbumModel v) => v.name;
static const Field<PhotoAlbumModel, String> _f$name = Field('name', _$name);
static String _$id(PhotoAlbumModel v) => v.id;
static const Field<PhotoAlbumModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(PhotoAlbumModel v) => v.overview;
static const Field<PhotoAlbumModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(PhotoAlbumModel v) => v.parentId;
static const Field<PhotoAlbumModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(PhotoAlbumModel v) => v.playlistId;
static const Field<PhotoAlbumModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(PhotoAlbumModel v) => v.images;
static const Field<PhotoAlbumModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(PhotoAlbumModel v) => v.childCount;
static const Field<PhotoAlbumModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(PhotoAlbumModel v) => v.primaryRatio;
static const Field<PhotoAlbumModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(PhotoAlbumModel v) => v.userData;
static const Field<PhotoAlbumModel, UserData> _f$userData =
Field('userData', _$userData);
static bool? _$canDelete(PhotoAlbumModel v) => v.canDelete;
static const Field<PhotoAlbumModel, bool> _f$canDelete =
Field('canDelete', _$canDelete, opt: true);
static bool? _$canDownload(PhotoAlbumModel v) => v.canDownload;
static const Field<PhotoAlbumModel, bool> _f$canDownload =
Field('canDownload', _$canDownload, opt: true);
static dto.BaseItemKind? _$jellyType(PhotoAlbumModel v) => v.jellyType;
static const Field<PhotoAlbumModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<PhotoAlbumModel> fields = const {
#photos: _f$photos,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#canDelete: _f$canDelete,
#canDownload: _f$canDownload,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'PhotoAlbumModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static PhotoAlbumModel _instantiate(DecodingData data) {
return PhotoAlbumModel(
photos: data.dec(_f$photos),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
canDelete: data.dec(_f$canDelete),
canDownload: data.dec(_f$canDownload),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static PhotoAlbumModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<PhotoAlbumModel>(map);
}
static PhotoAlbumModel fromJson(String json) {
return ensureInitialized().decodeJson<PhotoAlbumModel>(json);
}
}
mixin PhotoAlbumModelMappable {
String toJson() {
return PhotoAlbumModelMapper.ensureInitialized()
.encodeJson<PhotoAlbumModel>(this as PhotoAlbumModel);
}
Map<String, dynamic> toMap() {
return PhotoAlbumModelMapper.ensureInitialized()
.encodeMap<PhotoAlbumModel>(this as PhotoAlbumModel);
}
PhotoAlbumModelCopyWith<PhotoAlbumModel, PhotoAlbumModel, PhotoAlbumModel>
get copyWith => _PhotoAlbumModelCopyWithImpl(
this as PhotoAlbumModel, $identity, $identity);
@override
String toString() {
return PhotoAlbumModelMapper.ensureInitialized()
.stringifyValue(this as PhotoAlbumModel);
}
}
extension PhotoAlbumModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, PhotoAlbumModel, $Out> {
PhotoAlbumModelCopyWith<$R, PhotoAlbumModel, $Out> get $asPhotoAlbumModel =>
$base.as((v, t, t2) => _PhotoAlbumModelCopyWithImpl(v, t, t2));
}
abstract class PhotoAlbumModelCopyWith<$R, $In extends PhotoAlbumModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get photos;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{List<ItemBaseModel>? photos,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
bool? canDelete,
bool? canDownload,
dto.BaseItemKind? jellyType});
PhotoAlbumModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t);
}
class _PhotoAlbumModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, PhotoAlbumModel, $Out>
implements PhotoAlbumModelCopyWith<$R, PhotoAlbumModel, $Out> {
_PhotoAlbumModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<PhotoAlbumModel> $mapper =
PhotoAlbumModelMapper.ensureInitialized();
@override
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>>
get photos => ListCopyWith($value.photos, (v, t) => v.copyWith.$chain(t),
(v) => call(photos: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{List<ItemBaseModel>? photos,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? canDelete = $none,
Object? canDownload = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (photos != null) #photos: photos,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (canDelete != $none) #canDelete: canDelete,
if (canDownload != $none) #canDownload: canDownload,
if (jellyType != $none) #jellyType: jellyType
}));
@override
PhotoAlbumModel $make(CopyWithData data) => PhotoAlbumModel(
photos: data.get(#photos, or: $value.photos),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
canDelete: data.get(#canDelete, or: $value.canDelete),
canDownload: data.get(#canDownload, or: $value.canDownload),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
PhotoAlbumModelCopyWith<$R2, PhotoAlbumModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_PhotoAlbumModelCopyWithImpl($value, $cast, t);
}
class PhotoModelMapper extends SubClassMapperBase<PhotoModel> {
PhotoModelMapper._();
static PhotoModelMapper? _instance;
static PhotoModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = PhotoModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'PhotoModel';
static String? _$albumId(PhotoModel v) => v.albumId;
static const Field<PhotoModel, String> _f$albumId =
Field('albumId', _$albumId);
static DateTime? _$dateTaken(PhotoModel v) => v.dateTaken;
static const Field<PhotoModel, DateTime> _f$dateTaken =
Field('dateTaken', _$dateTaken);
static ImagesData? _$thumbnail(PhotoModel v) => v.thumbnail;
static const Field<PhotoModel, ImagesData> _f$thumbnail =
Field('thumbnail', _$thumbnail);
static FladderItemType _$internalType(PhotoModel v) => v.internalType;
static const Field<PhotoModel, FladderItemType> _f$internalType =
Field('internalType', _$internalType);
static String _$name(PhotoModel v) => v.name;
static const Field<PhotoModel, String> _f$name = Field('name', _$name);
static String _$id(PhotoModel v) => v.id;
static const Field<PhotoModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(PhotoModel v) => v.overview;
static const Field<PhotoModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(PhotoModel v) => v.parentId;
static const Field<PhotoModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(PhotoModel v) => v.playlistId;
static const Field<PhotoModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(PhotoModel v) => v.images;
static const Field<PhotoModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(PhotoModel v) => v.childCount;
static const Field<PhotoModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(PhotoModel v) => v.primaryRatio;
static const Field<PhotoModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(PhotoModel v) => v.userData;
static const Field<PhotoModel, UserData> _f$userData =
Field('userData', _$userData);
static bool? _$canDownload(PhotoModel v) => v.canDownload;
static const Field<PhotoModel, bool> _f$canDownload =
Field('canDownload', _$canDownload);
static bool? _$canDelete(PhotoModel v) => v.canDelete;
static const Field<PhotoModel, bool> _f$canDelete =
Field('canDelete', _$canDelete);
static dto.BaseItemKind? _$jellyType(PhotoModel v) => v.jellyType;
static const Field<PhotoModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<PhotoModel> fields = const {
#albumId: _f$albumId,
#dateTaken: _f$dateTaken,
#thumbnail: _f$thumbnail,
#internalType: _f$internalType,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#canDownload: _f$canDownload,
#canDelete: _f$canDelete,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'PhotoModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static PhotoModel _instantiate(DecodingData data) {
return PhotoModel(
albumId: data.dec(_f$albumId),
dateTaken: data.dec(_f$dateTaken),
thumbnail: data.dec(_f$thumbnail),
internalType: data.dec(_f$internalType),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
canDownload: data.dec(_f$canDownload),
canDelete: data.dec(_f$canDelete),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static PhotoModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<PhotoModel>(map);
}
static PhotoModel fromJson(String json) {
return ensureInitialized().decodeJson<PhotoModel>(json);
}
}
mixin PhotoModelMappable {
String toJson() {
return PhotoModelMapper.ensureInitialized()
.encodeJson<PhotoModel>(this as PhotoModel);
}
Map<String, dynamic> toMap() {
return PhotoModelMapper.ensureInitialized()
.encodeMap<PhotoModel>(this as PhotoModel);
}
PhotoModelCopyWith<PhotoModel, PhotoModel, PhotoModel> get copyWith =>
_PhotoModelCopyWithImpl(this as PhotoModel, $identity, $identity);
@override
String toString() {
return PhotoModelMapper.ensureInitialized()
.stringifyValue(this as PhotoModel);
}
}
extension PhotoModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, PhotoModel, $Out> {
PhotoModelCopyWith<$R, PhotoModel, $Out> get $asPhotoModel =>
$base.as((v, t, t2) => _PhotoModelCopyWithImpl(v, t, t2));
}
abstract class PhotoModelCopyWith<$R, $In extends PhotoModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{String? albumId,
DateTime? dateTaken,
ImagesData? thumbnail,
FladderItemType? internalType,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
bool? canDownload,
bool? canDelete,
dto.BaseItemKind? jellyType});
PhotoModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _PhotoModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, PhotoModel, $Out>
implements PhotoModelCopyWith<$R, PhotoModel, $Out> {
_PhotoModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<PhotoModel> $mapper =
PhotoModelMapper.ensureInitialized();
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{Object? albumId = $none,
Object? dateTaken = $none,
Object? thumbnail = $none,
FladderItemType? internalType,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? canDownload = $none,
Object? canDelete = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (albumId != $none) #albumId: albumId,
if (dateTaken != $none) #dateTaken: dateTaken,
if (thumbnail != $none) #thumbnail: thumbnail,
if (internalType != null) #internalType: internalType,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (canDownload != $none) #canDownload: canDownload,
if (canDelete != $none) #canDelete: canDelete,
if (jellyType != $none) #jellyType: jellyType
}));
@override
PhotoModel $make(CopyWithData data) => PhotoModel(
albumId: data.get(#albumId, or: $value.albumId),
dateTaken: data.get(#dateTaken, or: $value.dateTaken),
thumbnail: data.get(#thumbnail, or: $value.thumbnail),
internalType: data.get(#internalType, or: $value.internalType),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
canDownload: data.get(#canDownload, or: $value.canDownload),
canDelete: data.get(#canDelete, or: $value.canDelete),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
PhotoModelCopyWith<$R2, PhotoModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_PhotoModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,98 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:collection/collection.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:fladder/models/items/series_model.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' as dto;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/episode_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'season_model.mapper.dart';
@MappableClass()
class SeasonModel extends ItemBaseModel with SeasonModelMappable {
final ImagesData? parentImages;
final String seasonName;
final List<EpisodeModel> episodes;
final int episodeCount;
final String seriesId;
final String seriesName;
const SeasonModel({
required this.parentImages,
required this.seasonName,
this.episodes = const [],
required this.episodeCount,
required this.seriesId,
required this.seriesName,
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
required super.canDelete,
required super.canDownload,
super.jellyType,
});
factory SeasonModel.fromBaseDto(dto.BaseItemDto item, Ref ref) {
return SeasonModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.seasonId ?? item.parentId,
playlistId: item.playlistItemId,
images: ImagesData.fromBaseItem(item, ref),
primaryRatio: item.primaryImageAspectRatio,
seasonName: item.seasonName ?? "",
episodeCount: item.episodeCount ?? 0,
parentImages: ImagesData.fromBaseItemParent(item, ref, primary: const Size(2000, 2000)),
seriesId: item.seriesId ?? item.parentId ?? item.id ?? "",
canDelete: item.canDelete,
canDownload: item.canDownload,
seriesName: item.seriesName ?? "",
);
}
EpisodeModel? get nextUp {
return episodes.lastWhereOrNull((element) => element.userData.progress > 0) ??
episodes.firstWhereOrNull((element) => element.userData.played == false);
}
@override
ImagesData? get getPosters => images ?? parentImages;
String localizedName(BuildContext context) => name.replaceFirst("Season", context.localized.season(1));
@override
SeriesModel get parentBaseModel => SeriesModel(
originalTitle: '',
sortName: '',
status: "",
name: seriesName,
id: parentId ?? "",
playlistId: playlistId,
overview: overview,
parentId: parentId,
images: images,
childCount: childCount,
primaryRatio: primaryRatio,
userData: UserData(),
);
static List<SeasonModel> seasonsFromDto(List<dto.BaseItemDto>? dto, Ref ref) {
return dto?.map((e) => SeasonModel.fromBaseDto(e, ref)).toList() ?? [];
}
}

View file

@ -0,0 +1,287 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'season_model.dart';
class SeasonModelMapper extends SubClassMapperBase<SeasonModel> {
SeasonModelMapper._();
static SeasonModelMapper? _instance;
static SeasonModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = SeasonModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
EpisodeModelMapper.ensureInitialized();
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'SeasonModel';
static ImagesData? _$parentImages(SeasonModel v) => v.parentImages;
static const Field<SeasonModel, ImagesData> _f$parentImages =
Field('parentImages', _$parentImages);
static String _$seasonName(SeasonModel v) => v.seasonName;
static const Field<SeasonModel, String> _f$seasonName =
Field('seasonName', _$seasonName);
static List<EpisodeModel> _$episodes(SeasonModel v) => v.episodes;
static const Field<SeasonModel, List<EpisodeModel>> _f$episodes =
Field('episodes', _$episodes, opt: true, def: const []);
static int _$episodeCount(SeasonModel v) => v.episodeCount;
static const Field<SeasonModel, int> _f$episodeCount =
Field('episodeCount', _$episodeCount);
static String _$seriesId(SeasonModel v) => v.seriesId;
static const Field<SeasonModel, String> _f$seriesId =
Field('seriesId', _$seriesId);
static String _$seriesName(SeasonModel v) => v.seriesName;
static const Field<SeasonModel, String> _f$seriesName =
Field('seriesName', _$seriesName);
static String _$name(SeasonModel v) => v.name;
static const Field<SeasonModel, String> _f$name = Field('name', _$name);
static String _$id(SeasonModel v) => v.id;
static const Field<SeasonModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(SeasonModel v) => v.overview;
static const Field<SeasonModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(SeasonModel v) => v.parentId;
static const Field<SeasonModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(SeasonModel v) => v.playlistId;
static const Field<SeasonModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(SeasonModel v) => v.images;
static const Field<SeasonModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(SeasonModel v) => v.childCount;
static const Field<SeasonModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(SeasonModel v) => v.primaryRatio;
static const Field<SeasonModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(SeasonModel v) => v.userData;
static const Field<SeasonModel, UserData> _f$userData =
Field('userData', _$userData);
static bool? _$canDelete(SeasonModel v) => v.canDelete;
static const Field<SeasonModel, bool> _f$canDelete =
Field('canDelete', _$canDelete);
static bool? _$canDownload(SeasonModel v) => v.canDownload;
static const Field<SeasonModel, bool> _f$canDownload =
Field('canDownload', _$canDownload);
static dto.BaseItemKind? _$jellyType(SeasonModel v) => v.jellyType;
static const Field<SeasonModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<SeasonModel> fields = const {
#parentImages: _f$parentImages,
#seasonName: _f$seasonName,
#episodes: _f$episodes,
#episodeCount: _f$episodeCount,
#seriesId: _f$seriesId,
#seriesName: _f$seriesName,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#canDelete: _f$canDelete,
#canDownload: _f$canDownload,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'SeasonModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static SeasonModel _instantiate(DecodingData data) {
return SeasonModel(
parentImages: data.dec(_f$parentImages),
seasonName: data.dec(_f$seasonName),
episodes: data.dec(_f$episodes),
episodeCount: data.dec(_f$episodeCount),
seriesId: data.dec(_f$seriesId),
seriesName: data.dec(_f$seriesName),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
canDelete: data.dec(_f$canDelete),
canDownload: data.dec(_f$canDownload),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static SeasonModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<SeasonModel>(map);
}
static SeasonModel fromJson(String json) {
return ensureInitialized().decodeJson<SeasonModel>(json);
}
}
mixin SeasonModelMappable {
String toJson() {
return SeasonModelMapper.ensureInitialized()
.encodeJson<SeasonModel>(this as SeasonModel);
}
Map<String, dynamic> toMap() {
return SeasonModelMapper.ensureInitialized()
.encodeMap<SeasonModel>(this as SeasonModel);
}
SeasonModelCopyWith<SeasonModel, SeasonModel, SeasonModel> get copyWith =>
_SeasonModelCopyWithImpl(this as SeasonModel, $identity, $identity);
@override
String toString() {
return SeasonModelMapper.ensureInitialized()
.stringifyValue(this as SeasonModel);
}
}
extension SeasonModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, SeasonModel, $Out> {
SeasonModelCopyWith<$R, SeasonModel, $Out> get $asSeasonModel =>
$base.as((v, t, t2) => _SeasonModelCopyWithImpl(v, t, t2));
}
abstract class SeasonModelCopyWith<$R, $In extends SeasonModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, EpisodeModel,
EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>> get episodes;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{ImagesData? parentImages,
String? seasonName,
List<EpisodeModel>? episodes,
int? episodeCount,
String? seriesId,
String? seriesName,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
bool? canDelete,
bool? canDownload,
dto.BaseItemKind? jellyType});
SeasonModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _SeasonModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SeasonModel, $Out>
implements SeasonModelCopyWith<$R, SeasonModel, $Out> {
_SeasonModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SeasonModel> $mapper =
SeasonModelMapper.ensureInitialized();
@override
ListCopyWith<$R, EpisodeModel,
EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>>
get episodes => ListCopyWith($value.episodes,
(v, t) => v.copyWith.$chain(t), (v) => call(episodes: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{Object? parentImages = $none,
String? seasonName,
List<EpisodeModel>? episodes,
int? episodeCount,
String? seriesId,
String? seriesName,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? canDelete = $none,
Object? canDownload = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (parentImages != $none) #parentImages: parentImages,
if (seasonName != null) #seasonName: seasonName,
if (episodes != null) #episodes: episodes,
if (episodeCount != null) #episodeCount: episodeCount,
if (seriesId != null) #seriesId: seriesId,
if (seriesName != null) #seriesName: seriesName,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (canDelete != $none) #canDelete: canDelete,
if (canDownload != $none) #canDownload: canDownload,
if (jellyType != $none) #jellyType: jellyType
}));
@override
SeasonModel $make(CopyWithData data) => SeasonModel(
parentImages: data.get(#parentImages, or: $value.parentImages),
seasonName: data.get(#seasonName, or: $value.seasonName),
episodes: data.get(#episodes, or: $value.episodes),
episodeCount: data.get(#episodeCount, or: $value.episodeCount),
seriesId: data.get(#seriesId, or: $value.seriesId),
seriesName: data.get(#seriesName, or: $value.seriesName),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
canDelete: data.get(#canDelete, or: $value.canDelete),
canDownload: data.get(#canDownload, or: $value.canDownload),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
SeasonModelCopyWith<$R2, SeasonModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SeasonModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,96 @@
import 'package:fladder/screens/details_screens/series_detail_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart' as dto;
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/episode_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/items/overview_model.dart';
import 'package:fladder/models/items/season_model.dart';
import 'package:dart_mappable/dart_mappable.dart';
part 'series_model.mapper.dart';
@MappableClass()
class SeriesModel extends ItemBaseModel with SeriesModelMappable {
final List<EpisodeModel>? availableEpisodes;
final List<SeasonModel>? seasons;
final String originalTitle;
final String sortName;
final String status;
final List<ItemBaseModel> related;
const SeriesModel({
this.availableEpisodes,
this.seasons,
required this.originalTitle,
required this.sortName,
required this.status,
this.related = const [],
required super.name,
required super.id,
required super.overview,
required super.parentId,
required super.playlistId,
required super.images,
required super.childCount,
required super.primaryRatio,
required super.userData,
super.canDownload,
super.canDelete,
super.jellyType,
});
EpisodeModel? get nextUp => availableEpisodes?.nextUp ?? availableEpisodes?.firstOrNull;
@override
String detailedName(BuildContext context) => name;
@override
ItemBaseModel get parentBaseModel => this;
@override
Widget get detailScreenWidget => SeriesDetailScreen(item: this);
@override
bool get emptyShow => childCount == 0;
@override
bool get playAble => userData.unPlayedItemCount != 0;
@override
bool get identifiable => true;
@override
bool get unWatched =>
!userData.played && userData.progress <= 0 && userData.unPlayedItemCount == 0 && childCount != 0;
@override
String get subText => overview.yearAired?.toString() ?? "";
List<ItemBaseModel> fetchAllShows() {
return availableEpisodes?.map((e) => e).toList() ?? [];
}
@override
bool get syncAble => true;
factory SeriesModel.fromBaseDto(dto.BaseItemDto item, Ref ref) => SeriesModel(
name: item.name ?? "",
id: item.id ?? "",
childCount: item.childCount,
overview: OverviewModel.fromBaseItemDto(item, ref),
userData: UserData.fromDto(item.userData),
parentId: item.parentId,
playlistId: item.playlistItemId,
images: ImagesData.fromBaseItem(item, ref, getOriginalSize: true),
primaryRatio: item.primaryImageAspectRatio,
originalTitle: item.originalTitle ?? "",
sortName: item.sortName ?? "",
canDelete: item.canDelete,
canDownload: item.canDownload,
status: item.status ?? "Continuing",
);
}

View file

@ -0,0 +1,309 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, unnecessary_cast, override_on_non_overriding_member
// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
part of 'series_model.dart';
class SeriesModelMapper extends SubClassMapperBase<SeriesModel> {
SeriesModelMapper._();
static SeriesModelMapper? _instance;
static SeriesModelMapper ensureInitialized() {
if (_instance == null) {
MapperContainer.globals.use(_instance = SeriesModelMapper._());
ItemBaseModelMapper.ensureInitialized().addSubMapper(_instance!);
EpisodeModelMapper.ensureInitialized();
SeasonModelMapper.ensureInitialized();
ItemBaseModelMapper.ensureInitialized();
OverviewModelMapper.ensureInitialized();
UserDataMapper.ensureInitialized();
}
return _instance!;
}
@override
final String id = 'SeriesModel';
static List<EpisodeModel>? _$availableEpisodes(SeriesModel v) =>
v.availableEpisodes;
static const Field<SeriesModel, List<EpisodeModel>> _f$availableEpisodes =
Field('availableEpisodes', _$availableEpisodes, opt: true);
static List<SeasonModel>? _$seasons(SeriesModel v) => v.seasons;
static const Field<SeriesModel, List<SeasonModel>> _f$seasons =
Field('seasons', _$seasons, opt: true);
static String _$originalTitle(SeriesModel v) => v.originalTitle;
static const Field<SeriesModel, String> _f$originalTitle =
Field('originalTitle', _$originalTitle);
static String _$sortName(SeriesModel v) => v.sortName;
static const Field<SeriesModel, String> _f$sortName =
Field('sortName', _$sortName);
static String _$status(SeriesModel v) => v.status;
static const Field<SeriesModel, String> _f$status = Field('status', _$status);
static List<ItemBaseModel> _$related(SeriesModel v) => v.related;
static const Field<SeriesModel, List<ItemBaseModel>> _f$related =
Field('related', _$related, opt: true, def: const []);
static String _$name(SeriesModel v) => v.name;
static const Field<SeriesModel, String> _f$name = Field('name', _$name);
static String _$id(SeriesModel v) => v.id;
static const Field<SeriesModel, String> _f$id = Field('id', _$id);
static OverviewModel _$overview(SeriesModel v) => v.overview;
static const Field<SeriesModel, OverviewModel> _f$overview =
Field('overview', _$overview);
static String? _$parentId(SeriesModel v) => v.parentId;
static const Field<SeriesModel, String> _f$parentId =
Field('parentId', _$parentId);
static String? _$playlistId(SeriesModel v) => v.playlistId;
static const Field<SeriesModel, String> _f$playlistId =
Field('playlistId', _$playlistId);
static ImagesData? _$images(SeriesModel v) => v.images;
static const Field<SeriesModel, ImagesData> _f$images =
Field('images', _$images);
static int? _$childCount(SeriesModel v) => v.childCount;
static const Field<SeriesModel, int> _f$childCount =
Field('childCount', _$childCount);
static double? _$primaryRatio(SeriesModel v) => v.primaryRatio;
static const Field<SeriesModel, double> _f$primaryRatio =
Field('primaryRatio', _$primaryRatio);
static UserData _$userData(SeriesModel v) => v.userData;
static const Field<SeriesModel, UserData> _f$userData =
Field('userData', _$userData);
static bool? _$canDownload(SeriesModel v) => v.canDownload;
static const Field<SeriesModel, bool> _f$canDownload =
Field('canDownload', _$canDownload, opt: true);
static bool? _$canDelete(SeriesModel v) => v.canDelete;
static const Field<SeriesModel, bool> _f$canDelete =
Field('canDelete', _$canDelete, opt: true);
static dto.BaseItemKind? _$jellyType(SeriesModel v) => v.jellyType;
static const Field<SeriesModel, dto.BaseItemKind> _f$jellyType =
Field('jellyType', _$jellyType, opt: true);
@override
final MappableFields<SeriesModel> fields = const {
#availableEpisodes: _f$availableEpisodes,
#seasons: _f$seasons,
#originalTitle: _f$originalTitle,
#sortName: _f$sortName,
#status: _f$status,
#related: _f$related,
#name: _f$name,
#id: _f$id,
#overview: _f$overview,
#parentId: _f$parentId,
#playlistId: _f$playlistId,
#images: _f$images,
#childCount: _f$childCount,
#primaryRatio: _f$primaryRatio,
#userData: _f$userData,
#canDownload: _f$canDownload,
#canDelete: _f$canDelete,
#jellyType: _f$jellyType,
};
@override
final bool ignoreNull = true;
@override
final String discriminatorKey = 'type';
@override
final dynamic discriminatorValue = 'SeriesModel';
@override
late final ClassMapperBase superMapper =
ItemBaseModelMapper.ensureInitialized();
static SeriesModel _instantiate(DecodingData data) {
return SeriesModel(
availableEpisodes: data.dec(_f$availableEpisodes),
seasons: data.dec(_f$seasons),
originalTitle: data.dec(_f$originalTitle),
sortName: data.dec(_f$sortName),
status: data.dec(_f$status),
related: data.dec(_f$related),
name: data.dec(_f$name),
id: data.dec(_f$id),
overview: data.dec(_f$overview),
parentId: data.dec(_f$parentId),
playlistId: data.dec(_f$playlistId),
images: data.dec(_f$images),
childCount: data.dec(_f$childCount),
primaryRatio: data.dec(_f$primaryRatio),
userData: data.dec(_f$userData),
canDownload: data.dec(_f$canDownload),
canDelete: data.dec(_f$canDelete),
jellyType: data.dec(_f$jellyType));
}
@override
final Function instantiate = _instantiate;
static SeriesModel fromMap(Map<String, dynamic> map) {
return ensureInitialized().decodeMap<SeriesModel>(map);
}
static SeriesModel fromJson(String json) {
return ensureInitialized().decodeJson<SeriesModel>(json);
}
}
mixin SeriesModelMappable {
String toJson() {
return SeriesModelMapper.ensureInitialized()
.encodeJson<SeriesModel>(this as SeriesModel);
}
Map<String, dynamic> toMap() {
return SeriesModelMapper.ensureInitialized()
.encodeMap<SeriesModel>(this as SeriesModel);
}
SeriesModelCopyWith<SeriesModel, SeriesModel, SeriesModel> get copyWith =>
_SeriesModelCopyWithImpl(this as SeriesModel, $identity, $identity);
@override
String toString() {
return SeriesModelMapper.ensureInitialized()
.stringifyValue(this as SeriesModel);
}
}
extension SeriesModelValueCopy<$R, $Out>
on ObjectCopyWith<$R, SeriesModel, $Out> {
SeriesModelCopyWith<$R, SeriesModel, $Out> get $asSeriesModel =>
$base.as((v, t, t2) => _SeriesModelCopyWithImpl(v, t, t2));
}
abstract class SeriesModelCopyWith<$R, $In extends SeriesModel, $Out>
implements ItemBaseModelCopyWith<$R, $In, $Out> {
ListCopyWith<$R, EpisodeModel,
EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>>?
get availableEpisodes;
ListCopyWith<$R, SeasonModel,
SeasonModelCopyWith<$R, SeasonModel, SeasonModel>>? get seasons;
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>> get related;
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview;
@override
UserDataCopyWith<$R, UserData, UserData> get userData;
@override
$R call(
{List<EpisodeModel>? availableEpisodes,
List<SeasonModel>? seasons,
String? originalTitle,
String? sortName,
String? status,
List<ItemBaseModel>? related,
String? name,
String? id,
OverviewModel? overview,
String? parentId,
String? playlistId,
ImagesData? images,
int? childCount,
double? primaryRatio,
UserData? userData,
bool? canDownload,
bool? canDelete,
dto.BaseItemKind? jellyType});
SeriesModelCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>(Then<$Out2, $R2> t);
}
class _SeriesModelCopyWithImpl<$R, $Out>
extends ClassCopyWithBase<$R, SeriesModel, $Out>
implements SeriesModelCopyWith<$R, SeriesModel, $Out> {
_SeriesModelCopyWithImpl(super.value, super.then, super.then2);
@override
late final ClassMapperBase<SeriesModel> $mapper =
SeriesModelMapper.ensureInitialized();
@override
ListCopyWith<$R, EpisodeModel,
EpisodeModelCopyWith<$R, EpisodeModel, EpisodeModel>>?
get availableEpisodes => $value.availableEpisodes != null
? ListCopyWith($value.availableEpisodes!,
(v, t) => v.copyWith.$chain(t), (v) => call(availableEpisodes: v))
: null;
@override
ListCopyWith<$R, SeasonModel,
SeasonModelCopyWith<$R, SeasonModel, SeasonModel>>?
get seasons => $value.seasons != null
? ListCopyWith($value.seasons!, (v, t) => v.copyWith.$chain(t),
(v) => call(seasons: v))
: null;
@override
ListCopyWith<$R, ItemBaseModel,
ItemBaseModelCopyWith<$R, ItemBaseModel, ItemBaseModel>>
get related => ListCopyWith($value.related,
(v, t) => v.copyWith.$chain(t), (v) => call(related: v));
@override
OverviewModelCopyWith<$R, OverviewModel, OverviewModel> get overview =>
$value.overview.copyWith.$chain((v) => call(overview: v));
@override
UserDataCopyWith<$R, UserData, UserData> get userData =>
$value.userData.copyWith.$chain((v) => call(userData: v));
@override
$R call(
{Object? availableEpisodes = $none,
Object? seasons = $none,
String? originalTitle,
String? sortName,
String? status,
List<ItemBaseModel>? related,
String? name,
String? id,
OverviewModel? overview,
Object? parentId = $none,
Object? playlistId = $none,
Object? images = $none,
Object? childCount = $none,
Object? primaryRatio = $none,
UserData? userData,
Object? canDownload = $none,
Object? canDelete = $none,
Object? jellyType = $none}) =>
$apply(FieldCopyWithData({
if (availableEpisodes != $none) #availableEpisodes: availableEpisodes,
if (seasons != $none) #seasons: seasons,
if (originalTitle != null) #originalTitle: originalTitle,
if (sortName != null) #sortName: sortName,
if (status != null) #status: status,
if (related != null) #related: related,
if (name != null) #name: name,
if (id != null) #id: id,
if (overview != null) #overview: overview,
if (parentId != $none) #parentId: parentId,
if (playlistId != $none) #playlistId: playlistId,
if (images != $none) #images: images,
if (childCount != $none) #childCount: childCount,
if (primaryRatio != $none) #primaryRatio: primaryRatio,
if (userData != null) #userData: userData,
if (canDownload != $none) #canDownload: canDownload,
if (canDelete != $none) #canDelete: canDelete,
if (jellyType != $none) #jellyType: jellyType
}));
@override
SeriesModel $make(CopyWithData data) => SeriesModel(
availableEpisodes:
data.get(#availableEpisodes, or: $value.availableEpisodes),
seasons: data.get(#seasons, or: $value.seasons),
originalTitle: data.get(#originalTitle, or: $value.originalTitle),
sortName: data.get(#sortName, or: $value.sortName),
status: data.get(#status, or: $value.status),
related: data.get(#related, or: $value.related),
name: data.get(#name, or: $value.name),
id: data.get(#id, or: $value.id),
overview: data.get(#overview, or: $value.overview),
parentId: data.get(#parentId, or: $value.parentId),
playlistId: data.get(#playlistId, or: $value.playlistId),
images: data.get(#images, or: $value.images),
childCount: data.get(#childCount, or: $value.childCount),
primaryRatio: data.get(#primaryRatio, or: $value.primaryRatio),
userData: data.get(#userData, or: $value.userData),
canDownload: data.get(#canDownload, or: $value.canDownload),
canDelete: data.get(#canDelete, or: $value.canDelete),
jellyType: data.get(#jellyType, or: $value.jellyType));
@override
SeriesModelCopyWith<$R2, SeriesModel, $Out2> $chain<$R2, $Out2>(
Then<$Out2, $R2> t) =>
_SeriesModelCopyWithImpl($value, $cast, t);
}

View file

@ -0,0 +1,61 @@
import 'dart:ui';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'trick_play_model.freezed.dart';
part 'trick_play_model.g.dart';
@freezed
class TrickPlayModel with _$TrickPlayModel {
factory TrickPlayModel({
required int width,
required int height,
required int tileWidth,
required int tileHeight,
required int thumbnailCount,
required Duration interval,
@Default([]) List<String> images,
}) = _TrickPlayModel;
const TrickPlayModel._();
int get imagesPerTile => tileWidth * tileHeight;
String? getTile(Duration position) {
final int currentIndex = (position.inMilliseconds ~/ interval.inMilliseconds).clamp(0, thumbnailCount);
final int indexOfTile = (currentIndex ~/ imagesPerTile).clamp(0, images.length);
return images.elementAtOrNull(indexOfTile);
}
Offset offset(Duration position) {
final int currentIndex = (position.inMilliseconds ~/ interval.inMilliseconds).clamp(0, thumbnailCount - 1);
final int tileIndex = currentIndex % imagesPerTile;
final int column = tileIndex % tileWidth;
final int row = tileIndex ~/ tileWidth;
return Offset((width * column).toDouble(), (height * row).toDouble());
}
static Map<String, TrickPlayModel> toTrickPlayMap(Map<String, dynamic> map) {
Map<String, TrickPlayModel> newMap = {};
final firstMap = (((map.entries.first as MapEntry).value as Map<String, dynamic>));
newMap.addEntries(firstMap.entries.map(
(e) {
final map = e.value as Map<String, dynamic>;
return MapEntry(
e.key,
TrickPlayModel(
width: map['Width'] as int? ?? 0,
height: map['Height'] as int? ?? 0,
tileWidth: map['TileWidth'] as int? ?? 0,
tileHeight: map['TileHeight'] as int? ?? 0,
thumbnailCount: map['ThumbnailCount'] as int? ?? 0,
interval: Duration(milliseconds: map['Interval'] as int? ?? 0),
),
);
},
));
return newMap;
}
factory TrickPlayModel.fromJson(Map<String, dynamic> json) => _$TrickPlayModelFromJson(json);
}

View file

@ -0,0 +1,297 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'trick_play_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
TrickPlayModel _$TrickPlayModelFromJson(Map<String, dynamic> json) {
return _TrickPlayModel.fromJson(json);
}
/// @nodoc
mixin _$TrickPlayModel {
int get width => throw _privateConstructorUsedError;
int get height => throw _privateConstructorUsedError;
int get tileWidth => throw _privateConstructorUsedError;
int get tileHeight => throw _privateConstructorUsedError;
int get thumbnailCount => throw _privateConstructorUsedError;
Duration get interval => throw _privateConstructorUsedError;
List<String> get images => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$TrickPlayModelCopyWith<TrickPlayModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $TrickPlayModelCopyWith<$Res> {
factory $TrickPlayModelCopyWith(
TrickPlayModel value, $Res Function(TrickPlayModel) then) =
_$TrickPlayModelCopyWithImpl<$Res, TrickPlayModel>;
@useResult
$Res call(
{int width,
int height,
int tileWidth,
int tileHeight,
int thumbnailCount,
Duration interval,
List<String> images});
}
/// @nodoc
class _$TrickPlayModelCopyWithImpl<$Res, $Val extends TrickPlayModel>
implements $TrickPlayModelCopyWith<$Res> {
_$TrickPlayModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? width = null,
Object? height = null,
Object? tileWidth = null,
Object? tileHeight = null,
Object? thumbnailCount = null,
Object? interval = null,
Object? images = null,
}) {
return _then(_value.copyWith(
width: null == width
? _value.width
: width // ignore: cast_nullable_to_non_nullable
as int,
height: null == height
? _value.height
: height // ignore: cast_nullable_to_non_nullable
as int,
tileWidth: null == tileWidth
? _value.tileWidth
: tileWidth // ignore: cast_nullable_to_non_nullable
as int,
tileHeight: null == tileHeight
? _value.tileHeight
: tileHeight // ignore: cast_nullable_to_non_nullable
as int,
thumbnailCount: null == thumbnailCount
? _value.thumbnailCount
: thumbnailCount // ignore: cast_nullable_to_non_nullable
as int,
interval: null == interval
? _value.interval
: interval // ignore: cast_nullable_to_non_nullable
as Duration,
images: null == images
? _value.images
: images // ignore: cast_nullable_to_non_nullable
as List<String>,
) as $Val);
}
}
/// @nodoc
abstract class _$$TrickPlayModelImplCopyWith<$Res>
implements $TrickPlayModelCopyWith<$Res> {
factory _$$TrickPlayModelImplCopyWith(_$TrickPlayModelImpl value,
$Res Function(_$TrickPlayModelImpl) then) =
__$$TrickPlayModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int width,
int height,
int tileWidth,
int tileHeight,
int thumbnailCount,
Duration interval,
List<String> images});
}
/// @nodoc
class __$$TrickPlayModelImplCopyWithImpl<$Res>
extends _$TrickPlayModelCopyWithImpl<$Res, _$TrickPlayModelImpl>
implements _$$TrickPlayModelImplCopyWith<$Res> {
__$$TrickPlayModelImplCopyWithImpl(
_$TrickPlayModelImpl _value, $Res Function(_$TrickPlayModelImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? width = null,
Object? height = null,
Object? tileWidth = null,
Object? tileHeight = null,
Object? thumbnailCount = null,
Object? interval = null,
Object? images = null,
}) {
return _then(_$TrickPlayModelImpl(
width: null == width
? _value.width
: width // ignore: cast_nullable_to_non_nullable
as int,
height: null == height
? _value.height
: height // ignore: cast_nullable_to_non_nullable
as int,
tileWidth: null == tileWidth
? _value.tileWidth
: tileWidth // ignore: cast_nullable_to_non_nullable
as int,
tileHeight: null == tileHeight
? _value.tileHeight
: tileHeight // ignore: cast_nullable_to_non_nullable
as int,
thumbnailCount: null == thumbnailCount
? _value.thumbnailCount
: thumbnailCount // ignore: cast_nullable_to_non_nullable
as int,
interval: null == interval
? _value.interval
: interval // ignore: cast_nullable_to_non_nullable
as Duration,
images: null == images
? _value._images
: images // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$TrickPlayModelImpl extends _TrickPlayModel {
_$TrickPlayModelImpl(
{required this.width,
required this.height,
required this.tileWidth,
required this.tileHeight,
required this.thumbnailCount,
required this.interval,
final List<String> images = const []})
: _images = images,
super._();
factory _$TrickPlayModelImpl.fromJson(Map<String, dynamic> json) =>
_$$TrickPlayModelImplFromJson(json);
@override
final int width;
@override
final int height;
@override
final int tileWidth;
@override
final int tileHeight;
@override
final int thumbnailCount;
@override
final Duration interval;
final List<String> _images;
@override
@JsonKey()
List<String> get images {
if (_images is EqualUnmodifiableListView) return _images;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_images);
}
@override
String toString() {
return 'TrickPlayModel(width: $width, height: $height, tileWidth: $tileWidth, tileHeight: $tileHeight, thumbnailCount: $thumbnailCount, interval: $interval, images: $images)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$TrickPlayModelImpl &&
(identical(other.width, width) || other.width == width) &&
(identical(other.height, height) || other.height == height) &&
(identical(other.tileWidth, tileWidth) ||
other.tileWidth == tileWidth) &&
(identical(other.tileHeight, tileHeight) ||
other.tileHeight == tileHeight) &&
(identical(other.thumbnailCount, thumbnailCount) ||
other.thumbnailCount == thumbnailCount) &&
(identical(other.interval, interval) ||
other.interval == interval) &&
const DeepCollectionEquality().equals(other._images, _images));
}
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(
runtimeType,
width,
height,
tileWidth,
tileHeight,
thumbnailCount,
interval,
const DeepCollectionEquality().hash(_images));
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$TrickPlayModelImplCopyWith<_$TrickPlayModelImpl> get copyWith =>
__$$TrickPlayModelImplCopyWithImpl<_$TrickPlayModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$TrickPlayModelImplToJson(
this,
);
}
}
abstract class _TrickPlayModel extends TrickPlayModel {
factory _TrickPlayModel(
{required final int width,
required final int height,
required final int tileWidth,
required final int tileHeight,
required final int thumbnailCount,
required final Duration interval,
final List<String> images}) = _$TrickPlayModelImpl;
_TrickPlayModel._() : super._();
factory _TrickPlayModel.fromJson(Map<String, dynamic> json) =
_$TrickPlayModelImpl.fromJson;
@override
int get width;
@override
int get height;
@override
int get tileWidth;
@override
int get tileHeight;
@override
int get thumbnailCount;
@override
Duration get interval;
@override
List<String> get images;
@override
@JsonKey(ignore: true)
_$$TrickPlayModelImplCopyWith<_$TrickPlayModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View file

@ -0,0 +1,33 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'trick_play_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$TrickPlayModelImpl _$$TrickPlayModelImplFromJson(Map<String, dynamic> json) =>
_$TrickPlayModelImpl(
width: (json['width'] as num).toInt(),
height: (json['height'] as num).toInt(),
tileWidth: (json['tileWidth'] as num).toInt(),
tileHeight: (json['tileHeight'] as num).toInt(),
thumbnailCount: (json['thumbnailCount'] as num).toInt(),
interval: Duration(microseconds: (json['interval'] as num).toInt()),
images: (json['images'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const [],
);
Map<String, dynamic> _$$TrickPlayModelImplToJson(
_$TrickPlayModelImpl instance) =>
<String, dynamic>{
'width': instance.width,
'height': instance.height,
'tileWidth': instance.tileWidth,
'tileHeight': instance.tileHeight,
'thumbnailCount': instance.thumbnailCount,
'interval': instance.interval.inMicroseconds,
'images': instance.images,
};