mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-18 19:56:32 -07:00
feature: Details screen rework (#190)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
473e817e0f
commit
d2138da785
21 changed files with 462 additions and 394 deletions
|
|
@ -5,14 +5,15 @@ import 'package:ficonsax/ficonsax.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/models/book_model.dart';
|
||||
import 'package:fladder/models/items/images_models.dart';
|
||||
import 'package:fladder/providers/items/book_details_provider.dart';
|
||||
import 'package:fladder/providers/user_provider.dart';
|
||||
import 'package:fladder/screens/details_screens/components/overview_header.dart';
|
||||
import 'package:fladder/screens/shared/detail_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_play_button.dart';
|
||||
import 'package:fladder/screens/shared/media/expanding_overview.dart';
|
||||
import 'package:fladder/screens/shared/media/external_urls.dart';
|
||||
import 'package:fladder/screens/shared/media/poster_list_item.dart';
|
||||
import 'package:fladder/util/fladder_image.dart';
|
||||
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
|
||||
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
|
|
@ -65,50 +66,34 @@ class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.2),
|
||||
if (MediaQuery.sizeOf(context).width < 500)
|
||||
Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.sizeOf(context).width * 0.75),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 0.76,
|
||||
child: Card(
|
||||
child: FladderImage(image: details.cover?.primary),
|
||||
),
|
||||
),
|
||||
).padding(padding),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
if (MediaQuery.sizeOf(context).width > 500) ...{
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery.sizeOf(context).width * 0.3,
|
||||
maxHeight: MediaQuery.sizeOf(context).height * 0.75),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 0.76,
|
||||
child: Card(
|
||||
child: FladderImage(image: details.cover?.primary),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 32),
|
||||
},
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (details.nextUp != null)
|
||||
OverviewHeader(
|
||||
subTitle: details.book!.parentName ?? details.parentModel?.name,
|
||||
name: details.nextUp!.name,
|
||||
subTitle: details.book?.parentName ?? details.parentModel?.name,
|
||||
name: details.nextUp?.name ?? "",
|
||||
image: ImagesData(
|
||||
logo: details.book?.getPosters?.primary,
|
||||
),
|
||||
centerButtons: Builder(
|
||||
builder: (context) {
|
||||
//Wrapped so the correct context is used for refreshing the pages
|
||||
return MediaPlayButton(
|
||||
item: details.nextUp!,
|
||||
onPressed: () async => details.nextUp.play(context, ref, provider: provider),
|
||||
);
|
||||
},
|
||||
),
|
||||
productionYear: details.nextUp!.overview.productionYear,
|
||||
runTime: details.nextUp!.overview.runTime,
|
||||
genres: details.nextUp!.overview.genreItems,
|
||||
studios: details.nextUp!.overview.studios,
|
||||
officialRating: details.nextUp!.overview.parentalRating,
|
||||
communityRating: details.nextUp!.overview.communityRating,
|
||||
externalUrls: details.nextUp!.overview.externalUrls,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
|
|
@ -116,14 +101,6 @@ class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
|
|||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
//Wrapped so the correct context is used for refreshing the pages
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return MediaPlayButton(
|
||||
item: details.nextUp!,
|
||||
onPressed: () async => details.nextUp.play(context, ref, provider: provider));
|
||||
},
|
||||
),
|
||||
if (details.parentModel != null)
|
||||
SelectableIconButton(
|
||||
onPressed: () async => await details.parentModel?.navigateTo(context),
|
||||
|
|
@ -177,52 +154,61 @@ class _BookDetailScreenState extends ConsumerState<BookDetailScreen> {
|
|||
text: details.nextUp!.overview.summary,
|
||||
).padding(padding),
|
||||
if (details.chapters.length > 1)
|
||||
Builder(builder: (context) {
|
||||
final parentContext = context;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(context.localized.chapter(details.chapters.length),
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Divider(),
|
||||
),
|
||||
...details.chapters.map(
|
||||
(e) {
|
||||
final current = e == details.nextUp;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Opacity(
|
||||
opacity: e.userData.played ? 0.65 : 1,
|
||||
child: Card(
|
||||
color: current ? Theme.of(context).colorScheme.surfaceContainerHighest : null,
|
||||
child: PosterListItem(
|
||||
poster: e,
|
||||
onPressed: (action, item) => showBottomSheetPill(
|
||||
context: context,
|
||||
item: item,
|
||||
content: (context, scrollController) => ListView(
|
||||
shrinkWrap: true,
|
||||
controller: scrollController,
|
||||
children: item
|
||||
.generateActions(
|
||||
parentContext,
|
||||
ref,
|
||||
)
|
||||
.listTileItems(context, useIcons: true),
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final parentContext = context;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(context.localized.chapter(details.chapters.length),
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Divider(),
|
||||
),
|
||||
...details.chapters.map(
|
||||
(e) {
|
||||
final current = e == details.nextUp;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Opacity(
|
||||
opacity: e.userData.played ? 0.65 : 1,
|
||||
child: Card(
|
||||
color: current ? Theme.of(context).colorScheme.surfaceContainerHighest : null,
|
||||
child: PosterListItem(
|
||||
poster: e,
|
||||
onPressed: (action, item) => showBottomSheetPill(
|
||||
context: context,
|
||||
item: item,
|
||||
content: (context, scrollController) => ListView(
|
||||
shrinkWrap: true,
|
||||
controller: scrollController,
|
||||
children: item
|
||||
.generateActions(
|
||||
parentContext,
|
||||
ref,
|
||||
)
|
||||
.listTileItems(context, useIcons: true),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
).padding(padding);
|
||||
})
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
).padding(padding);
|
||||
},
|
||||
),
|
||||
if (details.nextUp?.overview.externalUrls?.isNotEmpty == true)
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: ExternalUrlsRow(
|
||||
urls: details.nextUp?.overview.externalUrls,
|
||||
),
|
||||
)
|
||||
].addPadding(const EdgeInsets.symmetric(vertical: 16)),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/models/items/images_models.dart';
|
||||
import 'package:fladder/models/items/item_shared_models.dart';
|
||||
import 'package:fladder/screens/shared/media/components/chip_button.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_header.dart';
|
||||
import 'package:fladder/screens/shared/media/components/small_detail_widgets.dart';
|
||||
import 'package:fladder/screens/shared/media/external_urls.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/humanize_duration.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class OverviewHeader extends ConsumerWidget {
|
||||
final String name;
|
||||
final ImagesData? image;
|
||||
final Widget? centerButtons;
|
||||
final EdgeInsets? padding;
|
||||
final String? subTitle;
|
||||
final String? originalTitle;
|
||||
|
|
@ -19,10 +25,10 @@ class OverviewHeader extends ConsumerWidget {
|
|||
final double? communityRating;
|
||||
final List<Studio> studios;
|
||||
final List<GenreItems> genres;
|
||||
final List<ExternalUrls>? externalUrls;
|
||||
final List<Widget> actions;
|
||||
const OverviewHeader({
|
||||
required this.name,
|
||||
this.image,
|
||||
this.centerButtons,
|
||||
this.padding,
|
||||
this.subTitle,
|
||||
this.originalTitle,
|
||||
|
|
@ -31,134 +37,118 @@ class OverviewHeader extends ConsumerWidget {
|
|||
this.runTime,
|
||||
this.officialRating,
|
||||
this.communityRating,
|
||||
this.externalUrls,
|
||||
this.genres = const [],
|
||||
this.studios = const [],
|
||||
this.actions = const [],
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final mainStyle = Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
final mainStyle = Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
final subStyle = Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontSize: 20,
|
||||
final subStyle = Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 18,
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: padding ?? EdgeInsets.zero,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 32),
|
||||
if (subTitle == null)
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
name,
|
||||
style: mainStyle,
|
||||
),
|
||||
)
|
||||
else ...{
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
subTitle ?? "",
|
||||
style: mainStyle,
|
||||
),
|
||||
final fullHeight =
|
||||
(MediaQuery.sizeOf(context).height - (MediaQuery.paddingOf(context).top + 150)).clamp(50, 1250).toDouble();
|
||||
|
||||
final crossAlignment =
|
||||
AdaptiveLayout.of(context).layout != LayoutState.phone ? CrossAxisAlignment.start : CrossAxisAlignment.center;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: fullHeight,
|
||||
),
|
||||
child: Padding(
|
||||
padding: padding ?? EdgeInsets.zero,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: crossAlignment,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
MediaHeader(
|
||||
name: name,
|
||||
logo: image?.logo,
|
||||
onTap: onTitleClicked,
|
||||
),
|
||||
Flexible(
|
||||
child: Opacity(
|
||||
opacity: 0.75,
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
name,
|
||||
style: subStyle,
|
||||
onTap: onTitleClicked,
|
||||
),
|
||||
),
|
||||
if (onTitleClicked != null)
|
||||
IconButton(
|
||||
onPressed: onTitleClicked,
|
||||
icon: Transform.translate(offset: const Offset(0, 1.5), child: const Icon(Icons.read_more_rounded)))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
if (name != originalTitle && originalTitle != null)
|
||||
SelectableText(
|
||||
originalTitle.toString(),
|
||||
style: subStyle,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (productionYear != null)
|
||||
SelectableText(
|
||||
productionYear.toString(),
|
||||
style: subStyle,
|
||||
),
|
||||
if (runTime != null && (runTime?.inSeconds ?? 0) > 1)
|
||||
SelectableText(
|
||||
runTime.humanize.toString(),
|
||||
style: subStyle,
|
||||
),
|
||||
if (officialRating != null)
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 8),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: crossAlignment,
|
||||
children: [
|
||||
if (subTitle != null)
|
||||
Flexible(
|
||||
child: SelectableText(
|
||||
officialRating.toString(),
|
||||
style: subStyle,
|
||||
subTitle ?? "",
|
||||
textAlign: TextAlign.center,
|
||||
style: mainStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (communityRating != null)
|
||||
Row(
|
||||
if (name.toLowerCase() != originalTitle?.toLowerCase() && originalTitle != null)
|
||||
SelectableText(
|
||||
originalTitle.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: subStyle,
|
||||
),
|
||||
].addInBetween(const SizedBox(height: 4)),
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: crossAlignment,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.center,
|
||||
runAlignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.star_rate_rounded,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
Text(
|
||||
communityRating?.toStringAsFixed(1) ?? "",
|
||||
style: subStyle,
|
||||
),
|
||||
],
|
||||
if (officialRating != null)
|
||||
ChipButton(
|
||||
label: officialRating.toString(),
|
||||
),
|
||||
if (productionYear != null)
|
||||
SelectableText(
|
||||
productionYear.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: subStyle,
|
||||
),
|
||||
if (runTime != null && (runTime?.inSeconds ?? 0) > 1)
|
||||
SelectableText(
|
||||
runTime.humanize.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: subStyle,
|
||||
),
|
||||
if (communityRating != null)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.star_rate_rounded,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
Text(
|
||||
communityRating?.toStringAsFixed(1) ?? "",
|
||||
style: subStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
].addInBetween(CircleAvatar(
|
||||
radius: 3,
|
||||
backgroundColor: Theme.of(context).colorScheme.onSurface,
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (studios.isNotEmpty)
|
||||
Text(
|
||||
"${context.localized.watchOn} ${studios.map((e) => e.name).first}",
|
||||
style: subStyle?.copyWith(fontSize: 16, color: Colors.grey),
|
||||
if (genres.isNotEmpty)
|
||||
Genres(
|
||||
genres: genres.take(6).toList(),
|
||||
),
|
||||
].addInBetween(const SizedBox(height: 10)),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (externalUrls?.isNotEmpty ?? false)
|
||||
ExternalUrlsRow(
|
||||
urls: externalUrls,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (genres.isNotEmpty)
|
||||
Genres(
|
||||
genres: genres.take(10).toList(),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: actions.addPadding(
|
||||
const EdgeInsets.symmetric(horizontal: 6),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (centerButtons != null) centerButtons!,
|
||||
].addInBetween(const SizedBox(height: 21)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@ import 'package:fladder/screens/details_screens/components/overview_header.dart'
|
|||
import 'package:fladder/screens/shared/detail_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||
import 'package:fladder/screens/shared/media/chapter_row.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_header.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_play_button.dart';
|
||||
import 'package:fladder/screens/shared/media/episode_posters.dart';
|
||||
import 'package:fladder/screens/shared/media/expanding_overview.dart';
|
||||
import 'package:fladder/screens/shared/media/external_urls.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
|
||||
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
|
|
@ -41,6 +42,8 @@ class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
|||
final details = ref.watch(providerInstance);
|
||||
final seasonDetails = details.series;
|
||||
final episodeDetails = details.episode;
|
||||
final wrapAlignment =
|
||||
AdaptiveLayout.of(context).layout != LayoutState.phone ? WrapAlignment.start : WrapAlignment.center;
|
||||
|
||||
return DetailScaffold(
|
||||
label: widget.item.name,
|
||||
|
|
@ -67,15 +70,24 @@ class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.35),
|
||||
MediaHeader(
|
||||
name: details.series?.name ?? "",
|
||||
logo: seasonDetails.images?.logo,
|
||||
),
|
||||
OverviewHeader(
|
||||
name: details.series?.name ?? "",
|
||||
image: seasonDetails.images,
|
||||
centerButtons: episodeDetails.playAble
|
||||
? MediaPlayButton(
|
||||
item: episodeDetails,
|
||||
onPressed: () async {
|
||||
await details.episode.play(context, ref);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
onLongPressed: () async {
|
||||
await details.episode.play(context, ref, showPlaybackOption: true);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
)
|
||||
: null,
|
||||
padding: padding,
|
||||
subTitle: details.episode?.name,
|
||||
subTitle: details.episode?.detailedName(context),
|
||||
originalTitle: details.series?.originalTitle,
|
||||
onTitleClicked: () => details.series?.navigateTo(context),
|
||||
productionYear: details.series?.overview.productionYear,
|
||||
|
|
@ -84,25 +96,13 @@ class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
|||
genres: details.series?.overview.genreItems ?? [],
|
||||
officialRating: details.series?.overview.parentalRating,
|
||||
communityRating: details.series?.overview.communityRating,
|
||||
externalUrls: details.series?.overview.externalUrls,
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: wrapAlignment,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (episodeDetails.playAble)
|
||||
MediaPlayButton(
|
||||
item: episodeDetails,
|
||||
onPressed: () async {
|
||||
await details.episode.play(context, ref);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
onLongPressed: () async {
|
||||
await details.episode.play(context, ref, showPlaybackOption: true);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
),
|
||||
SelectableIconButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
|
|
@ -169,6 +169,13 @@ class _ItemDetailScreenState extends ConsumerState<EpisodeDetailScreen> {
|
|||
),
|
||||
episodes: details.episodes.where((element) => element.season == episodeDetails.season).toList(),
|
||||
),
|
||||
if (details.series?.overview.externalUrls?.isNotEmpty == true)
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: ExternalUrlsRow(
|
||||
urls: details.series?.overview.externalUrls,
|
||||
),
|
||||
)
|
||||
].addPadding(const EdgeInsets.symmetric(vertical: 16)),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
|
|
@ -11,9 +12,9 @@ import 'package:fladder/screens/details_screens/components/media_stream_informat
|
|||
import 'package:fladder/screens/details_screens/components/overview_header.dart';
|
||||
import 'package:fladder/screens/shared/detail_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/media/chapter_row.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_header.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_play_button.dart';
|
||||
import 'package:fladder/screens/shared/media/expanding_overview.dart';
|
||||
import 'package:fladder/screens/shared/media/external_urls.dart';
|
||||
import 'package:fladder/screens/shared/media/people_row.dart';
|
||||
import 'package:fladder/screens/shared/media/poster_row.dart';
|
||||
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
|
||||
|
|
@ -37,6 +38,8 @@ class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final details = ref.watch(providerInstance);
|
||||
final wrapAlignment =
|
||||
AdaptiveLayout.of(context).layout != LayoutState.phone ? WrapAlignment.start : WrapAlignment.center;
|
||||
|
||||
return DetailScaffold(
|
||||
label: widget.item.name,
|
||||
|
|
@ -64,14 +67,28 @@ class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.25),
|
||||
MediaHeader(
|
||||
name: details.name,
|
||||
logo: details.images?.logo,
|
||||
),
|
||||
OverviewHeader(
|
||||
name: details.name,
|
||||
image: details.images,
|
||||
padding: padding,
|
||||
centerButtons: MediaPlayButton(
|
||||
item: details,
|
||||
onLongPressed: () async {
|
||||
await details.play(
|
||||
context,
|
||||
ref,
|
||||
showPlaybackOption: true,
|
||||
);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
onPressed: () async {
|
||||
await details.play(
|
||||
context,
|
||||
ref,
|
||||
);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
),
|
||||
originalTitle: details.originalTitle,
|
||||
productionYear: details.overview.productionYear,
|
||||
runTime: details.overview.runTime,
|
||||
|
|
@ -79,31 +96,13 @@ class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
|||
studios: details.overview.studios,
|
||||
officialRating: details.overview.parentalRating,
|
||||
communityRating: details.overview.communityRating,
|
||||
externalUrls: details.overview.externalUrls,
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: wrapAlignment,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
MediaPlayButton(
|
||||
item: details,
|
||||
onLongPressed: () async {
|
||||
await details.play(
|
||||
context,
|
||||
ref,
|
||||
showPlaybackOption: true,
|
||||
);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
onPressed: () async {
|
||||
await details.play(
|
||||
context,
|
||||
ref,
|
||||
);
|
||||
ref.read(providerInstance.notifier).fetchDetails(widget.item);
|
||||
},
|
||||
),
|
||||
SelectableIconButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
|
|
@ -157,6 +156,13 @@ class _ItemDetailScreenState extends ConsumerState<MovieDetailScreen> {
|
|||
),
|
||||
if (details.related.isNotEmpty)
|
||||
PosterRow(posters: details.related, contentPadding: padding, label: "Related"),
|
||||
if (details.overview.externalUrls?.isNotEmpty == true)
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: ExternalUrlsRow(
|
||||
urls: details.overview.externalUrls,
|
||||
),
|
||||
)
|
||||
].addPadding(const EdgeInsets.symmetric(vertical: 16)),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,12 +9,11 @@ import 'package:fladder/providers/items/season_details_provider.dart';
|
|||
import 'package:fladder/providers/user_provider.dart';
|
||||
import 'package:fladder/screens/details_screens/components/overview_header.dart';
|
||||
import 'package:fladder/screens/shared/detail_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_header.dart';
|
||||
import 'package:fladder/screens/shared/media/episode_details_list.dart';
|
||||
import 'package:fladder/screens/shared/media/expanding_overview.dart';
|
||||
import 'package:fladder/screens/shared/media/external_urls.dart';
|
||||
import 'package:fladder/screens/shared/media/people_row.dart';
|
||||
import 'package:fladder/screens/shared/media/person_list_.dart';
|
||||
import 'package:fladder/util/fladder_image.dart';
|
||||
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
|
|
@ -56,51 +55,20 @@ class _SeasonDetailScreenState extends ConsumerState<SeasonDetailScreen> {
|
|||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.25),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.spaceAround,
|
||||
runAlignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 300),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 0.67,
|
||||
child: Card(
|
||||
child: FladderImage(image: details.getPosters?.primary),
|
||||
),
|
||||
),
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 600,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
MediaHeader(
|
||||
name: "${details.seriesName} - ${details.name}",
|
||||
logo: details.parentImages?.logo,
|
||||
),
|
||||
OverviewHeader(
|
||||
name: details.seriesName,
|
||||
padding: padding,
|
||||
subTitle: details.localizedName(context),
|
||||
onTitleClicked: () => details.parentBaseModel.navigateTo(context),
|
||||
originalTitle: details.seriesName,
|
||||
productionYear: details.overview.productionYear,
|
||||
runTime: details.overview.runTime,
|
||||
studios: details.overview.studios,
|
||||
officialRating: details.overview.parentalRating,
|
||||
genres: details.overview.genreItems,
|
||||
communityRating: details.overview.communityRating,
|
||||
externalUrls: details.overview.externalUrls,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(padding),
|
||||
OverviewHeader(
|
||||
name: details.seriesName,
|
||||
image: details.parentImages,
|
||||
padding: padding,
|
||||
subTitle: details.localizedName(context),
|
||||
onTitleClicked: () => details.parentBaseModel.navigateTo(context),
|
||||
originalTitle: details.seriesName,
|
||||
productionYear: details.overview.productionYear,
|
||||
runTime: details.overview.runTime,
|
||||
studios: details.overview.studios,
|
||||
officialRating: details.overview.parentalRating,
|
||||
genres: details.overview.genreItems,
|
||||
communityRating: details.overview.communityRating,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
|
|
@ -191,6 +159,13 @@ class _SeasonDetailScreenState extends ConsumerState<SeasonDetailScreen> {
|
|||
people: details.overview.people,
|
||||
contentPadding: padding,
|
||||
),
|
||||
if (details.overview.externalUrls?.isNotEmpty == true)
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: ExternalUrlsRow(
|
||||
urls: details.overview.externalUrls,
|
||||
),
|
||||
)
|
||||
].addPadding(const EdgeInsets.symmetric(vertical: 16)),
|
||||
)
|
||||
: null,
|
||||
|
|
|
|||
|
|
@ -10,14 +10,15 @@ import 'package:fladder/providers/items/series_details_provider.dart';
|
|||
import 'package:fladder/providers/user_provider.dart';
|
||||
import 'package:fladder/screens/details_screens/components/overview_header.dart';
|
||||
import 'package:fladder/screens/shared/detail_scaffold.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_header.dart';
|
||||
import 'package:fladder/screens/shared/media/components/media_play_button.dart';
|
||||
import 'package:fladder/screens/shared/media/components/next_up_episode.dart';
|
||||
import 'package:fladder/screens/shared/media/episode_posters.dart';
|
||||
import 'package:fladder/screens/shared/media/expanding_overview.dart';
|
||||
import 'package:fladder/screens/shared/media/external_urls.dart';
|
||||
import 'package:fladder/screens/shared/media/people_row.dart';
|
||||
import 'package:fladder/screens/shared/media/poster_row.dart';
|
||||
import 'package:fladder/screens/shared/media/season_row.dart';
|
||||
import 'package:fladder/util/adaptive_layout.dart';
|
||||
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
|
||||
import 'package:fladder/util/item_base_model/play_item_helpers.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
|
|
@ -41,6 +42,9 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final details = ref.watch(providerId);
|
||||
final wrapAlignment =
|
||||
AdaptiveLayout.of(context).layout != LayoutState.phone ? WrapAlignment.start : WrapAlignment.center;
|
||||
|
||||
return DetailScaffold(
|
||||
label: details?.name ?? "",
|
||||
item: details,
|
||||
|
|
@ -67,13 +71,24 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: MediaQuery.of(context).size.height * 0.35),
|
||||
MediaHeader(
|
||||
name: details.name,
|
||||
logo: details.images?.logo,
|
||||
),
|
||||
OverviewHeader(
|
||||
name: details.name,
|
||||
image: details.images,
|
||||
centerButtons: MediaPlayButton(
|
||||
item: details.nextUp,
|
||||
onPressed: details.nextUp != null
|
||||
? () async {
|
||||
await details.nextUp.play(context, ref);
|
||||
ref.read(providerId.notifier).fetchDetails(widget.item);
|
||||
}
|
||||
: null,
|
||||
onLongPressed: details.nextUp != null
|
||||
? () async {
|
||||
await details.nextUp.play(context, ref, showPlaybackOption: true);
|
||||
ref.read(providerId.notifier).fetchDetails(widget.item);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
padding: padding,
|
||||
originalTitle: details.originalTitle,
|
||||
productionYear: details.overview.productionYear,
|
||||
|
|
@ -82,28 +97,13 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
|||
officialRating: details.overview.parentalRating,
|
||||
genres: details.overview.genreItems,
|
||||
communityRating: details.overview.communityRating,
|
||||
externalUrls: details.overview.externalUrls,
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: wrapAlignment,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
MediaPlayButton(
|
||||
item: details.nextUp,
|
||||
onPressed: details.nextUp != null
|
||||
? () async {
|
||||
await details.nextUp.play(context, ref);
|
||||
ref.read(providerId.notifier).fetchDetails(widget.item);
|
||||
}
|
||||
: null,
|
||||
onLongPressed: details.nextUp != null
|
||||
? () async {
|
||||
await details.nextUp.play(context, ref, showPlaybackOption: true);
|
||||
ref.read(providerId.notifier).fetchDetails(widget.item);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
SelectableIconButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
|
|
@ -159,6 +159,13 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
|||
),
|
||||
if (details.related.isNotEmpty)
|
||||
PosterRow(posters: details.related, contentPadding: padding, label: context.localized.related),
|
||||
if (details.overview.externalUrls?.isNotEmpty == true)
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: ExternalUrlsRow(
|
||||
urls: details.overview.externalUrls,
|
||||
),
|
||||
)
|
||||
].addPadding(const EdgeInsets.symmetric(vertical: 16)),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue