feat: UI 2.0 and other Improvements (#357)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2025-06-01 10:37:19 +02:00 committed by GitHub
parent 9ca06eaa37
commit e7b5bb40ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
169 changed files with 4584 additions and 3626 deletions

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
Future<void> showDialogAdaptive(
{required BuildContext context, required Widget Function(BuildContext context) builder}) {

View file

@ -1,12 +1,15 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class AnimatedFadeSize extends ConsumerWidget {
final Duration duration;
final Widget child;
final Alignment alignment;
const AnimatedFadeSize({
this.duration = const Duration(milliseconds: 125),
required this.child,
this.alignment = Alignment.center,
super.key,
});
@ -14,6 +17,7 @@ class AnimatedFadeSize extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
return AnimatedSize(
duration: duration,
alignment: alignment,
curve: Curves.easeInOutCubic,
child: AnimatedSwitcher(
duration: duration,

View file

@ -3,8 +3,7 @@ import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/models/settings/home_settings_model.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/list_padding.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/map_bool_helper.dart';
@ -100,33 +99,37 @@ class CategoryChip<T> extends StatelessWidget {
label: Text(context.localized.clear),
)
].addInBetween(const SizedBox(width: 6));
Widget header() => Row(
Widget header(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Material(
color: Colors.transparent,
textStyle: Theme.of(context).textTheme.titleLarge,
child: dialogueTitle ?? label,
),
const Spacer(),
FilledButton.tonal(
onPressed: () {
Navigator.of(context).pop();
newEntry = null;
onCancel?.call();
},
child: Text(context.localized.cancel),
Row(
children: [
FilledButton.tonal(
onPressed: () {
Navigator.of(context).pop();
newEntry = null;
onCancel?.call();
},
child: Text(context.localized.cancel),
),
if (onClear != null)
ElevatedButton.icon(
onPressed: () {
Navigator.of(context).pop();
newEntry = null;
onClear!();
},
icon: const Icon(IconsaxPlusLinear.back_square),
label: Text(context.localized.clear),
)
].addInBetween(const SizedBox(width: 6)),
),
if (onClear != null)
ElevatedButton.icon(
onPressed: () {
Navigator.of(context).pop();
newEntry = null;
onClear!();
},
icon: const Icon(IconsaxPlusLinear.back_square),
label: Text(context.localized.clear),
)
].addInBetween(const SizedBox(width: 6)),
],
);
if (AdaptiveLayout.viewSizeOf(context) != ViewSize.phone) {
@ -156,7 +159,7 @@ class CategoryChip<T> extends StatelessWidget {
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: header(),
child: header(context),
),
const Divider(),
CategoryChipEditor(

View file

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:window_manager/window_manager.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
class DefaultTitleBar extends ConsumerStatefulWidget {
final String? label;

View file

@ -1,22 +1,18 @@
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/models/media_playback_model.dart';
import 'package:fladder/models/settings/home_settings_model.dart';
import 'package:fladder/providers/video_player_provider.dart';
import 'package:fladder/routes/auto_router.gr.dart';
import 'package:fladder/theme.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/fladder_image.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/refresh_state.dart';
import 'package:fladder/util/router_extension.dart';
import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart';
import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart';
import 'package:fladder/widgets/shared/item_actions.dart';
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
@ -64,9 +60,9 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
Widget build(BuildContext context) {
final padding = EdgeInsets.symmetric(horizontal: MediaQuery.sizeOf(context).width / 25);
final backGroundColor = Theme.of(context).colorScheme.surface.withValues(alpha: 0.8);
final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state));
final minHeight = 450.0.clamp(0, MediaQuery.sizeOf(context).height).toDouble();
final maxHeight = MediaQuery.sizeOf(context).height - 10;
final sideBarPadding = AdaptiveLayout.of(context).sideBarWidth;
return PullToRefresh(
onRefresh: () async {
await widget.onRefresh?.call();
@ -78,16 +74,6 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
},
refreshOnStart: true,
child: Scaffold(
floatingActionButtonAnimator:
playerState == VideoPlayerState.minimized ? FloatingActionButtonAnimator.noAnimation : null,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: switch (playerState) {
VideoPlayerState.minimized => const Padding(
padding: EdgeInsets.all(8.0),
child: FloatingPlayerBar(),
),
_ => null,
},
backgroundColor: Theme.of(context).colorScheme.surface,
extendBodyBehindAppBar: true,
body: Stack(
@ -164,7 +150,6 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
Padding(
padding: EdgeInsets.only(
bottom: 0,
left: MediaQuery.of(context).padding.left,
top: MediaQuery.of(context).padding.top,
),
child: ConstrainedBox(
@ -172,7 +157,9 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
minHeight: MediaQuery.sizeOf(context).height,
maxWidth: MediaQuery.sizeOf(context).width,
),
child: widget.content(padding),
child: widget.content(padding.copyWith(
left: sideBarPadding + 25 + MediaQuery.paddingOf(context).left,
)),
),
),
],
@ -182,9 +169,11 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
IconTheme(
data: IconThemeData(color: Theme.of(context).colorScheme.onSurface),
child: Padding(
padding: MediaQuery.paddingOf(context).add(
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
padding: MediaQuery.paddingOf(context)
.copyWith(left: sideBarPadding + MediaQuery.paddingOf(context).left)
.add(
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
child: Row(
children: [
IconButton.filledTonal(
@ -255,13 +244,13 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
child: SettingsUserIcon(),
),
),
Tooltip(
message: context.localized.home,
child: IconButton(
onPressed: () => context.router.navigate(const DashboardRoute()),
icon: const Icon(IconsaxPlusLinear.home),
),
),
if (AdaptiveLayout.layoutModeOf(context) == LayoutMode.single)
Tooltip(
message: context.localized.home,
child: IconButton(
onPressed: () => context.navigateTo(const DashboardRoute()),
icon: const Icon(IconsaxPlusLinear.home),
)),
],
),
),

View file

@ -1,7 +1,7 @@
import 'package:desktop_drop/desktop_drop.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/screens/shared/outlined_text_field.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:flutter/foundation.dart';
// ignore: depend_on_referenced_packages
import 'package:path/path.dart' as p;

View file

@ -47,7 +47,7 @@ class _FloatingSearchBarState extends ConsumerState<FloatingSearchBar> {
closedColor: Colors.transparent,
closedElevation: 0,
closedBuilder: (context, openAction) => Card(
clipBehavior: Clip.antiAlias,
clipBehavior: Clip.hardEdge,
shadowColor: Colors.transparent,
elevation: 5,
margin: EdgeInsets.zero,

View file

@ -7,7 +7,7 @@ import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/screens/shared/media/banner_play_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.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';
@ -51,16 +51,15 @@ class _CarouselBannerState extends ConsumerState<CarouselBanner> {
final itemExtent = widget.items.length == 1 ? MediaQuery.sizeOf(context).width : maxExtent;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4)
.copyWith(top: AdaptiveLayout.of(context).isDesktop ? 6 : 10),
padding: EdgeInsets.only(top: AdaptiveLayout.of(context).isDesktop ? 6 : 10),
child: Stack(
children: [
CarouselView(
elevation: 3,
shrinkExtent: 0,
controller: carouselController,
shape: RoundedRectangleBorder(borderRadius: border),
padding: const EdgeInsets.symmetric(horizontal: 6),
shape: RoundedRectangleBorder(borderRadius: border),
enableSplash: false,
itemExtent: itemExtent,
children: [
@ -146,8 +145,8 @@ class _CarouselBannerState extends ConsumerState<CarouselBanner> {
? null
: (details) async {
Offset localPosition = details.globalPosition;
RelativeRect position = RelativeRect.fromLTRB(localPosition.dx - 320,
localPosition.dy, localPosition.dx, localPosition.dy);
RelativeRect position = RelativeRect.fromLTRB(
localPosition.dx, localPosition.dy, localPosition.dx, localPosition.dy);
final poster = widget.items[index];
await showMenu(

View file

@ -5,7 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/items/chapters_model.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/disable_keypad_focus.dart';
import 'package:fladder/util/humanize_duration.dart';
import 'package:fladder/util/localization_helper.dart';
@ -67,8 +67,8 @@ class ChapterRow extends ConsumerWidget {
FlatButton(
onSecondaryTapDown: (details) async {
Offset localPosition = details.globalPosition;
RelativeRect position = RelativeRect.fromLTRB(
localPosition.dx - 80, localPosition.dy, localPosition.dx, localPosition.dy);
RelativeRect position =
RelativeRect.fromLTRB(localPosition.dx, localPosition.dy, localPosition.dx, localPosition.dy);
await showMenu(
context: context,
position: position,

View file

@ -7,7 +7,7 @@ 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';
import 'package:fladder/screens/shared/media/episode_posters.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/sticky_header_text.dart';
import 'package:fladder/util/string_extensions.dart';

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/models/book_model.dart';
import 'package:fladder/models/item_base_model.dart';
@ -11,7 +11,7 @@ import 'package:fladder/models/items/series_model.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/screens/shared/media/components/poster_placeholder.dart';
import 'package:fladder/theme.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/disable_keypad_focus.dart';
import 'package:fladder/util/fladder_image.dart';
import 'package:fladder/util/humanize_duration.dart';
@ -137,7 +137,7 @@ class _PosterImageState extends ConsumerState<PosterImage> {
border: Border.all(width: 3, color: Theme.of(context).colorScheme.primary),
borderRadius: FladderTheme.defaultShape.borderRadius,
),
clipBehavior: Clip.antiAlias,
clipBehavior: Clip.hardEdge,
child: Stack(
alignment: Alignment.topCenter,
children: [
@ -225,7 +225,7 @@ class _PosterImageState extends ConsumerState<PosterImage> {
onSecondaryTapDown: (details) async {
Offset localPosition = details.globalPosition;
RelativeRect position = RelativeRect.fromLTRB(
localPosition.dx - 320, localPosition.dy, localPosition.dx, localPosition.dy);
localPosition.dx, localPosition.dy, localPosition.dx, localPosition.dy);
await showMenu(
context: context,
position: position,

View file

@ -2,7 +2,7 @@ import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart';
import 'package:fladder/providers/sync_provider.dart';
import 'package:fladder/screens/shared/media/episode_posters.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.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';

View file

@ -9,7 +9,7 @@ import 'package:fladder/providers/sync/sync_provider_helpers.dart';
import 'package:fladder/providers/sync_provider.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/screens/syncing/sync_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/disable_keypad_focus.dart';
import 'package:fladder/util/fladder_image.dart';
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
@ -241,12 +241,13 @@ class EpisodePoster extends ConsumerWidget {
LayoutBuilder(
builder: (context, constraints) {
return FlatButton(
onSecondaryTapDown: (details) {
onSecondaryTapDown: (details) async {
Offset localPosition = details.globalPosition;
RelativeRect position = RelativeRect.fromLTRB(
localPosition.dx - 260, localPosition.dy, localPosition.dx, localPosition.dy);
localPosition.dx, localPosition.dy, localPosition.dx, localPosition.dy);
showMenu(context: context, position: position, items: actions.popupMenuItems(useIcons: true));
await showMenu(
context: context, position: position, items: actions.popupMenuItems(useIcons: true));
},
onTap: onTap,
onLongPress: onLongPress,

View file

@ -1,9 +1,11 @@
import 'package:iconsax_plus/iconsax_plus.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:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/sticky_header_text.dart';
class ExpandingOverview extends ConsumerStatefulWidget {
final String text;
@ -68,11 +70,11 @@ class _ExpandingOverviewState extends ConsumerState<ExpandingOverview> {
child: expanded
? IconButton.filledTonal(
onPressed: toggleState,
icon: const Icon(IconsaxPlusLinear.arrow_up_2),
icon: const Icon(IconsaxPlusLinear.arrow_up_1),
)
: IconButton.filledTonal(
onPressed: toggleState,
icon: const Icon(IconsaxPlusLinear.arrow_down_1),
icon: const Icon(IconsaxPlusLinear.arrow_down),
),
),
),

View file

@ -6,7 +6,7 @@ import 'package:url_launcher/url_launcher.dart' as urilauncher;
import 'package:url_launcher/url_launcher_string.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/sticky_header_text.dart';

View file

@ -25,7 +25,7 @@ class _ItemDetailListWidgetState extends ConsumerState<ItemDetailListWidget> {
return Card(
elevation: widget.elevation,
margin: EdgeInsets.zero,
clipBehavior: Clip.antiAlias,
clipBehavior: Clip.hardEdge,
child: Stack(
children: [
FlatButton(

View file

@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:async/async.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/screens/shared/media/banner_play_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.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';
@ -87,7 +87,7 @@ class _MediaBannerState extends ConsumerState<MediaBanner> {
final double dragOpacity = (1 - dragOffset.abs()).clamp(0, 1);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
padding: const EdgeInsets.symmetric(vertical: 6),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [

View file

@ -7,7 +7,7 @@ import 'package:fladder/jellyfin/jellyfin_open_api.enums.swagger.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/screens/details_screens/person_detail_screen.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/fladder_image.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/string_extensions.dart';
@ -22,12 +22,14 @@ class PeopleRow extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
Widget placeHolder(String name) {
return Card(
child: FractionallySizedBox(
widthFactor: 0.4,
return Center(
child: SizedBox(
height: 75,
width: 75,
child: Card(
elevation: 5,
shape: const CircleBorder(),
shadowColor: Colors.transparent,
color: Theme.of(context).colorScheme.primaryContainer.withValues(alpha: 0.50),
child: Center(
child: Text(
name.getInitials(),

View file

@ -1,11 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sticky_headers/sticky_headers.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart';
import 'package:fladder/screens/shared/media/poster_widget.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/sticky_header_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:sticky_headers/sticky_headers.dart';
class PosterGrid extends ConsumerWidget {
final String? name;

View file

@ -1,10 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/models/book_model.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.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';
@ -12,8 +15,6 @@ import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/widgets/shared/clickable_text.dart';
import 'package:fladder/widgets/shared/item_actions.dart';
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class PosterListItem extends ConsumerWidget {
final ItemBaseModel poster;
@ -64,12 +65,12 @@ class PosterListItem extends ConsumerWidget {
color: Theme.of(context).colorScheme.primary.withValues(alpha: selected == true ? 0.25 : 0),
borderRadius: BorderRadius.circular(6),
),
child: FlatButton(
child: InkWell(
onTap: () => pressedWidget(context),
onSecondaryTapDown: (details) async {
Offset localPosition = details.globalPosition;
RelativeRect position =
RelativeRect.fromLTRB(localPosition.dx - 320, localPosition.dy, localPosition.dx, localPosition.dy);
RelativeRect.fromLTRB(localPosition.dx, localPosition.dy, localPosition.dx, localPosition.dy);
await showMenu(
context: context,
position: position,

View file

@ -1,18 +1,23 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/screens/shared/media/poster_widget.dart';
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
import 'package:fladder/widgets/shared/horizontal_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class PosterRow extends ConsumerStatefulWidget {
final List<ItemBaseModel> posters;
final String label;
final double? collectionAspectRatio;
final Function()? onLabelClick;
final EdgeInsets contentPadding;
const PosterRow({
required this.posters,
this.contentPadding = const EdgeInsets.symmetric(horizontal: 16),
required this.label,
this.collectionAspectRatio,
this.onLabelClick,
super.key,
});
@ -32,6 +37,7 @@ class _PosterRowState extends ConsumerState<PosterRow> {
@override
Widget build(BuildContext context) {
final dominantRatio = widget.collectionAspectRatio ?? widget.posters.getMostCommonType.aspectRatio;
return HorizontalList(
contentPadding: widget.contentPadding,
label: widget.label,
@ -41,6 +47,7 @@ class _PosterRowState extends ConsumerState<PosterRow> {
final poster = widget.posters[index];
return PosterWidget(
poster: poster,
aspectRatio: dominantRatio,
key: Key(poster.id),
);
},

View file

@ -4,9 +4,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/item_shared_models.dart';
import 'package:fladder/models/settings/home_settings_model.dart';
import 'package:fladder/screens/shared/media/components/poster_image.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/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/widgets/shared/clickable_text.dart';

View file

@ -4,7 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/items/season_model.dart';
import 'package:fladder/screens/shared/flat_button.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/adaptive_layout/adaptive_layout.dart';
import 'package:fladder/util/disable_keypad_focus.dart';
import 'package:fladder/util/fladder_image.dart';
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
@ -124,11 +124,11 @@ class SeasonPoster extends ConsumerWidget {
LayoutBuilder(
builder: (context, constraints) {
return FlatButton(
onSecondaryTapDown: (details) {
onSecondaryTapDown: (details) async {
Offset localPosition = details.globalPosition;
RelativeRect position = RelativeRect.fromLTRB(
localPosition.dx - 260, localPosition.dy, localPosition.dx, localPosition.dy);
showMenu(
localPosition.dx, localPosition.dy, localPosition.dx, localPosition.dy);
await showMenu(
context: context,
position: position,
items: season.generateActions(context, ref).popupMenuItems(useIcons: true));

View file

@ -1,7 +1,5 @@
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/widgets/shared/shapes.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class NestedBottomAppBar extends ConsumerWidget {
@ -10,27 +8,17 @@ class NestedBottomAppBar extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final double bottomPadding =
(AdaptiveLayout.of(context).isDesktop || kIsWeb) ? 12 : MediaQuery.of(context).padding.bottom;
return Card(
color: Theme.of(context).colorScheme.surface,
shape: BottomBarShape(),
elevation: 0,
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: SizedBox(
height: kBottomNavigationBarHeight + 12 + bottomPadding,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12)
.copyWith(
bottom: bottomPadding,
)
.add(EdgeInsets.only(
left: MediaQuery.of(context).padding.left,
right: MediaQuery.of(context).padding.right,
)),
child: child,
),
return Padding(
padding: const EdgeInsets.all(8.0).copyWith(bottom: MediaQuery.paddingOf(context).bottom),
child: Card(
color: Theme.of(context).colorScheme.surfaceContainerLow,
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(24),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: child,
),
),
);

View file

@ -2,38 +2,38 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/media_playback_model.dart';
import 'package:fladder/models/settings/home_settings_model.dart';
import 'package:fladder/providers/video_player_provider.dart';
import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/widgets/navigation_scaffold/components/floating_player_bar.dart';
class NestedScaffold extends ConsumerWidget {
final Widget body;
const NestedScaffold({required this.body, super.key});
final Widget? background;
const NestedScaffold({
required this.body,
this.background,
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state));
return Card(
child: Scaffold(
backgroundColor: Colors.transparent,
floatingActionButtonAnimator:
playerState == VideoPlayerState.minimized ? FloatingActionButtonAnimator.noAnimation : null,
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: switch (AdaptiveLayout.layoutOf(context)) {
ViewSize.phone => null,
_ => switch (playerState) {
VideoPlayerState.minimized => const Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: FloatingPlayerBar(),
),
_ => null,
},
},
body: body,
),
return Stack(
alignment: Alignment.bottomCenter,
children: [
if (background != null) background!,
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Theme.of(context).colorScheme.surface.withValues(alpha: 0.98),
Theme.of(context).colorScheme.surface.withValues(alpha: 0.8),
],
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: body,
),
),
],
);
}
}

View file

@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/util/list_padding.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/widgets/navigation_scaffold/components/settings_user_icon.dart';
import 'package:fladder/widgets/shared/shapes.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class NestedSliverAppBar extends ConsumerWidget {
final BuildContext parent;
@ -29,15 +30,14 @@ class NestedSliverAppBar extends ConsumerWidget {
padding: const EdgeInsets.only(bottom: 24),
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 10,
children: [
IconButton.filledTonal(
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.surface),
),
onPressed: () => Scaffold.of(parent).openDrawer(),
icon: const Icon(
IconsaxPlusBold.menu,
size: 28,
SizedBox(
width: 30,
child: IconButton(
onPressed: () => Scaffold.of(parent).openDrawer(),
icon: const Icon(IconsaxPlusLinear.menu),
padding: EdgeInsets.zero,
),
),
Expanded(
@ -62,8 +62,9 @@ class NestedSliverAppBar extends ConsumerWidget {
const Icon(IconsaxPlusLinear.search_normal),
const SizedBox(width: 16),
Transform.translate(
offset: const Offset(0, 2.5),
child: Text(searchTitle ?? "${context.localized.search}...")),
offset: const Offset(0, 1.5),
child: Text(searchTitle ?? "${context.localized.search}..."),
),
],
),
),
@ -73,7 +74,7 @@ class NestedSliverAppBar extends ConsumerWidget {
),
),
const SettingsUserIcon()
].addInBetween(const SizedBox(width: 16)),
],
),
),
),

View file

@ -49,7 +49,7 @@ class UserIcon extends ConsumerWidget {
elevation: 0,
surfaceTintColor: Colors.transparent,
color: Colors.transparent,
clipBehavior: Clip.antiAlias,
clipBehavior: Clip.hardEdge,
child: SizedBox.fromSize(
size: size,
child: Stack(