diff --git a/lib/models/common/enum_with_label.dart b/lib/models/common/enum_with_label.dart new file mode 100644 index 000000000..3067a209a --- /dev/null +++ b/lib/models/common/enum_with_label.dart @@ -0,0 +1,4 @@ +abstract class EnumWithLabel { + String get label; + int get index; +} diff --git a/lib/models/common/home_tab_type.dart b/lib/models/common/home_tab_type.dart index 8d367b65a..27250d5e7 100644 --- a/lib/models/common/home_tab_type.dart +++ b/lib/models/common/home_tab_type.dart @@ -1,5 +1,7 @@ +import 'package:PiliPlus/models/common/enum_with_label.dart'; import 'package:PiliPlus/pages/bangumi/controller.dart'; import 'package:PiliPlus/pages/bangumi/view.dart'; +import 'package:PiliPlus/pages/common/common_controller.dart'; import 'package:PiliPlus/pages/hot/controller.dart'; import 'package:PiliPlus/pages/hot/view.dart'; import 'package:PiliPlus/pages/live/controller.dart'; @@ -8,9 +10,10 @@ import 'package:PiliPlus/pages/rank/controller.dart'; import 'package:PiliPlus/pages/rank/view.dart'; import 'package:PiliPlus/pages/rcmd/controller.dart'; import 'package:PiliPlus/pages/rcmd/view.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; -enum HomeTabType { +enum HomeTabType implements EnumWithLabel { live('直播'), rcmd('推荐'), hot('热门'), @@ -18,45 +21,26 @@ enum HomeTabType { bangumi('番剧'), cinema('影视'); - final String description; - const HomeTabType(this.description); -} + @override + final String label; + const HomeTabType(this.label); -List get homeTabsConfig => [ - { - 'label': '直播', - 'type': HomeTabType.live, - 'ctr': Get.find, - 'page': const LivePage(), - }, - { - 'label': '推荐', - 'type': HomeTabType.rcmd, - 'ctr': Get.find, - 'page': const RcmdPage(), - }, - { - 'label': '热门', - 'type': HomeTabType.hot, - 'ctr': Get.find, - 'page': const HotPage(), - }, - { - 'label': '分区', - 'type': HomeTabType.rank, - 'ctr': Get.find, - 'page': const RankPage(), - }, - { - 'label': '番剧', - 'type': HomeTabType.bangumi, - 'ctr': Get.find, - 'page': const BangumiPage(tabType: HomeTabType.bangumi), - }, - { - 'label': '影视', - 'type': HomeTabType.cinema, - 'ctr': Get.find, - 'page': const BangumiPage(tabType: HomeTabType.cinema), - }, - ]; + ScrollOrRefreshMixin Function() get ctr => switch (this) { + HomeTabType.live => Get.find, + HomeTabType.rcmd => Get.find, + HomeTabType.hot => Get.find, + HomeTabType.rank => + (Get.find) as ScrollOrRefreshMixin Function(), + HomeTabType.bangumi || HomeTabType.cinema => () => + Get.find(tag: name), + }; + + Widget get page => switch (this) { + HomeTabType.live => const LivePage(), + HomeTabType.rcmd => const RcmdPage(), + HomeTabType.hot => const HotPage(), + HomeTabType.rank => const RankPage(), + HomeTabType.bangumi => const BangumiPage(tabType: HomeTabType.bangumi), + HomeTabType.cinema => const BangumiPage(tabType: HomeTabType.cinema), + }; +} diff --git a/lib/models/common/nav_bar_config.dart b/lib/models/common/nav_bar_config.dart index ef3fea5b2..d93d4f712 100644 --- a/lib/models/common/nav_bar_config.dart +++ b/lib/models/common/nav_bar_config.dart @@ -1,68 +1,34 @@ +import 'package:PiliPlus/models/common/enum_with_label.dart'; +import 'package:PiliPlus/pages/dynamics/view.dart'; +import 'package:PiliPlus/pages/home/view.dart'; +import 'package:PiliPlus/pages/media/view.dart'; import 'package:flutter/material.dart'; -// enum NavigationBarType { -// home( -// '首页', -// Icon(Icons.home_outlined, size: 23), -// Icon(Icons.home, size: 21), -// ), -// dynamics( -// '动态', -// Icon(Icons.motion_photos_on_outlined, size: 21), -// Icon(Icons.motion_photos_on, size: 21), -// ), -// media( -// '媒体库', -// Icon(Icons.video_collection_outlined, size: 21), -// Icon(Icons.video_collection, size: 21), -// ); +enum NavigationBarType implements EnumWithLabel { + home( + '首页', + Icon(Icons.home_outlined, size: 23), + Icon(Icons.home, size: 21), + HomePage(), + ), + dynamics( + '动态', + Icon(Icons.motion_photos_on_outlined, size: 21), + Icon(Icons.motion_photos_on, size: 21), + DynamicsPage(), + ), + media( + '媒体库', + Icon(Icons.video_collection_outlined, size: 21), + Icon(Icons.video_collection, size: 21), + MediaPage(), + ); -// final Icon icon; -// final Icon selectIcon; -// final String label; + @override + final String label; + final Icon icon; + final Icon selectIcon; + final Widget page; -// const NavigationBarType(this.label, this.icon, this.selectIcon); -// } - -// TODO enum -List defaultNavigationBars = [ - { - 'id': 0, - 'icon': const Icon( - Icons.home_outlined, - size: 23, - ), - 'selectIcon': const Icon( - Icons.home, - size: 23, - ), - 'label': "首页", - 'count': 0, - }, - { - 'id': 1, - 'icon': const Icon( - Icons.motion_photos_on_outlined, - size: 21, - ), - 'selectIcon': const Icon( - Icons.motion_photos_on, - size: 21, - ), - 'label': "动态", - 'count': 0, - }, - { - 'id': 2, - 'icon': const Icon( - Icons.video_collection_outlined, - size: 21, - ), - 'selectIcon': const Icon( - Icons.video_collection, - size: 21, - ), - 'label': "媒体库", - 'count': 0, - } -]; + const NavigationBarType(this.label, this.icon, this.selectIcon, this.page); +} diff --git a/lib/pages/common/common_controller.dart b/lib/pages/common/common_controller.dart index 3aa22c3df..d6c9eeb6f 100644 --- a/lib/pages/common/common_controller.dart +++ b/lib/pages/common/common_controller.dart @@ -6,7 +6,7 @@ import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -abstract mixin class ScrollOrRefreshMixin { +mixin ScrollOrRefreshMixin { ScrollController get scrollController; void animateToTop() => scrollController.animToTop(); diff --git a/lib/pages/dynamics_tab/view.dart b/lib/pages/dynamics_tab/view.dart index e64efde2e..0d10a816b 100644 --- a/lib/pages/dynamics_tab/view.dart +++ b/lib/pages/dynamics_tab/view.dart @@ -6,6 +6,7 @@ import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; +import 'package:PiliPlus/models/common/nav_bar_config.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/common/common_page.dart'; import 'package:PiliPlus/pages/dynamics/controller.dart'; @@ -82,7 +83,7 @@ class _DynamicsTabPageState @override void listener() { - if (_mainController.navigationBars[0]['id'] != 1 && + if (_mainController.navigationBars[0] != NavigationBarType.dynamics && _mainController.selectedIndex.value == 0) { return; } diff --git a/lib/pages/home/controller.dart b/lib/pages/home/controller.dart index 76914aee0..adf87b049 100644 --- a/lib/pages/home/controller.dart +++ b/lib/pages/home/controller.dart @@ -13,8 +13,7 @@ import 'package:get/get.dart'; class HomeController extends GetxController with GetSingleTickerProviderStateMixin, ScrollOrRefreshMixin { - late List tabs; - late List tabsCtrList; + late List tabs; late TabController tabController; RxBool isLogin = false.obs; @@ -28,15 +27,7 @@ class HomeController extends GetxController late RxString defaultSearch = ''.obs; late int lateCheckSearchAt = 0; - ScrollOrRefreshMixin get controller { - final index = tabController.index; - return tabsCtrList[index]!( - tag: switch (tabs[index]['type']) { - HomeTabType.bangumi => HomeTabType.bangumi.name, - HomeTabType.cinema => HomeTabType.cinema.name, - _ => null, - }); - } + ScrollOrRefreshMixin get controller => tabs[tabController.index].ctr(); @override ScrollController get scrollController => controller.scrollController; @@ -73,21 +64,12 @@ class HomeController extends GetxController } void setTabConfig() { - final defaultTabs = [...homeTabsConfig]; - final tabbarSort = GStorage.tabbarSort; - defaultTabs - ..retainWhere( - (item) => tabbarSort.contains((item['type'] as HomeTabType).name)) - ..sort((a, b) => tabbarSort - .indexOf((a['type'] as HomeTabType).name) - .compareTo(tabbarSort.indexOf((b['type'] as HomeTabType).name))); - - tabs = defaultTabs; - - tabsCtrList = tabs.map((e) => e['ctr']).toList(); + List? localTabs = GStorage.setting.get(SettingBoxKey.tabBarSort); + tabs = localTabs?.map((i) => HomeTabType.values[i]).toList() ?? + HomeTabType.values; tabController = TabController( - initialIndex: max(0, tabbarSort.indexOf(HomeTabType.rcmd.name)), + initialIndex: max(0, tabs.indexOf(HomeTabType.rcmd)), length: tabs.length, vsync: this, ); diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index 35daa9aeb..c10533fcc 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -49,7 +49,7 @@ class _HomePageState extends State child: TabBar( controller: _homeController.tabController, tabs: [ - for (var i in _homeController.tabs) Tab(text: i['label']) + for (var i in _homeController.tabs) Tab(text: i.label) ], isScrollable: true, dividerColor: Colors.transparent, @@ -71,8 +71,7 @@ class _HomePageState extends State Expanded( child: tabBarView( controller: _homeController.tabController, - children: - _homeController.tabs.map((e) => e['page']).toList(), + children: _homeController.tabs.map((e) => e.page).toList(), ), ), ], diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart index 934ff0a8b..9cdaec42d 100644 --- a/lib/pages/hot/view.dart +++ b/lib/pages/hot/view.dart @@ -80,9 +80,8 @@ class _HotPageState extends CommonPageState try { HomeController homeController = Get.find(); - int index = homeController.tabs.indexWhere( - (item) => item['type'] == HomeTabType.rank, - ); + int index = homeController.tabs + .indexOf(HomeTabType.rank); if (index != -1) { homeController.tabController.animateTo(index); } else { diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index c5777a0eb..10b3c293d 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -5,18 +5,14 @@ import 'package:PiliPlus/grpc/im.dart'; import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart'; import 'package:PiliPlus/models/common/msg/msg_unread_type.dart'; import 'package:PiliPlus/models/common/nav_bar_config.dart'; -import 'package:PiliPlus/pages/dynamics/view.dart'; -import 'package:PiliPlus/pages/home/view.dart'; -import 'package:PiliPlus/pages/media/view.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; -import 'package:flutter/material.dart'; import 'package:get/get.dart'; class MainController extends GetxController { - List pages = []; - RxList navigationBars = [].obs; + RxList navigationBars = [].obs; + int dynCount = 0; StreamController? bottomBarStream; late bool hideTabBar; @@ -58,7 +54,7 @@ class MainController extends GetxController { SettingBoxKey.dynamicBadgeMode, defaultValue: DynamicBadgeMode.number.index)]; - dynIndex = navigationBars.indexWhere((e) => e['id'] == 1); + dynIndex = navigationBars.indexOf(NavigationBarType.dynamics); if (dynamicBadgeMode != DynamicBadgeMode.hidden) { if (dynIndex != -1) { if (checkDynamic) { @@ -68,7 +64,7 @@ class MainController extends GetxController { } } - homeIndex = navigationBars.indexWhere((e) => e['id'] == 0); + homeIndex = navigationBars.indexOf(NavigationBarType.home); if (msgBadgeMode != DynamicBadgeMode.hidden) { if (homeIndex != -1) { lastCheckUnreadAt = DateTime.now().millisecondsSinceEpoch; @@ -141,8 +137,8 @@ class MainController extends GetxController { } Future setCount([int count = 0]) async { - if (dynIndex == -1 || navigationBars[dynIndex]['count'] == count) return; - navigationBars[dynIndex]['count'] = count; + if (dynIndex == -1 || dynCount == count) return; + dynCount = count; navigationBars.refresh(); } @@ -161,28 +157,19 @@ class MainController extends GetxController { } void setNavBarConfig() { - List defaultNavTabs = [...defaultNavigationBars]; - List navBarSort = - GStorage.setting.get(SettingBoxKey.navBarSort, defaultValue: [0, 1, 2]); - defaultNavTabs - ..retainWhere((item) => navBarSort.contains(item['id'])) - ..sort((a, b) => - navBarSort.indexOf(a['id']).compareTo(navBarSort.indexOf(b['id']))); - navigationBars.value = defaultNavTabs; - int defaultHomePage = GStorage.setting - .get(SettingBoxKey.defaultHomePage, defaultValue: 0) as int; - int defaultIndex = - navigationBars.indexWhere((item) => item['id'] == defaultHomePage); - // 如果找不到匹配项,默认索引设置为0或其他合适的值 - selectedIndex.value = defaultIndex != -1 ? defaultIndex : 0; - pages = navigationBars - .map((e) => switch (e['id']) { - 0 => const HomePage(), - 1 => const DynamicsPage(), - 2 => const MediaPage(), - _ => throw UnimplementedError(), - }) - .toList(); + List? navBarSort = + (GStorage.setting.get(SettingBoxKey.navBarSort) as List?)?.cast(); + int defaultHomePage = GStorage.defaultHomePage; + late final List navigationBars; + if (navBarSort == null) { + navigationBars = NavigationBarType.values; + } else { + navigationBars = + navBarSort.map((i) => NavigationBarType.values[i]).toList(); + if (!navBarSort.contains(defaultHomePage)) defaultHomePage = 0; + } + this.navigationBars.value = navigationBars; + selectedIndex.value = defaultHomePage; } @override diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 1dd4086b4..9756bea60 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/tabs.dart'; import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart'; import 'package:PiliPlus/models/common/image_type.dart'; +import 'package:PiliPlus/models/common/nav_bar_config.dart'; import 'package:PiliPlus/pages/dynamics/controller.dart'; import 'package:PiliPlus/pages/dynamics/view.dart'; import 'package:PiliPlus/pages/home/controller.dart'; @@ -94,8 +95,8 @@ class _MainAppState extends State void _checkDefaultSearch([bool shouldCheck = false]) { if (_mainController.homeIndex != -1 && _homeController.enableSearchWord) { if (shouldCheck && - _mainController.pages[_mainController.selectedIndex.value] - is! HomePage) { + _mainController.navigationBars[_mainController.selectedIndex.value] != + NavigationBarType.home) { return; } int now = DateTime.now().millisecondsSinceEpoch; @@ -112,8 +113,8 @@ class _MainAppState extends State _mainController.homeIndex != -1 && _mainController.msgBadgeMode != DynamicBadgeMode.hidden) { if (shouldCheck && - _mainController.pages[_mainController.selectedIndex.value] - is! HomePage) { + _mainController.navigationBars[_mainController.selectedIndex.value] != + NavigationBarType.home) { return; } int now = DateTime.now().millisecondsSinceEpoch; @@ -128,6 +129,7 @@ class _MainAppState extends State void setIndex(int value) { feedBack(); + final currentPage = _mainController.navigationBars[value].page; if (value != _mainController.selectedIndex.value) { _mainController.selectedIndex.value = value; if (_mainController.mainTabBarView) { @@ -135,7 +137,6 @@ class _MainAppState extends State } else { _mainController.controller.jumpToPage(value); } - dynamic currentPage = _mainController.pages[value]; if (currentPage is HomePage) { _checkDefaultSearch(); _checkUnread(); @@ -143,8 +144,6 @@ class _MainAppState extends State _mainController.setCount(); } } else { - dynamic currentPage = _mainController.pages[value]; - int now = DateTime.now().millisecondsSinceEpoch; if (now - _lastSelectTime < 500) { EasyThrottle.throttle('topOrRefresh', const Duration(milliseconds: 500), @@ -241,16 +240,23 @@ class _MainAppState extends State ..._mainController.navigationBars .map((e) { return NavigationDrawerDestination( - label: Text(e['label']), + label: Text(e.label), icon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['icon'], + type: e, + count: e == + NavigationBarType + .dynamics + ? _mainController.dynCount + : 0, ), selectedIcon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['selectIcon'], + type: e, + count: e == + NavigationBarType + .dynamics + ? _mainController.dynCount + : 0, + selected: true, ), ); }), @@ -271,17 +277,20 @@ class _MainAppState extends State destinations: _mainController.navigationBars .map( (e) => NavigationRailDestination( + label: Text(e.label), icon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['icon'], + type: e, + count: e == NavigationBarType.dynamics + ? _mainController.dynCount + : 0, ), selectedIcon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['selectIcon'], + type: e, + count: e == NavigationBarType.dynamics + ? _mainController.dynCount + : 0, + selected: true, ), - label: Text(e['label']), ), ) .toList(), @@ -315,12 +324,16 @@ class _MainAppState extends State isPortrait ? Axis.horizontal : Axis.vertical, physics: const NeverScrollableScrollPhysics(), controller: _mainController.controller, - children: _mainController.pages, + children: _mainController.navigationBars + .map((i) => i.page) + .toList(), ) : PageView( physics: const NeverScrollableScrollPhysics(), controller: _mainController.controller, - children: _mainController.pages, + children: _mainController.navigationBars + .map((i) => i.page) + .toList(), ), ), ), @@ -353,17 +366,22 @@ class _MainAppState extends State _mainController.navigationBars.map( (e) { return NavigationDestination( + label: e.label, icon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['icon'], + type: e, + count: e == + NavigationBarType.dynamics + ? _mainController.dynCount + : 0, ), selectedIcon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['selectIcon'], + type: e, + count: e == + NavigationBarType.dynamics + ? _mainController.dynCount + : 0, + selected: true, ), - label: e['label'], ); }, ).toList(), @@ -383,17 +401,24 @@ class _MainAppState extends State items: _mainController.navigationBars .map( (e) => BottomNavigationBarItem( + label: e.label, icon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['icon'], + type: e, + count: e == + NavigationBarType + .dynamics + ? _mainController.dynCount + : 0, ), activeIcon: _buildIcon( - id: e['id'], - count: e['count'], - icon: e['selectIcon'], + type: e, + count: e == + NavigationBarType + .dynamics + ? _mainController.dynCount + : 0, + selected: true, ), - label: e['label'], ), ) .toList(), @@ -409,21 +434,21 @@ class _MainAppState extends State } Widget _buildIcon({ - required int id, + required NavigationBarType type, required int count, - required Widget icon, - }) => - id == 1 && - _mainController.dynamicBadgeMode != DynamicBadgeMode.hidden && - count > 0 - ? Badge( - label: _mainController.dynamicBadgeMode == DynamicBadgeMode.number - ? Text(count.toString()) - : null, - padding: const EdgeInsets.fromLTRB(6, 0, 6, 0), - child: icon, - ) - : icon; + bool selected = false, + }) { + final icon = selected ? type.selectIcon : type.icon; + return count > 0 + ? Badge( + label: _mainController.dynamicBadgeMode == DynamicBadgeMode.number + ? Text(count.toString()) + : null, + padding: const EdgeInsets.fromLTRB(6, 0, 6, 0), + child: icon, + ) + : icon; + } Widget userAndSearchVertical(ThemeData theme) { return Column( diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index e995b0786..49acc107a 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models/common/nav_bar_config.dart'; import 'package:PiliPlus/models/user/fav_folder.dart'; import 'package:PiliPlus/pages/common/common_page.dart'; import 'package:PiliPlus/pages/main/controller.dart'; @@ -29,7 +30,7 @@ class _MediaPageState extends CommonPageState @override void listener() { - if (_mainController.navigationBars[0]['id'] != 2 && + if (_mainController.navigationBars[0] != NavigationBarType.media && _mainController.selectedIndex.value == 0) { return; } diff --git a/lib/pages/setting/navigation_bar_set.dart b/lib/pages/setting/navigation_bar_set.dart deleted file mode 100644 index cbf75fed4..000000000 --- a/lib/pages/setting/navigation_bar_set.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:PiliPlus/models/common/nav_bar_config.dart'; -import 'package:PiliPlus/utils/storage.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; - -class NavigationBarSetPage extends StatefulWidget { - const NavigationBarSetPage({super.key}); - - @override - State createState() => _NavigationbarSetPageState(); -} - -class _NavigationbarSetPageState extends State { - late List defaultNavTabs; - late List navBarSort; - - @override - void initState() { - super.initState(); - defaultNavTabs = defaultNavigationBars; - navBarSort = List.from(GStorage.setting - .get(SettingBoxKey.navBarSort, defaultValue: [0, 1, 2])); - // 对 tabData 进行排序 - defaultNavTabs.sort((a, b) { - int indexA = navBarSort.indexOf(a['id']); - int indexB = navBarSort.indexOf(b['id']); - - // 如果类型在 sortOrder 中不存在,则放在末尾 - if (indexA == -1) indexA = navBarSort.length; - if (indexB == -1) indexB = navBarSort.length; - - return indexA.compareTo(indexB); - }); - } - - void saveEdit() { - List sortedTabbar = defaultNavTabs - .where((i) => navBarSort.contains(i['id'])) - .map((i) => i['id']) - .toList(); - if (sortedTabbar.isEmpty) { - sortedTabbar = [0, 1, 2]; - } - GStorage.setting.put(SettingBoxKey.navBarSort, sortedTabbar); - SmartDialog.showToast('保存成功,下次启动时生效'); - } - - void onReorder(int oldIndex, int newIndex) { - setState(() { - if (newIndex > oldIndex) { - newIndex -= 1; - } - final tabsItem = defaultNavTabs.removeAt(oldIndex); - defaultNavTabs.insert(newIndex, tabsItem); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Navbar编辑'), - actions: [ - TextButton( - onPressed: saveEdit, - child: const Text('保存'), - ), - const SizedBox(width: 12) - ], - ), - body: ReorderableListView( - onReorder: onReorder, - footer: SizedBox( - height: MediaQuery.of(context).padding.bottom + 30, - ), - children: defaultNavTabs - .map( - (item) => CheckboxListTile( - key: Key(item['label']), - value: navBarSort.contains(item['id']), - onChanged: (bool? newValue) { - int tabTypeId = item['id']; - if (!newValue!) { - navBarSort.remove(tabTypeId); - } else { - navBarSort.add(tabTypeId); - } - setState(() {}); - }, - title: Text(item['label']), - secondary: const Icon(Icons.drag_indicator_rounded), - ), - ) - .toList(), - ), - ); - } -} diff --git a/lib/pages/setting/pages/bar_set.dart b/lib/pages/setting/pages/bar_set.dart new file mode 100644 index 000000000..2c392105e --- /dev/null +++ b/lib/pages/setting/pages/bar_set.dart @@ -0,0 +1,94 @@ +import 'package:PiliPlus/models/common/enum_with_label.dart'; +import 'package:PiliPlus/utils/storage.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; + +class BarSetPage extends StatefulWidget { + const BarSetPage({super.key}); + + @override + State createState() => _BarSetPageState(); +} + +class _BarSetPageState extends State { + late final List defaultBars; + late final Map barIndex; + late final String key; + late final String title; + + @override + void initState() { + super.initState(); + Map args = Get.arguments; + key = args['key']; + title = args['title'] ?? ''; + defaultBars = List.from(args['defaultBars']); + List? bars = (GStorage.setting.get(key) as List?)?.cast(); + if (bars != null) { + barIndex = {for (var (k, v) in bars.indexed) v: k}; + + // 对 tabData 进行排序 + defaultBars.sort((a, b) { + final indexA = barIndex[a.index] ?? barIndex.length; + final indexB = barIndex[b.index] ?? barIndex.length; + return indexA.compareTo(indexB); + }); + } else { + barIndex = {for (var (k, v) in defaultBars.indexed) v.index: k}; + } + } + + void saveEdit() { + List sortedBar = defaultBars + .where((i) => barIndex.containsKey(i.index)) + .map((i) => i.index) + .toList(); + GStorage.setting.put(key, sortedBar); + SmartDialog.showToast('保存成功,下次启动时生效'); + } + + void onReorder(int oldIndex, int newIndex) { + setState(() { + if (newIndex > oldIndex) newIndex -= 1; + defaultBars.insert(newIndex, defaultBars.removeAt(oldIndex)); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('$title编辑'), + actions: [ + TextButton(onPressed: saveEdit, child: const Text('保存')), + const SizedBox(width: 12) + ], + ), + body: ReorderableListView( + onReorder: onReorder, + footer: SizedBox( + height: MediaQuery.of(context).padding.bottom + 30, + child: const Align( + alignment: Alignment.centerRight, child: Text('*长按拖动排序 ')), + ), + children: defaultBars + .map((i) => CheckboxListTile( + key: Key(i.label), + value: barIndex.containsKey(i.index), + onChanged: (bool? value) { + if (value!) { + barIndex[i.index] = -1; + } else { + barIndex.remove(i.index); + } + setState(() {}); + }, + title: Text(i.label), + secondary: const Icon(Icons.drag_indicator_rounded), + )) + .toList(), + ), + ); + } +} diff --git a/lib/pages/setting/pages/color_select.dart b/lib/pages/setting/pages/color_select.dart index c09e5443f..335bf8309 100644 --- a/lib/pages/setting/pages/color_select.dart +++ b/lib/pages/setting/pages/color_select.dart @@ -257,11 +257,11 @@ class _ColorSelectPageState extends State { ), IgnorePointer( child: NavigationBar( - destinations: defaultNavigationBars + destinations: NavigationBarType.values .map( (item) => NavigationDestination( - icon: item['icon'], - label: item['label'], + icon: item.icon, + label: item.label, ), ) .toList(), diff --git a/lib/pages/setting/pages/home_tabbar_set.dart b/lib/pages/setting/pages/home_tabbar_set.dart deleted file mode 100644 index d07bd2168..000000000 --- a/lib/pages/setting/pages/home_tabbar_set.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'package:PiliPlus/models/common/home_tab_type.dart'; -import 'package:PiliPlus/utils/storage.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; - -class TabbarSetPage extends StatefulWidget { - const TabbarSetPage({super.key}); - - @override - State createState() => _TabbarSetPageState(); -} - -class _TabbarSetPageState extends State { - late List defaultTabs; - late List tabbarSort; - - @override - void initState() { - super.initState(); - defaultTabs = homeTabsConfig; - tabbarSort = GStorage.tabbarSort; - // 对 tabData 进行排序 - defaultTabs.sort((a, b) { - int indexA = tabbarSort.indexOf((a['type'] as HomeTabType).name); - int indexB = tabbarSort.indexOf((b['type'] as HomeTabType).name); - - // 如果类型在 sortOrder 中不存在,则放在末尾 - if (indexA == -1) indexA = tabbarSort.length; - if (indexB == -1) indexB = tabbarSort.length; - - return indexA.compareTo(indexB); - }); - } - - void saveEdit() { - List sortedTabbar = defaultTabs - .where((i) => tabbarSort.contains((i['type'] as HomeTabType).name)) - .map((i) => (i['type'] as HomeTabType).name) - .toList(); - GStorage.setting.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 HomeTabType).name), - onChanged: (bool? newValue) { - String tabTypeId = (defaultTabs[i]['type'] as HomeTabType).name; - 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, - footer: SizedBox( - height: MediaQuery.of(context).padding.bottom + 30, - child: const Align( - alignment: Alignment.centerRight, child: Text('*长按拖动排序 ')), - ), - children: listTiles, - ), - ); - } -} diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index 2087c880f..a76c6729e 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -14,6 +14,7 @@ import 'package:PiliPlus/models/common/audio_normalization.dart'; import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart'; import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; import 'package:PiliPlus/models/common/dynamic/up_panel_position.dart'; +import 'package:PiliPlus/models/common/home_tab_type.dart'; import 'package:PiliPlus/models/common/member/tab_type.dart'; import 'package:PiliPlus/models/common/msg/msg_unread_type.dart'; import 'package:PiliPlus/models/common/nav_bar_config.dart'; @@ -591,8 +592,8 @@ List get styleSettings => [ return SelectDialog( title: '首页启动页', value: GStorage.defaultHomePage, - values: defaultNavigationBars.map((e) { - return (e['id'] as int, e['label'] as String); + values: NavigationBarType.values.map((e) { + return (e.index, e.label); }).toList(), ); }, @@ -606,7 +607,7 @@ List get styleSettings => [ leading: const Icon(Icons.home_outlined), title: '默认启动页', getSubtitle: () => - '当前启动页:${defaultNavigationBars.firstWhere((e) => e['id'] == GStorage.defaultHomePage)['label']}', + '当前启动页:${NavigationBarType.values.firstWhere((e) => e.index == GStorage.defaultHomePage).label}', ), SettingsModel( settingsType: SettingsType.normal, @@ -699,15 +700,24 @@ List get styleSettings => [ ), SettingsModel( settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed('/tabbarSetting'), + onTap: (setState) => Get.toNamed('/barSetting', arguments: { + 'key': SettingBoxKey.tabBarSort, + 'defaultBars': HomeTabType.values, + 'title': '首页标签页' + }), title: '首页标签页', subtitle: '删除或调换首页标签页', leading: const Icon(Icons.toc_outlined), ), SettingsModel( settingsType: SettingsType.normal, - onTap: (setState) => Get.toNamed('/navbarSetting'), + onTap: (setState) => Get.toNamed('/barSetting', arguments: { + 'key': SettingBoxKey.navBarSort, + 'defaultBars': NavigationBarType.values, + 'title': 'Navbar' + }), title: 'Navbar编辑', + subtitle: '删除或调换Navbar', leading: const Icon(Icons.toc_outlined), ), if (Platform.isAndroid) diff --git a/lib/pages/setting/widgets/select_item.dart b/lib/pages/setting/widgets/select_item.dart deleted file mode 100644 index c6a1425b1..000000000 --- a/lib/pages/setting/widgets/select_item.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:PiliPlus/models/common/video/audio_quality.dart'; -import 'package:PiliPlus/models/common/video/video_decode_type.dart'; -import 'package:PiliPlus/models/common/video/video_quality.dart'; -import 'package:PiliPlus/utils/storage.dart'; -import 'package:flutter/material.dart'; -import 'package:hive/hive.dart'; - -class SetSelectItem extends StatefulWidget { - final String? title; - final String? subTitle; - final String? setKey; - const SetSelectItem({ - this.title, - this.subTitle, - this.setKey, - super.key, - }); - - @override - State createState() => _SetSelectItemState(); -} - -class _SetSelectItemState extends State { - late dynamic currentVal; - late int currentIndex; - late List menus; - late List popMenuItems; - - Box get setting => GStorage.setting; - - @override - void initState() { - super.initState(); - late String defaultVal; - switch (widget.setKey) { - case 'defaultVideoQa': - defaultVal = VideoQuality.values.last.description; - List list = menus = VideoQuality.values.reversed.toList(); - currentVal = setting.get(widget.setKey, defaultValue: defaultVal); - currentIndex = - list.firstWhere((i) => i.description == currentVal).index; - - popMenuItems = [ - for (var i in list) ...[ - PopupMenuItem( - value: i.code, - child: Text(i.description), - ) - ] - ]; - - break; - case 'defaultAudioQa': - defaultVal = AudioQuality.values.last.description; - List list = menus = AudioQuality.values.reversed.toList(); - currentVal = setting.get(widget.setKey, defaultValue: defaultVal); - currentIndex = - list.firstWhere((i) => i.description == currentVal).index; - - popMenuItems = [ - for (var i in list) ...[ - PopupMenuItem( - value: i.index, - child: Text(i.description), - ), - ] - ]; - break; - case 'defaultDecode': - defaultVal = VideoDecodeFormatType.values[0].description; - currentVal = setting.get(widget.setKey, defaultValue: defaultVal); - List list = menus = VideoDecodeFormatType.values; - - currentIndex = - list.firstWhere((i) => i.description == currentVal).index; - - popMenuItems = [ - for (var i in list) ...[ - PopupMenuItem( - value: i.index, - child: Text(i.description), - ), - ] - ]; - break; - case 'defaultVideoSpeed': - defaultVal = '1.0'; - currentVal = setting.get(widget.setKey, defaultValue: defaultVal); - - break; - } - } - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - TextStyle subTitleStyle = - theme.textTheme.labelMedium!.copyWith(color: theme.colorScheme.outline); - return ListTile( - onTap: () {}, - title: Text(widget.title!), - subtitle: Text( - '当前${widget.title!} $currentVal', - style: subTitleStyle, - ), - trailing: PopupMenuButton( - initialValue: currentIndex, - icon: const Icon( - Icons.arrow_forward_rounded, - size: 22, - ), - onSelected: (item) { - currentVal = menus.firstWhere((e) => e.code == item).first; - setState(() {}); - }, - itemBuilder: (BuildContext context) => - [...popMenuItems], - ), - ); - } -} diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index c01dd13b7..a27e88356 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -34,11 +34,10 @@ import 'package:PiliPlus/pages/search/view.dart'; import 'package:PiliPlus/pages/search_result/view.dart'; import 'package:PiliPlus/pages/search_trending/view.dart'; import 'package:PiliPlus/pages/setting/extra_setting.dart'; -import 'package:PiliPlus/pages/setting/navigation_bar_set.dart'; +import 'package:PiliPlus/pages/setting/pages/bar_set.dart'; import 'package:PiliPlus/pages/setting/pages/color_select.dart'; import 'package:PiliPlus/pages/setting/pages/display_mode.dart'; import 'package:PiliPlus/pages/setting/pages/font_size_select.dart'; -import 'package:PiliPlus/pages/setting/pages/home_tabbar_set.dart'; import 'package:PiliPlus/pages/setting/pages/logs.dart'; import 'package:PiliPlus/pages/setting/pages/play_speed_set.dart'; import 'package:PiliPlus/pages/setting/play_setting.dart'; @@ -116,8 +115,6 @@ 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()), // 屏幕帧率 @@ -165,9 +162,6 @@ class Routes { CustomGetPage(name: '/sponsorBlock', page: () => const SponsorBlockPage()), CustomGetPage(name: '/createFav', page: () => const CreateFavPage()), CustomGetPage(name: '/editProfile', page: () => const EditProfilePage()), - // navigation bar - CustomGetPage( - name: '/navbarSetting', page: () => const NavigationBarSetPage()), CustomGetPage( name: '/settingsSearch', page: () => const SettingsSearchPage()), CustomGetPage( @@ -176,6 +170,7 @@ class Routes { name: '/searchTrending', page: () => const SearchTrendingPage()), CustomGetPage(name: '/dynTopic', page: () => const DynTopicPage()), CustomGetPage(name: '/articleList', page: () => const ArticleListPage()), + CustomGetPage(name: '/barSetting', page: () => const BarSetPage()), ]; } diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 421947a5f..56290c334 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -56,9 +56,9 @@ class GStorage { ), ); - static List get tabbarSort => - List.from(setting.get(SettingBoxKey.tabbarSort) ?? - HomeTabType.values.map((item) => item.name).toList()); + static List get tabbarSort => + List.from(setting.get(SettingBoxKey.tabBarSort) ?? + HomeTabType.values.map((item) => item.index).toList()); static List> get blockSettings { List list = List.from(setting.get(SettingBoxKey.blockSettings) ?? @@ -846,7 +846,7 @@ class SettingBoxKey { enableMYBar = 'enableMYBar', hideSearchBar = 'hideSearchBar', // 收起顶栏 hideTabBar = 'hideTabBar', // 收起底栏 - tabbarSort = 'tabbarSort', // 首页tabbar + tabBarSort = 'tabBarSort', // 首页tabbar dynamicBadgeMode = 'dynamicBadgeMode', msgBadgeMode = 'msgBadgeMode', msgUnReadTypeV2 = 'msgUnReadTypeV2',