mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
history page, comic menu
This commit is contained in:
@@ -6,6 +6,7 @@ class ComicTile extends StatelessWidget {
|
|||||||
required this.comic,
|
required this.comic,
|
||||||
this.enableLongPressed = true,
|
this.enableLongPressed = true,
|
||||||
this.badge,
|
this.badge,
|
||||||
|
this.menuOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Comic comic;
|
final Comic comic;
|
||||||
@@ -14,14 +15,48 @@ class ComicTile extends StatelessWidget {
|
|||||||
|
|
||||||
final String? badge;
|
final String? badge;
|
||||||
|
|
||||||
|
final List<MenuEntry>? menuOptions;
|
||||||
|
|
||||||
void onTap() {
|
void onTap() {
|
||||||
App.mainNavigatorKey?.currentContext
|
App.mainNavigatorKey?.currentContext
|
||||||
?.to(() => ComicPage(id: comic.id, sourceKey: comic.sourceKey));
|
?.to(() => ComicPage(id: comic.id, sourceKey: comic.sourceKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onLongPress() {}
|
void onLongPress(BuildContext context) {
|
||||||
|
var renderBox = context.findRenderObject() as RenderBox;
|
||||||
|
var size = renderBox.size;
|
||||||
|
var location = renderBox.localToGlobal(
|
||||||
|
Offset(size.width / 2, size.height / 2),
|
||||||
|
);
|
||||||
|
showMenu(location);
|
||||||
|
}
|
||||||
|
|
||||||
void onSecondaryTap(TapDownDetails details) {}
|
void onSecondaryTap(TapDownDetails details) {
|
||||||
|
showMenu(details.globalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void showMenu(Offset location) {
|
||||||
|
showMenuX(
|
||||||
|
App.rootContext,
|
||||||
|
location,
|
||||||
|
[
|
||||||
|
MenuEntry(
|
||||||
|
icon: Icons.chrome_reader_mode_outlined,
|
||||||
|
text: 'Details'.tl,
|
||||||
|
onClick: onTap,
|
||||||
|
),
|
||||||
|
MenuEntry(
|
||||||
|
icon: Icons.copy,
|
||||||
|
text: 'Copy Title'.tl,
|
||||||
|
onClick: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: comic.title));
|
||||||
|
App.rootContext.showMessage(message: 'Title copied'.tl);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
...?menuOptions,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -114,7 +149,7 @@ class ComicTile extends StatelessWidget {
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
onLongPress: enableLongPressed ? onLongPress : null,
|
onLongPress: enableLongPressed ? () => onLongPress(context) : null,
|
||||||
onSecondaryTapDown: onSecondaryTap,
|
onSecondaryTapDown: onSecondaryTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 8, 24, 8),
|
padding: const EdgeInsets.fromLTRB(16, 8, 24, 8),
|
||||||
@@ -209,7 +244,8 @@ class ComicTile extends StatelessWidget {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
onLongPress: enableLongPressed ? onLongPress : null,
|
onLongPress:
|
||||||
|
enableLongPressed ? () => onLongPress(context) : null,
|
||||||
onSecondaryTapDown: onSecondaryTap,
|
onSecondaryTapDown: onSecondaryTap,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: const SizedBox.expand(),
|
child: const SizedBox.expand(),
|
||||||
@@ -300,9 +336,8 @@ class _ComicDescription extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(height: 2),
|
||||||
height: 2,
|
const Spacer(),
|
||||||
),
|
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
@@ -420,12 +455,18 @@ class SliverGridComics extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.comics,
|
required this.comics,
|
||||||
this.onLastItemBuild,
|
this.onLastItemBuild,
|
||||||
|
this.badgeBuilder,
|
||||||
|
this.menuBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<Comic> comics;
|
final List<Comic> comics;
|
||||||
|
|
||||||
final void Function()? onLastItemBuild;
|
final void Function()? onLastItemBuild;
|
||||||
|
|
||||||
|
final String? Function(Comic)? badgeBuilder;
|
||||||
|
|
||||||
|
final List<MenuEntry> Function(Comic)? menuBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StateBuilder<SliverGridComicsController>(
|
return StateBuilder<SliverGridComicsController>(
|
||||||
@@ -440,6 +481,8 @@ class SliverGridComics extends StatelessWidget {
|
|||||||
return _SliverGridComics(
|
return _SliverGridComics(
|
||||||
comics: comics,
|
comics: comics,
|
||||||
onLastItemBuild: onLastItemBuild,
|
onLastItemBuild: onLastItemBuild,
|
||||||
|
badgeBuilder: badgeBuilder,
|
||||||
|
menuBuilder: menuBuilder,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -450,12 +493,18 @@ class _SliverGridComics extends StatelessWidget {
|
|||||||
const _SliverGridComics({
|
const _SliverGridComics({
|
||||||
required this.comics,
|
required this.comics,
|
||||||
this.onLastItemBuild,
|
this.onLastItemBuild,
|
||||||
|
this.badgeBuilder,
|
||||||
|
this.menuBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<Comic> comics;
|
final List<Comic> comics;
|
||||||
|
|
||||||
final void Function()? onLastItemBuild;
|
final void Function()? onLastItemBuild;
|
||||||
|
|
||||||
|
final String? Function(Comic)? badgeBuilder;
|
||||||
|
|
||||||
|
final List<MenuEntry> Function(Comic)? menuBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverGrid(
|
return SliverGrid(
|
||||||
@@ -464,7 +513,12 @@ class _SliverGridComics extends StatelessWidget {
|
|||||||
if (index == comics.length - 1) {
|
if (index == comics.length - 1) {
|
||||||
onLastItemBuild?.call();
|
onLastItemBuild?.call();
|
||||||
}
|
}
|
||||||
return ComicTile(comic: comics[index]);
|
var badge = badgeBuilder?.call(comics[index]);
|
||||||
|
return ComicTile(
|
||||||
|
comic: comics[index],
|
||||||
|
badge: badge,
|
||||||
|
menuOptions: menuBuilder?.call(comics[index]),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
childCount: comics.length,
|
childCount: comics.length,
|
||||||
),
|
),
|
||||||
|
@@ -5,15 +5,19 @@ class BlurEffect extends StatelessWidget {
|
|||||||
|
|
||||||
final double blur;
|
final double blur;
|
||||||
|
|
||||||
|
final BorderRadius? borderRadius;
|
||||||
|
|
||||||
const BlurEffect({
|
const BlurEffect({
|
||||||
required this.child,
|
required this.child,
|
||||||
|
this.borderRadius,
|
||||||
this.blur = 15,
|
this.blur = 15,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ClipRect(
|
return ClipRRect(
|
||||||
|
borderRadius: borderRadius ?? BorderRadius.zero,
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
filter: ImageFilter.blur(
|
filter: ImageFilter.blur(
|
||||||
sigmaX: blur,
|
sigmaX: blur,
|
||||||
|
@@ -172,11 +172,12 @@ class FlyoutContent extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return IntrinsicWidth(
|
return IntrinsicWidth(
|
||||||
|
child: BlurEffect(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: Material(
|
child: Material(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
type: MaterialType.card,
|
type: MaterialType.card,
|
||||||
elevation: 1,
|
color: context.colorScheme.surface.withOpacity(0.82),
|
||||||
surfaceTintColor: Theme.of(context).colorScheme.surfaceTint,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
minWidth: minFlyoutWidth,
|
minWidth: minFlyoutWidth,
|
||||||
@@ -190,10 +191,7 @@ class FlyoutContent extends StatelessWidget {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold, fontSize: 16)),
|
fontWeight: FontWeight.bold, fontSize: 16)),
|
||||||
if (content != null)
|
if (content != null)
|
||||||
Padding(
|
content!,
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: content!,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 12,
|
height: 12,
|
||||||
),
|
),
|
||||||
@@ -206,6 +204,7 @@ class FlyoutContent extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
).paddingAll(4),
|
).paddingAll(4),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -91,13 +91,11 @@ class SliverGridDelegateWithComics extends SliverGridDelegate{
|
|||||||
}
|
}
|
||||||
|
|
||||||
SliverGridLayout getDetailedModeLayout(SliverConstraints constraints, double scale){
|
SliverGridLayout getDetailedModeLayout(SliverConstraints constraints, double scale){
|
||||||
const maxCrossAxisExtent = 650;
|
const minCrossAxisExtent = 360;
|
||||||
final itemHeight = 164 * scale;
|
final itemHeight = 152 * scale;
|
||||||
final width = constraints.crossAxisExtent;
|
final width = constraints.crossAxisExtent;
|
||||||
var crossItems = width ~/ maxCrossAxisExtent;
|
var crossItems = width ~/ minCrossAxisExtent;
|
||||||
if (width % maxCrossAxisExtent != 0) {
|
crossItems = math.max(1, crossItems);
|
||||||
crossItems += 1;
|
|
||||||
}
|
|
||||||
return SliverGridRegularTileLayout(
|
return SliverGridRegularTileLayout(
|
||||||
crossAxisCount: crossItems,
|
crossAxisCount: crossItems,
|
||||||
mainAxisStride: itemHeight,
|
mainAxisStride: itemHeight,
|
||||||
|
@@ -1,16 +1,15 @@
|
|||||||
part of "components.dart";
|
part of "components.dart";
|
||||||
|
|
||||||
void showDesktopMenu(
|
void showMenuX(BuildContext context, Offset location, List<MenuEntry> entries) {
|
||||||
BuildContext context, Offset location, List<DesktopMenuEntry> entries) {
|
Navigator.of(context).push(_MenuRoute(entries, location));
|
||||||
Navigator.of(context).push(DesktopMenuRoute(entries, location));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DesktopMenuRoute<T> extends PopupRoute<T> {
|
class _MenuRoute<T> extends PopupRoute<T> {
|
||||||
final List<DesktopMenuEntry> entries;
|
final List<MenuEntry> entries;
|
||||||
|
|
||||||
final Offset location;
|
final Offset location;
|
||||||
|
|
||||||
DesktopMenuRoute(this.entries, this.location);
|
_MenuRoute(this.entries, this.location);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get barrierColor => Colors.transparent;
|
Color? get barrierColor => Colors.transparent;
|
||||||
@@ -24,7 +23,7 @@ class DesktopMenuRoute<T> extends PopupRoute<T> {
|
|||||||
@override
|
@override
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
Widget buildPage(BuildContext context, Animation<double> animation,
|
||||||
Animation<double> secondaryAnimation) {
|
Animation<double> secondaryAnimation) {
|
||||||
const width = 196.0;
|
var width = entries.first.icon == null ? 216.0 : 242.0;
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
var left = location.dx;
|
var left = location.dx;
|
||||||
if (left + width > size.width - 10) {
|
if (left + width > size.width - 10) {
|
||||||
@@ -41,22 +40,33 @@ class DesktopMenuRoute<T> extends PopupRoute<T> {
|
|||||||
left: left,
|
left: left,
|
||||||
top: top,
|
top: top,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: width,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: context.colorScheme.surface,
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.2),
|
color: context.colorScheme.shadow.withOpacity(0.2),
|
||||||
blurRadius: 4,
|
blurRadius: 8,
|
||||||
offset: const Offset(0, 2),
|
blurStyle: BlurStyle.outer,
|
||||||
),
|
),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
|
child: BlurEffect(
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
child: Material(
|
child: Material(
|
||||||
|
color: context.brightness == Brightness.light
|
||||||
|
? const Color(0xFFFAFAFA).withOpacity(0.72)
|
||||||
|
: const Color(0xFF090909).withOpacity(0.72),
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
child: Container(
|
||||||
|
width: width,
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 12, horizontal: 6),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: entries.map((e) => buildEntry(e, context)).toList(),
|
children:
|
||||||
|
entries.map((e) => buildEntry(e, context)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -65,7 +75,7 @@ class DesktopMenuRoute<T> extends PopupRoute<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildEntry(DesktopMenuEntry entry, BuildContext context) {
|
Widget buildEntry(MenuEntry entry, BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -73,24 +83,22 @@ class DesktopMenuRoute<T> extends PopupRoute<T> {
|
|||||||
entry.onClick();
|
entry.onClick();
|
||||||
},
|
},
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 32,
|
height: App.isMobile ? 42 : 36,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(
|
|
||||||
width: 4,
|
|
||||||
),
|
|
||||||
if (entry.icon != null)
|
if (entry.icon != null)
|
||||||
Icon(
|
Icon(
|
||||||
entry.icon,
|
entry.icon,
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(width: 12),
|
||||||
width: 4,
|
|
||||||
),
|
|
||||||
Text(entry.text),
|
Text(entry.text),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,10 +116,10 @@ class DesktopMenuRoute<T> extends PopupRoute<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DesktopMenuEntry {
|
class MenuEntry {
|
||||||
final String text;
|
final String text;
|
||||||
final IconData? icon;
|
final IconData? icon;
|
||||||
final void Function() onClick;
|
final void Function() onClick;
|
||||||
|
|
||||||
DesktopMenuEntry({required this.text, this.icon, required this.onClick});
|
MenuEntry({required this.text, this.icon, required this.onClick});
|
||||||
}
|
}
|
||||||
|
@@ -129,6 +129,14 @@ class History {
|
|||||||
HistoryManager().addHistory(history);
|
HistoryManager().addHistory(history);
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is History && type == other.type && id == other.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(id, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
class HistoryManager with ChangeNotifier {
|
class HistoryManager with ChangeNotifier {
|
||||||
@@ -190,6 +198,7 @@ class HistoryManager with ChangeNotifier {
|
|||||||
void clearHistory() {
|
void clearHistory() {
|
||||||
_db.execute("delete from history;");
|
_db.execute("delete from history;");
|
||||||
updateCache();
|
updateCache();
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove(String id, ComicType type) async {
|
void remove(String id, ComicType type) async {
|
||||||
|
133
lib/pages/history_page.dart
Normal file
133
lib/pages/history_page.dart
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:venera/components/components.dart';
|
||||||
|
import 'package:venera/foundation/app.dart';
|
||||||
|
import 'package:venera/foundation/comic_source/comic_source.dart';
|
||||||
|
import 'package:venera/foundation/comic_type.dart';
|
||||||
|
import 'package:venera/foundation/history.dart';
|
||||||
|
import 'package:venera/utils/translations.dart';
|
||||||
|
|
||||||
|
class HistoryPage extends StatefulWidget {
|
||||||
|
const HistoryPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HistoryPage> createState() => _HistoryPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HistoryPageState extends State<HistoryPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
HistoryManager().addListener(onUpdate);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
HistoryManager().removeListener(onUpdate);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onUpdate() {
|
||||||
|
setState(() {
|
||||||
|
comics = HistoryManager().getAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var comics = HistoryManager().getAll();
|
||||||
|
|
||||||
|
var controller = FlyoutController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: SmoothCustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverAppbar(
|
||||||
|
title: Text('History'.tl),
|
||||||
|
actions: [
|
||||||
|
Tooltip(
|
||||||
|
message: 'Clear History'.tl,
|
||||||
|
child: Flyout(
|
||||||
|
controller: controller,
|
||||||
|
flyoutBuilder: (context) {
|
||||||
|
return FlyoutContent(
|
||||||
|
title: 'Clear History'.tl,
|
||||||
|
content: Text(
|
||||||
|
'Are you sure you want to clear your history?'.tl),
|
||||||
|
actions: [
|
||||||
|
Button.filled(
|
||||||
|
color: context.colorScheme.error,
|
||||||
|
onPressed: () {
|
||||||
|
HistoryManager().clearHistory();
|
||||||
|
context.pop();
|
||||||
|
},
|
||||||
|
child: Text('Clear'.tl),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.clear_all),
|
||||||
|
onPressed: () {
|
||||||
|
controller.show();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SliverGridComics(
|
||||||
|
comics: comics.map(
|
||||||
|
(e) {
|
||||||
|
return Comic(
|
||||||
|
e.title,
|
||||||
|
e.cover,
|
||||||
|
e.id,
|
||||||
|
e.subtitle,
|
||||||
|
null,
|
||||||
|
getDescription(e),
|
||||||
|
e.type.comicSource?.key ?? "Invalid",
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList(),
|
||||||
|
badgeBuilder: (c) {
|
||||||
|
return ComicSource.find(c.sourceKey)?.name;
|
||||||
|
},
|
||||||
|
menuBuilder: (c) {
|
||||||
|
return [
|
||||||
|
MenuEntry(
|
||||||
|
icon: Icons.remove,
|
||||||
|
text: 'Remove'.tl,
|
||||||
|
onClick: () {
|
||||||
|
HistoryManager().remove(
|
||||||
|
c.id,
|
||||||
|
ComicType(c.sourceKey.hashCode),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDescription(History h) {
|
||||||
|
var res = "";
|
||||||
|
if (h.ep >= 1) {
|
||||||
|
res += "Chapter @ep".tlParams({
|
||||||
|
"ep": h.ep,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (h.page >= 1) {
|
||||||
|
if (h.ep >= 1) {
|
||||||
|
res += " - ";
|
||||||
|
}
|
||||||
|
res += "Page @page".tlParams({
|
||||||
|
"page": h.page,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,7 @@ import 'package:venera/foundation/local.dart';
|
|||||||
import 'package:venera/foundation/log.dart';
|
import 'package:venera/foundation/log.dart';
|
||||||
import 'package:venera/pages/comic_page.dart';
|
import 'package:venera/pages/comic_page.dart';
|
||||||
import 'package:venera/pages/comic_source_page.dart';
|
import 'package:venera/pages/comic_source_page.dart';
|
||||||
|
import 'package:venera/pages/history_page.dart';
|
||||||
import 'package:venera/pages/search_page.dart';
|
import 'package:venera/pages/search_page.dart';
|
||||||
import 'package:venera/utils/io.dart';
|
import 'package:venera/utils/io.dart';
|
||||||
import 'package:venera/utils/translations.dart';
|
import 'package:venera/utils/translations.dart';
|
||||||
@@ -113,7 +114,9 @@ class _HistoryState extends State<_History> {
|
|||||||
),
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
onTap: () {},
|
onTap: () {
|
||||||
|
context.to(() => const HistoryPage());
|
||||||
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
@@ -178,26 +178,26 @@ class _ReaderGestureDetectorState extends State<_ReaderGestureDetector> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onSecondaryTapUp(Offset location) {
|
void onSecondaryTapUp(Offset location) {
|
||||||
showDesktopMenu(
|
showMenuX(
|
||||||
context,
|
context,
|
||||||
location,
|
location,
|
||||||
[
|
[
|
||||||
DesktopMenuEntry(
|
MenuEntry(
|
||||||
text: "Settings".tl,
|
text: "Settings".tl,
|
||||||
onClick: () {
|
onClick: () {
|
||||||
context.readerScaffold.openSetting();
|
context.readerScaffold.openSetting();
|
||||||
}),
|
}),
|
||||||
DesktopMenuEntry(
|
MenuEntry(
|
||||||
text: "Chapters".tl,
|
text: "Chapters".tl,
|
||||||
onClick: () {
|
onClick: () {
|
||||||
context.readerScaffold.openChapterDrawer();
|
context.readerScaffold.openChapterDrawer();
|
||||||
}),
|
}),
|
||||||
DesktopMenuEntry(
|
MenuEntry(
|
||||||
text: "Fullscreen".tl,
|
text: "Fullscreen".tl,
|
||||||
onClick: () {
|
onClick: () {
|
||||||
context.reader.fullscreen();
|
context.reader.fullscreen();
|
||||||
}),
|
}),
|
||||||
DesktopMenuEntry(
|
MenuEntry(
|
||||||
text: "Exit".tl,
|
text: "Exit".tl,
|
||||||
onClick: () {
|
onClick: () {
|
||||||
context.pop();
|
context.pop();
|
||||||
|
@@ -102,6 +102,7 @@ class _ReaderState extends State<Reader> with _ReaderLocation, _ReaderWindow {
|
|||||||
chapter = widget.initialChapter ?? 1;
|
chapter = widget.initialChapter ?? 1;
|
||||||
mode = ReaderMode.fromKey(appdata.settings['readerMode']);
|
mode = ReaderMode.fromKey(appdata.settings['readerMode']);
|
||||||
history = widget.history;
|
history = widget.history;
|
||||||
|
updateHistory();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user