From 26e8553d9e974b0b82e5b3bb2ab5316cec273b80 Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Sun, 1 Dec 2024 12:39:07 +0800 Subject: [PATCH] opt: dynamic detail/html page Closes #26 Signed-off-by: bggRGjQaUbCoE --- lib/common/widgets/article_content.dart | 2 +- lib/common/widgets/html_render.dart | 8 +- lib/pages/dynamics/detail/view.dart | 114 +++++++++++++----- lib/pages/dynamics/widgets/content_panel.dart | 4 +- lib/pages/html/view.dart | 84 +++++++++++-- lib/pages/webview/webview_page.dart | 29 +++-- lib/utils/storage.dart | 4 + 7 files changed, 184 insertions(+), 61 deletions(-) diff --git a/lib/common/widgets/article_content.dart b/lib/common/widgets/article_content.dart index 5d507aa9..fc9492c8 100644 --- a/lib/common/widgets/article_content.dart +++ b/lib/common/widgets/article_content.dart @@ -26,7 +26,7 @@ Widget articleContent({ text: item.word?.words, style: TextStyle( letterSpacing: 0.3, - fontSize: FontSize.large.value, + fontSize: 17, height: LineHeight.percent(125).size, fontStyle: item.word?.style?.italic == true ? FontStyle.italic : null, diff --git a/lib/common/widgets/html_render.dart b/lib/common/widgets/html_render.dart index 5c3a7a24..9c391a64 100644 --- a/lib/common/widgets/html_render.dart +++ b/lib/common/widgets/html_render.dart @@ -73,7 +73,7 @@ Widget htmlRender({ ], style: { 'html': Style( - fontSize: FontSize.large, + fontSize: FontSize(17), lineHeight: LineHeight.percent(160), letterSpacing: 0.3, ), @@ -91,7 +91,7 @@ Widget htmlRender({ // margin: Margins.zero, ), 'span': Style( - fontSize: FontSize.medium, + fontSize: FontSize.large, height: Height(1.8), ), 'div': Style(height: Height.auto()), @@ -109,12 +109,12 @@ Widget htmlRender({ margin: Margins.only(bottom: 8), ), 'h3,h4,h5': Style( - fontSize: FontSize.large, + fontSize: FontSize(17), fontWeight: FontWeight.bold, margin: Margins.only(bottom: 4), ), 'figcaption': Style( - fontSize: FontSize.medium, + fontSize: FontSize.large, textAlign: TextAlign.center, // margin: Margins.only(top: 4), ), diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index 9c64c107..9ce92a02 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -7,6 +7,7 @@ import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item.dart'; import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPalaX/utils/extension.dart'; import 'package:PiliPalaX/utils/global_data.dart'; +import 'package:PiliPalaX/utils/storage.dart'; import 'package:PiliPalaX/utils/utils.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; @@ -47,6 +48,8 @@ class _DynamicDetailPageState extends State int? opusId; bool isOpusId = false; + late final List _ratio = GStorage.dynamicDetailRatio; + @override void initState() { super.initState(); @@ -202,7 +205,53 @@ class _DynamicDetailPageState extends State ); }, ), - // actions: _detailModel != null ? appBarAction() : [], + actions: context.orientation == Orientation.landscape + ? [ + IconButton( + tooltip: '页面比例调节', + onPressed: () { + showDialog( + context: context, + builder: (context) => Align( + alignment: Alignment.topRight, + child: Container( + margin: EdgeInsets.only( + top: 56, + right: 16, + ), + width: context.width / 4, + height: 32, + child: Builder( + builder: (context) => Slider( + min: 1, + max: 100, + value: _ratio.first, + onChanged: (value) async { + if (value >= 10 && value <= 90) { + _ratio[0] = value; + _ratio[1] = 100 - value; + await GStorage.setting.put( + SettingBoxKey.dynamicDetailRatio, + _ratio, + ); + (context as Element).markNeedsBuild(); + setState(() {}); + } + }, + ), + ), + ), + ), + ); + }, + icon: Transform.rotate( + angle: pi / 2, + child: Icon(Icons.splitscreen), + ), + ), + const SizedBox(width: 16), + ] + : null, ), body: refreshIndicator( onRefresh: () async { @@ -239,41 +288,42 @@ class _DynamicDetailPageState extends State return Row( children: [ Expanded( + flex: _ratio[0].toInt(), child: CustomScrollView( - controller: ScrollController(), - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverPadding( - padding: EdgeInsets.only(left: padding / 2), - sliver: SliverToBoxAdapter( - child: DynamicPanel( - item: _dynamicDetailController.item, - source: 'detail', - ), - )), - ]), - ), - Expanded( - child: CustomScrollView( - controller: - _dynamicDetailController.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverPadding( - padding: EdgeInsets.only(right: padding / 2), - sliver: replyPersistentHeader(context)), - SliverPadding( - padding: EdgeInsets.only(right: padding / 2), - sliver: Obx( - () => replyList(_dynamicDetailController - .loadingState.value), + controller: ScrollController(), + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: EdgeInsets.only(left: padding / 4), + sliver: SliverToBoxAdapter( + child: DynamicPanel( + item: _dynamicDetailController.item, + source: 'detail', ), ), - ] - // .map( - // (e) => SliverPadding(padding: padding, sliver: e)) - // .toList(), ), + ], + ), + ), + Expanded( + flex: _ratio[1].toInt(), + child: CustomScrollView( + controller: _dynamicDetailController.scrollController, + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: EdgeInsets.only(right: padding / 4), + sliver: replyPersistentHeader(context), + ), + SliverPadding( + padding: EdgeInsets.only(right: padding / 4), + sliver: Obx( + () => replyList(_dynamicDetailController + .loadingState.value), + ), + ), + ], + ), ), ], ); diff --git a/lib/pages/dynamics/widgets/content_panel.dart b/lib/pages/dynamics/widgets/content_panel.dart index 2c45e8b1..8c36f077 100644 --- a/lib/pages/dynamics/widgets/content_panel.dart +++ b/lib/pages/dynamics/widgets/content_panel.dart @@ -61,9 +61,9 @@ class Content extends StatelessWidget { selectionControls: MaterialTextSelectionControls(), child: Text.rich( /// fix 默认20px高度 - style: const TextStyle( + style: TextStyle( height: 0, - fontSize: 15, + fontSize: source == 'detail' ? 16 : 15, ), richNode(item, context), maxLines: source == 'detail' ? 999 : 6, diff --git a/lib/pages/html/view.dart b/lib/pages/html/view.dart index 91be6678..d327e4b5 100644 --- a/lib/pages/html/view.dart +++ b/lib/pages/html/view.dart @@ -7,6 +7,7 @@ import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item.dart'; import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPalaX/utils/extension.dart'; import 'package:PiliPalaX/utils/global_data.dart'; +import 'package:PiliPalaX/utils/storage.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -42,6 +43,8 @@ class _HtmlRenderPageState extends State bool _isFabVisible = true; late AnimationController fabAnimationCtr; + late final List _ratio = GStorage.dynamicDetailRatio; + @override void initState() { super.initState(); @@ -134,6 +137,49 @@ class _HtmlRenderPageState extends State title: Text(title), actions: [ const SizedBox(width: 4), + if (context.orientation == Orientation.landscape) + IconButton( + tooltip: '页面比例调节', + onPressed: () { + showDialog( + context: context, + builder: (context) => Align( + alignment: Alignment.topRight, + child: Container( + margin: EdgeInsets.only( + top: 56, + right: 16, + ), + width: context.width / 4, + height: 32, + child: Builder( + builder: (context) => Slider( + min: 1, + max: 100, + value: _ratio.first, + onChanged: (value) async { + if (value >= 10 && value <= 90) { + _ratio[0] = value; + _ratio[1] = 100 - value; + await GStorage.setting.put( + SettingBoxKey.dynamicDetailRatio, + _ratio, + ); + (context as Element).markNeedsBuild(); + setState(() {}); + } + }, + ), + ), + ), + ), + ); + }, + icon: Transform.rotate( + angle: pi / 2, + child: Icon(Icons.splitscreen), + ), + ), IconButton( tooltip: '用内置浏览器打开', onPressed: () { @@ -217,6 +263,7 @@ class _HtmlRenderPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( + flex: _ratio[0].toInt(), child: CustomScrollView( controller: orientation == Orientation.portrait ? _htmlRenderCtr.scrollController @@ -225,7 +272,7 @@ class _HtmlRenderPageState extends State SliverPadding( padding: orientation == Orientation.portrait ? EdgeInsets.symmetric(horizontal: padding) - : EdgeInsets.only(left: padding / 2), + : EdgeInsets.only(left: padding / 4), sliver: SliverToBoxAdapter( child: Obx( () => _htmlRenderCtr.loaded.value @@ -237,21 +284,31 @@ class _HtmlRenderPageState extends State SliverPadding( padding: orientation == Orientation.portrait ? EdgeInsets.symmetric(horizontal: padding) - : EdgeInsets.only(left: padding / 2), + : EdgeInsets.only(left: padding / 4), sliver: _buildContent, ), if (orientation == Orientation.portrait) ...[ - SliverToBoxAdapter( - child: Divider( - thickness: 8, - color: Theme.of(context) - .dividerColor - .withOpacity(0.05), + SliverPadding( + padding: EdgeInsets.symmetric(horizontal: padding), + sliver: SliverToBoxAdapter( + child: Divider( + thickness: 8, + color: Theme.of(context) + .dividerColor + .withOpacity(0.05), + ), ), ), - SliverToBoxAdapter(child: replyHeader()), - Obx( - () => replyList(_htmlRenderCtr.loadingState.value), + SliverPadding( + padding: EdgeInsets.symmetric(horizontal: padding), + sliver: SliverToBoxAdapter(child: replyHeader()), + ), + SliverPadding( + padding: EdgeInsets.symmetric(horizontal: padding), + sliver: Obx( + () => + replyList(_htmlRenderCtr.loadingState.value), + ), ), ], ], @@ -263,17 +320,18 @@ class _HtmlRenderPageState extends State color: Theme.of(context).dividerColor.withOpacity(0.05)), Expanded( + flex: _ratio[1].toInt(), child: CustomScrollView( controller: _htmlRenderCtr.scrollController, slivers: [ SliverPadding( - padding: EdgeInsets.only(right: padding / 2), + padding: EdgeInsets.only(right: padding / 4), sliver: SliverToBoxAdapter( child: replyHeader(), ), ), SliverPadding( - padding: EdgeInsets.only(right: padding / 2), + padding: EdgeInsets.only(right: padding / 4), sliver: Obx( () => replyList(_htmlRenderCtr.loadingState.value), diff --git a/lib/pages/webview/webview_page.dart b/lib/pages/webview/webview_page.dart index 009fe7c1..a27ac7f2 100644 --- a/lib/pages/webview/webview_page.dart +++ b/lib/pages/webview/webview_page.dart @@ -8,8 +8,17 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -// ignore: constant_identifier_names -enum WebviewMenuItem { Refresh, Copy, Open_In_Browser, Clear_Cache, Go_Back } +enum WebviewMenuItem { refresh, copy, openInBrowser, clearCache, goBack } + +extension WebviewMenuItemExt on WebviewMenuItem { + String get title => [ + '刷新', + '复制链接', + '浏览器中打开', + '清除缓存', + '返回', + ][index]; +} class WebviewPageNew extends StatefulWidget { const WebviewPageNew({super.key}); @@ -63,22 +72,22 @@ class _WebviewPageNewState extends State { PopupMenuButton( onSelected: (item) async { switch (item) { - case WebviewMenuItem.Refresh: + case WebviewMenuItem.refresh: _webViewController?.reload(); break; - case WebviewMenuItem.Copy: + case WebviewMenuItem.copy: WebUri? uri = await _webViewController?.getUrl(); if (uri != null) { Utils.copyText(uri.toString()); } break; - case WebviewMenuItem.Open_In_Browser: + case WebviewMenuItem.openInBrowser: WebUri? uri = await _webViewController?.getUrl(); if (uri != null) { Utils.launchURL(uri.toString()); } break; - case WebviewMenuItem.Clear_Cache: + case WebviewMenuItem.clearCache: try { await InAppWebViewController.clearAllCache(); await _webViewController?.clearHistory(); @@ -87,9 +96,11 @@ class _WebviewPageNewState extends State { SmartDialog.showToast(e.toString()); } break; - case WebviewMenuItem.Go_Back: + case WebviewMenuItem.goBack: if (await _webViewController?.canGoBack() == true) { _webViewController?.goBack(); + } else { + Get.back(); } break; } @@ -99,9 +110,9 @@ class _WebviewPageNewState extends State { (item) => PopupMenuItem(value: item, child: Text(item.name))), const PopupMenuDivider(), PopupMenuItem( - value: WebviewMenuItem.Go_Back, + value: WebviewMenuItem.goBack, child: Text( - WebviewMenuItem.Go_Back.name, + WebviewMenuItem.goBack.name, style: TextStyle(color: Theme.of(context).colorScheme.error), )), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 9d8b16be..35c7bb3a 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -108,6 +108,9 @@ class GStorage { static bool get grpcReply => setting.get(SettingBoxKey.grpcReply, defaultValue: true); + static List get dynamicDetailRatio => + setting.get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0]); + static MemberTabType get memberTab => MemberTabType .values[setting.get(SettingBoxKey.memberTab, defaultValue: 0)]; @@ -310,6 +313,7 @@ class SettingBoxKey { memberTab = 'memberTab', subtitleFontScale = 'subtitleFontScale', subtitleFontScaleFS = 'subtitleFontScaleFS', + dynamicDetailRatio = 'dynamicDetailRatio', // 代理host port systemProxyHost = 'systemProxyHost',