Add AppbarStyle.shadow;

Improve favorites page ui.
This commit is contained in:
2024-11-23 12:12:52 +08:00
parent a1474ca9c3
commit c2b8760d86
6 changed files with 219 additions and 200 deletions

View File

@@ -115,6 +115,11 @@ class _AppbarState extends State<Appbar> {
} }
} }
enum AppbarStyle {
blur,
shadow,
}
class SliverAppbar extends StatelessWidget { class SliverAppbar extends StatelessWidget {
const SliverAppbar({ const SliverAppbar({
super.key, super.key,
@@ -122,6 +127,7 @@ class SliverAppbar extends StatelessWidget {
this.leading, this.leading,
this.actions, this.actions,
this.radius = 0, this.radius = 0,
this.style = AppbarStyle.blur,
}); });
final Widget? leading; final Widget? leading;
@@ -132,6 +138,8 @@ class SliverAppbar extends StatelessWidget {
final double radius; final double radius;
final AppbarStyle style;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SliverPersistentHeader( return SliverPersistentHeader(
@@ -142,6 +150,7 @@ class SliverAppbar extends StatelessWidget {
actions: actions, actions: actions,
topPadding: MediaQuery.of(context).padding.top, topPadding: MediaQuery.of(context).padding.top,
radius: radius, radius: radius,
style: style,
), ),
); );
} }
@@ -160,57 +169,74 @@ class _MySliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final double radius; final double radius;
_MySliverAppBarDelegate( final AppbarStyle style;
{this.leading,
required this.title, _MySliverAppBarDelegate({
this.actions, this.leading,
required this.topPadding, required this.title,
this.radius = 0}); this.actions,
required this.topPadding,
this.radius = 0,
this.style = AppbarStyle.blur,
});
@override @override
Widget build( Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) { BuildContext context, double shrinkOffset, bool overlapsContent) {
return SizedBox.expand( var body = Row(
child: BlurEffect( children: [
blur: 15, const SizedBox(width: 8),
child: Material( leading ??
color: context.colorScheme.surface.withOpacity(0.72), (Navigator.of(context).canPop()
elevation: 0, ? Tooltip(
borderRadius: BorderRadius.circular(radius), message: "Back".tl,
child: Row( child: IconButton(
children: [ icon: const Icon(Icons.arrow_back),
const SizedBox(width: 8), onPressed: () => Navigator.maybePop(context),
leading ??
(Navigator.of(context).canPop()
? Tooltip(
message: "Back".tl,
child: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.maybePop(context),
),
)
: const SizedBox()),
const SizedBox(
width: 16,
), ),
Expanded( )
child: DefaultTextStyle( : const SizedBox()),
style: const SizedBox(
DefaultTextStyle.of(context).style.copyWith(fontSize: 20), width: 16,
maxLines: 1,
overflow: TextOverflow.ellipsis,
child: title,
),
),
...?actions,
const SizedBox(
width: 8,
)
],
).paddingTop(topPadding),
), ),
), Expanded(
); child: DefaultTextStyle(
style:
DefaultTextStyle.of(context).style.copyWith(fontSize: 20),
maxLines: 1,
overflow: TextOverflow.ellipsis,
child: title,
),
),
...?actions,
const SizedBox(
width: 8,
)
],
).paddingTop(topPadding);
if(style == AppbarStyle.blur) {
return SizedBox.expand(
child: BlurEffect(
blur: 15,
child: Material(
color: context.colorScheme.surface.withOpacity(0.72),
elevation: 0,
borderRadius: BorderRadius.circular(radius),
child: body,
),
),
);
} else {
return SizedBox.expand(
child: Material(
color: context.colorScheme.surface,
elevation: shrinkOffset == 0 ? 0 : 2,
borderRadius: BorderRadius.circular(radius),
child: body,
),
);
}
} }
@override @override
@@ -224,7 +250,10 @@ class _MySliverAppBarDelegate extends SliverPersistentHeaderDelegate {
return oldDelegate is! _MySliverAppBarDelegate || return oldDelegate is! _MySliverAppBarDelegate ||
leading != oldDelegate.leading || leading != oldDelegate.leading ||
title != oldDelegate.title || title != oldDelegate.title ||
actions != oldDelegate.actions; actions != oldDelegate.actions ||
topPadding != oldDelegate.topPadding ||
radius != oldDelegate.radius ||
style != oldDelegate.style;
} }
} }

View File

@@ -778,7 +778,7 @@ class _SliverGridComics extends StatelessWidget {
duration: const Duration(milliseconds: 150), duration: const Duration(milliseconds: 150),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected color: isSelected
? Theme.of(context).colorScheme.secondaryContainer ? Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.72)
: null, : null,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),

View File

@@ -9,6 +9,7 @@ import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/appdata.dart'; import 'package:venera/foundation/appdata.dart';
import 'package:venera/foundation/comic_source/comic_source.dart'; import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/comic_type.dart'; import 'package:venera/foundation/comic_type.dart';
import 'package:venera/foundation/consts.dart';
import 'package:venera/foundation/favorites.dart'; import 'package:venera/foundation/favorites.dart';
import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/local.dart';
import 'package:venera/foundation/res.dart'; import 'package:venera/foundation/res.dart';

View File

@@ -74,6 +74,9 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
body: SmoothCustomScrollView(slivers: [ body: SmoothCustomScrollView(slivers: [
if (!searchMode && !multiSelectMode) if (!searchMode && !multiSelectMode)
SliverAppbar( SliverAppbar(
style: context.width < changePoint
? AppbarStyle.shadow
: AppbarStyle.blur,
leading: Tooltip( leading: Tooltip(
message: "Folders".tl, message: "Folders".tl,
child: context.width <= _kTwoPanelChangeWidth child: context.width <= _kTwoPanelChangeWidth
@@ -225,8 +228,7 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
showConfirmDialog( showConfirmDialog(
context: App.rootContext, context: App.rootContext,
title: "Delete".tl, title: "Delete".tl,
content: content: "Delete folder '@f' ?".tlParams({
"Delete folder '@f' ?".tlParams({
"f": widget.folder, "f": widget.folder,
}), }),
btnColor: context.colorScheme.error, btnColor: context.colorScheme.error,
@@ -243,6 +245,9 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
) )
else if (multiSelectMode) else if (multiSelectMode)
SliverAppbar( SliverAppbar(
style: context.width < changePoint
? AppbarStyle.shadow
: AppbarStyle.blur,
leading: Tooltip( leading: Tooltip(
message: "Cancel".tl, message: "Cancel".tl,
child: IconButton( child: IconButton(
@@ -287,8 +292,8 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
showConfirmDialog( showConfirmDialog(
context: context, context: context,
title: "Delete".tl, title: "Delete".tl,
content: content: "Delete @c comics?"
"Delete @c comics?".tlParams({"c": selectedComics.length}), .tlParams({"c": selectedComics.length}),
btnColor: context.colorScheme.error, btnColor: context.colorScheme.error,
onConfirm: () { onConfirm: () {
_deleteComicWithId(); _deleteComicWithId();
@@ -300,6 +305,9 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
) )
else if (searchMode) else if (searchMode)
SliverAppbar( SliverAppbar(
style: context.width < changePoint
? AppbarStyle.shadow
: AppbarStyle.blur,
leading: Tooltip( leading: Tooltip(
message: "Cancel".tl, message: "Cancel".tl,
child: IconButton( child: IconButton(
@@ -407,159 +415,134 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
.where((folder) => folder != favPage.folder) .where((folder) => folder != favPage.folder)
.toList(); .toList();
showDialog( showPopUpWidget(
context: App.rootContext, App.rootContext,
builder: (context) { StatefulBuilder(
return StatefulBuilder( builder: (context, setState) {
builder: (context, setState) { return PopUpWidgetScaffold(
return Dialog( title: favPage.folder ?? "Unselected".tl,
shape: RoundedRectangleBorder( body: Padding(
borderRadius: BorderRadius.circular(12.0), padding: EdgeInsets.only(bottom: context.padding.bottom + 16),
), child: Container(
child: Padding( constraints:
padding: const EdgeInsets.only(bottom: 50), const BoxConstraints(maxHeight: 700, maxWidth: 500),
child: Container( child: Column(
constraints: children: [
const BoxConstraints(maxHeight: 700, maxWidth: 500), Expanded(
child: Column( child: ListView.builder(
children: [ itemCount: targetFolders.length + 1,
Container( itemBuilder: (context, index) {
decoration: const BoxDecoration( if (index == targetFolders.length) {
borderRadius: BorderRadius.vertical( return SizedBox(
top: Radius.circular(12.0), height: 36,
), child: Center(
), child: TextButton(
padding: const EdgeInsets.all(16.0), onPressed: () {
child: Center( newFolder().then((v) {
child: Text( setState(() {
favPage.folder ?? "Unselected".tl, targetFolders = LocalFavoritesManager()
style: const TextStyle( .folderNames
fontSize: 18, .where((folder) =>
fontWeight: FontWeight.bold, folder != favPage.folder)
.toList();
});
});
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.add, size: 20),
const SizedBox(width: 4),
Text("New Folder".tl),
],
),
),
), ),
);
}
var folder = targetFolders[index];
var disabled = false;
if (selectedLocalFolders.isNotEmpty) {
if (added.contains(folder) &&
!added.contains(selectedLocalFolders.first)) {
disabled = true;
} else if (!added.contains(folder) &&
added.contains(selectedLocalFolders.first)) {
disabled = true;
}
}
return CheckboxListTile(
title: Row(
children: [
Text(folder),
const SizedBox(width: 8),
],
), ),
), value: selectedLocalFolders.contains(folder),
), onChanged: disabled
Expanded( ? null
child: ListView.builder( : (v) {
itemCount: targetFolders.length + 1, setState(() {
itemBuilder: (context, index) { if (v!) {
if (index == targetFolders.length) { selectedLocalFolders.add(folder);
return SizedBox( } else {
height: 36, selectedLocalFolders.remove(folder);
child: Center( }
child: TextButton( });
onPressed: () { },
newFolder().then((v) { );
setState(() { },
targetFolders = ),
LocalFavoritesManager() ),
.folderNames Center(
.where((folder) => child: FilledButton(
folder != onPressed: () {
favPage.folder) if (selectedLocalFolders.isEmpty) {
.toList(); return;
}); }
}); if (option == 'move') {
}, for (var c in selectedComics.keys) {
child: Row( for (var s in selectedLocalFolders) {
mainAxisSize: MainAxisSize.min, LocalFavoritesManager().moveFavorite(
children: [ favPage.folder as String,
const Icon(Icons.add, size: 20), s,
const SizedBox(width: 4), c.id,
Text("New Folder".tl), (c as FavoriteItem).type);
], }
), }
), } else {
for (var c in selectedComics.keys) {
for (var s in selectedLocalFolders) {
LocalFavoritesManager().addComic(
s,
FavoriteItem(
id: c.id,
name: c.title,
coverPath: c.cover,
author: c.subtitle ?? '',
type: ComicType((c.sourceKey == 'local'
? 0
: c.sourceKey.hashCode)),
tags: c.tags ?? [],
), ),
); );
} }
var folder = targetFolders[index]; }
var disabled = false; }
if (selectedLocalFolders.isNotEmpty) { App.rootContext.pop();
if (added.contains(folder) && updateComics();
!added _cancel();
.contains(selectedLocalFolders.first)) { },
disabled = true; child: Text(option == 'move' ? "Move".tl : "Add".tl),
} else if (!added.contains(folder) && ),
added
.contains(selectedLocalFolders.first)) {
disabled = true;
}
}
return CheckboxListTile(
title: Row(
children: [
Text(folder),
const SizedBox(width: 8),
],
),
value: selectedLocalFolders.contains(folder),
onChanged: disabled
? null
: (v) {
setState(() {
if (v!) {
selectedLocalFolders.add(folder);
} else {
selectedLocalFolders.remove(folder);
}
});
},
);
},
),
),
Center(
child: FilledButton(
onPressed: () {
if (selectedLocalFolders.isEmpty) {
return;
}
if (option == 'move') {
for (var c in selectedComics.keys) {
for (var s in selectedLocalFolders) {
LocalFavoritesManager().moveFavorite(
favPage.folder as String,
s,
c.id,
(c as FavoriteItem).type);
}
}
} else {
for (var c in selectedComics.keys) {
for (var s in selectedLocalFolders) {
LocalFavoritesManager().addComic(
s,
FavoriteItem(
id: c.id,
name: c.title,
coverPath: c.cover,
author: c.subtitle ?? '',
type: ComicType((c.sourceKey == 'local'
? 0
: c.sourceKey.hashCode)),
tags: c.tags ?? [],
),
);
}
}
}
context.pop();
updateComics();
_cancel();
},
child:
Text(option == 'move' ? "Move".tl : "Add".tl),
).paddingVertical(16),
),
],
), ),
), ],
)); ),
}, ),
); ),
}, );
},
),
); );
} }

View File

@@ -94,6 +94,9 @@ class _NormalFavoritePageState extends State<_NormalFavoritePage> {
return ComicList( return ComicList(
key: comicListKey, key: comicListKey,
leadingSliver: SliverAppbar( leadingSliver: SliverAppbar(
style: context.width < changePoint
? AppbarStyle.shadow
: AppbarStyle.blur,
leading: Tooltip( leading: Tooltip(
message: "Folders".tl, message: "Folders".tl,
child: context.width <= _kTwoPanelChangeWidth child: context.width <= _kTwoPanelChangeWidth
@@ -211,6 +214,9 @@ class _MultiFolderFavoritesPageState extends State<_MultiFolderFavoritesPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var sliverAppBar = SliverAppbar( var sliverAppBar = SliverAppbar(
style: context.width < changePoint
? AppbarStyle.shadow
: AppbarStyle.blur,
leading: Tooltip( leading: Tooltip(
message: "Folders".tl, message: "Folders".tl,
child: context.width <= _kTwoPanelChangeWidth child: context.width <= _kTwoPanelChangeWidth

View File

@@ -393,8 +393,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: HEAD ref: "829a566b738a26ea98e523807f49838e21308543"
resolved-ref: "51a27e2ca0e05becfb8ee3a506294dc4460721a8" resolved-ref: "829a566b738a26ea98e523807f49838e21308543"
url: "https://github.com/pkuislm/flutter_saf.git" url: "https://github.com/pkuislm/flutter_saf.git"
source: git source: git
version: "0.0.1" version: "0.0.1"