mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Add AppbarStyle.shadow;
Improve favorites page ui.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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),
|
||||||
),
|
),
|
||||||
|
@@ -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';
|
||||||
|
@@ -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),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
));
|
),
|
||||||
},
|
),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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"
|
||||||
|
Reference in New Issue
Block a user