106 lines
3.2 KiB
Dart
106 lines
3.2 KiB
Dart
|
|
import 'package:flutter/widgets.dart';
|
||
|
|
|
||
|
|
import '../../../core/contracts/tmdb.dart';
|
||
|
|
import '../../../shared/mappers/tmdb_image_selector.dart';
|
||
|
|
import '../../../shared/mappers/tmdb_image_url.dart';
|
||
|
|
import '../../../shared/utils/format_utils.dart';
|
||
|
|
import '../utils/detail_helpers.dart';
|
||
|
|
import '../model/detail_hero_model.dart';
|
||
|
|
import '../model/detail_image_model.dart';
|
||
|
|
import '../model/detail_section_model.dart';
|
||
|
|
import '../model/detail_view_state.dart';
|
||
|
|
import '../widgets/tmdb_cast_section.dart';
|
||
|
|
import '../widgets/tmdb_recommendation_section.dart';
|
||
|
|
|
||
|
|
|
||
|
|
DetailViewState buildTmdbDetailViewState({
|
||
|
|
required String mediaType,
|
||
|
|
required TmdbEnrichedDetail? enriched,
|
||
|
|
required TmdbRecommendation? seed,
|
||
|
|
required String imageBaseUrl,
|
||
|
|
required String language,
|
||
|
|
required Widget? heroActions,
|
||
|
|
required List<DetailSection> hitStateSections,
|
||
|
|
required bool showSpinner,
|
||
|
|
}) {
|
||
|
|
final detail = enriched?.detail;
|
||
|
|
|
||
|
|
final title = (detail?.title.isNotEmpty ?? false)
|
||
|
|
? detail!.title
|
||
|
|
: (seed?.title ?? '');
|
||
|
|
final posterPath = detail?.posterPath ?? seed?.posterPath;
|
||
|
|
final backdropPath = detail?.backdropPath ?? seed?.backdropPath;
|
||
|
|
final voteAverage = detail?.voteAverage ?? seed?.voteAverage;
|
||
|
|
final overview = (detail?.overview?.trim().isNotEmpty ?? false)
|
||
|
|
? detail!.overview!.trim()
|
||
|
|
: (seed?.overview?.trim() ?? '');
|
||
|
|
final tagline = detail?.tagline?.trim();
|
||
|
|
|
||
|
|
final metaParts = <String>[];
|
||
|
|
final year = yearOf(detail?.releaseDate);
|
||
|
|
if (year != null) metaParts.add(year);
|
||
|
|
final runtime = formatRuntimeMinutes(detail?.runtime);
|
||
|
|
if (runtime != null) metaParts.add(runtime);
|
||
|
|
|
||
|
|
final genreNames = [
|
||
|
|
for (final g in detail?.genres ?? const <TmdbGenre>[])
|
||
|
|
if (g.name.isNotEmpty) g.name,
|
||
|
|
];
|
||
|
|
|
||
|
|
final cast = enriched?.credits?.cast ?? const <TmdbCastMember>[];
|
||
|
|
final recommendations =
|
||
|
|
enriched?.recommendations?.results ?? const <TmdbRecommendation>[];
|
||
|
|
|
||
|
|
final posterUrl = TmdbImageUrl.poster(imageBaseUrl, posterPath);
|
||
|
|
final backdropUrl = TmdbImageUrl.backdrop(imageBaseUrl, backdropPath);
|
||
|
|
final logoUrl = TmdbImageSelector.logoUrl(
|
||
|
|
enriched?.images,
|
||
|
|
imageBaseUrl,
|
||
|
|
language: language,
|
||
|
|
);
|
||
|
|
final fallbackUrls = TmdbImageSelector.buildFallbackUrls(
|
||
|
|
primaryUrl: backdropUrl,
|
||
|
|
candidates: [posterUrl],
|
||
|
|
);
|
||
|
|
|
||
|
|
final sections = <DetailSection>[
|
||
|
|
...hitStateSections,
|
||
|
|
if (cast.isNotEmpty)
|
||
|
|
DetailSection(
|
||
|
|
id: 'tmdb_cast',
|
||
|
|
child: TmdbCastSection(cast: cast, imageBaseUrl: imageBaseUrl),
|
||
|
|
),
|
||
|
|
if (recommendations.isNotEmpty)
|
||
|
|
DetailSection(
|
||
|
|
id: 'tmdb_recommendations',
|
||
|
|
child: TmdbRecommendationSection(
|
||
|
|
items: recommendations,
|
||
|
|
imageBaseUrl: imageBaseUrl,
|
||
|
|
fallbackMediaType: mediaType,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
];
|
||
|
|
|
||
|
|
return DetailViewState(
|
||
|
|
image: DetailImageModel(
|
||
|
|
backdropUrl: backdropUrl,
|
||
|
|
fallbackUrls: fallbackUrls,
|
||
|
|
),
|
||
|
|
navTitle: title,
|
||
|
|
hero: DetailHeroModel(
|
||
|
|
title: title,
|
||
|
|
logoUrl: logoUrl,
|
||
|
|
posterUrl: posterUrl,
|
||
|
|
imageHeaders: null,
|
||
|
|
rating: voteAverage,
|
||
|
|
metaParts: metaParts,
|
||
|
|
genres: genreNames,
|
||
|
|
tagline: tagline,
|
||
|
|
overview: overview,
|
||
|
|
actions: heroActions,
|
||
|
|
),
|
||
|
|
sections: sections,
|
||
|
|
showLoadingBelowHero: showSpinner,
|
||
|
|
);
|
||
|
|
}
|