Compare commits

..

1 Commits

Author SHA1 Message Date
ed8443ba02 feat: navigation Bar编辑 2024-03-27 22:26:47 +08:00
14 changed files with 201 additions and 160 deletions

View File

@ -1,5 +1,10 @@
import 'package:flutter/material.dart';
import '../../pages/dynamics/index.dart';
import '../../pages/home/index.dart';
import '../../pages/media/index.dart';
import '../../pages/rank/index.dart';
List defaultNavigationBars = [
{
'id': 0,
@ -13,6 +18,7 @@ List defaultNavigationBars = [
),
'label': "首页",
'count': 0,
'page': const HomePage(),
},
{
'id': 1,
@ -26,6 +32,7 @@ List defaultNavigationBars = [
),
'label': "排行榜",
'count': 0,
'page': const RankPage(),
},
{
'id': 2,
@ -39,6 +46,7 @@ List defaultNavigationBars = [
),
'label': "动态",
'count': 0,
'page': const DynamicsPage(),
},
{
'id': 3,
@ -52,5 +60,6 @@ List defaultNavigationBars = [
),
'label': "媒体库",
'count': 0,
'page': const MediaPage(),
}
];

View File

@ -437,8 +437,7 @@ class SearchArticleItemModel {
pubTime = json['pub_time'];
like = json['like'];
title = Em.regTitle(json['title']);
subTitle =
Em.decodeHtmlEntities(json['title'].replaceAll(RegExp(r'<[^>]*>'), ''));
subTitle = json['title'].replaceAll(RegExp(r'<[^>]*>'), '');
rankOffset = json['rank_offset'];
mid = json['mid'];
imageUrls = json['image_urls'];

View File

@ -185,7 +185,7 @@ class HistoryItem extends StatelessWidget {
? '已看完'
: '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}',
right: 6.0,
bottom: 8.0,
bottom: 6.0,
type: 'gray',
),
// 右上角
@ -258,24 +258,6 @@ class HistoryItem extends StatelessWidget {
),
),
),
Positioned(
left: 3,
right: 3,
bottom: 0,
child: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft:
Radius.circular(StyleString.imgRadius.x),
bottomRight:
Radius.circular(StyleString.imgRadius.x),
),
child: LinearProgressIndicator(
value: videoItem.progress == -1
? 100
: videoItem.progress / videoItem.duration,
),
),
)
],
),
VideoContent(videoItem: videoItem, ctr: ctr)

View File

@ -6,23 +6,16 @@ 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';
import 'package:pilipala/pages/rank/index.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart';
import '../../models/common/dynamic_badge_mode.dart';
import '../../models/common/nav_bar_config.dart';
class MainController extends GetxController {
List<Widget> pages = <Widget>[
const HomePage(),
const RankPage(),
const DynamicsPage(),
const MediaPage(),
];
RxList navigationBars = defaultNavigationBars.obs;
List<Widget> pages = <Widget>[];
RxList navigationBars = [].obs;
late List defaultNavTabs;
late List<int> navBarSort;
final StreamController<bool> bottomBarStream =
StreamController<bool>.broadcast();
Box setting = GStrorage.setting;
@ -41,10 +34,7 @@ class MainController extends GetxController {
Utils.checkUpdata();
}
hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true);
int defaultHomePage =
setting.get(SettingBoxKey.defaultHomePage, defaultValue: 0) as int;
selectedIndex = defaultNavigationBars
.indexWhere((item) => item['id'] == defaultHomePage);
var userInfo = userInfoCache.get('userInfoCache');
userLogin.value = userInfo != null;
dynamicBadgeType.value = DynamicBadgeMode.values[setting.get(
@ -53,6 +43,7 @@ class MainController extends GetxController {
if (dynamicBadgeType.value != DynamicBadgeMode.hidden) {
getUnreadDynamic();
}
setNavBarConfig();
}
void onBackPressed(BuildContext context) {
@ -93,4 +84,21 @@ class MainController extends GetxController {
}
navigationBars.refresh();
}
void setNavBarConfig() async {
defaultNavTabs = [...defaultNavigationBars];
navBarSort =
setting.get(SettingBoxKey.navBarSort, defaultValue: [0, 1, 2, 3]);
defaultNavTabs.retainWhere((item) => navBarSort.contains(item['id']));
defaultNavTabs.sort((a, b) =>
navBarSort.indexOf(a['id']).compareTo(navBarSort.indexOf(b['id'])));
navigationBars.value = defaultNavTabs;
int defaultHomePage =
setting.get(SettingBoxKey.defaultHomePage, defaultValue: 0) as int;
int defaultIndex =
navigationBars.indexWhere((item) => item['id'] == defaultHomePage);
// 如果找不到匹配项默认索引设置为0或其他合适的值
selectedIndex = defaultIndex != -1 ? defaultIndex : 0;
pages = navigationBars.map<Widget>((e) => e['page']).toList();
}
}

View File

@ -0,0 +1,100 @@
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';
import '../../../models/common/nav_bar_config.dart';
class NavigationBarSetPage extends StatefulWidget {
const NavigationBarSetPage({super.key});
@override
State<NavigationBarSetPage> createState() => _NavigationbarSetPageState();
}
class _NavigationbarSetPageState extends State<NavigationBarSetPage> {
Box settingStorage = GStrorage.setting;
late List defaultNavTabs;
late List<int> navBarSort;
@override
void initState() {
super.initState();
defaultNavTabs = defaultNavigationBars;
navBarSort = settingStorage
.get(SettingBoxKey.navBarSort, defaultValue: [0, 1, 2, 3]);
// 对 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<int> sortedTabbar = defaultNavTabs
.where((i) => navBarSort.contains(i['id']))
.map<int>((i) => i['id'])
.toList();
settingStorage.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) {
final listTiles = [
for (int i = 0; i < defaultNavTabs.length; i++) ...[
CheckboxListTile(
key: Key(defaultNavTabs[i]['label']),
value: navBarSort.contains(defaultNavTabs[i]['id']),
onChanged: (bool? newValue) {
int tabTypeId = defaultNavTabs[i]['id'];
if (!newValue!) {
navBarSort.remove(tabTypeId);
} else {
navBarSort.add(tabTypeId);
}
setState(() {});
},
title: Text(defaultNavTabs[i]['label']),
secondary: const Icon(Icons.drag_indicator_rounded),
enabled: defaultNavTabs[i]['id'] != 3,
)
]
];
return Scaffold(
appBar: AppBar(
title: const Text('Navbar编辑'),
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

@ -284,12 +284,17 @@ class _StyleSettingState extends State<StyleSetting> {
onTap: () => Get.toNamed('/tabbarSetting'),
title: Text('首页tabbar', style: titleStyle),
),
ListTile(
dense: false,
onTap: () => Get.toNamed('/navbarSetting'),
title: Text('navbar设置', style: titleStyle),
),
if (Platform.isAndroid)
ListTile(
dense: false,
onTap: () => Get.toNamed('/displayModeSetting'),
title: Text('屏幕帧率', style: titleStyle),
)
),
],
),
);

View File

@ -1,4 +1,3 @@
import 'package:expandable/expandable.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
@ -17,6 +16,7 @@ import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart';
import '../../../../http/user.dart';
import '../widgets/expandable_section.dart';
import 'widgets/action_item.dart';
import 'widgets/fav_panel.dart';
import 'widgets/intro_detail.dart';
@ -140,8 +140,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
late bool enableAi;
bool isProcessing = false;
RxBool isExpand = false.obs;
late ExpandableController _expandableCtr;
void Function()? handleState(Future Function() action) {
return isProcessing
? null
@ -165,7 +163,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
follower = Utils.numFormat(videoIntroController.userStat['follower']);
followStatus = videoIntroController.followStatus;
enableAi = setting.get(SettingBoxKey.enableAi, defaultValue: true);
_expandableCtr = ExpandableController(initialExpanded: false);
}
// 收藏
@ -219,7 +216,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
showIntroDetail() {
feedBack();
isExpand.value = !(isExpand.value);
_expandableCtr.toggle();
}
// 用户主页
@ -243,12 +239,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
);
}
@override
void dispose() {
_expandableCtr.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final ThemeData t = Theme.of(context);
@ -266,34 +256,14 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => showIntroDetail(),
child: ExpandablePanel(
controller: _expandableCtr,
collapsed: Text(
child: Text(
widget.videoDetail!.title!,
softWrap: true,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
expanded: Text(
widget.videoDetail!.title!,
softWrap: true,
maxLines: 4,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
theme: const ExpandableThemeData(
animationDuration: Duration(milliseconds: 300),
scrollAnimationDuration: Duration(milliseconds: 300),
crossFadePoint: 0,
fadeCurve: Curves.ease,
sizeCurve: Curves.linear,
),
),
),
Stack(
@ -358,16 +328,12 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
),
/// 视频简介
ExpandablePanel(
controller: _expandableCtr,
collapsed: const SizedBox(height: 0),
expanded: IntroDetail(videoDetail: widget.videoDetail!),
theme: const ExpandableThemeData(
animationDuration: Duration(milliseconds: 300),
scrollAnimationDuration: Duration(milliseconds: 300),
crossFadePoint: 0,
fadeCurve: Curves.ease,
sizeCurve: Curves.linear,
Obx(
() => ExpandedSection(
expand: isExpand.value,
begin: 0,
end: 1,
child: IntroDetail(videoDetail: widget.videoDetail!),
),
),

View File

@ -149,17 +149,14 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
delegate: _MySliverPersistentHeaderDelegate(
child: Container(
height: 40,
padding: const EdgeInsets.fromLTRB(12, 0, 6, 0),
color: Theme.of(context).colorScheme.surface,
padding: const EdgeInsets.fromLTRB(12, 6, 6, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => Text(
Text(
'${_videoReplyController.sortTypeLabel.value}评论',
style: const TextStyle(fontSize: 13),
),
),
SizedBox(
height: 35,
child: TextButton.icon(

View File

@ -393,13 +393,7 @@ class PlPlayerController {
}
// 配置Player 音轨、字幕等等
_videoPlayerController = await _createVideoController(
dataSource,
_looping,
enableHA,
width,
height,
seekTo,
);
dataSource, _looping, enableHA, width, height);
// 获取视频时长 00:00
_duration.value = duration ?? _videoPlayerController!.state.duration;
updateDurationSecond();
@ -410,7 +404,7 @@ class PlPlayerController {
if (!_listenersInitialized) {
startListeners();
}
await _initializePlayer(duration: _duration.value);
await _initializePlayer(seekTo: seekTo, duration: _duration.value);
bool autoEnterFullcreen =
setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false);
if (autoEnterFullcreen && _isFirstTime) {
@ -430,7 +424,6 @@ class PlPlayerController {
bool enableHA,
double? width,
double? height,
Duration? seekTo,
) async {
// 每次配置时先移除监听
removeListeners();
@ -513,11 +506,7 @@ class PlPlayerController {
);
}
player.open(
Media(
dataSource.videoSource!,
httpHeaders: dataSource.httpHeaders,
start: seekTo ?? Duration.zero,
),
Media(dataSource.videoSource!, httpHeaders: dataSource.httpHeaders),
play: false,
);
// 音轨
@ -530,6 +519,7 @@ class PlPlayerController {
// 开始播放
Future _initializePlayer({
Duration seekTo = Duration.zero,
Duration? duration,
}) async {
// 设置倍速
@ -547,6 +537,11 @@ class PlPlayerController {
// await setLooping(_looping);
// }
// 跳转播放
if (seekTo != Duration.zero) {
await this.seekTo(seekTo);
}
// 自动播放
if (_autoPlay) {
await play(duration: duration);
@ -666,14 +661,21 @@ class PlPlayerController {
await _videoPlayerController?.stream.buffer.first;
}
await _videoPlayerController?.seek(position);
// if (playerStatus.stopped) {
// play();
// }
} else {
print('seek duration else');
_timerForSeek?.cancel();
_timerForSeek =
Timer.periodic(const Duration(milliseconds: 200), (Timer t) async {
//_timerForSeek = null;
if (duration.value.inSeconds != 0) {
await _videoPlayerController!.stream.buffer.first;
await _videoPlayerController?.seek(position);
// if (playerStatus.status.value == PlayerStatus.paused) {
// play();
// }
t.cancel();
_timerForSeek = null;
}

View File

@ -39,6 +39,7 @@ 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/navigation_bar_set.dart';
import '../pages/setting/pages/play_gesture_set.dart';
import '../pages/setting/pages/play_speed_set.dart';
import '../pages/setting/recommend_setting.dart';
@ -170,6 +171,9 @@ class Routes {
// 播放器手势
CustomGetPage(
name: '/playerGestureSet', page: () => const PlayGesturePage()),
// navigation bar
CustomGetPage(
name: '/navbarSetting', page: () => const NavigationBarSetPage()),
];
}

View File

@ -19,17 +19,7 @@ class Em {
return regCate(matchStr);
}, onNonMatch: (String str) {
if (str != '') {
str = decodeHtmlEntities(str);
Map map = {'type': 'text', 'text': str};
res.add(map);
}
return str;
});
return res;
}
static String decodeHtmlEntities(String title) {
return title
str = str
.replaceAll('&lt;', '<')
.replaceAll('&gt;', '>')
.replaceAll('&#34;', '"')
@ -37,7 +27,12 @@ class Em {
.replaceAll('&quot;', '"')
.replaceAll('&apos;', "'")
.replaceAll('&nbsp;', " ")
.replaceAll('&amp;', "&")
.replaceAll('&#x27;', "'");
.replaceAll('&amp;', "&");
Map map = {'type': 'text', 'text': str};
res.add(map);
}
return str;
});
return res;
}
}

View File

@ -148,7 +148,8 @@ class SettingBoxKey {
hideTabBar = 'hideTabBar', // 收起底栏
tabbarSort = 'tabbarSort', // 首页tabbar
dynamicBadgeMode = 'dynamicBadgeMode',
enableGradientBg = 'enableGradientBg';
enableGradientBg = 'enableGradientBg',
navBarSort = 'navBarSort';
}
class LocalCacheKey {

View File

@ -433,14 +433,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.3"
expandable:
dependency: "direct main"
description:
name: expandable
sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.1"
extended_image:
dependency: "direct main"
description:
@ -865,11 +857,10 @@ packages:
media_kit:
dependency: "direct main"
description:
path: media_kit
ref: HEAD
resolved-ref: "77a130b1d7ce733b47d2133b57563716090450d0"
url: "https://github.com/media-kit/media-kit.git"
source: git
name: media_kit
sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.10+1"
media_kit_libs_android_video:
dependency: transitive
@ -906,11 +897,10 @@ packages:
media_kit_libs_video:
dependency: "direct main"
description:
path: "libs/universal/media_kit_libs_video"
ref: HEAD
resolved-ref: "77a130b1d7ce733b47d2133b57563716090450d0"
url: "https://github.com/media-kit/media-kit.git"
source: git
name: media_kit_libs_video
sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.4"
media_kit_libs_windows_video:
dependency: transitive
@ -931,11 +921,10 @@ packages:
media_kit_video:
dependency: "direct main"
description:
path: media_kit_video
ref: HEAD
resolved-ref: "77a130b1d7ce733b47d2133b57563716090450d0"
url: "https://github.com/media-kit/media-kit.git"
source: git
name: media_kit_video
sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.4"
meta:
dependency: transitive

View File

@ -142,8 +142,6 @@ dependencies:
path: 1.8.3
# 电池优化
disable_battery_optimization: ^1.1.1
# 展开/收起
expandable: ^5.0.1
dev_dependencies:
flutter_test:
@ -163,20 +161,6 @@ dev_dependencies:
hive_generator: ^2.0.0
build_runner: ^2.4.8
dependency_overrides:
media_kit:
git:
url: https://github.com/media-kit/media-kit.git
path: media_kit
media_kit_video:
git:
url: https://github.com/media-kit/media-kit.git
path: media_kit_video
media_kit_libs_video:
git:
url: https://github.com/media-kit/media-kit.git
path: libs/universal/media_kit_libs_video
flutter_launcher_icons:
android: true
ios: true