feat: 首页tabbar 编辑排序
This commit is contained in:
@ -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 = [
|
||||
|
@ -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<Widget> 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<bool> searchBarStream =
|
||||
StreamController<bool>.broadcast();
|
||||
late bool hideSearchBar;
|
||||
late List defaultTabs;
|
||||
late List<String> 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<Widget>((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<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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,11 @@ class _HomePageState extends State<HomePage>
|
||||
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<CustomTabs> {
|
||||
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<CustomTabs> {
|
||||
_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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
90
lib/pages/setting/pages/home_tabbar_set.dart
Normal file
90
lib/pages/setting/pages/home_tabbar_set.dart
Normal 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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -254,6 +254,11 @@ class _StyleSettingState extends State<StyleSetting> {
|
||||
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,
|
||||
|
@ -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()),
|
||||
// 屏幕帧率
|
||||
|
@ -144,7 +144,8 @@ class SettingBoxKey {
|
||||
customRows = 'customRows', // 自定义列
|
||||
enableMYBar = 'enableMYBar',
|
||||
hideSearchBar = 'hideSearchBar', // 收起顶栏
|
||||
hideTabBar = 'hideTabBar'; // 收起底栏
|
||||
hideTabBar = 'hideTabBar', // 收起底栏
|
||||
tabbarSort = 'tabbarSort'; // 首页tabbar
|
||||
}
|
||||
|
||||
class LocalCacheKey {
|
||||
|
Reference in New Issue
Block a user