mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-09 07:28:14 -07:00
feat: UI 2.0 and other Improvements (#357)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
9ca06eaa37
commit
e7b5bb40ff
169 changed files with 4584 additions and 3626 deletions
|
|
@ -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}) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue