refactor: extract shared mixins and helpers, drop dead abstractions
Introduces shared seams for paginated views, D-pad reorder, media control routing, async singletons and the device method channel, then points the open-coded copies at them. Also removes unused models and duplicated provider/server plumbing, folds the twice-implemented artifact store in the server, and factors the repeated Flutter toolchain prologue in CI into a composite action.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import '../i18n/strings.g.dart';
|
||||
import '../media/media_backend.dart';
|
||||
import '../media/media_item.dart';
|
||||
import '../media/media_kind.dart';
|
||||
@@ -147,7 +148,9 @@ abstract class MetadataEditAdapter {
|
||||
|
||||
Future<List<MetadataArtworkOption>> fetchArtwork(MetadataEditDraft draft, MetadataEditField field);
|
||||
|
||||
Future<bool> applyArtworkOption(MetadataEditDraft draft, MetadataEditField field, MetadataArtworkOption option);
|
||||
Future<bool> applyArtworkOption(MetadataEditDraft draft, MetadataEditField field, MetadataArtworkOption option) {
|
||||
return applyArtworkFromUrl(draft, field, option.sourceUrl);
|
||||
}
|
||||
|
||||
Future<bool> applyArtworkFromUrl(MetadataEditDraft draft, MetadataEditField field, String url);
|
||||
|
||||
@@ -160,6 +163,133 @@ abstract class MetadataEditAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Basic-info fields shared by every backend; only the studio field type differs.
|
||||
List<MetadataEditField> metadataBasicFields(
|
||||
MediaKind kind, {
|
||||
MetadataEditFieldType studioType = MetadataEditFieldType.text,
|
||||
}) {
|
||||
return [
|
||||
MetadataEditField(id: 'title', label: t.metadataEdit.title, type: MetadataEditFieldType.text),
|
||||
if (kind != MediaKind.season)
|
||||
MetadataEditField(id: 'titleSort', label: t.metadataEdit.sortTitle, type: MetadataEditFieldType.text),
|
||||
if (kind == MediaKind.movie || kind == MediaKind.show)
|
||||
MetadataEditField(id: 'originalTitle', label: t.metadataEdit.originalTitle, type: MetadataEditFieldType.text),
|
||||
if (kind != MediaKind.season)
|
||||
MetadataEditField(
|
||||
id: 'originallyAvailableAt',
|
||||
label: t.metadataEdit.releaseDate,
|
||||
type: MetadataEditFieldType.date,
|
||||
),
|
||||
if (kind != MediaKind.season)
|
||||
MetadataEditField(id: 'contentRating', label: t.metadataEdit.contentRating, type: MetadataEditFieldType.text),
|
||||
if (kind == MediaKind.movie || kind == MediaKind.show)
|
||||
MetadataEditField(id: 'studio', label: t.metadataEdit.studio, type: studioType),
|
||||
if (kind == MediaKind.movie || kind == MediaKind.show)
|
||||
MetadataEditField(id: 'tagline', label: t.metadataEdit.tagline, type: MetadataEditFieldType.text),
|
||||
MetadataEditField(id: 'summary', label: t.metadataEdit.summary, type: MetadataEditFieldType.multilineText),
|
||||
];
|
||||
}
|
||||
|
||||
/// Artwork fields shared by every backend; each backend supplies its own artwork
|
||||
/// key names, which kinds carry a logo, and whether square art exists.
|
||||
List<MetadataEditField> metadataArtworkFields(
|
||||
MediaKind kind, {
|
||||
required String posterKey,
|
||||
required String backdropKey,
|
||||
required String logoKey,
|
||||
String? squareKey,
|
||||
Set<MediaKind> logoKinds = const {MediaKind.movie, MediaKind.show},
|
||||
}) {
|
||||
final fields = <MetadataEditField>[
|
||||
// Episode "posters" are 16:9 thumbnails, not 2:3 poster art.
|
||||
kind == MediaKind.episode
|
||||
? metadataArtworkField(
|
||||
posterKey,
|
||||
t.metadataEdit.poster,
|
||||
t.metadataEdit.selectPoster,
|
||||
80,
|
||||
45,
|
||||
2,
|
||||
16 / 9,
|
||||
imageType: ImageType.thumb,
|
||||
)
|
||||
: metadataArtworkField(posterKey, t.metadataEdit.poster, t.metadataEdit.selectPoster, 40, 60, 3, 2 / 3),
|
||||
];
|
||||
if (kind == MediaKind.movie || kind == MediaKind.show || kind == MediaKind.episode) {
|
||||
fields.add(
|
||||
metadataArtworkField(
|
||||
backdropKey,
|
||||
t.metadataEdit.background,
|
||||
t.metadataEdit.selectBackground,
|
||||
80,
|
||||
45,
|
||||
2,
|
||||
16 / 9,
|
||||
imageType: ImageType.art,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (logoKinds.contains(kind)) {
|
||||
fields.add(
|
||||
metadataArtworkField(
|
||||
logoKey,
|
||||
t.metadataEdit.logo,
|
||||
t.metadataEdit.selectLogo,
|
||||
80,
|
||||
32,
|
||||
2,
|
||||
2.5,
|
||||
fit: MetadataArtworkFit.contain,
|
||||
imageType: ImageType.logo,
|
||||
),
|
||||
);
|
||||
if (squareKey != null) {
|
||||
fields.add(
|
||||
metadataArtworkField(
|
||||
squareKey,
|
||||
t.metadataEdit.squareArt,
|
||||
t.metadataEdit.selectSquareArt,
|
||||
50,
|
||||
50,
|
||||
3,
|
||||
1,
|
||||
imageType: ImageType.avatar,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
MetadataEditField metadataArtworkField(
|
||||
String key,
|
||||
String label,
|
||||
String title,
|
||||
double width,
|
||||
double height,
|
||||
int columns,
|
||||
double aspectRatio, {
|
||||
MetadataArtworkFit fit = MetadataArtworkFit.cover,
|
||||
ImageType imageType = ImageType.poster,
|
||||
}) {
|
||||
return MetadataEditField(
|
||||
id: 'artwork:$key',
|
||||
label: label,
|
||||
type: MetadataEditFieldType.artwork,
|
||||
saveMode: MetadataEditSaveMode.immediate,
|
||||
artwork: MetadataArtworkConfig(
|
||||
key: key,
|
||||
selectTitle: title,
|
||||
previewWidth: width,
|
||||
previewHeight: height,
|
||||
gridColumns: columns,
|
||||
gridAspectRatio: aspectRatio,
|
||||
fit: fit,
|
||||
imageType: imageType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool metadataEditValueEquals(Object? a, Object? b) {
|
||||
if (identical(a, b)) return true;
|
||||
if (a is List && b is List) {
|
||||
|
||||
Reference in New Issue
Block a user