improve shortcuts

This commit is contained in:
wgh19
2024-05-20 22:19:06 +08:00
parent f33df47cd6
commit dd1ed690e1

View File

@@ -24,12 +24,14 @@ import '../components/illust_widget.dart';
import '../components/md.dart'; import '../components/md.dart';
import '../components/ugoira.dart'; import '../components/ugoira.dart';
const _kBottomBarHeight = 64.0; const _kBottomBarHeight = 64.0;
class IllustGalleryPage extends StatefulWidget { class IllustGalleryPage extends StatefulWidget {
const IllustGalleryPage({required this.illusts, required this.initialPage, const IllustGalleryPage(
this.nextUrl, super.key}); {required this.illusts,
required this.initialPage,
this.nextUrl,
super.key});
final List<Illust> illusts; final List<Illust> illusts;
@@ -55,50 +57,47 @@ class _IllustGalleryPageState extends State<IllustGalleryPage> {
illusts = List.from(widget.illusts); illusts = List.from(widget.illusts);
controller = PageController(initialPage: widget.initialPage); controller = PageController(initialPage: widget.initialPage);
nextUrl = widget.nextUrl; nextUrl = widget.nextUrl;
if(nextUrl == "end") { if (nextUrl == "end") {
nextUrl = null; nextUrl = null;
} }
super.initState(); super.initState();
} }
void nextPage() {
var length = illusts.length;
if (controller.page == length - 1) return;
controller.nextPage(
duration: const Duration(milliseconds: 200), curve: Curves.ease);
}
void previousPage() {
if (controller.page == 0) return;
controller.previousPage(
duration: const Duration(milliseconds: 200), curve: Curves.ease);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var length = illusts.length; var length = illusts.length;
if(nextUrl != null) { if (nextUrl != null) {
length++; length++;
} }
return CallbackShortcuts( return PageView.builder(
bindings: { controller: controller,
LogicalKeySet(LogicalKeyboardKey.arrowLeft): () { itemCount: length,
if(controller.page == 0) return; itemBuilder: (context, index) {
controller.previousPage( if (index == illusts.length) {
duration: const Duration(milliseconds: 200), curve: Curves.ease); return buildLast();
},
LogicalKeySet(LogicalKeyboardKey.arrowRight): () {
if(controller.page == length-1) return;
controller.nextPage(
duration: const Duration(milliseconds: 200), curve: Curves.ease);
} }
return IllustPage(illusts[index],
nextPage: nextPage, previousPage: previousPage);
}, },
child: Focus(
autofocus: true,
child: PageView.builder(
controller: controller,
itemCount: length,
itemBuilder: (context, index) {
if(index == illusts.length) {
return buildLast();
}
return IllustPage(illusts[index]);
},
),
),
); );
} }
Widget buildLast(){ Widget buildLast() {
if(nextUrl == null) { if (nextUrl == null) {
return const SizedBox(); return const SizedBox();
} }
load(); load();
@@ -108,13 +107,13 @@ class _IllustGalleryPageState extends State<IllustGalleryPage> {
} }
void load() async { void load() async {
if(loading) return; if (loading) return;
loading = true; loading = true;
var res = await Network().getIllustsWithNextUrl(nextUrl!); var res = await Network().getIllustsWithNextUrl(nextUrl!);
loading = false; loading = false;
if(res.error) { if (res.error) {
if(mounted) { if (mounted) {
context.showToast(message: "Network Error"); context.showToast(message: "Network Error");
} }
} else { } else {
@@ -125,14 +124,18 @@ class _IllustGalleryPageState extends State<IllustGalleryPage> {
} }
} }
class IllustPage extends StatefulWidget { class IllustPage extends StatefulWidget {
const IllustPage(this.illust, {this.favoriteCallback, super.key}); const IllustPage(this.illust,
{this.favoriteCallback, this.nextPage, this.previousPage, super.key});
final Illust illust; final Illust illust;
final void Function(bool)? favoriteCallback; final void Function(bool)? favoriteCallback;
final void Function()? nextPage;
final void Function()? previousPage;
@override @override
State<IllustPage> createState() => _IllustPageState(); State<IllustPage> createState() => _IllustPageState();
} }
@@ -140,7 +143,7 @@ class IllustPage extends StatefulWidget {
class _IllustPageState extends State<IllustPage> { class _IllustPageState extends State<IllustPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ColoredBox( return buildKeyboardListener(ColoredBox(
color: FluentTheme.of(context).micaBackgroundColor, color: FluentTheme.of(context).micaBackgroundColor,
child: SizedBox.expand( child: SizedBox.expand(
child: ColoredBox( child: ColoredBox(
@@ -166,11 +169,41 @@ class _IllustPageState extends State<IllustPage> {
}), }),
), ),
), ),
));
}
final scrollController = ScrollController();
Widget buildKeyboardListener(Widget child) {
return KeyboardListener(
focusNode: FocusNode(),
autofocus: true,
onKeyEvent: (event) {
if (event is! KeyUpEvent) return;
const kShortcutScrollOffset = 200;
if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
scrollController.animateTo(
scrollController.offset + kShortcutScrollOffset,
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut);
} else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
scrollController.animateTo(
scrollController.offset - kShortcutScrollOffset,
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut);
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
widget.nextPage?.call();
} else if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
widget.previousPage?.call();
}
},
child: child,
); );
} }
Widget buildBody(double width, double height) { Widget buildBody(double width, double height) {
return ListView.builder( return ListView.builder(
controller: scrollController,
itemCount: widget.illust.images.length + 2, itemCount: widget.illust.images.length + 2,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemBuilder: (context, index) { itemBuilder: (context, index) {
@@ -180,9 +213,9 @@ class _IllustPageState extends State<IllustPage> {
void openImage(int index) { void openImage(int index) {
var images = <String>[]; var images = <String>[];
for(var i = 0; i < widget.illust.images.length; i++) { for (var i = 0; i < widget.illust.images.length; i++) {
var downloadFile = DownloadManager().getImage(widget.illust.id, i); var downloadFile = DownloadManager().getImage(widget.illust.id, i);
if(downloadFile != null) { if (downloadFile != null) {
images.add("file://${downloadFile.path}"); images.add("file://${downloadFile.path}");
} else { } else {
images.add(widget.illust.images[i].original); images.add(widget.illust.images[i].original);
@@ -200,7 +233,7 @@ class _IllustPageState extends State<IllustPage> {
} }
index--; index--;
File? downloadFile; File? downloadFile;
if(widget.illust.downloaded) { if (widget.illust.downloaded) {
downloadFile = DownloadManager().getImage(widget.illust.id, index); downloadFile = DownloadManager().getImage(widget.illust.id, index);
} }
if (index == widget.illust.images.length) { if (index == widget.illust.images.length) {
@@ -218,7 +251,7 @@ class _IllustPageState extends State<IllustPage> {
} }
Widget image; Widget image;
if(!widget.illust.isUgoira) { if (!widget.illust.isUgoira) {
image = SizedBox( image = SizedBox(
width: imageWidth, width: imageWidth,
height: imageHeight, height: imageHeight,
@@ -227,7 +260,8 @@ class _IllustPageState extends State<IllustPage> {
child: Image( child: Image(
key: ValueKey(index), key: ValueKey(index),
image: downloadFile == null image: downloadFile == null
? CachedImageProvider(widget.illust.images[index].large) as ImageProvider ? CachedImageProvider(widget.illust.images[index].large)
as ImageProvider
: FileImage(downloadFile) as ImageProvider, : FileImage(downloadFile) as ImageProvider,
width: imageWidth, width: imageWidth,
fit: BoxFit.cover, fit: BoxFit.cover,
@@ -235,11 +269,12 @@ class _IllustPageState extends State<IllustPage> {
loadingBuilder: (context, child, loadingProgress) { loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child; if (loadingProgress == null) return child;
double? value; double? value;
if(loadingProgress.expectedTotalBytes != null) { if (loadingProgress.expectedTotalBytes != null) {
value = (loadingProgress.cumulativeBytesLoaded / value = (loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!)*100; loadingProgress.expectedTotalBytes!) *
100;
} }
if(value != null && (value > 100 || value < 0)) { if (value != null && (value > 100 || value < 0)) {
value = null; value = null;
} }
return Center( return Center(
@@ -251,8 +286,7 @@ class _IllustPageState extends State<IllustPage> {
), ),
), ),
); );
} }),
),
), ),
); );
} else { } else {
@@ -271,7 +305,8 @@ class _IllustPageState extends State<IllustPage> {
} }
class _BottomBar extends StatefulWidget { class _BottomBar extends StatefulWidget {
const _BottomBar(this.illust, this.height, this.width, {this.favoriteCallback}); const _BottomBar(this.illust, this.height, this.width,
{this.favoriteCallback});
final void Function(bool)? favoriteCallback; final void Function(bool)? favoriteCallback;
@@ -285,7 +320,7 @@ class _BottomBar extends StatefulWidget {
State<_BottomBar> createState() => _BottomBarState(); State<_BottomBar> createState() => _BottomBarState();
} }
class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin {
double pageHeight = 0; double pageHeight = 0;
double widgetHeight = 48; double widgetHeight = 48;
@@ -299,7 +334,8 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
late final AnimationController animationController; late final AnimationController animationController;
double get minValue => pageHeight - widgetHeight; double get minValue => pageHeight - widgetHeight;
double get maxValue => pageHeight - _kBottomBarHeight - context.padding.bottom; double get maxValue =>
pageHeight - _kBottomBarHeight - context.padding.bottom;
@override @override
void initState() { void initState() {
@@ -315,9 +351,7 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
..onEnd = _handlePointerUp ..onEnd = _handlePointerUp
..onCancel = _handlePointerCancel; ..onCancel = _handlePointerCancel;
animationController = AnimationController( animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 180), vsync: this, duration: const Duration(milliseconds: 180), value: 1);
value: 1
);
super.initState(); super.initState();
} }
@@ -327,16 +361,16 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
final minValue = pageHeight - widgetHeight; final minValue = pageHeight - widgetHeight;
final maxValue = pageHeight - _kBottomBarHeight - context.padding.bottom; final maxValue = pageHeight - _kBottomBarHeight - context.padding.bottom;
var top = animationController.value * (maxValue - minValue) + minValue; var top = animationController.value * (maxValue - minValue) + minValue;
top = (top + offset).clamp(minValue, maxValue); top = (top + offset).clamp(minValue, maxValue);
animationController.value = (top - minValue) / (maxValue - minValue); animationController.value = (top - minValue) / (maxValue - minValue);
} }
void _handlePointerUp(DragEndDetails details) { void _handlePointerUp(DragEndDetails details) {
var speed = details.primaryVelocity ?? 0; var speed = details.primaryVelocity ?? 0;
const minShouldTransitionSpeed = 1000; const minShouldTransitionSpeed = 1000;
if(speed > minShouldTransitionSpeed) { if (speed > minShouldTransitionSpeed) {
animationController.forward(); animationController.forward();
} else if(speed < 0 - minShouldTransitionSpeed) { } else if (speed < 0 - minShouldTransitionSpeed) {
animationController.reverse(); animationController.reverse();
} else { } else {
_handlePointerCancel(); _handlePointerCancel();
@@ -344,8 +378,9 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
} }
void _handlePointerCancel() { void _handlePointerCancel() {
if(animationController.value == 1 || animationController.value == 0) return; if (animationController.value == 1 || animationController.value == 0)
if(animationController.value >= 0.5 ) { return;
if (animationController.value >= 0.5) {
animationController.forward(); animationController.forward();
} else { } else {
animationController.reverse(); animationController.reverse();
@@ -360,13 +395,13 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
}); });
} }
_recognizer.dispose(); _recognizer.dispose();
if(_width != widget.width) { if (_width != widget.width) {
_width = widget.width; _width = widget.width;
Future.microtask(() { Future.microtask(() {
final box = key.currentContext?.findRenderObject() as RenderBox?; final box = key.currentContext?.findRenderObject() as RenderBox?;
var oldHeight = widgetHeight; var oldHeight = widgetHeight;
widgetHeight = (box?.size.height) ?? 0; widgetHeight = (box?.size.height) ?? 0;
if(oldHeight != widgetHeight) { if (oldHeight != widgetHeight) {
setState(() {}); setState(() {});
} }
}); });
@@ -392,9 +427,9 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
_recognizer.addPointer(event); _recognizer.addPointer(event);
}, },
onPointerSignal: (event) { onPointerSignal: (event) {
if(event is PointerScrollEvent) { if (event is PointerScrollEvent) {
var offset = (event).scrollDelta.dy; var offset = (event).scrollDelta.dy;
if(offset < 0) { if (offset < 0) {
animationController.reverse(); animationController.reverse();
} else { } else {
animationController.forward(); animationController.forward();
@@ -402,9 +437,10 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
} }
}, },
child: Card( child: Card(
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)), borderRadius:
const BorderRadius.vertical(top: Radius.circular(8)),
backgroundColor: backgroundColor:
FluentTheme.of(context).micaBackgroundColor.withOpacity(0.96), FluentTheme.of(context).micaBackgroundColor.withOpacity(0.96),
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
@@ -420,9 +456,11 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
"${"Artwork ID".tl}: ${widget.illust.id}\n" "${"Artwork ID".tl}: ${widget.illust.id}\n"
"${"Artist ID".tl}: ${widget.illust.author.id}\n" "${"Artist ID".tl}: ${widget.illust.author.id}\n"
"${widget.illust.createDate.toString().split('.').first}", "${widget.illust.createDate.toString().split('.').first}",
style: TextStyle(color: ColorScheme.of(context).outline),) style: TextStyle(color: ColorScheme.of(context).outline),
.paddingLeft(4), ).paddingLeft(4),
SizedBox(height: 8 + context.padding.bottom,) SizedBox(
height: 8 + context.padding.bottom,
)
], ],
), ),
), ),
@@ -464,15 +502,16 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
bool isFollowing = false; bool isFollowing = false;
Widget buildAuthor() { Widget buildAuthor() {
void follow() async{ void follow() async {
if(isFollowing) return; if (isFollowing) return;
setState(() { setState(() {
isFollowing = true; isFollowing = true;
}); });
var method = widget.illust.author.isFollowed ? "delete" : "add"; var method = widget.illust.author.isFollowed ? "delete" : "add";
var res = await Network().follow(widget.illust.author.id.toString(), method); var res =
if(res.error) { await Network().follow(widget.illust.author.id.toString(), method);
if(mounted) { if (res.error) {
if (mounted) {
context.showToast(message: "Network Error"); context.showToast(message: "Network Error");
} }
} else { } else {
@@ -502,12 +541,12 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
child: ColoredBox( child: ColoredBox(
color: ColorScheme.of(context).secondaryContainer, color: ColorScheme.of(context).secondaryContainer,
child: GestureDetector( child: GestureDetector(
onTap: () => context.to(() => onTap: () => context.to(() => UserInfoPage(
UserInfoPage(
widget.illust.author.id.toString(), widget.illust.author.id.toString(),
followCallback: (b) => setState(() { followCallback: (b) => setState(() {
widget.illust.author.isFollowed = b; widget.illust.author.isFollowed = b;
}),)), }),
)),
child: AnimatedImage( child: AnimatedImage(
image: CachedImageProvider(widget.illust.author.avatar), image: CachedImageProvider(widget.illust.author.avatar),
width: 40, width: 40,
@@ -522,24 +561,28 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
const SizedBox( const SizedBox(
width: 8, width: 8,
), ),
if(showUserName) if (showUserName)
Expanded( Expanded(
child: Text( child: Text(
widget.illust.author.name, widget.illust.author.name,
maxLines: 2, maxLines: 2,
), ),
), ),
if(isFollowing) if (isFollowing)
Button(onPressed: follow, child: const SizedBox( Button(
width: 42, onPressed: follow,
height: 24, child: const SizedBox(
child: Center( width: 42,
child: SizedBox.square( height: 24,
dimension: 18, child: Center(
child: ProgressRing(strokeWidth: 2,), child: SizedBox.square(
), dimension: 18,
), child: ProgressRing(
)) strokeWidth: 2,
),
),
),
))
else if (!widget.illust.author.isFollowed) else if (!widget.illust.author.isFollowed)
Button(onPressed: follow, child: Text("Follow".tl).fixWidth(62)) Button(onPressed: follow, child: Text("Follow".tl).fixWidth(62))
else else
@@ -558,15 +601,16 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
bool isBookmarking = false; bool isBookmarking = false;
void favorite([String type = "public"]) async{ void favorite([String type = "public"]) async {
if(isBookmarking) return; if (isBookmarking) return;
setState(() { setState(() {
isBookmarking = true; isBookmarking = true;
}); });
var method = widget.illust.isBookmarked ? "delete" : "add"; var method = widget.illust.isBookmarked ? "delete" : "add";
var res = await Network().addBookmark(widget.illust.id.toString(), method, type); var res =
if(res.error) { await Network().addBookmark(widget.illust.id.toString(), method, type);
if(mounted) { if (res.error) {
if (mounted) {
context.showToast(message: "Network Error"); context.showToast(message: "Network Error");
} }
} else { } else {
@@ -579,7 +623,9 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
} }
Iterable<Widget> buildActions(double width) sync* { Iterable<Widget> buildActions(double width) sync* {
yield const SizedBox(width: 8,); yield const SizedBox(
width: 8,
);
void download() { void download() {
DownloadManager().addDownloadingTask(widget.illust); DownloadManager().addDownloadingTask(widget.illust);
@@ -594,13 +640,15 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
height: 28, height: 28,
child: Row( child: Row(
children: [ children: [
if(isBookmarking) if (isBookmarking)
const SizedBox( const SizedBox(
width: 18, width: 18,
height: 18, height: 18,
child: ProgressRing(strokeWidth: 2,), child: ProgressRing(
strokeWidth: 2,
),
) )
else if(widget.illust.isBookmarked) else if (widget.illust.isBookmarked)
Icon( Icon(
Icons.favorite, Icons.favorite,
color: ColorScheme.of(context).error, color: ColorScheme.of(context).error,
@@ -611,10 +659,12 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
Icons.favorite_border, Icons.favorite_border,
size: 18, size: 18,
), ),
if(showText) if (showText)
const SizedBox(width: 8,), const SizedBox(
if(showText) width: 8,
if(widget.illust.isBookmarked) ),
if (showText)
if (widget.illust.isBookmarked)
Text("Cancel".tl) Text("Cancel".tl)
else else
Text("Favorite".tl) Text("Favorite".tl)
@@ -623,10 +673,12 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
), ),
); );
yield const SizedBox(width: 8,); yield const SizedBox(
width: 8,
);
if (!widget.illust.downloaded) { if (!widget.illust.downloaded) {
if(widget.illust.downloading) { if (widget.illust.downloading) {
yield Button( yield Button(
onPressed: () => {}, onPressed: () => {},
child: SizedBox( child: SizedBox(
@@ -638,11 +690,15 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
color: ColorScheme.of(context).outline, color: ColorScheme.of(context).outline,
size: 18, size: 18,
), ),
if(showText) if (showText)
const SizedBox(width: 8,), const SizedBox(
if(showText) width: 8,
Text("Downloading".tl, ),
style: TextStyle(color: ColorScheme.of(context).outline),), if (showText)
Text(
"Downloading".tl,
style: TextStyle(color: ColorScheme.of(context).outline),
),
], ],
), ),
), ),
@@ -658,10 +714,11 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
FluentIcons.download, FluentIcons.download,
size: 18, size: 18,
), ),
if(showText) if (showText)
const SizedBox(width: 8,), const SizedBox(
if(showText) width: 8,
Text("Download".tl), ),
if (showText) Text("Download".tl),
], ],
), ),
), ),
@@ -669,7 +726,9 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
} }
} }
yield const SizedBox(width: 8,); yield const SizedBox(
width: 8,
);
yield Button( yield Button(
onPressed: () => CommentsPage.show(context, widget.illust.id.toString()), onPressed: () => CommentsPage.show(context, widget.illust.id.toString()),
@@ -681,68 +740,105 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
FluentIcons.comment, FluentIcons.comment,
size: 18, size: 18,
), ),
if(showText) if (showText)
const SizedBox(width: 8,), const SizedBox(
if(showText) width: 8,
Text("Comment".tl), ),
if (showText) Text("Comment".tl),
], ],
), ),
), ),
); );
} }
Widget buildStats(){ Widget buildStats() {
return SizedBox( return SizedBox(
height: 56, height: 56,
child: Row( child: Row(
children: [ children: [
const SizedBox(width: 2,), const SizedBox(
width: 2,
),
Expanded( Expanded(
child: Container( child: Container(
height: 52, height: 52,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: ColorScheme.of(context).outlineVariant, width: 0.6), border: Border.all(
borderRadius: BorderRadius.circular(4) color: ColorScheme.of(context).outlineVariant,
), width: 0.6),
borderRadius: BorderRadius.circular(4)),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
child: Row( child: Row(
children: [ children: [
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon(FluentIcons.view, size: 20,), const Icon(
Text("Views".tl, style: const TextStyle(fontSize: 12),) FluentIcons.view,
size: 20,
),
Text(
"Views".tl,
style: const TextStyle(fontSize: 12),
)
], ],
), ),
const SizedBox(width: 12,), const SizedBox(
Text(widget.illust.totalView.toString(), style: TextStyle(color: ColorScheme.of(context).primary, fontWeight: FontWeight.w500, fontSize: 18),) width: 12,
),
Text(
widget.illust.totalView.toString(),
style: TextStyle(
color: ColorScheme.of(context).primary,
fontWeight: FontWeight.w500,
fontSize: 18),
)
], ],
), ),
), ),
), ),
const SizedBox(width: 16,), const SizedBox(
Expanded(child: Container( width: 16,
),
Expanded(
child: Container(
height: 52, height: 52,
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: ColorScheme.of(context).outlineVariant, width: 0.6), border: Border.all(
borderRadius: BorderRadius.circular(4) color: ColorScheme.of(context).outlineVariant, width: 0.6),
), borderRadius: BorderRadius.circular(4)),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
child: Row( child: Row(
children: [ children: [
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon(FluentIcons.six_point_star, size: 20,), const Icon(
Text("Favorites".tl, style: const TextStyle(fontSize: 12),) FluentIcons.six_point_star,
size: 20,
),
Text(
"Favorites".tl,
style: const TextStyle(fontSize: 12),
)
], ],
), ),
const SizedBox(width: 12,), const SizedBox(
Text(widget.illust.totalBookmarks.toString(), style: TextStyle(color: ColorScheme.of(context).primary, fontWeight: FontWeight.w500, fontSize: 18),) width: 12,
),
Text(
widget.illust.totalBookmarks.toString(),
style: TextStyle(
color: ColorScheme.of(context).primary,
fontWeight: FontWeight.w500,
fontSize: 18),
)
], ],
), ),
)), )),
const SizedBox(width: 2,), const SizedBox(
width: 2,
),
], ],
), ),
); );
@@ -756,7 +852,7 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
runSpacing: 4, runSpacing: 4,
children: widget.illust.tags.map((e) { children: widget.illust.tags.map((e) {
var text = e.name; var text = e.name;
if(e.translatedName != null && e.name != e.translatedName) { if (e.translatedName != null && e.name != e.translatedName) {
text += "/${e.translatedName}"; text += "/${e.translatedName}";
} }
return MouseRegion( return MouseRegion(
@@ -767,7 +863,10 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
}, },
child: Card( child: Card(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6),
child: Text(text, style: const TextStyle(fontSize: 13),), child: Text(
text,
style: const TextStyle(fontSize: 13),
),
), ),
), ),
); );
@@ -785,13 +884,15 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
height: 28, height: 28,
child: Row( child: Row(
children: [ children: [
if(isBookmarking) if (isBookmarking)
const SizedBox( const SizedBox(
width: 18, width: 18,
height: 18, height: 18,
child: ProgressRing(strokeWidth: 2,), child: ProgressRing(
strokeWidth: 2,
),
) )
else if(widget.illust.isBookmarked) else if (widget.illust.isBookmarked)
Icon( Icon(
Icons.favorite, Icons.favorite,
color: ColorScheme.of(context).error, color: ColorScheme.of(context).error,
@@ -802,32 +903,44 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
Icons.favorite_border, Icons.favorite_border,
size: 18, size: 18,
), ),
const SizedBox(width: 8,), const SizedBox(
if(widget.illust.isBookmarked) width: 8,
Text("Cancel".tl) ),
else if (widget.illust.isBookmarked)
Text("Private".tl) Text("Cancel".tl)
else
Text("Private".tl)
], ],
), ),
), ),
), ),
const SizedBox(width: 6,), const SizedBox(
width: 6,
),
Button( Button(
onPressed: () { onPressed: () {
Share.share("${widget.illust.title}\nhttps://pixiv.net/artworks/${widget.illust.id}"); Share.share(
"${widget.illust.title}\nhttps://pixiv.net/artworks/${widget.illust.id}");
}, },
child: SizedBox( child: SizedBox(
height: 28, height: 28,
child: Row( child: Row(
children: [ children: [
const Icon(Icons.share, size: 18,), const Icon(
const SizedBox(width: 8,), Icons.share,
size: 18,
),
const SizedBox(
width: 8,
),
Text("Share".tl) Text("Share".tl)
], ],
), ),
), ),
), ),
const SizedBox(width: 6,), const SizedBox(
width: 6,
),
Button( Button(
onPressed: () { onPressed: () {
var text = "https://pixiv.net/artworks/${widget.illust.id}"; var text = "https://pixiv.net/artworks/${widget.illust.id}";
@@ -839,13 +952,17 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
child: Row( child: Row(
children: [ children: [
const Icon(Icons.copy, size: 18), const Icon(Icons.copy, size: 18),
const SizedBox(width: 8,), const SizedBox(
width: 8,
),
Text("Link".tl) Text("Link".tl)
], ],
), ),
), ),
), ),
const SizedBox(width: 6,), const SizedBox(
width: 6,
),
Button( Button(
onPressed: () { onPressed: () {
context.to(() => _RelatedIllustsPage(widget.illust.id.toString())); context.to(() => _RelatedIllustsPage(widget.illust.id.toString()));
@@ -855,7 +972,9 @@ class _BottomBarState extends State<_BottomBar> with TickerProviderStateMixin{
child: Row( child: Row(
children: [ children: [
const Icon(Icons.stars, size: 18), const Icon(Icons.stars, size: 18),
const SizedBox(width: 8,), const SizedBox(
width: 8,
),
Text("Related".tl) Text("Related".tl)
], ],
), ),
@@ -896,7 +1015,8 @@ class _RelatedIllustsPage extends StatefulWidget {
State<_RelatedIllustsPage> createState() => _RelatedIllustsPageState(); State<_RelatedIllustsPage> createState() => _RelatedIllustsPageState();
} }
class _RelatedIllustsPageState extends MultiPageLoadingState<_RelatedIllustsPage, Illust> { class _RelatedIllustsPageState
extends MultiPageLoadingState<_RelatedIllustsPage, Illust> {
@override @override
Widget? buildFrame(BuildContext context, Widget child) { Widget? buildFrame(BuildContext context, Widget child) {
return Column( return Column(
@@ -911,16 +1031,16 @@ class _RelatedIllustsPageState extends MultiPageLoadingState<_RelatedIllustsPage
@override @override
Widget buildContent(BuildContext context, final List<Illust> data) { Widget buildContent(BuildContext context, final List<Illust> data) {
return LayoutBuilder(builder: (context, constrains){ return LayoutBuilder(builder: (context, constrains) {
return MasonryGridView.builder( return MasonryGridView.builder(
padding: const EdgeInsets.symmetric(horizontal: 8) padding: const EdgeInsets.symmetric(horizontal: 8) +
+ EdgeInsets.only(bottom: context.padding.bottom), EdgeInsets.only(bottom: context.padding.bottom),
gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent( gridDelegate: const SliverSimpleGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 240, maxCrossAxisExtent: 240,
), ),
itemCount: data.length, itemCount: data.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if(index == data.length - 1){ if (index == data.length - 1) {
nextPage(); nextPage();
} }
return IllustWidget(data[index]); return IllustWidget(data[index]);
@@ -932,18 +1052,17 @@ class _RelatedIllustsPageState extends MultiPageLoadingState<_RelatedIllustsPage
String? nextUrl; String? nextUrl;
@override @override
Future<Res<List<Illust>>> loadData(page) async{ Future<Res<List<Illust>>> loadData(page) async {
if(nextUrl == "end") { if (nextUrl == "end") {
return Res.error("No more data"); return Res.error("No more data");
} }
var res = nextUrl == null var res = nextUrl == null
? await Network().relatedIllusts(widget.id) ? await Network().relatedIllusts(widget.id)
: await Network().getIllustsWithNextUrl(nextUrl!); : await Network().getIllustsWithNextUrl(nextUrl!);
if(!res.error) { if (!res.error) {
nextUrl = res.subData; nextUrl = res.subData;
nextUrl ??= "end"; nextUrl ??= "end";
} }
return res; return res;
} }
} }