feat: 首页tabbar 编辑排序

This commit is contained in:
guozhigq
2024-01-21 23:49:32 +08:00
parent dad4a28eb8
commit e052c6eafe
7 changed files with 168 additions and 62 deletions

View File

@ -9,6 +9,7 @@ enum TabType { live, rcmd, hot, bangumi }
extension TabTypeDesc on TabType { extension TabTypeDesc on TabType {
String get description => ['直播', '推荐', '热门', '番剧'][index]; String get description => ['直播', '推荐', '热门', '番剧'][index];
String get id => ['live', 'rcmd', 'hot', 'bangumi'][index];
} }
List tabsConfig = [ List tabsConfig = [

View File

@ -8,12 +8,13 @@ import 'package:pilipala/utils/storage.dart';
class HomeController extends GetxController with GetTickerProviderStateMixin { class HomeController extends GetxController with GetTickerProviderStateMixin {
bool flag = false; bool flag = false;
late List tabs; late RxList tabs = [].obs;
RxInt initialIndex = 1.obs; RxInt initialIndex = 1.obs;
late TabController tabController; late TabController tabController;
late List tabsCtrList; late List tabsCtrList;
late List<Widget> tabsPageList; late List<Widget> tabsPageList;
Box userInfoCache = GStrorage.userInfo; Box userInfoCache = GStrorage.userInfo;
Box settingStorage = GStrorage.setting;
RxBool userLogin = false.obs; RxBool userLogin = false.obs;
RxString userFace = ''.obs; RxString userFace = ''.obs;
var userInfo; var userInfo;
@ -21,6 +22,8 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
late final StreamController<bool> searchBarStream = late final StreamController<bool> searchBarStream =
StreamController<bool>.broadcast(); StreamController<bool>.broadcast();
late bool hideSearchBar; late bool hideSearchBar;
late List defaultTabs;
late List<String> tabbarSort;
@override @override
void onInit() { void onInit() {
@ -28,34 +31,10 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
userInfo = userInfoCache.get('userInfoCache'); userInfo = userInfoCache.get('userInfoCache');
userLogin.value = userInfo != null; userLogin.value = userInfo != null;
userFace.value = userInfo != null ? userInfo.face : ''; userFace.value = userInfo != null ? userInfo.face : '';
// 进行tabs配置 // 进行tabs配置
tabs = tabsConfig; setTabConfig();
tabsCtrList = tabsConfig.map((e) => e['ctr']).toList();
tabsPageList = tabsConfig.map<Widget>((e) => e['page']).toList();
tabController = TabController(
initialIndex: initialIndex.value,
length: tabs.length,
vsync: this,
);
hideSearchBar = hideSearchBar =
setting.get(SettingBoxKey.hideSearchBar, defaultValue: true); 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() { void onRefresh() {
@ -77,4 +56,42 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
if (val) return; if (val) return;
userFace.value = userInfo != null ? userInfo.face : ''; 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<Widget>((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;
}
}
});
}
} }

View File

@ -90,7 +90,11 @@ class _HomePageState extends State<HomePage>
ctr: _homeController, ctr: _homeController,
callback: showUserBottomSheet, callback: showUserBottomSheet,
), ),
const CustomTabs(), if (_homeController.tabs.length > 1) ...[
const CustomTabs(),
] else ...[
const SizedBox(height: 6),
],
Expanded( Expanded(
child: TabBarView( child: TabBarView(
controller: _homeController.tabController, controller: _homeController.tabController,
@ -250,17 +254,6 @@ class CustomTabs extends StatefulWidget {
class _CustomTabsState extends State<CustomTabs> { class _CustomTabsState extends State<CustomTabs> {
final HomeController _homeController = Get.put(HomeController()); 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) { void onTap(int index) {
feedBack(); feedBack();
@ -271,34 +264,30 @@ class _CustomTabsState extends State<CustomTabs> {
_homeController.tabController.index = index; _homeController.tabController.index = index;
} }
@override
void dispose() {
super.dispose();
_homeController.tabController.removeListener(listen);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 44, height: 44,
margin: const EdgeInsets.only(top: 4), margin: const EdgeInsets.only(top: 4),
child: ListView.separated( child: Obx(
padding: const EdgeInsets.symmetric(horizontal: 14.0), () => ListView.separated(
scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 14.0),
itemCount: _homeController.tabs.length, scrollDirection: Axis.horizontal,
separatorBuilder: (BuildContext context, int index) { itemCount: _homeController.tabs.length,
return const SizedBox(width: 10); separatorBuilder: (BuildContext context, int index) {
}, return const SizedBox(width: 10);
itemBuilder: (BuildContext context, int index) { },
String label = _homeController.tabs[index]['label']; itemBuilder: (BuildContext context, int index) {
return Obx( String label = _homeController.tabs[index]['label'];
() => CustomChip( return Obx(
onTap: () => onTap(index), () => CustomChip(
label: label, onTap: () => onTap(index),
selected: index == _homeController.initialIndex.value, label: label,
), selected: index == _homeController.initialIndex.value,
); ),
}, );
},
),
), ),
); );
} }

View File

@ -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<TabbarSetPage> createState() => _TabbarSetPageState();
}
class _TabbarSetPageState extends State<TabbarSetPage> {
Box settingStorage = GStrorage.setting;
late List defaultTabs;
late List<String> tabbarSort;
@override
void initState() {
super.initState();
defaultTabs = tabsConfig;
tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort,
defaultValue: ['live', 'rcmd', 'hot', 'bangumi']);
}
void saveEdit() {
List<String> sortedTabbar = defaultTabs
.where((i) => tabbarSort.contains((i['type'] as TabType).id))
.map<String>((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,
),
);
}
}

View File

@ -254,6 +254,11 @@ class _StyleSettingState extends State<StyleSetting> {
onTap: () => Get.toNamed('/fontSizeSetting'), onTap: () => Get.toNamed('/fontSizeSetting'),
title: Text('字体大小', style: titleStyle), title: Text('字体大小', style: titleStyle),
), ),
ListTile(
dense: false,
onTap: () => Get.toNamed('/tabbarSetting'),
title: Text('首页tabbar', style: titleStyle),
),
if (Platform.isAndroid) if (Platform.isAndroid)
ListTile( ListTile(
dense: false, dense: false,

View File

@ -36,6 +36,7 @@ import '../pages/setting/index.dart';
import '../pages/setting/pages/color_select.dart'; import '../pages/setting/pages/color_select.dart';
import '../pages/setting/pages/display_mode.dart'; import '../pages/setting/pages/display_mode.dart';
import '../pages/setting/pages/font_size_select.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/pages/play_speed_set.dart';
import '../pages/setting/play_setting.dart'; import '../pages/setting/play_setting.dart';
import '../pages/setting/privacy_setting.dart'; import '../pages/setting/privacy_setting.dart';
@ -112,6 +113,8 @@ class Routes {
// //
CustomGetPage(name: '/blackListPage', page: () => const BlackListPage()), CustomGetPage(name: '/blackListPage', page: () => const BlackListPage()),
CustomGetPage(name: '/colorSetting', page: () => const ColorSelectPage()), CustomGetPage(name: '/colorSetting', page: () => const ColorSelectPage()),
// 首页tabbar
CustomGetPage(name: '/tabbarSetting', page: () => const TabbarSetPage()),
CustomGetPage( CustomGetPage(
name: '/fontSizeSetting', page: () => const FontSizeSelectPage()), name: '/fontSizeSetting', page: () => const FontSizeSelectPage()),
// 屏幕帧率 // 屏幕帧率

View File

@ -144,7 +144,8 @@ class SettingBoxKey {
customRows = 'customRows', // 自定义列 customRows = 'customRows', // 自定义列
enableMYBar = 'enableMYBar', enableMYBar = 'enableMYBar',
hideSearchBar = 'hideSearchBar', // 收起顶栏 hideSearchBar = 'hideSearchBar', // 收起顶栏
hideTabBar = 'hideTabBar'; // 收起底栏 hideTabBar = 'hideTabBar', // 收起底栏
tabbarSort = 'tabbarSort'; // 首页tabbar
} }
class LocalCacheKey { class LocalCacheKey {