Merge branch 'main' into design

This commit is contained in:
guozhigq
2024-04-13 10:59:23 +08:00
7 changed files with 139 additions and 117 deletions

View File

@ -20,6 +20,7 @@ import 'package:pilipala/services/disable_battery_opt.dart';
import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/services/service_locator.dart';
import 'package:pilipala/utils/app_scheme.dart'; import 'package:pilipala/utils/app_scheme.dart';
import 'package:pilipala/utils/data.dart'; import 'package:pilipala/utils/data.dart';
import 'package:pilipala/utils/global_data.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc. import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc.
import 'package:pilipala/utils/recommend_filter.dart'; import 'package:pilipala/utils/recommend_filter.dart';
@ -64,14 +65,8 @@ void main() async {
}, },
); );
// 小白条、导航栏沉浸
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
systemNavigationBarColor: Colors.transparent,
systemNavigationBarDividerColor: Colors.transparent,
statusBarColor: Colors.transparent,
));
Data.init(); Data.init();
GlobalData();
PiliSchame.init(); PiliSchame.init();
DisableBatteryOpt(); DisableBatteryOpt();
}); });
@ -134,45 +129,51 @@ class MyApp extends StatelessWidget {
brightness: Brightness.dark, brightness: Brightness.dark,
); );
} }
final SnackBarThemeData snackBarThemeData = SnackBarThemeData(
actionTextColor: darkColorScheme.primary,
backgroundColor: darkColorScheme.secondaryContainer,
closeIconColor: darkColorScheme.secondary,
contentTextStyle: TextStyle(color: darkColorScheme.secondary),
elevation: 20,
);
ThemeData themeData = ThemeData(
// fontFamily: 'HarmonyOS',
colorScheme: currentThemeValue == ThemeType.dark
? darkColorScheme
: lightColorScheme,
snackBarTheme: snackBarThemeData,
pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.android: ZoomPageTransitionsBuilder(
allowEnterRouteSnapshotting: false,
),
},
),
);
// 小白条、导航栏沉浸
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: GlobalData().enableMYBar
? const Color(0x00010000)
: themeData.canvasColor,
systemNavigationBarDividerColor: GlobalData().enableMYBar
? const Color(0x00010000)
: themeData.canvasColor,
systemNavigationBarIconBrightness: currentThemeValue == ThemeType.dark
? Brightness.light
: Brightness.dark,
statusBarColor: Colors.transparent,
));
// 图片缓存 // 图片缓存
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20; // PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
return GetMaterialApp( return GetMaterialApp(
title: 'PiLiPaLa', title: 'PiLiPaLa',
theme: ThemeData( theme: themeData,
// fontFamily: 'HarmonyOS', darkTheme: themeData,
colorScheme: currentThemeValue == ThemeType.dark
? darkColorScheme
: lightColorScheme,
useMaterial3: true,
snackBarTheme: SnackBarThemeData(
actionTextColor: lightColorScheme.primary,
backgroundColor: lightColorScheme.secondaryContainer,
closeIconColor: lightColorScheme.secondary,
contentTextStyle: TextStyle(color: lightColorScheme.secondary),
elevation: 20,
),
pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.android: ZoomPageTransitionsBuilder(
allowEnterRouteSnapshotting: false,
),
},
),
),
darkTheme: ThemeData(
// fontFamily: 'HarmonyOS',
colorScheme: currentThemeValue == ThemeType.light
? lightColorScheme
: darkColorScheme,
useMaterial3: true,
snackBarTheme: SnackBarThemeData(
actionTextColor: darkColorScheme.primary,
backgroundColor: darkColorScheme.secondaryContainer,
closeIconColor: darkColorScheme.secondary,
contentTextStyle: TextStyle(color: darkColorScheme.secondary),
elevation: 20,
),
),
localizationsDelegates: const [ localizationsDelegates: const [
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,

View File

@ -10,6 +10,7 @@ import 'package:pilipala/pages/media/index.dart';
import 'package:pilipala/pages/rank/index.dart'; import 'package:pilipala/pages/rank/index.dart';
import 'package:pilipala/utils/event_bus.dart'; import 'package:pilipala/utils/event_bus.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import './controller.dart'; import './controller.dart';
@ -29,7 +30,6 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
int? _lastSelectTime; //上次点击时间 int? _lastSelectTime; //上次点击时间
Box setting = GStrorage.setting; Box setting = GStrorage.setting;
late bool enableMYBar;
@override @override
void initState() { void initState() {
@ -37,7 +37,6 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
_lastSelectTime = DateTime.now().millisecondsSinceEpoch; _lastSelectTime = DateTime.now().millisecondsSinceEpoch;
_mainController.pageController = _mainController.pageController =
PageController(initialPage: _mainController.selectedIndex); PageController(initialPage: _mainController.selectedIndex);
enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
} }
void setIndex(int value) async { void setIndex(int value) async {
@ -127,81 +126,82 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
}, },
children: _mainController.pages, children: _mainController.pages,
), ),
bottomNavigationBar: StreamBuilder( bottomNavigationBar: _mainController.navigationBars.length > 1
stream: _mainController.hideTabBar ? StreamBuilder(
? _mainController.bottomBarStream.stream.distinct() stream: _mainController.hideTabBar
: StreamController<bool>.broadcast().stream, ? _mainController.bottomBarStream.stream.distinct()
initialData: true, : StreamController<bool>.broadcast().stream,
builder: (context, AsyncSnapshot snapshot) { initialData: true,
return AnimatedSlide( builder: (context, AsyncSnapshot snapshot) {
curve: Curves.easeInOutCubicEmphasized, return AnimatedSlide(
duration: const Duration(milliseconds: 500), curve: Curves.easeInOutCubicEmphasized,
offset: Offset(0, snapshot.data ? 0 : 1), duration: const Duration(milliseconds: 500),
child: Obx( offset: Offset(0, snapshot.data ? 0 : 1),
() => enableMYBar child: GlobalData().enableMYBar
? NavigationBar( ? NavigationBar(
onDestinationSelected: (value) => setIndex(value), onDestinationSelected: (value) => setIndex(value),
selectedIndex: _mainController.selectedIndex, selectedIndex: _mainController.selectedIndex,
destinations: <Widget>[ destinations: <Widget>[
..._mainController.navigationBars.map((e) { ..._mainController.navigationBars.map((e) {
return NavigationDestination( return NavigationDestination(
icon: Obx( icon: Obx(
() => Badge( () => Badge(
label: label: _mainController
_mainController.dynamicBadgeType.value == .dynamicBadgeType.value ==
DynamicBadgeMode.number DynamicBadgeMode.number
? Text(e['count'].toString()) ? Text(e['count'].toString())
: null, : null,
padding: padding:
const EdgeInsets.fromLTRB(6, 0, 6, 0), const EdgeInsets.fromLTRB(6, 0, 6, 0),
isLabelVisible: isLabelVisible: _mainController
_mainController.dynamicBadgeType.value != .dynamicBadgeType.value !=
DynamicBadgeMode.hidden && DynamicBadgeMode.hidden &&
e['count'] > 0, e['count'] > 0,
child: e['icon'], child: e['icon'],
), ),
), ),
selectedIcon: e['selectIcon'], selectedIcon: e['selectIcon'],
label: e['label'], label: e['label'],
); );
}).toList(), }).toList(),
], ],
) )
: BottomNavigationBar( : BottomNavigationBar(
currentIndex: _mainController.selectedIndex, currentIndex: _mainController.selectedIndex,
onTap: (value) => setIndex(value), type: BottomNavigationBarType.fixed,
iconSize: 16, onTap: (value) => setIndex(value),
selectedFontSize: 12, iconSize: 16,
unselectedFontSize: 12, selectedFontSize: 12,
items: [ unselectedFontSize: 12,
..._mainController.navigationBars.map((e) { items: [
return BottomNavigationBarItem( ..._mainController.navigationBars.map((e) {
icon: Obx( return BottomNavigationBarItem(
() => Badge( icon: Obx(
label: () => Badge(
_mainController.dynamicBadgeType.value == label: _mainController
.dynamicBadgeType.value ==
DynamicBadgeMode.number DynamicBadgeMode.number
? Text(e['count'].toString()) ? Text(e['count'].toString())
: null, : null,
padding: padding:
const EdgeInsets.fromLTRB(6, 0, 6, 0), const EdgeInsets.fromLTRB(6, 0, 6, 0),
isLabelVisible: isLabelVisible: _mainController
_mainController.dynamicBadgeType.value != .dynamicBadgeType.value !=
DynamicBadgeMode.hidden && DynamicBadgeMode.hidden &&
e['count'] > 0, e['count'] > 0,
child: e['icon'], child: e['icon'],
), ),
), ),
activeIcon: e['selectIcon'], activeIcon: e['selectIcon'],
label: e['label'], label: e['label'],
); );
}).toList(), }).toList(),
], ],
), ),
), );
); },
}, )
), : null,
), ),
); );
} }

View File

@ -287,7 +287,7 @@ class _StyleSettingState extends State<StyleSetting> {
ListTile( ListTile(
dense: false, dense: false,
onTap: () => Get.toNamed('/navbarSetting'), onTap: () => Get.toNamed('/navbarSetting'),
title: Text('navbar设置', style: titleStyle), title: Text('底部导航栏设置', style: titleStyle),
), ),
if (Platform.isAndroid) if (Platform.isAndroid)
ListTile( ListTile(

View File

@ -140,8 +140,8 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (BuildContext context, snapshot) { builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
final Map data = snapshot.data as Map; Map? data = snapshot.data;
if (data['status']) { if (data != null && data['status']) {
// 请求成功 // 请求成功
return Obx( return Obx(
() => SliverList( () => SliverList(
@ -199,7 +199,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
} else { } else {
// 请求错误 // 请求错误
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data?['msg'] ?? '请求错误',
fn: () => setState(() {}), fn: () => setState(() {}),
); );
} }

View File

@ -108,7 +108,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
// 流 // 流
appbarStreamListen() { appbarStreamListen() {
appbarStream = StreamController<double>(); appbarStream = StreamController<double>.broadcast();
_extendNestCtr.addListener( _extendNestCtr.addListener(
() { () {
final double offset = _extendNestCtr.position.pixels; final double offset = _extendNestCtr.position.pixels;

View File

@ -1,5 +1,7 @@
import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@ -11,7 +13,8 @@ class DownloadUtils {
static Future<bool> requestStoragePer() async { static Future<bool> requestStoragePer() async {
await Permission.storage.request(); await Permission.storage.request();
PermissionStatus status = await Permission.storage.status; PermissionStatus status = await Permission.storage.status;
if (status == PermissionStatus.denied) { if (status == PermissionStatus.denied ||
status == PermissionStatus.permanentlyDenied) {
SmartDialog.show( SmartDialog.show(
useSystem: true, useSystem: true,
animationType: SmartAnimationType.centerFade_otherSlide, animationType: SmartAnimationType.centerFade_otherSlide,
@ -40,7 +43,8 @@ class DownloadUtils {
static Future<bool> requestPhotoPer() async { static Future<bool> requestPhotoPer() async {
await Permission.photos.request(); await Permission.photos.request();
PermissionStatus status = await Permission.photos.status; PermissionStatus status = await Permission.photos.status;
if (status == PermissionStatus.denied) { if (status == PermissionStatus.denied ||
status == PermissionStatus.permanentlyDenied) {
SmartDialog.show( SmartDialog.show(
useSystem: true, useSystem: true,
animationType: SmartAnimationType.centerFade_otherSlide, animationType: SmartAnimationType.centerFade_otherSlide,
@ -68,9 +72,20 @@ class DownloadUtils {
static Future<bool> downloadImg(String imgUrl, static Future<bool> downloadImg(String imgUrl,
{String imgType = 'cover'}) async { {String imgType = 'cover'}) async {
try { try {
if (!await requestPhotoPer()) { if (!Platform.isAndroid || !await requestPhotoPer()) {
return false; return false;
} }
final androidInfo = await DeviceInfoPlugin().androidInfo;
if (androidInfo.version.sdkInt <= 32) {
if (!await requestStoragePer()) {
return false;
}
} else {
if (!await requestPhotoPer()) {
return false;
}
}
SmartDialog.showLoading(msg: '保存中'); SmartDialog.showLoading(msg: '保存中');
var response = await Dio() var response = await Dio()
.get(imgUrl, options: Options(responseType: ResponseType.bytes)); .get(imgUrl, options: Options(responseType: ResponseType.bytes));

View File

@ -1,10 +1,16 @@
import 'package:hive/hive.dart';
import 'package:pilipala/utils/storage.dart';
import '../models/common/index.dart'; import '../models/common/index.dart';
Box setting = GStrorage.setting;
class GlobalData { class GlobalData {
int imgQuality = 10; int imgQuality = 10;
FullScreenGestureMode fullScreenGestureMode = FullScreenGestureMode fullScreenGestureMode =
FullScreenGestureMode.values.last; FullScreenGestureMode.values.last;
bool enablePlayerControlAnimation = true; bool enablePlayerControlAnimation = true;
final bool enableMYBar =
setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
// 私有构造函数 // 私有构造函数
GlobalData._(); GlobalData._();