From b075a98259ddcb4384ebe2f9d993446cdb269f67 Mon Sep 17 00:00:00 2001 From: violet-dev Date: Fri, 27 Dec 2024 15:08:36 +0900 Subject: [PATCH 1/6] Adopt article info initial height --- violet/lib/pages/common/utils.dart | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/violet/lib/pages/common/utils.dart b/violet/lib/pages/common/utils.dart index ab5cc2ba9..0d140ac03 100644 --- a/violet/lib/pages/common/utils.dart +++ b/violet/lib/pages/common/utils.dart @@ -1,6 +1,8 @@ // This source code is a part of Project Violet. // Copyright (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License. +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:violet/component/hentai.dart'; @@ -11,6 +13,9 @@ import 'package:violet/model/article_info.dart'; import 'package:violet/pages/article_info/article_info_page.dart'; import 'package:violet/widgets/article_item/image_provider_manager.dart'; +const String heroKey = 'articleInfoHero'; +const String pageKey = 'artcieInfoPage'; + // TODO: expand using optional arguments Future showArticleInfoById(BuildContext context, int id) async { final search = await HentaiManager.idSearch(id.toString()); @@ -56,6 +61,12 @@ Future showArticleInfoRaw({ if (!context.mounted) return; final height = MediaQuery.of(context).size.height; + + var defaultShowHeight = 400; + if (Platform.isWindows) { + defaultShowHeight = (height * 0.9).toInt(); + } + // https://github.com/flutter/flutter/issues/67219 Provider? cache; showModalBottomSheet( @@ -63,7 +74,7 @@ Future showArticleInfoRaw({ isScrollControlled: true, builder: (_) { return DraggableScrollableSheet( - initialChildSize: 400 / height, + initialChildSize: defaultShowHeight / height, minChildSize: 400 / height, maxChildSize: 0.9, expand: false, @@ -73,14 +84,14 @@ Future showArticleInfoRaw({ queryResult: queryResult, thumbnail: thumbnail, headers: headers, - heroKey: 'zxcvzxcvzxcv', + heroKey: heroKey, isBookmarked: isBookmarked, controller: controller, usableTabList: usableTabList, lockRead: lockRead, ), child: const ArticleInfoPage( - key: ObjectKey('asdfasdf'), + key: ObjectKey(pageKey), ), ); return cache!; From 2c8c00ae84e4d9b66c1af08924f894e6c56b897c Mon Sep 17 00:00:00 2001 From: violet-dev Date: Fri, 27 Dec 2024 15:10:20 +0900 Subject: [PATCH 2/6] Adopt article info thunmbnail size --- .../pages/article_info/article_info_page.dart | 58 +++---------- .../lib/pages/article_info/simple_info.dart | 86 +++++++++++-------- 2 files changed, 62 insertions(+), 82 deletions(-) diff --git a/violet/lib/pages/article_info/article_info_page.dart b/violet/lib/pages/article_info/article_info_page.dart index f68380053..0fa8a9096 100644 --- a/violet/lib/pages/article_info/article_info_page.dart +++ b/violet/lib/pages/article_info/article_info_page.dart @@ -1,6 +1,7 @@ // This source code is a part of Project Violet. // Copyright (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License. +import 'dart:io'; import 'dart:math'; import 'package:auto_animated/auto_animated.dart'; @@ -73,8 +74,6 @@ class ArticleInfoPage extends StatelessWidget { width: width - 16, height: Variables.articleInfoHeight, child: Container( - // width: width, - // height: height, color: Settings.themeWhat ? Colors.black.withOpacity(0.9) : Colors.white.withOpacity(0.97), @@ -83,13 +82,12 @@ class ArticleInfoPage extends StatelessWidget { children: [ Container( width: width, - height: 4 * 50.0 + 16, + height: simpleInfoHeight(), color: Settings.themeWhat ? Colors.grey.shade900.withOpacity(0.6) : Colors.white.withOpacity(0.2), child: SimpleInfoWidget(), ), - // _functionButtons(width, context, data), Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -99,7 +97,7 @@ class ArticleInfoPage extends StatelessWidget { backgroundColor: Settings.majorColor.withAlpha(230), ), onPressed: () async => - await _downloadButtonEvent(context, data), + await downloadButtonEvent(context, data), child: SizedBox( width: (width - 32 - 64 - 32) / 2, child: Text( @@ -115,7 +113,7 @@ class ArticleInfoPage extends StatelessWidget { ), onPressed: data.lockRead ? null - : () async => await _readButtonEvent(context, data), + : () async => await readButtonEvent(context, data), child: SizedBox( width: (width - 32 - 64 - 32) / 2, child: Text( @@ -152,7 +150,7 @@ class ArticleInfoPage extends StatelessWidget { expanded: PreviewAreaWidget( queryResult: data.queryResult, onPageTapped: (page) async => - await _readButtonEvent(context, data, page), + await readButtonEvent(context, data, page), ), collapsed: Container(), ), @@ -196,45 +194,13 @@ class ArticleInfoPage extends StatelessWidget { ); } - /*_functionButtons(width, context, data) { - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - child: Container( - width: (width - 32 - 64 - 32) / 2, - child: Text( - Translations.instance!.trans('download'), - textAlign: TextAlign.center, - ), - ), - style: ElevatedButton.styleFrom( - primary: Settings.majorColor.withAlpha(230), - ), - onPressed: () async => await _downloadButtonEvent(context, data), - ), - const SizedBox(width: 4.0), - ElevatedButton( - child: Container( - width: (width - 32 - 64 - 32) / 2, - child: Text( - Translations.instance!.trans('read'), - textAlign: TextAlign.center, - ), - ), - style: ElevatedButton.styleFrom( - primary: Settings.majorColor, - ), - onPressed: data.lockRead - ? null - : () async => await _readButtonEvent(context, data), - ), - ], - ); - }*/ + double simpleInfoHeight() { + const bottomPadding = 16; + final height = Platform.isWindows ? 4 * 100.0 : 4 * 50.0; + return height + bottomPadding; + } - _downloadButtonEvent(context, data) async { + downloadButtonEvent(context, data) async { if (!Settings.useInnerStorage && !await Permission.manageExternalStorage.isGranted) { if (await Permission.manageExternalStorage.request() == @@ -273,7 +239,7 @@ class ArticleInfoPage extends StatelessWidget { Navigator.pop(context); } - _readButtonEvent(BuildContext context, ArticleInfo data, [int? page]) async { + readButtonEvent(BuildContext context, ArticleInfo data, [int? page]) async { if (Settings.useVioletServer) { Future.delayed(const Duration(milliseconds: 100)).then((value) async { await VioletServer.view(data.queryResult.id()); diff --git a/violet/lib/pages/article_info/simple_info.dart b/violet/lib/pages/article_info/simple_info.dart index 795a745e2..318bf0cdc 100644 --- a/violet/lib/pages/article_info/simple_info.dart +++ b/violet/lib/pages/article_info/simple_info.dart @@ -1,6 +1,8 @@ // This source code is a part of Project Violet. // Copyright (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License. +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flare_flutter/flare_actor.dart'; import 'package:flare_flutter/flare_controls.dart'; @@ -20,22 +22,23 @@ class SimpleInfoWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final size = thumbnailSize(); final data = Provider.of(context); return Row( children: [ Stack( children: [ - _thumbnail(context, data), - _bookmark(data), + thumbnail(context, data), + bookmark(data), ], ), Expanded( child: SizedBox( - height: 4 * 50.0, - width: 3 * 50.0, + height: size.height, + width: size.width, child: Padding( padding: const EdgeInsets.all(4), - child: _simpleInfo(data), + child: simpleInfo(data), ), ), ), @@ -43,7 +46,14 @@ class SimpleInfoWidget extends StatelessWidget { ); } - Widget _thumbnail(BuildContext context, ArticleInfo data) { + Size thumbnailSize() { + final baseSize = Platform.isWindows ? 100.0 : 50.0; + final height = 4 * baseSize; + final width = 3 * baseSize; + return Size(width, height); + } + + Widget thumbnail(BuildContext context, ArticleInfo data) { return Hero( tag: data.heroKey, child: Padding( @@ -51,15 +61,15 @@ class SimpleInfoWidget extends StatelessWidget { child: ClipRRect( borderRadius: BorderRadius.circular(3.0), child: GestureDetector( - onTap: () => _thumbnailTapped(context, data), - child: _thumbnailImage(data), + onTap: () => thumbnailTapped(context, data), + child: thumbnailImage(data), ), ), ), ); } - void _thumbnailTapped(BuildContext context, ArticleInfo data) { + void thumbnailTapped(BuildContext context, ArticleInfo data) { Navigator.of(context).push(PageRouteBuilder( opaque: false, transitionDuration: const Duration(milliseconds: 500), @@ -76,18 +86,19 @@ class SimpleInfoWidget extends StatelessWidget { )); } - Widget _thumbnailImage(ArticleInfo data) { + Widget thumbnailImage(ArticleInfo data) { + final size = thumbnailSize(); return data.thumbnail != null ? CachedNetworkImage( imageUrl: data.thumbnail ?? '', fit: BoxFit.cover, httpHeaders: data.headers, - height: 4 * 50.0, - width: 3 * 50.0, + height: size.height, + width: size.width, ) : SizedBox( - height: 4 * 50.0, - width: 3 * 50.0, + height: size.height, + width: size.width, child: !Settings.simpleItemWidgetLoadingIcon ? const FlareActor( 'assets/flare/Loading2.flr', @@ -107,7 +118,7 @@ class SimpleInfoWidget extends StatelessWidget { ); } - Widget _bookmark(ArticleInfo data) { + Widget bookmark(ArticleInfo data) { return Padding( padding: const EdgeInsets.all(8), child: GestureDetector( @@ -135,29 +146,32 @@ class SimpleInfoWidget extends StatelessWidget { ); } - Widget _simpleInfo(ArticleInfo data) { - return Stack(children: [ - _simpleInfoTextArtist(data), - Padding( - padding: const EdgeInsets.fromLTRB(0, 4 * 50.0 - 50, 0, 0), - child: Theme( - data: ThemeData( - iconTheme: IconThemeData( - color: !Settings.themeWhat ? Colors.black : Colors.white)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - _simpleInfoDateTime(data), - _simpleInfoPages(data), - ], + Widget simpleInfo(ArticleInfo data) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + simpleInfoTextArtist(data), + Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Theme( + data: ThemeData( + iconTheme: IconThemeData( + color: !Settings.themeWhat ? Colors.black : Colors.white)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + simpleInfoDateTime(data), + simpleInfoPages(data), + ], + ), ), ), - ), - ]); + ], + ); } - Widget _simpleInfoTextArtist(ArticleInfo data) { + Widget simpleInfoTextArtist(ArticleInfo data) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.start, @@ -171,7 +185,7 @@ class SimpleInfoWidget extends StatelessWidget { ); } - Widget _simpleInfoDateTime(ArticleInfo data) { + Widget simpleInfoDateTime(ArticleInfo data) { return Row( children: [ const Icon( @@ -187,7 +201,7 @@ class SimpleInfoWidget extends StatelessWidget { ); } - Widget _simpleInfoPages(ArticleInfo data) { + Widget simpleInfoPages(ArticleInfo data) { final id = data.queryResult.id(); return Row( From b04efd2f592204e24c1babc11839589aa64680df Mon Sep 17 00:00:00 2001 From: violet-dev Date: Fri, 27 Dec 2024 15:33:14 +0900 Subject: [PATCH 3/6] Adopt button area size --- .../pages/article_info/article_info_page.dart | 97 ++++++++++++------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/violet/lib/pages/article_info/article_info_page.dart b/violet/lib/pages/article_info/article_info_page.dart index 0fa8a9096..bfa51f2f8 100644 --- a/violet/lib/pages/article_info/article_info_page.dart +++ b/violet/lib/pages/article_info/article_info_page.dart @@ -88,42 +88,7 @@ class ArticleInfoPage extends StatelessWidget { : Colors.white.withOpacity(0.2), child: SimpleInfoWidget(), ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Settings.majorColor.withAlpha(230), - ), - onPressed: () async => - await downloadButtonEvent(context, data), - child: SizedBox( - width: (width - 32 - 64 - 32) / 2, - child: Text( - Translations.instance!.trans('download'), - textAlign: TextAlign.center, - ), - ), - ), - const SizedBox(width: 4.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Settings.majorColor, - ), - onPressed: data.lockRead - ? null - : () async => await readButtonEvent(context, data), - child: SizedBox( - width: (width - 32 - 64 - 32) / 2, - child: Text( - Translations.instance!.trans('read'), - textAlign: TextAlign.center, - ), - ), - ), - ], - ), + buttonArea(context), TagInfoAreaWidget(queryResult: data.queryResult), const DividerWidget(), _CommentArea( @@ -200,6 +165,66 @@ class ArticleInfoPage extends StatelessWidget { return height + bottomPadding; } + Row buttonArea(BuildContext context) { + final width = MediaQuery.of(context).size.width; + final buttonWidth = (width - 32 - 64 - 32) / 2; + final buttonHeight = Platform.isWindows ? 36.0 : null; + final iconSize = Platform.isWindows ? 20.0 : null; + final data = Provider.of(context); + + SizedBox buttonInner(IconData icon, String text) { + return SizedBox( + width: buttonWidth, + height: buttonHeight, + child: Align( + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(icon, size: iconSize), + const SizedBox(width: 6.0), + Text( + text, + textAlign: TextAlign.center, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + ), + ); + } + + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Settings.majorColor.withAlpha(230), + ), + onPressed: () async => await downloadButtonEvent(context, data), + child: buttonInner( + MdiIcons.download, + Translations.instance!.trans('download'), + ), + ), + const SizedBox(width: 4.0), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Settings.majorColor, + ), + onPressed: data.lockRead + ? null + : () async => await readButtonEvent(context, data), + child: buttonInner( + MdiIcons.bookOpenPageVariant, + Translations.instance!.trans('read'), + ), + ), + ], + ); + } + downloadButtonEvent(context, data) async { if (!Settings.useInnerStorage && !await Permission.manageExternalStorage.isGranted) { From 1dfd3673c6e6d03b80296e038992d21620f865c8 Mon Sep 17 00:00:00 2001 From: violet-dev Date: Fri, 27 Dec 2024 15:36:20 +0900 Subject: [PATCH 4/6] Adjust default height --- violet/lib/pages/common/utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/violet/lib/pages/common/utils.dart b/violet/lib/pages/common/utils.dart index 0d140ac03..51e1f3f0f 100644 --- a/violet/lib/pages/common/utils.dart +++ b/violet/lib/pages/common/utils.dart @@ -64,7 +64,7 @@ Future showArticleInfoRaw({ var defaultShowHeight = 400; if (Platform.isWindows) { - defaultShowHeight = (height * 0.9).toInt(); + defaultShowHeight = (height * 0.85).toInt(); } // https://github.com/flutter/flutter/issues/67219 From 0a1840bc81a680490eb30d535e0e1f265cde0562 Mon Sep 17 00:00:00 2001 From: violet-dev Date: Fri, 27 Dec 2024 18:40:47 +0900 Subject: [PATCH 5/6] Full screen key mapping --- violet/lib/main.dart | 19 +++++++++++++++---- violet/pubspec.lock | 8 ++++++++ violet/pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 +++ .../windows/flutter/generated_plugins.cmake | 1 + 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/violet/lib/main.dart b/violet/lib/main.dart index 28320decb..5ccc43133 100644 --- a/violet/lib/main.dart +++ b/violet/lib/main.dart @@ -19,6 +19,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; // @dependent: android import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:fullscreen_window/fullscreen_window.dart'; import 'package:get/get.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -248,11 +249,14 @@ class CustomScrollBehavior extends MaterialScrollBehavior { } // A widget to listen for the Escape key, XButton1 and raise the WillPopScope event +// ignore: must_be_immutable class EscapeKeyListener extends StatelessWidget { final Widget child; final GlobalKey navigatorKey; - const EscapeKeyListener({ + bool toggleFullScreen = false; + + EscapeKeyListener({ super.key, required this.navigatorKey, required this.child, @@ -264,9 +268,16 @@ class EscapeKeyListener extends StatelessWidget { autofocus: true, focusNode: FocusNode(), onKeyEvent: (KeyEvent event) { - if (event is KeyDownEvent && - event.logicalKey == LogicalKeyboardKey.escape) { - navigatorPop(); + if (event is KeyDownEvent) { + switch (event.logicalKey) { + case LogicalKeyboardKey.escape: + navigatorPop(); + break; + case LogicalKeyboardKey.f11: + toggleFullScreen = !toggleFullScreen; + FullScreenWindow.setFullScreen(toggleFullScreen); + break; + } } }, // https://github.com/flutter/flutter/issues/115641#issuecomment-2267579790 diff --git a/violet/pubspec.lock b/violet/pubspec.lock index 1fd663897..61c48366b 100644 --- a/violet/pubspec.lock +++ b/violet/pubspec.lock @@ -937,6 +937,14 @@ packages: description: flutter source: sdk version: "0.0.0" + fullscreen_window: + dependency: "direct main" + description: + name: fullscreen_window + sha256: b3502f890a875de6cd300b06cfc542e089a324faef6c4fb5d5528f9e2ea68d8d + url: "https://pub.dev" + source: hosted + version: "1.1.0" get: dependency: "direct main" description: diff --git a/violet/pubspec.yaml b/violet/pubspec.yaml index 99c97b606..380af6247 100644 --- a/violet/pubspec.yaml +++ b/violet/pubspec.yaml @@ -102,6 +102,7 @@ dependencies: flutter_windowmanager: ^0.2.0 fluttertoast: ^8.2.4 freezed_annotation: ^2.4.4 + fullscreen_window: ^1.1.0 get: ^4.6.6 gradient_widgets: ^0.6.0 html: ^0.15.0 diff --git a/violet/windows/flutter/generated_plugin_registrant.cc b/violet/windows/flutter/generated_plugin_registrant.cc index 1c40f7cb5..9bcdbcae5 100644 --- a/violet/windows/flutter/generated_plugin_registrant.cc +++ b/violet/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterJsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterJsPlugin")); + FullscreenWindowPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FullscreenWindowPluginCApi")); LocalAuthPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("LocalAuthPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/violet/windows/flutter/generated_plugins.cmake b/violet/windows/flutter/generated_plugins.cmake index 7cf25e934..475375b94 100644 --- a/violet/windows/flutter/generated_plugins.cmake +++ b/violet/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus firebase_core flutter_js + fullscreen_window local_auth_windows permission_handler_windows sqlite3_flutter_libs From d9697a9f02a0bde2f89689e7dc60d55072d805f8 Mon Sep 17 00:00:00 2001 From: violet-dev Date: Fri, 27 Dec 2024 18:48:32 +0900 Subject: [PATCH 6/6] Move page by fps key --- violet/lib/pages/viewer/viewer_page.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/violet/lib/pages/viewer/viewer_page.dart b/violet/lib/pages/viewer/viewer_page.dart index a9fd4c845..69fae0a5e 100644 --- a/violet/lib/pages/viewer/viewer_page.dart +++ b/violet/lib/pages/viewer/viewer_page.dart @@ -105,15 +105,23 @@ class _ViewerPageState extends State { onKeyEvent: (KeyEvent event) { if (event is KeyDownEvent) { switch (event.logicalKey) { + case LogicalKeyboardKey.keyW: case LogicalKeyboardKey.arrowUp: - case LogicalKeyboardKey.arrowLeft: c.prev(); break; - + case LogicalKeyboardKey.keyS: case LogicalKeyboardKey.arrowDown: - case LogicalKeyboardKey.arrowRight: c.next(); break; + + case LogicalKeyboardKey.keyA: + case LogicalKeyboardKey.arrowLeft: + c.rightButton(); + break; + case LogicalKeyboardKey.keyD: + case LogicalKeyboardKey.arrowRight: + c.leftButton(); + break; } } },