From aa4e251295429c959854af3898e191020a6e1655 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 11:37:19 +0800 Subject: [PATCH 1/7] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E9=A1=B5null?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/related/view.dart | 3 ++- lib/pages/video/detail/view.dart | 2 +- lib/plugin/pl_player/controller.dart | 15 ++++++++------- lib/plugin/pl_player/view.dart | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/pages/video/detail/related/view.dart b/lib/pages/video/detail/related/view.dart index 5b6fdc962..51c296f33 100644 --- a/lib/pages/video/detail/related/view.dart +++ b/lib/pages/video/detail/related/view.dart @@ -9,7 +9,8 @@ import './controller.dart'; class RelatedVideoPanel extends StatelessWidget { final ReleatedController _releatedController = - Get.put(ReleatedController(), tag: Get.arguments['heroTag']); + Get.put(ReleatedController(), tag: Get.arguments?['heroTag']); + RelatedVideoPanel({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index d063c3b2c..59fa39b2c 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -235,7 +235,7 @@ class _VideoDetailPageState extends State videoIntroController.isPaused = false; if (_extendNestCtr.position.pixels == 0 && autoplay) { await Future.delayed(const Duration(milliseconds: 300)); - plPlayerController!.seekTo(videoDetailController.defaultST); + plPlayerController?.seekTo(videoDetailController.defaultST); plPlayerController?.play(); } plPlayerController?.addStatusLister(playerListener); diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index fd3f02c9e..aeb705c62 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -621,7 +621,7 @@ class PlPlayerController { if (duration.value.inSeconds != 0) { if (type != 'slider') { /// 拖动进度条调节时,不等待第一帧,防止抖动 - await _videoPlayerController!.stream.buffer.first; + await _videoPlayerController?.stream.buffer.first; } await _videoPlayerController?.seek(position); // if (playerStatus.stopped) { @@ -1086,12 +1086,13 @@ class PlPlayerController { localCache.put(LocalCacheKey.danmakuOpacity, opacityVal); localCache.put(LocalCacheKey.danmakuFontScale, fontSizeVal); localCache.put(LocalCacheKey.danmakuDuration, danmakuDurationVal); - - var pp = _videoPlayerController!.platform as NativePlayer; - await pp.setProperty('audio-files', ''); - removeListeners(); - await _videoPlayerController?.dispose(); - _videoPlayerController = null; + if (_videoPlayerController != null) { + var pp = _videoPlayerController!.platform as NativePlayer; + await pp.setProperty('audio-files', ''); + removeListeners(); + await _videoPlayerController?.dispose(); + _videoPlayerController = null; + } _instance = null; // 关闭所有视频页面恢复亮度 resetBrightness(); diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 860342ef2..b289dde0d 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -703,7 +703,7 @@ class _PLVideoPlayerState extends State ), ); } else { - return nil; + return const SizedBox(); } }), From 538b3d88aa0578fe03e8960b8f19658d87f8a3c9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 14:01:33 +0800 Subject: [PATCH 2/7] =?UTF-8?q?mod:=20=E4=BB=A3=E7=A0=81=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/reply_new/view.dart | 95 ++++++---------------- 1 file changed, 27 insertions(+), 68 deletions(-) diff --git a/lib/pages/video/detail/reply_new/view.dart b/lib/pages/video/detail/reply_new/view.dart index cd5418227..01c95adc3 100644 --- a/lib/pages/video/detail/reply_new/view.dart +++ b/lib/pages/video/detail/reply_new/view.dart @@ -2,12 +2,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:hive/hive.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/utils/feed_back.dart'; -import 'package:pilipala/utils/storage.dart'; class VideoReplyNewDialog extends StatefulWidget { final int? oid; @@ -34,23 +32,16 @@ class _VideoReplyNewDialogState extends State final TextEditingController _replyContentController = TextEditingController(); final FocusNode replyContentFocusNode = FocusNode(); final GlobalKey _formKey = GlobalKey(); - bool ableClean = false; - Timer? timer; - Box localCache = GStrorage.localCache; - late double sheetHeight; @override void initState() { super.initState(); // 监听输入框聚焦 // replyContentFocusNode.addListener(_onFocus); - _replyContentController.addListener(_printLatestValue); // 界面观察者 必须 WidgetsBinding.instance.addObserver(this); // 自动聚焦 _autoFocus(); - - sheetHeight = localCache.get('sheetHeight'); } _autoFocus() async { @@ -60,12 +51,6 @@ class _VideoReplyNewDialogState extends State } } - _printLatestValue() { - setState(() { - ableClean = _replyContentController.text != ''; - }); - } - Future submitReplyAdd() async { feedBack(); String message = _replyContentController.text; @@ -113,12 +98,14 @@ class _VideoReplyNewDialogState extends State mainAxisSize: MainAxisSize.min, children: [ ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 200, - ), + constraints: const BoxConstraints( + maxHeight: 200, + minHeight: 120, + ), + child: Container( + padding: const EdgeInsets.only( + top: 12, right: 15, left: 15, bottom: 10), child: SingleChildScrollView( - padding: const EdgeInsets.only( - top: 6, right: 15, left: 15, bottom: 10), child: Form( key: _formKey, autovalidateMode: AutovalidateMode.onUserInteraction, @@ -137,7 +124,9 @@ class _VideoReplyNewDialogState extends State style: Theme.of(context).textTheme.bodyLarge, ), ), - )), + ), + ), + ), Divider( height: 1, color: Theme.of(context).dividerColor.withOpacity(0.1), @@ -152,34 +141,23 @@ class _VideoReplyNewDialogState extends State width: 36, height: 36, child: IconButton( - onPressed: () { - if (keyboardHeight > 0) { - FocusScope.of(context).unfocus(); - } else { - FocusScope.of(context) - .requestFocus(replyContentFocusNode); - } - }, - icon: Icon( - keyboardHeight > 0 - ? Icons.keyboard_hide - : Icons.keyboard, - size: 22, - color: Theme.of(context).colorScheme.onBackground), - highlightColor: - Theme.of(context).colorScheme.onInverseSurface, - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - backgroundColor: - MaterialStateProperty.resolveWith((states) { - // 如果按钮被按下,返回高亮颜色 - if (states.contains(MaterialState.pressed)) { - return Theme.of(context).highlightColor; - } - // 默认状态下,返回透明颜色 - return Colors.transparent; - }), - )), + onPressed: () { + FocusScope.of(context) + .requestFocus(replyContentFocusNode); + }, + icon: Icon(Icons.keyboard, + size: 22, + color: Theme.of(context).colorScheme.onBackground), + highlightColor: + Theme.of(context).colorScheme.onInverseSurface, + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + backgroundColor: + MaterialStateProperty.resolveWith((states) { + return Theme.of(context).highlightColor; + }), + ), + ), ), const Spacer(), TextButton( @@ -200,22 +178,3 @@ class _VideoReplyNewDialogState extends State ); } } - -typedef DebounceCallback = void Function(); - -class Debouncer { - DebounceCallback? callback; - final int? milliseconds; - Timer? _timer; - - Debouncer({this.milliseconds}); - - run(DebounceCallback callback) { - if (_timer != null) { - _timer!.cancel(); - } - _timer = Timer(Duration(milliseconds: milliseconds!), () { - callback(); - }); - } -} From 27c954ec9561fb62a10855401078aecde9cd9f25 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 16:09:08 +0800 Subject: [PATCH 3/7] =?UTF-8?q?fix:=20=E4=B8=A4=E6=AC=A1=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E5=87=BA=E5=BA=94=E7=94=A8=20issues=20#303?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/main/controller.dart | 7 ++++--- lib/pages/main/view.dart | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index 15962da46..04b4ef08c 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; @@ -66,15 +67,15 @@ class MainController extends GetxController { hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true); } - Future onBackPressed(BuildContext context) { + void onBackPressed(BuildContext context) { if (_lastPressedAt == null || DateTime.now().difference(_lastPressedAt!) > const Duration(seconds: 2)) { // 两次点击时间间隔超过2秒,重新记录时间戳 _lastPressedAt = DateTime.now(); SmartDialog.showToast("再按一次退出Pili"); - return Future.value(false); // 不退出应用 + return; // 不退出应用 } - return Future.value(true); // 退出应用 + SystemNavigator.pop(); // 退出应用 } } diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index eb3444e1d..7fa7b2875 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -94,7 +94,10 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { localCache.put('sheetHeight', sheetHeight); localCache.put('statusBarHeight', statusBarHeight); return PopScope( - onPopInvoked: (bool status) => _mainController.onBackPressed(context), + canPop: false, + onPopInvoked: (bool didPop) async { + _mainController.onBackPressed(context); + }, child: Scaffold( extendBody: true, body: PageView( From 9e40e162ac632d80d93bc3a9b9bcf69b70f1d791 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 16:21:38 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=E4=BC=98=E5=85=88=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/main/controller.dart | 5 +++++ lib/pages/main/view.dart | 15 +++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index 04b4ef08c..a16e841dc 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -57,6 +57,8 @@ class MainController extends GetxController { Box setting = GStrorage.setting; DateTime? _lastPressedAt; late bool hideTabBar; + late PageController pageController; + int selectedIndex = 0; @override void onInit() { @@ -73,6 +75,9 @@ class MainController extends GetxController { const Duration(seconds: 2)) { // 两次点击时间间隔超过2秒,重新记录时间戳 _lastPressedAt = DateTime.now(); + if (selectedIndex != 0) { + pageController.jumpTo(0); + } SmartDialog.showToast("再按一次退出Pili"); return; // 不退出应用 } diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 7fa7b2875..528ab8686 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -24,8 +24,6 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { final DynamicsController _dynamicController = Get.put(DynamicsController()); final MediaController _mediaController = Get.put(MediaController()); - PageController? _pageController; - int selectedIndex = 0; int? _lastSelectTime; //上次点击时间 Box setting = GStrorage.setting; late bool enableMYBar; @@ -34,13 +32,14 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { void initState() { super.initState(); _lastSelectTime = DateTime.now().millisecondsSinceEpoch; - _pageController = PageController(initialPage: selectedIndex); + _mainController.pageController = + PageController(initialPage: _mainController.selectedIndex); enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true); } void setIndex(int value) async { feedBack(); - _pageController!.jumpToPage(value); + _mainController.pageController!.jumpToPage(value); var currentPage = _mainController.pages[value]; if (currentPage is HomePage) { if (_homeController.flag) { @@ -102,9 +101,9 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { extendBody: true, body: PageView( physics: const NeverScrollableScrollPhysics(), - controller: _pageController, + controller: _mainController.pageController, onPageChanged: (index) { - selectedIndex = index; + _mainController.selectedIndex = index; setState(() {}); }, children: _mainController.pages, @@ -122,7 +121,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { child: enableMYBar ? NavigationBar( onDestinationSelected: (value) => setIndex(value), - selectedIndex: selectedIndex, + selectedIndex: _mainController.selectedIndex, destinations: [ ..._mainController.navigationBars.map((e) { return NavigationDestination( @@ -134,7 +133,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { ], ) : BottomNavigationBar( - currentIndex: selectedIndex, + currentIndex: _mainController.selectedIndex, onTap: (value) => setIndex(value), iconSize: 16, selectedFontSize: 12, From 7428cde10879e659eb4e26b0ea8ec9c5909bb883 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 18:50:25 +0800 Subject: [PATCH 5/7] =?UTF-8?q?mod:=20flutter=203.16=20=E7=89=B9=E6=80=A7?= =?UTF-8?q?=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/widgets/video_card_h.dart | 2 +- lib/common/widgets/video_card_v.dart | 3 ++- lib/main.dart | 5 ++--- lib/pages/bangumi/view.dart | 2 +- lib/pages/live/view.dart | 5 +++-- lib/pages/media/view.dart | 2 +- lib/pages/search_panel/widgets/article_panel.dart | 7 +++---- lib/pages/search_panel/widgets/live_panel.dart | 2 +- lib/pages/search_panel/widgets/media_bangumi_panel.dart | 6 +++--- lib/plugin/pl_player/controller.dart | 2 +- lib/plugin/pl_player/view.dart | 5 ++--- 11 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart index b00f1759f..9fc7daad3 100644 --- a/lib/common/widgets/video_card_h.dart +++ b/lib/common/widgets/video_card_h.dart @@ -69,7 +69,7 @@ class VideoCardH extends StatelessWidget { final double width = (boxConstraints.maxWidth - StyleString.cardSpace * 6 / - MediaQuery.of(context).textScaleFactor) / + MediaQuery.textScalerOf(context).scale(1.0)) / 2; return Container( constraints: const BoxConstraints(minHeight: 88), diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart index c5577af33..0bbd53779 100644 --- a/lib/common/widgets/video_card_v.dart +++ b/lib/common/widgets/video_card_v.dart @@ -326,7 +326,8 @@ class VideoStat extends StatelessWidget { maxLines: 1, text: TextSpan( style: TextStyle( - fontSize: Theme.of(context).textTheme.labelSmall!.fontSize, + fontSize: MediaQuery.textScalerOf(context) + .scale(Theme.of(context).textTheme.labelSmall!.fontSize!), color: Theme.of(context).colorScheme.outline, ), children: [ diff --git a/lib/main.dart b/lib/main.dart index 4e1482d7c..2c7ef1ee0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -156,9 +156,8 @@ class MyApp extends StatelessWidget { return FlutterSmartDialog( toastBuilder: (String msg) => CustomToast(msg: msg), child: MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: - MediaQuery.of(context).textScaleFactor * textScale), + data: MediaQuery.of(context) + .copyWith(textScaler: TextScaler.linear(textScale)), child: child!, ), ); diff --git a/lib/pages/bangumi/view.dart b/lib/pages/bangumi/view.dart index 9a101f166..560f09a5c 100644 --- a/lib/pages/bangumi/view.dart +++ b/lib/pages/bangumi/view.dart @@ -224,7 +224,7 @@ class _BangumiPageState extends State // 列数 crossAxisCount: 3, mainAxisExtent: Get.size.width / 3 / 0.65 + - 32 * MediaQuery.of(context).textScaleFactor, + MediaQuery.textScalerOf(context).scale(32.0), ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { diff --git a/lib/pages/live/view.dart b/lib/pages/live/view.dart index 302d226d6..f693acf17 100644 --- a/lib/pages/live/view.dart +++ b/lib/pages/live/view.dart @@ -162,8 +162,9 @@ class _LivePageState extends State crossAxisCount: crossAxisCount, mainAxisExtent: Get.size.width / crossAxisCount / StyleString.aspectRatio + - (crossAxisCount == 1 ? 48 : 68) * - MediaQuery.of(context).textScaleFactor, + MediaQuery.textScalerOf(context).scale( + (crossAxisCount == 1 ? 48 : 68), + ), ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 9bfac15cc..c3bad4b97 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -163,7 +163,7 @@ class _MediaPageState extends State // const SizedBox(height: 10), SizedBox( width: double.infinity, - height: 200 * MediaQuery.of(context).textScaleFactor, + height: MediaQuery.textScalerOf(context).scale(200), child: FutureBuilder( future: _futureBuilderFuture, builder: (context, snapshot) { diff --git a/lib/pages/search_panel/widgets/article_panel.dart b/lib/pages/search_panel/widgets/article_panel.dart index 6e73151ac..35e396404 100644 --- a/lib/pages/search_panel/widgets/article_panel.dart +++ b/lib/pages/search_panel/widgets/article_panel.dart @@ -26,10 +26,9 @@ Widget searchArticlePanel(BuildContext context, ctr, list) { StyleString.safeSpace, 5, StyleString.safeSpace, 5), child: LayoutBuilder(builder: (context, boxConstraints) { double width = (boxConstraints.maxWidth - - StyleString.cardSpace * - 6 / - MediaQuery.of(context).textScaleFactor) / - 2; + StyleString.cardSpace * + 6 / + MediaQuery.textScalerOf(context).scale(2.0)); return Container( constraints: const BoxConstraints(minHeight: 88), height: width / StyleString.aspectRatio, diff --git a/lib/pages/search_panel/widgets/live_panel.dart b/lib/pages/search_panel/widgets/live_panel.dart index 606b44f66..6fb5f5b89 100644 --- a/lib/pages/search_panel/widgets/live_panel.dart +++ b/lib/pages/search_panel/widgets/live_panel.dart @@ -17,7 +17,7 @@ Widget searchLivePanel(BuildContext context, ctr, list) { mainAxisSpacing: StyleString.cardSpace + 3, mainAxisExtent: MediaQuery.sizeOf(context).width / 2 / StyleString.aspectRatio + - 66 * MediaQuery.of(context).textScaleFactor), + MediaQuery.textScalerOf(context).scale(66.0)), itemCount: list.length, itemBuilder: (context, index) { return LiveItem(liveItem: list![index]); diff --git a/lib/pages/search_panel/widgets/media_bangumi_panel.dart b/lib/pages/search_panel/widgets/media_bangumi_panel.dart index b8ae8d2ee..18799d3a0 100644 --- a/lib/pages/search_panel/widgets/media_bangumi_panel.dart +++ b/lib/pages/search_panel/widgets/media_bangumi_panel.dart @@ -67,11 +67,11 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) { TextSpan( text: i['text'], style: TextStyle( - fontSize: Theme.of(context) + fontSize: MediaQuery.textScalerOf(context) + .scale(Theme.of(context) .textTheme .titleSmall! - .fontSize! * - MediaQuery.of(context).textScaleFactor, + .fontSize!), fontWeight: FontWeight.bold, color: i['type'] == 'em' ? Theme.of(context).colorScheme.primary diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index aeb705c62..d35987f84 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -786,7 +786,7 @@ class PlPlayerController { volume.value = volumeNew; try { - FlutterVolumeController.showSystemUI = false; + FlutterVolumeController.updateShowSystemUI(false); await FlutterVolumeController.setVolume(volumeNew); } catch (err) { print(err); diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index b289dde0d..3980453b6 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_volume_controller/flutter_volume_controller.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; @@ -130,7 +129,7 @@ class _PLVideoPlayerState extends State setting.get(SettingBoxKey.enableBackgroundPlay, defaultValue: false); Future.microtask(() async { try { - FlutterVolumeController.showSystemUI = true; + FlutterVolumeController.updateShowSystemUI(true); _ctr.volumeValue.value = (await FlutterVolumeController.getVolume())!; FlutterVolumeController.addListener((double value) { if (mounted && !_ctr.volumeInterceptEventStream.value) { @@ -154,7 +153,7 @@ class _PLVideoPlayerState extends State Future setVolume(double value) async { try { - FlutterVolumeController.showSystemUI = false; + FlutterVolumeController.updateShowSystemUI(false); await FlutterVolumeController.setVolume(value); } catch (_) {} _ctr.volumeValue.value = value; From dad4a28eb89795559642a1932008972faf34962d Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 20:30:51 +0800 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=E6=9C=AA=E8=AF=BB=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=AE=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 3 ++ lib/http/common.dart | 17 ++++++++ lib/pages/main/controller.dart | 33 +++++++++++++++ lib/pages/main/view.dart | 75 ++++++++++++++++++++-------------- 4 files changed, 97 insertions(+), 31 deletions(-) create mode 100644 lib/http/common.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index c8edf863f..1731519b0 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -467,4 +467,7 @@ class Api { /// page_size static const getSeasonDetailApi = '/x/polymer/web-space/seasons_archives_list'; + + /// 获取未读动态数 + static const getUnreadDynamic = '/x/web-interface/dynamic/entrance'; } diff --git a/lib/http/common.dart b/lib/http/common.dart new file mode 100644 index 000000000..d711a7e77 --- /dev/null +++ b/lib/http/common.dart @@ -0,0 +1,17 @@ +import 'index.dart'; + +class CommonHttp { + static Future unReadDynamic() async { + var res = await Request().get(Api.getUnreadDynamic, + data: {'alltype_offset': 0, 'video_offset': '', 'article_offset': 0}); + if (res.data['code'] == 0) { + return {'status': true, 'data': res.data['data']['dyn_basic_infos']}; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } +} diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index a16e841dc..a55c143e1 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -5,6 +5,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; +import 'package:pilipala/http/common.dart'; import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/pages/home/view.dart'; import 'package:pilipala/pages/media/index.dart'; @@ -28,6 +29,7 @@ class MainController extends GetxController { size: 21, ), 'label': "首页", + 'count': 0, }, { 'icon': const Icon( @@ -39,6 +41,7 @@ class MainController extends GetxController { size: 21, ), 'label': "动态", + 'count': 0, }, { 'icon': const Icon( @@ -50,6 +53,7 @@ class MainController extends GetxController { size: 21, ), 'label': "媒体库", + 'count': 0, } ].obs; final StreamController bottomBarStream = @@ -59,6 +63,8 @@ class MainController extends GetxController { late bool hideTabBar; late PageController pageController; int selectedIndex = 0; + Box userInfoCache = GStrorage.userInfo; + RxBool userLogin = false.obs; @override void onInit() { @@ -67,6 +73,9 @@ class MainController extends GetxController { Utils.checkUpdata(); } hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true); + var userInfo = userInfoCache.get('userInfoCache'); + userLogin.value = userInfo != null; + getUnreadDynamic(); } void onBackPressed(BuildContext context) { @@ -83,4 +92,28 @@ class MainController extends GetxController { } SystemNavigator.pop(); // 退出应用 } + + void getUnreadDynamic() async { + if (!userLogin.value) { + return; + } + int dynamicItemIndex = + navigationBars.indexWhere((item) => item['label'] == "动态"); + var res = await CommonHttp.unReadDynamic(); + var data = res['data']; + if (dynamicItemIndex != -1) { + navigationBars[dynamicItemIndex]['count'] = + data == null ? 0 : data.length; // 修改 count 属性为新的值 + } + navigationBars.refresh(); + } + + void clearUnread() async { + int dynamicItemIndex = + navigationBars.indexWhere((item) => item['label'] == "动态"); + if (dynamicItemIndex != -1) { + navigationBars[dynamicItemIndex]['count'] = 0; // 修改 count 属性为新的值 + } + navigationBars.refresh(); + } } diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 528ab8686..5a570a8f0 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -39,7 +39,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { void setIndex(int value) async { feedBack(); - _mainController.pageController!.jumpToPage(value); + _mainController.pageController.jumpToPage(value); var currentPage = _mainController.pages[value]; if (currentPage is HomePage) { if (_homeController.flag) { @@ -67,6 +67,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { _lastSelectTime = DateTime.now().millisecondsSinceEpoch; } _dynamicController.flag = true; + _mainController.clearUnread(); } else { _dynamicController.flag = false; } @@ -118,36 +119,48 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { curve: Curves.easeInOutCubicEmphasized, duration: const Duration(milliseconds: 500), offset: Offset(0, snapshot.data ? 0 : 1), - child: enableMYBar - ? NavigationBar( - onDestinationSelected: (value) => setIndex(value), - selectedIndex: _mainController.selectedIndex, - destinations: [ - ..._mainController.navigationBars.map((e) { - return NavigationDestination( - icon: e['icon'], - selectedIcon: e['selectIcon'], - label: e['label'], - ); - }).toList(), - ], - ) - : BottomNavigationBar( - currentIndex: _mainController.selectedIndex, - onTap: (value) => setIndex(value), - iconSize: 16, - selectedFontSize: 12, - unselectedFontSize: 12, - items: [ - ..._mainController.navigationBars.map((e) { - return BottomNavigationBarItem( - icon: e['icon'], - activeIcon: e['selectIcon'], - label: e['label'], - ); - }).toList(), - ], - ), + child: Obx( + () => enableMYBar + ? NavigationBar( + onDestinationSelected: (value) => setIndex(value), + selectedIndex: _mainController.selectedIndex, + destinations: [ + ..._mainController.navigationBars.map((e) { + return NavigationDestination( + icon: Badge( + label: Text(e['count'].toString()), + padding: const EdgeInsets.fromLTRB(6, 0, 6, 0), + isLabelVisible: e['count'] > 0, + child: e['icon'], + ), + selectedIcon: e['selectIcon'], + label: e['label'], + ); + }).toList(), + ], + ) + : BottomNavigationBar( + currentIndex: _mainController.selectedIndex, + onTap: (value) => setIndex(value), + iconSize: 16, + selectedFontSize: 12, + unselectedFontSize: 12, + items: [ + ..._mainController.navigationBars.map((e) { + return BottomNavigationBarItem( + icon: Badge( + label: Text(e['count'].toString()), + padding: const EdgeInsets.fromLTRB(6, 0, 6, 0), + isLabelVisible: e['count'] > 0, + child: e['icon'], + ), + activeIcon: e['selectIcon'], + label: e['label'], + ); + }).toList(), + ], + ), + ), ); }, ), From e052c6eafeafad06f1d3e13edc3d854f4eff64e6 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 21 Jan 2024 23:49:32 +0800 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20=E9=A6=96=E9=A1=B5tabbar=20?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/common/tab_type.dart | 1 + lib/pages/home/controller.dart | 69 +++++++++------ lib/pages/home/view.dart | 59 ++++++------- lib/pages/setting/pages/home_tabbar_set.dart | 90 ++++++++++++++++++++ lib/pages/setting/style_setting.dart | 5 ++ lib/router/app_pages.dart | 3 + lib/utils/storage.dart | 3 +- 7 files changed, 168 insertions(+), 62 deletions(-) create mode 100644 lib/pages/setting/pages/home_tabbar_set.dart diff --git a/lib/models/common/tab_type.dart b/lib/models/common/tab_type.dart index 90d190292..e530d7e52 100644 --- a/lib/models/common/tab_type.dart +++ b/lib/models/common/tab_type.dart @@ -9,6 +9,7 @@ enum TabType { live, rcmd, hot, bangumi } extension TabTypeDesc on TabType { String get description => ['直播', '推荐', '热门', '番剧'][index]; + String get id => ['live', 'rcmd', 'hot', 'bangumi'][index]; } List tabsConfig = [ diff --git a/lib/pages/home/controller.dart b/lib/pages/home/controller.dart index 614d103ae..64510ee14 100644 --- a/lib/pages/home/controller.dart +++ b/lib/pages/home/controller.dart @@ -8,12 +8,13 @@ import 'package:pilipala/utils/storage.dart'; class HomeController extends GetxController with GetTickerProviderStateMixin { bool flag = false; - late List tabs; + late RxList tabs = [].obs; RxInt initialIndex = 1.obs; late TabController tabController; late List tabsCtrList; late List tabsPageList; Box userInfoCache = GStrorage.userInfo; + Box settingStorage = GStrorage.setting; RxBool userLogin = false.obs; RxString userFace = ''.obs; var userInfo; @@ -21,6 +22,8 @@ class HomeController extends GetxController with GetTickerProviderStateMixin { late final StreamController searchBarStream = StreamController.broadcast(); late bool hideSearchBar; + late List defaultTabs; + late List tabbarSort; @override void onInit() { @@ -28,34 +31,10 @@ class HomeController extends GetxController with GetTickerProviderStateMixin { userInfo = userInfoCache.get('userInfoCache'); userLogin.value = userInfo != null; userFace.value = userInfo != null ? userInfo.face : ''; - // 进行tabs配置 - tabs = tabsConfig; - tabsCtrList = tabsConfig.map((e) => e['ctr']).toList(); - tabsPageList = tabsConfig.map((e) => e['page']).toList(); - - tabController = TabController( - initialIndex: initialIndex.value, - length: tabs.length, - vsync: this, - ); + setTabConfig(); hideSearchBar = setting.get(SettingBoxKey.hideSearchBar, defaultValue: true); - - // 监听 tabController 切换 - tabController.animation!.addListener(() { - if (tabController.indexIsChanging) { - if (initialIndex.value != tabController.index) { - initialIndex.value = tabController.index; - } - } else { - final int temp = tabController.animation!.value.round(); - if (initialIndex.value != temp) { - initialIndex.value = temp; - tabController.index = initialIndex.value; - } - } - }); } void onRefresh() { @@ -77,4 +56,42 @@ class HomeController extends GetxController with GetTickerProviderStateMixin { if (val) return; userFace.value = userInfo != null ? userInfo.face : ''; } + + void setTabConfig() async { + defaultTabs = tabsConfig; + tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort, + defaultValue: ['live', 'rcmd', 'hot', 'bangumi']); + + tabs.value = defaultTabs + .where((i) => tabbarSort.contains((i['type'] as TabType).id)) + .toList(); + + if (tabbarSort.contains(TabType.rcmd.id)) { + initialIndex.value = tabbarSort.indexOf(TabType.rcmd.id); + } else { + initialIndex.value = 0; + } + tabsCtrList = tabs.map((e) => e['ctr']).toList(); + tabsPageList = tabs.map((e) => e['page']).toList(); + + tabController = TabController( + initialIndex: initialIndex.value, + length: tabs.length, + vsync: this, + ); + // 监听 tabController 切换 + tabController.animation!.addListener(() { + if (tabController.indexIsChanging) { + if (initialIndex.value != tabController.index) { + initialIndex.value = tabController.index; + } + } else { + final int temp = tabController.animation!.value.round(); + if (initialIndex.value != temp) { + initialIndex.value = temp; + tabController.index = initialIndex.value; + } + } + }); + } } diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index f9823334e..c31460fb0 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -90,7 +90,11 @@ class _HomePageState extends State ctr: _homeController, callback: showUserBottomSheet, ), - const CustomTabs(), + if (_homeController.tabs.length > 1) ...[ + const CustomTabs(), + ] else ...[ + const SizedBox(height: 6), + ], Expanded( child: TabBarView( controller: _homeController.tabController, @@ -250,17 +254,6 @@ class CustomTabs extends StatefulWidget { class _CustomTabsState extends State { final HomeController _homeController = Get.put(HomeController()); - int currentTabIndex = 1; - - @override - void initState() { - super.initState(); - _homeController.tabController.addListener(listen); - } - - void listen() { - _homeController.initialIndex.value = _homeController.tabController.index; - } void onTap(int index) { feedBack(); @@ -271,34 +264,30 @@ class _CustomTabsState extends State { _homeController.tabController.index = index; } - @override - void dispose() { - super.dispose(); - _homeController.tabController.removeListener(listen); - } - @override Widget build(BuildContext context) { return Container( height: 44, margin: const EdgeInsets.only(top: 4), - child: ListView.separated( - padding: const EdgeInsets.symmetric(horizontal: 14.0), - scrollDirection: Axis.horizontal, - itemCount: _homeController.tabs.length, - separatorBuilder: (BuildContext context, int index) { - return const SizedBox(width: 10); - }, - itemBuilder: (BuildContext context, int index) { - String label = _homeController.tabs[index]['label']; - return Obx( - () => CustomChip( - onTap: () => onTap(index), - label: label, - selected: index == _homeController.initialIndex.value, - ), - ); - }, + child: Obx( + () => ListView.separated( + padding: const EdgeInsets.symmetric(horizontal: 14.0), + scrollDirection: Axis.horizontal, + itemCount: _homeController.tabs.length, + separatorBuilder: (BuildContext context, int index) { + return const SizedBox(width: 10); + }, + itemBuilder: (BuildContext context, int index) { + String label = _homeController.tabs[index]['label']; + return Obx( + () => CustomChip( + onTap: () => onTap(index), + label: label, + selected: index == _homeController.initialIndex.value, + ), + ); + }, + ), ), ); } diff --git a/lib/pages/setting/pages/home_tabbar_set.dart b/lib/pages/setting/pages/home_tabbar_set.dart new file mode 100644 index 000000000..445ca4f5b --- /dev/null +++ b/lib/pages/setting/pages/home_tabbar_set.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/models/common/tab_type.dart'; +import 'package:pilipala/utils/storage.dart'; + +class TabbarSetPage extends StatefulWidget { + const TabbarSetPage({super.key}); + + @override + State createState() => _TabbarSetPageState(); +} + +class _TabbarSetPageState extends State { + Box settingStorage = GStrorage.setting; + late List defaultTabs; + late List tabbarSort; + + @override + void initState() { + super.initState(); + defaultTabs = tabsConfig; + tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort, + defaultValue: ['live', 'rcmd', 'hot', 'bangumi']); + } + + void saveEdit() { + List sortedTabbar = defaultTabs + .where((i) => tabbarSort.contains((i['type'] as TabType).id)) + .map((i) => (i['type'] as TabType).id) + .toList(); + if (sortedTabbar.isEmpty) { + SmartDialog.showToast('请至少设置一项!'); + return; + } + settingStorage.put(SettingBoxKey.tabbarSort, sortedTabbar); + SmartDialog.showToast('保存成功,下次启动时生效'); + } + + void onReorder(int oldIndex, int newIndex) { + setState(() { + if (newIndex > oldIndex) { + newIndex -= 1; + } + final tabsItem = defaultTabs.removeAt(oldIndex); + defaultTabs.insert(newIndex, tabsItem); + }); + } + + @override + Widget build(BuildContext context) { + final listTiles = [ + for (int i = 0; i < defaultTabs.length; i++) ...[ + CheckboxListTile( + key: Key(defaultTabs[i]['label']), + value: tabbarSort.contains((defaultTabs[i]['type'] as TabType).id), + onChanged: (bool? newValue) { + String tabTypeId = (defaultTabs[i]['type'] as TabType).id; + if (!newValue!) { + tabbarSort.remove(tabTypeId); + } else { + tabbarSort.add(tabTypeId); + } + setState(() {}); + }, + title: Text(defaultTabs[i]['label']), + secondary: const Icon(Icons.drag_indicator_rounded), + ) + ] + ]; + + return Scaffold( + appBar: AppBar( + title: const Text('Tabbar编辑'), + actions: [ + TextButton(onPressed: () => saveEdit(), child: const Text('保存')), + const SizedBox(width: 12) + ], + ), + body: ReorderableListView( + onReorder: onReorder, + physics: const NeverScrollableScrollPhysics(), + footer: SizedBox( + height: MediaQuery.of(context).padding.bottom + 30, + ), + children: listTiles, + ), + ); + } +} diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index a4e39aa09..57ec110a8 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -254,6 +254,11 @@ class _StyleSettingState extends State { onTap: () => Get.toNamed('/fontSizeSetting'), title: Text('字体大小', style: titleStyle), ), + ListTile( + dense: false, + onTap: () => Get.toNamed('/tabbarSetting'), + title: Text('首页tabbar', style: titleStyle), + ), if (Platform.isAndroid) ListTile( dense: false, diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 996869be8..64d8da316 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -36,6 +36,7 @@ import '../pages/setting/index.dart'; import '../pages/setting/pages/color_select.dart'; import '../pages/setting/pages/display_mode.dart'; import '../pages/setting/pages/font_size_select.dart'; +import '../pages/setting/pages/home_tabbar_set.dart'; import '../pages/setting/pages/play_speed_set.dart'; import '../pages/setting/play_setting.dart'; import '../pages/setting/privacy_setting.dart'; @@ -112,6 +113,8 @@ class Routes { // CustomGetPage(name: '/blackListPage', page: () => const BlackListPage()), CustomGetPage(name: '/colorSetting', page: () => const ColorSelectPage()), + // 首页tabbar + CustomGetPage(name: '/tabbarSetting', page: () => const TabbarSetPage()), CustomGetPage( name: '/fontSizeSetting', page: () => const FontSizeSelectPage()), // 屏幕帧率 diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index f59a7bc15..990376111 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -144,7 +144,8 @@ class SettingBoxKey { customRows = 'customRows', // 自定义列 enableMYBar = 'enableMYBar', hideSearchBar = 'hideSearchBar', // 收起顶栏 - hideTabBar = 'hideTabBar'; // 收起底栏 + hideTabBar = 'hideTabBar', // 收起底栏 + tabbarSort = 'tabbarSort'; // 首页tabbar } class LocalCacheKey {