feature: Details screen rework (#190)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2024-12-27 15:21:47 +01:00 committed by GitHub
parent 473e817e0f
commit d2138da785
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 462 additions and 394 deletions

View file

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/screens/shared/flat_button.dart';
class ChipButton extends ConsumerWidget {
final String label;
final Function()? onPressed;
@ -8,19 +11,20 @@ class ChipButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return TextButton(
onPressed: onPressed,
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.surface.withOpacity(0.75),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide.none,
return Card(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.15),
shadowColor: Colors.transparent,
child: FlatButton(
onTap: onPressed,
// ),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
child: Text(
label,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600),
),
),
),
child: Text(
label,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600),
),
);
}
}

View file

@ -1,50 +1,66 @@
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/fladder_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/util/fladder_image.dart';
class MediaHeader extends ConsumerWidget {
final String name;
final ImageData? logo;
final Function()? onTap;
const MediaHeader({
required this.name,
required this.logo,
this.onTap,
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final maxWidth =
switch (AdaptiveLayout.layoutOf(context)) { LayoutState.desktop || LayoutState.tablet => 0.55, _ => 1 };
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Material(
elevation: 30,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(150)),
shadowColor: Colors.black.withOpacity(0.35),
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.2,
maxWidth: MediaQuery.sizeOf(context).width * maxWidth,
),
child: FladderImage(
image: logo,
enableBlur: true,
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) => Container(
color: Colors.red,
width: 512,
height: 512,
child: child,
),
placeHolder: const SizedBox(height: 0),
fit: BoxFit.contain,
),
final maxSize = 700.0;
final textWidget = Container(
height: 512,
alignment: Alignment.center,
child: SelectableText(
name,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
fontSize: 55,
),
),
);
return Center(
child: Material(
elevation: 30,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(150)),
shadowColor: Colors.black.withOpacity(0.3),
color: Colors.transparent,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: (MediaQuery.sizeOf(context).height * 0.275).clamp(0, maxSize),
maxWidth: MediaQuery.sizeOf(context).width.clamp(0, maxSize),
),
child: Stack(
children: [
logo != null
? FladderImage(
image: logo,
enableBlur: true,
alignment: Alignment.bottomCenter,
imageErrorBuilder: (context, object, stack) => textWidget,
placeHolder: const SizedBox(height: 0),
fit: BoxFit.contain,
)
: textWidget,
if (onTap != null)
Positioned.fill(
child: GestureDetector(
onTap: onTap,
),
),
],
),
),
),

View file

@ -1,8 +1,10 @@
import 'package:flutter/material.dart';
import 'package:ficonsax/ficonsax.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/screens/shared/animated_fade_size.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class MediaPlayButton extends ConsumerWidget {
final ItemBaseModel? item;
@ -33,8 +35,8 @@ class MediaPlayButton extends ConsumerWidget {
child: Text(
item?.playButtonLabel(context) ?? "",
maxLines: 2,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.bold,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w700,
color: textColor,
),
),

View file

@ -1,3 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:fladder/models/items/episode_model.dart';
import 'package:fladder/providers/sync_provider.dart';
import 'package:fladder/screens/details_screens/components/media_stream_information.dart';
@ -5,9 +10,7 @@ import 'package:fladder/screens/shared/media/episode_posters.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/sticky_header_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:fladder/util/string_extensions.dart';
class NextUpEpisode extends ConsumerWidget {
final EpisodeModel nextEpisode;
@ -17,6 +20,7 @@ class NextUpEpisode extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final alreadyPlayed = nextEpisode.userData.played;
final episodeSummary = nextEpisode.overview.summary.maxLength(limitTo: 250);
return Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
@ -53,7 +57,7 @@ class NextUpEpisode extends ConsumerWidget {
const SizedBox(height: 16),
if (nextEpisode.overview.summary.isNotEmpty)
HtmlWidget(
nextEpisode.overview.summary,
episodeSummary,
textStyle: Theme.of(context).textTheme.titleMedium,
),
],
@ -88,7 +92,7 @@ class NextUpEpisode extends ConsumerWidget {
mediaStreams: nextEpisode.mediaStreams.copyWith(defaultSubStreamIndex: index))),
),
if (nextEpisode.overview.summary.isNotEmpty)
HtmlWidget(nextEpisode.overview.summary, textStyle: Theme.of(context).textTheme.titleMedium),
HtmlWidget(episodeSummary, textStyle: Theme.of(context).textTheme.titleMedium),
],
),
),

View file

@ -82,6 +82,8 @@ class Genres extends StatelessWidget {
return Wrap(
runSpacing: 8,
spacing: 8,
runAlignment: WrapAlignment.center,
alignment: WrapAlignment.center,
children: genres
.map(
(genre) => ChipButton(