mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
improve ui
This commit is contained in:
@@ -73,8 +73,12 @@ class _AppbarState extends State<Appbar> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var content = SizedBox(
|
var content = Container(
|
||||||
height: _kAppBarHeight,
|
decoration: BoxDecoration(
|
||||||
|
color: widget.backgroundColor ??
|
||||||
|
context.colorScheme.surface.withOpacity(0.72),
|
||||||
|
),
|
||||||
|
height: _kAppBarHeight + context.padding.top,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -102,17 +106,12 @@ class _AppbarState extends State<Appbar> {
|
|||||||
width: 8,
|
width: 8,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
).paddingTop(context.padding.top),
|
||||||
).paddingTop(context.padding.top);
|
);
|
||||||
if (widget.backgroundColor != Colors.transparent) {
|
return BlurEffect(
|
||||||
return Material(
|
blur: _scrolledUnder ? 15 : 0,
|
||||||
elevation: (_scrolledUnder && context.width < changePoint) ? 1 : 0,
|
child: content,
|
||||||
surfaceTintColor: Theme.of(context).colorScheme.surfaceTint,
|
);
|
||||||
color: widget.backgroundColor ?? Theme.of(context).colorScheme.surface,
|
|
||||||
child: content,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +191,7 @@ class _MySliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
)
|
)
|
||||||
: const SizedBox()),
|
: const SizedBox()),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 24,
|
width: 16,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
|
@@ -735,6 +735,12 @@ class ComicListState extends State<ComicList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadPage(int page) async {
|
Future<void> _loadPage(int page) async {
|
||||||
|
if (widget.loadPage == null && widget.loadNext == null) {
|
||||||
|
_error = "loadPage and loadNext can't be null at the same time";
|
||||||
|
Future.microtask(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
}
|
||||||
if (_loading[page] == true) {
|
if (_loading[page] == true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -790,9 +796,6 @@ class ComicListState extends State<ComicList> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.loadPage == null && widget.loadNext == null) {
|
|
||||||
throw Exception("loadPage and loadNext can't be null at the same time");
|
|
||||||
}
|
|
||||||
if (_error != null) {
|
if (_error != null) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -814,19 +817,27 @@ class ComicListState extends State<ComicList> {
|
|||||||
}
|
}
|
||||||
if (_data[_page] == null) {
|
if (_data[_page] == null) {
|
||||||
_loadPage(_page);
|
_loadPage(_page);
|
||||||
return const Center(
|
return Column(
|
||||||
child: CircularProgressIndicator(),
|
children: [
|
||||||
|
if (widget.errorLeading != null) widget.errorLeading!,
|
||||||
|
const Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return SmoothCustomScrollView(
|
return SmoothCustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
if (widget.leadingSliver != null) widget.leadingSliver!,
|
if (widget.leadingSliver != null) widget.leadingSliver!,
|
||||||
_buildSliverPageSelector(),
|
if (_maxPage != 1) _buildSliverPageSelector(),
|
||||||
SliverGridComics(
|
SliverGridComics(
|
||||||
comics: _data[_page] ?? const [],
|
comics: _data[_page] ?? const [],
|
||||||
menuBuilder: widget.menuBuilder,
|
menuBuilder: widget.menuBuilder,
|
||||||
),
|
),
|
||||||
if (_data[_page]!.length > 6) _buildSliverPageSelector(),
|
if (_data[_page]!.length > 6 && _maxPage != 1)
|
||||||
|
_buildSliverPageSelector(),
|
||||||
if (widget.trailingSliver != null) widget.trailingSliver!,
|
if (widget.trailingSliver != null) widget.trailingSliver!,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@@ -148,7 +148,7 @@ class _NaviPaneState extends State<NaviPane>
|
|||||||
return _NaviPopScope(
|
return _NaviPopScope(
|
||||||
action: () {
|
action: () {
|
||||||
if (App.mainNavigatorKey!.currentState!.canPop()) {
|
if (App.mainNavigatorKey!.currentState!.canPop()) {
|
||||||
App.mainNavigatorKey!.currentState!.pop();
|
App.mainNavigatorKey!.currentState!.maybePop();
|
||||||
} else {
|
} else {
|
||||||
SystemNavigator.pop();
|
SystemNavigator.pop();
|
||||||
}
|
}
|
||||||
@@ -627,16 +627,9 @@ class _NaviPopScope extends StatelessWidget {
|
|||||||
? child
|
? child
|
||||||
: PopScope(
|
: PopScope(
|
||||||
canPop: App.isAndroid ? false : true,
|
canPop: App.isAndroid ? false : true,
|
||||||
// flutter <3.24.0 api
|
|
||||||
onPopInvoked: (value) {
|
|
||||||
action();
|
|
||||||
},
|
|
||||||
/*
|
|
||||||
flutter >=3.24.0 api
|
|
||||||
onPopInvokedWithResult: (value, result) {
|
onPopInvokedWithResult: (value, result) {
|
||||||
action();
|
action();
|
||||||
},
|
},
|
||||||
*/
|
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
if (popGesture) {
|
if (popGesture) {
|
||||||
|
@@ -116,6 +116,7 @@ mixin _AppRouteTransitionMixin<T> on PageRoute<T> {
|
|||||||
route.fullscreenDialog ||
|
route.fullscreenDialog ||
|
||||||
route.animation!.status != AnimationStatus.completed ||
|
route.animation!.status != AnimationStatus.completed ||
|
||||||
route.secondaryAnimation!.status != AnimationStatus.dismissed ||
|
route.secondaryAnimation!.status != AnimationStatus.dismissed ||
|
||||||
|
!route.popGestureEnabled ||
|
||||||
route.navigator!.userGestureInProgress) {
|
route.navigator!.userGestureInProgress) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -728,28 +728,32 @@ class ComicSourceParser {
|
|||||||
|
|
||||||
return retryZone(func);
|
return retryZone(func);
|
||||||
};
|
};
|
||||||
addFolder = (name) async {
|
if(_checkExists("favorites.addFolder")) {
|
||||||
try {
|
addFolder = (name) async {
|
||||||
await JsEngine().runCode("""
|
try {
|
||||||
|
await JsEngine().runCode("""
|
||||||
ComicSource.sources.$_key.favorites.addFolder(${jsonEncode(name)})
|
ComicSource.sources.$_key.favorites.addFolder(${jsonEncode(name)})
|
||||||
""");
|
""");
|
||||||
return const Res(true);
|
return const Res(true);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Log.error("Network", "$e\n$s");
|
Log.error("Network", "$e\n$s");
|
||||||
return Res.error(e.toString());
|
return Res.error(e.toString());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
deleteFolder = (key) async {
|
}
|
||||||
try {
|
if(_checkExists("favorites.deleteFolder")) {
|
||||||
await JsEngine().runCode("""
|
deleteFolder = (key) async {
|
||||||
|
try {
|
||||||
|
await JsEngine().runCode("""
|
||||||
ComicSource.sources.$_key.favorites.deleteFolder(${jsonEncode(key)})
|
ComicSource.sources.$_key.favorites.deleteFolder(${jsonEncode(key)})
|
||||||
""");
|
""");
|
||||||
return const Res(true);
|
return const Res(true);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Log.error("Network", "$e\n$s");
|
Log.error("Network", "$e\n$s");
|
||||||
return Res.error(e.toString());
|
return Res.error(e.toString());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FavoriteData(
|
return FavoriteData(
|
||||||
|
@@ -153,6 +153,8 @@ class HistoryManager with ChangeNotifier {
|
|||||||
|
|
||||||
Map<String, bool>? _cachedHistory;
|
Map<String, bool>? _cachedHistory;
|
||||||
|
|
||||||
|
static const _kMaxHistoryLength = 200;
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
_db = sqlite3.open("${App.dataPath}/history.db");
|
_db = sqlite3.open("${App.dataPath}/history.db");
|
||||||
|
|
||||||
@@ -176,6 +178,12 @@ class HistoryManager with ChangeNotifier {
|
|||||||
///
|
///
|
||||||
/// This function would be called when user start reading.
|
/// This function would be called when user start reading.
|
||||||
Future<void> addHistory(History newItem) async {
|
Future<void> addHistory(History newItem) async {
|
||||||
|
while(count() >= _kMaxHistoryLength) {
|
||||||
|
_db.execute("""
|
||||||
|
delete from history
|
||||||
|
where time == (select min(time) from history);
|
||||||
|
""");
|
||||||
|
}
|
||||||
_db.execute("""
|
_db.execute("""
|
||||||
insert or replace into history (id, title, subtitle, cover, time, type, ep, page, readEpisode, max_page)
|
insert or replace into history (id, title, subtitle, cover, time, type, ep, page, readEpisode, max_page)
|
||||||
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
@@ -207,6 +215,7 @@ class HistoryManager with ChangeNotifier {
|
|||||||
where id == ? and type == ?;
|
where id == ? and type == ?;
|
||||||
""", [id, type.value]);
|
""", [id, type.value]);
|
||||||
updateCache();
|
updateCache();
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<History?> find(String id, ComicType type) async {
|
Future<History?> find(String id, ComicType type) async {
|
||||||
|
@@ -56,13 +56,16 @@ class _CategoryComicsPageState extends State<CategoryComicsPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var topPadding = context.padding.top + 56.0;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
appBar: Appbar(
|
appBar: Appbar(
|
||||||
title: Text(widget.category),
|
title: Text(widget.category),
|
||||||
),
|
),
|
||||||
body: ComicList(
|
body: ComicList(
|
||||||
key: Key(widget.category + optionsValue.toString()),
|
key: Key(widget.category + optionsValue.toString()),
|
||||||
leadingSliver: buildOptions().toSliver(),
|
errorLeading: SizedBox(height: topPadding),
|
||||||
|
leadingSliver: buildOptions().paddingTop(topPadding).toSliver(),
|
||||||
loadPage: (i) => data.load(
|
loadPage: (i) => data.load(
|
||||||
widget.category,
|
widget.category,
|
||||||
widget.param,
|
widget.param,
|
||||||
|
@@ -92,6 +92,9 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
|
|||||||
@override
|
@override
|
||||||
Future<Res<ComicDetails>> loadData() async {
|
Future<Res<ComicDetails>> loadData() async {
|
||||||
var comicSource = ComicSource.find(widget.sourceKey);
|
var comicSource = ComicSource.find(widget.sourceKey);
|
||||||
|
if(comicSource == null) {
|
||||||
|
return const Res.error('Comic source not found');
|
||||||
|
}
|
||||||
isAddToLocalFav = LocalFavoritesManager().isExist(
|
isAddToLocalFav = LocalFavoritesManager().isExist(
|
||||||
widget.id,
|
widget.id,
|
||||||
ComicType(widget.sourceKey.hashCode),
|
ComicType(widget.sourceKey.hashCode),
|
||||||
|
@@ -206,6 +206,7 @@ class _BodyState extends State<_Body> {
|
|||||||
source.data['settings'][key] ?? item.value['default'] ?? '';
|
source.data['settings'][key] ?? item.value['default'] ?? '';
|
||||||
yield ListTile(
|
yield ListTile(
|
||||||
title: Text((item.value['title'] as String).ts(source.key)),
|
title: Text((item.value['title'] as String).ts(source.key)),
|
||||||
|
subtitle: Text(current, maxLines: 1, overflow: TextOverflow.ellipsis),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.edit),
|
icon: const Icon(Icons.edit),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
@@ -71,11 +71,16 @@ class NetworkFavoritePage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NormalFavoritePage extends StatelessWidget {
|
class _NormalFavoritePage extends StatefulWidget {
|
||||||
_NormalFavoritePage(this.data);
|
const _NormalFavoritePage(this.data);
|
||||||
|
|
||||||
final FavoriteData data;
|
final FavoriteData data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_NormalFavoritePage> createState() => _NormalFavoritePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NormalFavoritePageState extends State<_NormalFavoritePage> {
|
||||||
final comicListKey = GlobalKey<ComicListState>();
|
final comicListKey = GlobalKey<ComicListState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -95,7 +100,7 @@ class _NormalFavoritePage extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(data.title),
|
title: Text(widget.data.title),
|
||||||
),
|
),
|
||||||
errorLeading: Appbar(
|
errorLeading: Appbar(
|
||||||
leading: Tooltip(
|
leading: Tooltip(
|
||||||
@@ -110,10 +115,10 @@ class _NormalFavoritePage extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
title: Text(data.title),
|
title: Text(widget.data.title),
|
||||||
),
|
),
|
||||||
loadPage: data.loadComic == null ? null : (i) => data.loadComic!(i),
|
loadPage: widget.data.loadComic == null ? null : (i) => widget.data.loadComic!(i),
|
||||||
loadNext: data.loadNext == null ? null : (next) => data.loadNext!(next),
|
loadNext: widget.data.loadNext == null ? null : (next) => widget.data.loadNext!(next),
|
||||||
menuBuilder: (comic) {
|
menuBuilder: (comic) {
|
||||||
return [
|
return [
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
@@ -280,7 +285,7 @@ class _MultiFolderFavoritesPageState extends State<_MultiFolderFavoritesPage> {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
maxCrossAxisExtent: 450,
|
maxCrossAxisExtent: 450,
|
||||||
itemHeight: 64,
|
itemHeight: 52,
|
||||||
),
|
),
|
||||||
if (widget.data.addFolder != null)
|
if (widget.data.addFolder != null)
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
@@ -342,17 +347,13 @@ class _FolderTile extends StatelessWidget {
|
|||||||
return Material(
|
return Material(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8, 8, 16, 8),
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
Icon(
|
Icon(
|
||||||
Icons.folder,
|
Icons.folder,
|
||||||
size: 35,
|
size: 28,
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@@ -370,15 +371,11 @@ class _FolderTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
if (deleteFolder != null)
|
if (deleteFolder != null)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.delete_forever_outlined),
|
icon: const Icon(Icons.delete_outline),
|
||||||
onPressed: () => onDeleteFolder(context),
|
onPressed: () => onDeleteFolder(context),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
const Icon(Icons.arrow_right),
|
const Icon(Icons.arrow_right),
|
||||||
if (deleteFolder == null)
|
|
||||||
const SizedBox(
|
|
||||||
width: 8,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@@ -85,7 +85,7 @@ class _HistoryPageState extends State<HistoryPage> {
|
|||||||
e.subtitle,
|
e.subtitle,
|
||||||
null,
|
null,
|
||||||
getDescription(e),
|
getDescription(e),
|
||||||
e.type.comicSource?.key ?? "Invalid",
|
e.type.comicSource?.key ?? "Invalid:${e.type.value}",
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
@@ -100,10 +100,17 @@ class _HistoryPageState extends State<HistoryPage> {
|
|||||||
icon: Icons.remove,
|
icon: Icons.remove,
|
||||||
text: 'Remove'.tl,
|
text: 'Remove'.tl,
|
||||||
onClick: () {
|
onClick: () {
|
||||||
HistoryManager().remove(
|
if(c.sourceKey.startsWith("Invalid")) {
|
||||||
c.id,
|
HistoryManager().remove(
|
||||||
ComicType(c.sourceKey.hashCode),
|
c.id,
|
||||||
);
|
ComicType(int.parse(c.sourceKey.split(':')[1])),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
HistoryManager().remove(
|
||||||
|
c.id,
|
||||||
|
ComicType(c.sourceKey.hashCode),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@@ -38,23 +38,23 @@ class _RankingPageState extends State<RankingPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var topPadding = context.padding.top + 56;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
appBar: Appbar(
|
appBar: Appbar(
|
||||||
title: Text("Ranking".tl),
|
title: Text("Ranking".tl),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: ComicList(
|
||||||
children: [
|
key: Key(optionValue),
|
||||||
Expanded(
|
errorLeading: SizedBox(height: topPadding),
|
||||||
child: ComicList(
|
leadingSliver:
|
||||||
loadPage: data.rankingData!.load == null
|
buildOptions().sliverPadding(EdgeInsets.only(top: topPadding)),
|
||||||
? null
|
loadPage: data.rankingData!.load == null
|
||||||
: (i) => data.rankingData!.load!(optionValue, i),
|
? null
|
||||||
loadNext: data.rankingData!.loadWithNext == null
|
: (i) => data.rankingData!.load!(optionValue, i),
|
||||||
? null
|
loadNext: data.rankingData!.loadWithNext == null
|
||||||
: (i) => data.rankingData!.loadWithNext!(optionValue, i),
|
? null
|
||||||
),
|
: (i) => data.rankingData!.loadWithNext!(optionValue, i),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user