mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-08 23:18:16 -07:00
feat: Improve library search screen (#477)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
571b682b80
commit
d22d340181
41 changed files with 2881 additions and 2026 deletions
|
|
@ -7,6 +7,7 @@ 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';
|
||||
import 'package:fladder/widgets/shared/button_group.dart';
|
||||
import 'package:fladder/widgets/shared/modal_bottom_sheet.dart';
|
||||
import 'package:fladder/widgets/shared/modal_side_sheet.dart';
|
||||
|
||||
|
|
@ -20,7 +21,6 @@ class CategoryChip<T> extends StatelessWidget {
|
|||
final VoidCallback? onCancel;
|
||||
final VoidCallback? onClear;
|
||||
final VoidCallback? onDismiss;
|
||||
|
||||
const CategoryChip({
|
||||
required this.label,
|
||||
this.dialogueTitle,
|
||||
|
|
@ -37,37 +37,21 @@ class CategoryChip<T> extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var selection = items.included.isNotEmpty;
|
||||
return FilterChip(
|
||||
selected: selection,
|
||||
showCheckmark: activeIcon == null,
|
||||
return ExpressiveButton(
|
||||
isSelected: selection,
|
||||
icon: selection ? Icon(activeIcon ?? IconsaxPlusBold.archive_tick) : null,
|
||||
label: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 6,
|
||||
children: [
|
||||
if (activeIcon != null)
|
||||
AnimatedSize(
|
||||
duration: const Duration(milliseconds: 250),
|
||||
child: selection
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: Icon(
|
||||
activeIcon!,
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
label,
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
Icons.arrow_drop_down_rounded,
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const Icon(
|
||||
IconsaxPlusLinear.arrow_down,
|
||||
size: 16,
|
||||
)
|
||||
],
|
||||
),
|
||||
onSelected: items.isNotEmpty
|
||||
? (_) async {
|
||||
onPressed: items.isNotEmpty
|
||||
? () async {
|
||||
final newEntry = await openActionSheet(context);
|
||||
if (newEntry != null) {
|
||||
onSave?.call(newEntry);
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ class _DetailScaffoldState extends ConsumerState<DetailScaffold> {
|
|||
onPressed: () => context.router.popBack(),
|
||||
icon: Padding(
|
||||
padding: EdgeInsets.all(AdaptiveLayout.of(context).inputDevice == InputDevice.pointer ? 0 : 4),
|
||||
child: const Icon(IconsaxPlusLinear.arrow_left_2),
|
||||
child: const BackButtonIcon(),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
await widget.poster.navigateTo(context);
|
||||
}
|
||||
|
||||
final posterRadius = FladderTheme.smallShape.borderRadius;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final poster = widget.poster;
|
||||
|
|
@ -101,7 +103,7 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
width: 1.0,
|
||||
color: Colors.white.withValues(alpha: 0.10),
|
||||
),
|
||||
borderRadius: FladderTheme.defaultShape.borderRadius,
|
||||
borderRadius: posterRadius,
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
|
|
@ -135,7 +137,7 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.15),
|
||||
border: Border.all(width: 3, color: Theme.of(context).colorScheme.primary),
|
||||
borderRadius: FladderTheme.defaultShape.borderRadius,
|
||||
borderRadius: posterRadius,
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Stack(
|
||||
|
|
@ -201,6 +203,102 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (widget.poster.unWatched)
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: StatusCard(
|
||||
color: Colors.amber,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.amber,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.inlineTitle)
|
||||
IgnorePointer(
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(
|
||||
widget.poster.title.maxLength(limitTo: 25),
|
||||
style:
|
||||
Theme.of(context).textTheme.labelLarge?.copyWith(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.poster.unPlayedItemCount != null && widget.poster is SeriesModel)
|
||||
IgnorePointer(
|
||||
child: Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: StatusCard(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
useFittedBox: widget.poster.unPlayedItemCount != 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: widget.poster.unPlayedItemCount != 0
|
||||
? Container(
|
||||
constraints: const BoxConstraints(minWidth: 16),
|
||||
child: Text(
|
||||
widget.poster.userData.unPlayedItemCount.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
overflow: TextOverflow.visible,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Icon(
|
||||
Icons.check_rounded,
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.poster.overview.runTime != null &&
|
||||
((widget.poster is PhotoModel) &&
|
||||
(widget.poster as PhotoModel).internalType == FladderItemType.video)) ...{
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Padding(
|
||||
padding: padding,
|
||||
child: Card(
|
||||
elevation: 5,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
widget.poster.overview.runTime.humanizeSmall ?? "",
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
//Desktop overlay
|
||||
if (AdaptiveLayout.of(context).inputDevice != InputDevice.touch &&
|
||||
widget.poster.type != FladderItemType.person)
|
||||
|
|
@ -215,7 +313,7 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.55),
|
||||
border: Border.all(width: 3, color: Theme.of(context).colorScheme.primary),
|
||||
borderRadius: FladderTheme.defaultShape.borderRadius,
|
||||
borderRadius: posterRadius,
|
||||
)),
|
||||
//Poster Button
|
||||
Focus(
|
||||
|
|
@ -317,102 +415,6 @@ class _PosterImageState extends ConsumerState<PosterImage> {
|
|||
},
|
||||
),
|
||||
),
|
||||
if (widget.poster.unWatched)
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: StatusCard(
|
||||
color: Colors.amber,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.amber,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.inlineTitle)
|
||||
IgnorePointer(
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(
|
||||
widget.poster.title.maxLength(limitTo: 25),
|
||||
style:
|
||||
Theme.of(context).textTheme.labelLarge?.copyWith(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.poster.unPlayedItemCount != null && widget.poster is SeriesModel)
|
||||
IgnorePointer(
|
||||
child: Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: StatusCard(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
useFittedBox: widget.poster.unPlayedItemCount != 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: widget.poster.unPlayedItemCount != 0
|
||||
? Container(
|
||||
constraints: const BoxConstraints(minWidth: 16),
|
||||
child: Text(
|
||||
widget.poster.userData.unPlayedItemCount.toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
overflow: TextOverflow.visible,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Icon(
|
||||
Icons.check_rounded,
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.poster.overview.runTime != null &&
|
||||
((widget.poster is PhotoModel) &&
|
||||
(widget.poster as PhotoModel).internalType == FladderItemType.video)) ...{
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: Padding(
|
||||
padding: padding,
|
||||
child: Card(
|
||||
elevation: 5,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
widget.poster.overview.runTime.humanizeSmall ?? "",
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class NestedScaffold extends ConsumerWidget {
|
|||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Theme.of(context).colorScheme.surface.withValues(alpha: backgroundOpacity),
|
||||
Theme.of(context).colorScheme.surface.withValues(alpha: backgroundOpacity - 0.15),
|
||||
Theme.of(context).colorScheme.surface.withValues(alpha: backgroundOpacity / 1.5),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import 'package:fladder/screens/shared/animated_fade_size.dart';
|
||||
import 'package:fladder/theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/screens/shared/animated_fade_size.dart';
|
||||
import 'package:fladder/theme.dart';
|
||||
|
||||
class OutlinedTextField extends ConsumerStatefulWidget {
|
||||
final String? label;
|
||||
final FocusNode? focusNode;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue