mirror of
https://github.com/venera-app/venera.git
synced 2025-12-16 07:01:16 +00:00
Merge pull request #594 from lings03/favorite
Optimize favorite page and home page.
This commit is contained in:
@@ -753,9 +753,9 @@ class SliverGridComics extends StatefulWidget {
|
|||||||
|
|
||||||
final List<MenuEntry> Function(Comic)? menuBuilder;
|
final List<MenuEntry> Function(Comic)? menuBuilder;
|
||||||
|
|
||||||
final void Function(Comic)? onTap;
|
final void Function(Comic, int heroID)? onTap;
|
||||||
|
|
||||||
final void Function(Comic)? onLongPressed;
|
final void Function(Comic, int heroID)? onLongPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SliverGridComics> createState() => _SliverGridComicsState();
|
State<SliverGridComics> createState() => _SliverGridComicsState();
|
||||||
@@ -856,28 +856,30 @@ class _SliverGridComics extends StatelessWidget {
|
|||||||
|
|
||||||
final List<MenuEntry> Function(Comic)? menuBuilder;
|
final List<MenuEntry> Function(Comic)? menuBuilder;
|
||||||
|
|
||||||
final void Function(Comic)? onTap;
|
final void Function(Comic, int heroID)? onTap;
|
||||||
|
|
||||||
final void Function(Comic)? onLongPressed;
|
final void Function(Comic, int heroID)? onLongPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverGrid(
|
return SliverGrid(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate((context, index) {
|
||||||
(context, index) {
|
|
||||||
if (index == comics.length - 1) {
|
if (index == comics.length - 1) {
|
||||||
onLastItemBuild?.call();
|
onLastItemBuild?.call();
|
||||||
}
|
}
|
||||||
var badge = badgeBuilder?.call(comics[index]);
|
var badge = badgeBuilder?.call(comics[index]);
|
||||||
var isSelected =
|
var isSelected = selection == null
|
||||||
selection == null ? false : selection![comics[index]] ?? false;
|
? false
|
||||||
|
: selection![comics[index]] ?? false;
|
||||||
var comic = ComicTile(
|
var comic = ComicTile(
|
||||||
comic: comics[index],
|
comic: comics[index],
|
||||||
badge: badge,
|
badge: badge,
|
||||||
menuOptions: menuBuilder?.call(comics[index]),
|
menuOptions: menuBuilder?.call(comics[index]),
|
||||||
onTap: onTap != null ? () => onTap!(comics[index]) : null,
|
onTap: onTap != null
|
||||||
|
? () => onTap!(comics[index], heroIDs[index])
|
||||||
|
: null,
|
||||||
onLongPressed: onLongPressed != null
|
onLongPressed: onLongPressed != null
|
||||||
? () => onLongPressed!(comics[index])
|
? () => onLongPressed!(comics[index], heroIDs[index])
|
||||||
: null,
|
: null,
|
||||||
heroID: heroIDs[index],
|
heroID: heroIDs[index],
|
||||||
);
|
);
|
||||||
@@ -889,19 +891,16 @@ 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)
|
? Theme.of(
|
||||||
.colorScheme
|
context,
|
||||||
.secondaryContainer
|
).colorScheme.secondaryContainer.toOpacity(0.72)
|
||||||
.toOpacity(0.72)
|
|
||||||
: null,
|
: null,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(4),
|
margin: const EdgeInsets.all(4),
|
||||||
child: comic,
|
child: comic,
|
||||||
);
|
);
|
||||||
},
|
}, childCount: comics.length),
|
||||||
childCount: comics.length,
|
|
||||||
),
|
|
||||||
gridDelegate: SliverGridDelegateWithComics(),
|
gridDelegate: SliverGridDelegateWithComics(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1627,7 +1626,7 @@ class _SMClipper extends CustomClipper<Rect> {
|
|||||||
|
|
||||||
class SimpleComicTile extends StatelessWidget {
|
class SimpleComicTile extends StatelessWidget {
|
||||||
const SimpleComicTile(
|
const SimpleComicTile(
|
||||||
{super.key, required this.comic, this.onTap, this.withTitle = false});
|
{super.key, required this.comic, this.onTap, this.withTitle = false, this.heroID});
|
||||||
|
|
||||||
final Comic comic;
|
final Comic comic;
|
||||||
|
|
||||||
@@ -1635,6 +1634,8 @@ class SimpleComicTile extends StatelessWidget {
|
|||||||
|
|
||||||
final bool withTitle;
|
final bool withTitle;
|
||||||
|
|
||||||
|
final int? heroID;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var image = _findImageProvider(comic);
|
var image = _findImageProvider(comic);
|
||||||
@@ -1660,6 +1661,13 @@ class SimpleComicTile extends StatelessWidget {
|
|||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (heroID != null) {
|
||||||
|
child = Hero(
|
||||||
|
tag: "cover$heroID",
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
child = AnimatedTapRegion(
|
child = AnimatedTapRegion(
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
onTap: onTap ??
|
onTap: onTap ??
|
||||||
@@ -1668,6 +1676,9 @@ class SimpleComicTile extends StatelessWidget {
|
|||||||
() => ComicPage(
|
() => ComicPage(
|
||||||
id: comic.id,
|
id: comic.id,
|
||||||
sourceKey: comic.sourceKey,
|
sourceKey: comic.sourceKey,
|
||||||
|
cover: comic.cover,
|
||||||
|
title: comic.title,
|
||||||
|
heroID: heroID,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -241,6 +241,10 @@ class _AppScrollBarState extends State<AppScrollBar> {
|
|||||||
|
|
||||||
late final VerticalDragGestureRecognizer _dragGestureRecognizer;
|
late final VerticalDragGestureRecognizer _dragGestureRecognizer;
|
||||||
|
|
||||||
|
bool _isVisible = false;
|
||||||
|
Timer? _hideTimer;
|
||||||
|
static const _hideDuration = Duration(seconds: 2);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -248,7 +252,41 @@ class _AppScrollBarState extends State<AppScrollBar> {
|
|||||||
_scrollController.addListener(onChanged);
|
_scrollController.addListener(onChanged);
|
||||||
Future.microtask(onChanged);
|
Future.microtask(onChanged);
|
||||||
_dragGestureRecognizer = VerticalDragGestureRecognizer()
|
_dragGestureRecognizer = VerticalDragGestureRecognizer()
|
||||||
..onUpdate = onUpdate;
|
..onUpdate = onUpdate
|
||||||
|
..onStart = (_) {
|
||||||
|
_showScrollbar();
|
||||||
|
}
|
||||||
|
..onEnd = (_) {
|
||||||
|
_scheduleHide();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_hideTimer?.cancel();
|
||||||
|
_scrollController.removeListener(onChanged);
|
||||||
|
_dragGestureRecognizer.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showScrollbar() {
|
||||||
|
if (!_isVisible && mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isVisible = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_hideTimer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _scheduleHide() {
|
||||||
|
_hideTimer?.cancel();
|
||||||
|
_hideTimer = Timer(_hideDuration, () {
|
||||||
|
if (mounted && _isVisible) {
|
||||||
|
setState(() {
|
||||||
|
_isVisible = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdate(DragUpdateDetails details) {
|
void onUpdate(DragUpdateDetails details) {
|
||||||
@@ -269,14 +307,24 @@ class _AppScrollBarState extends State<AppScrollBar> {
|
|||||||
void onChanged() {
|
void onChanged() {
|
||||||
if (_scrollController.positions.isEmpty) return;
|
if (_scrollController.positions.isEmpty) return;
|
||||||
var position = _scrollController.position;
|
var position = _scrollController.position;
|
||||||
|
|
||||||
|
bool hasChanged = false;
|
||||||
if (position.minScrollExtent != minExtent ||
|
if (position.minScrollExtent != minExtent ||
|
||||||
position.maxScrollExtent != maxExtent ||
|
position.maxScrollExtent != maxExtent ||
|
||||||
position.pixels != this.position) {
|
position.pixels != this.position) {
|
||||||
setState(() {
|
hasChanged = true;
|
||||||
minExtent = position.minScrollExtent;
|
minExtent = position.minScrollExtent;
|
||||||
maxExtent = position.maxScrollExtent;
|
maxExtent = position.maxScrollExtent;
|
||||||
this.position = position.pixels;
|
this.position = position.pixels;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (hasChanged) {
|
||||||
|
_showScrollbar();
|
||||||
|
_scheduleHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChanged && mounted) {
|
||||||
|
setState(() {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,8 +348,13 @@ class _AppScrollBarState extends State<AppScrollBar> {
|
|||||||
Positioned(
|
Positioned(
|
||||||
top: top + widget.topPadding,
|
top: top + widget.topPadding,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
opacity: _isVisible ? 1.0 : 0.0,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
|
onEnter: (_) => _showScrollbar(),
|
||||||
|
onExit: (_) => _scheduleHide(),
|
||||||
child: Listener(
|
child: Listener(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
onPointerDown: (event) {
|
onPointerDown: (event) {
|
||||||
@@ -328,6 +381,7 @@ class _AppScrollBarState extends State<AppScrollBar> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -689,7 +689,7 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
onTap: (c) {
|
onTap: (c, heroID) {
|
||||||
if (multiSelectMode) {
|
if (multiSelectMode) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedComics.containsKey(c as FavoriteItem)) {
|
if (selectedComics.containsKey(c as FavoriteItem)) {
|
||||||
@@ -701,20 +701,24 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
|||||||
lastSelectedIndex = comics.indexOf(c);
|
lastSelectedIndex = comics.indexOf(c);
|
||||||
});
|
});
|
||||||
} else if (appdata.settings["onClickFavorite"] == "viewDetail") {
|
} else if (appdata.settings["onClickFavorite"] == "viewDetail") {
|
||||||
App.mainNavigatorKey?.currentContext
|
|
||||||
?.to(() => ComicPage(id: c.id, sourceKey: c.sourceKey));
|
|
||||||
} else {
|
|
||||||
App.mainNavigatorKey?.currentContext?.to(
|
App.mainNavigatorKey?.currentContext?.to(
|
||||||
() => ReaderWithLoading(
|
() => ComicPage(
|
||||||
id: c.id,
|
id: c.id,
|
||||||
sourceKey: c.sourceKey,
|
sourceKey: c.sourceKey,
|
||||||
|
cover: c.cover,
|
||||||
|
title: c.title,
|
||||||
|
heroID: heroID,
|
||||||
),
|
),
|
||||||
enableIOSGesture: false,
|
enableIOSGesture: false,
|
||||||
iosFullScreenGesture: false,
|
iosFullScreenGesture: false,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
App.mainNavigatorKey?.currentContext?.to(
|
||||||
|
() => ReaderWithLoading(id: c.id, sourceKey: c.sourceKey),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPressed: (c) {
|
onLongPressed: (c, heroID) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (!multiSelectMode) {
|
if (!multiSelectMode) {
|
||||||
multiSelectMode = true;
|
multiSelectMode = true;
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ class _HistoryPageState extends State<HistoryPage> {
|
|||||||
selections: selectedComics,
|
selections: selectedComics,
|
||||||
onLongPressed: null,
|
onLongPressed: null,
|
||||||
onTap: multiSelectMode
|
onTap: multiSelectMode
|
||||||
? (c) {
|
? (c, heroID) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedComics.containsKey(c as History)) {
|
if (selectedComics.containsKey(c as History)) {
|
||||||
selectedComics.remove(c);
|
selectedComics.remove(c);
|
||||||
|
|||||||
@@ -302,13 +302,18 @@ class _HistoryState extends State<_History> {
|
|||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemCount: history.length,
|
itemCount: history.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
|
final heroID = history[index].id.hashCode;
|
||||||
return SimpleComicTile(
|
return SimpleComicTile(
|
||||||
comic: history[index],
|
comic: history[index],
|
||||||
|
heroID: heroID,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.to(
|
context.to(
|
||||||
() => ComicPage(
|
() => ComicPage(
|
||||||
id: history[index].id,
|
id: history[index].id,
|
||||||
sourceKey: history[index].type.sourceKey,
|
sourceKey: history[index].type.sourceKey,
|
||||||
|
cover: history[index].cover,
|
||||||
|
title: history[index].title,
|
||||||
|
heroID: heroID,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -386,7 +391,9 @@ class _LocalState extends State<_Local> {
|
|||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 8, vertical: 2),
|
horizontal: 8,
|
||||||
|
vertical: 2,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
@@ -405,9 +412,22 @@ class _LocalState extends State<_Local> {
|
|||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemCount: local.length,
|
itemCount: local.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return SimpleComicTile(comic: local[index])
|
final heroID = local[index].id.hashCode;
|
||||||
.paddingHorizontal(8)
|
return SimpleComicTile(
|
||||||
.paddingVertical(2);
|
comic: local[index],
|
||||||
|
heroID: heroID,
|
||||||
|
onTap: () {
|
||||||
|
context.to(
|
||||||
|
() => ComicPage(
|
||||||
|
id: local[index].id,
|
||||||
|
sourceKey: local[index].sourceKey,
|
||||||
|
cover: local[index].cover,
|
||||||
|
title: local[index].title,
|
||||||
|
heroID: heroID,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).paddingHorizontal(8).paddingVertical(2);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
).paddingHorizontal(8),
|
).paddingHorizontal(8),
|
||||||
|
|||||||
@@ -285,13 +285,13 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
|
|||||||
SliverGridComics(
|
SliverGridComics(
|
||||||
comics: comics,
|
comics: comics,
|
||||||
selections: selectedComics,
|
selections: selectedComics,
|
||||||
onLongPressed: (c) {
|
onLongPressed: (c, heroID) {
|
||||||
setState(() {
|
setState(() {
|
||||||
multiSelectMode = true;
|
multiSelectMode = true;
|
||||||
selectedComics[c as LocalComic] = true;
|
selectedComics[c as LocalComic] = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onTap: (c) {
|
onTap: (c, heroID) {
|
||||||
if (multiSelectMode) {
|
if (multiSelectMode) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedComics.containsKey(c as LocalComic)) {
|
if (selectedComics.containsKey(c as LocalComic)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user