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 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 = []; 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 []) if (g.name.isNotEmpty) g.name, ]; final cast = enriched?.credits?.cast ?? const []; final recommendations = enriched?.recommendations?.results ?? const []; 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 = [ ...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, ); }