Merge branch 'main' into pr/434
This commit is contained in:
107
.gitignore
vendored
107
.gitignore
vendored
@ -21,6 +21,29 @@ migrate_working_dir/
|
|||||||
# is commented out by default.
|
# is commented out by default.
|
||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter repo-specific
|
||||||
|
/bin/cache/
|
||||||
|
/bin/internal/bootstrap.bat
|
||||||
|
/bin/internal/bootstrap.sh
|
||||||
|
/bin/mingit/
|
||||||
|
/dev/benchmarks/mega_gallery/
|
||||||
|
/dev/bots/.recipe_deps
|
||||||
|
/dev/bots/android_tools/
|
||||||
|
/dev/devicelab/ABresults*.json
|
||||||
|
/dev/docs/doc/
|
||||||
|
/dev/docs/api_docs.zip
|
||||||
|
/dev/docs/flutter.docs.zip
|
||||||
|
/dev/docs/lib/
|
||||||
|
/dev/docs/pubspec.yaml
|
||||||
|
/dev/integration_tests/**/xcuserdata
|
||||||
|
/dev/integration_tests/**/Pods
|
||||||
|
/packages/flutter/coverage/
|
||||||
|
version
|
||||||
|
analysis_benchmark.json
|
||||||
|
|
||||||
|
# packages file containing multi-root paths
|
||||||
|
.packages.generated
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
**/ios/Flutter/.last_build_id
|
**/ios/Flutter/.last_build_id
|
||||||
@ -31,15 +54,83 @@ migrate_working_dir/
|
|||||||
.pub-cache/
|
.pub-cache/
|
||||||
.pub/
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
|
flutter_*.png
|
||||||
# Symbolication related
|
linked_*.ds
|
||||||
app.*.symbols
|
unlinked.ds
|
||||||
|
unlinked_spec.ds
|
||||||
|
|
||||||
# Obfuscation related
|
# Obfuscation related
|
||||||
app.*.map.json
|
app.*.map.json
|
||||||
|
|
||||||
# Android Studio will place build artifacts here
|
# Android related
|
||||||
/android/app/debug
|
**/android/**/gradle-wrapper.jar
|
||||||
/android/app/profile
|
.gradle/
|
||||||
/android/app/release
|
**/android/captures/
|
||||||
/*/flutter/[Gg]enerated*[Pp]lugin*
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
**/android/key.properties
|
||||||
|
*.jks
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Flutter.podspec
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/ephemeral
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/Flutter/flutter_export_environment.sh
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
**/Flutter/ephemeral/
|
||||||
|
**/Pods/
|
||||||
|
**/macos/Flutter/GeneratedPluginRegistrant.swift
|
||||||
|
**/macos/Flutter/ephemeral
|
||||||
|
**/xcuserdata/
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
**/windows/flutter/generated_plugin_registrant.cc
|
||||||
|
**/windows/flutter/generated_plugin_registrant.h
|
||||||
|
**/windows/flutter/generated_plugins.cmake
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
**/linux/flutter/generated_plugin_registrant.cc
|
||||||
|
**/linux/flutter/generated_plugin_registrant.h
|
||||||
|
**/linux/flutter/generated_plugins.cmake
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# Symbols
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
!/dev/ci/**/Gemfile.lock
|
||||||
|
!.vscode/settings.json
|
||||||
39
change_log/1.0.17.0125.md
Normal file
39
change_log/1.0.17.0125.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
## 1.0.17
|
||||||
|
|
||||||
|
|
||||||
|
### 功能
|
||||||
|
+ 视频全屏时隐藏进度条
|
||||||
|
+ 动态内容增加投稿跳转
|
||||||
|
+ 未开启自动播放时点击封面播放
|
||||||
|
+ 弹幕发送标识
|
||||||
|
+ 定时关闭
|
||||||
|
+ 推荐视频卡片拉黑up功能
|
||||||
|
+ 首页tabbar编辑排序
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
+ 连续跳转搜索页未刷新
|
||||||
|
+ 搜索结果为空时页面异常
|
||||||
|
+ 评论区链接解析
|
||||||
|
+ 视频全屏状态栏背景色
|
||||||
|
+ 私信对话气泡位置
|
||||||
|
+ 设置up关注分组样式
|
||||||
|
+ 每次推荐请求数据相同
|
||||||
|
+ iOS代理网络异常
|
||||||
|
+ 双击切换播放状态无声
|
||||||
|
+ 设置自定义倍速白屏
|
||||||
|
+ 免登录查看1080p
|
||||||
|
|
||||||
|
### 优化
|
||||||
|
+ 首页web端推荐观看数展示
|
||||||
|
+ 首页web端推荐接口更新
|
||||||
|
+ 首页样式
|
||||||
|
+ 搜索页跳转
|
||||||
|
+ 弹幕资源优化
|
||||||
|
+ 图片渲染占用内存优化(部分)
|
||||||
|
+ 两次返回退出应用
|
||||||
|
+ schame 补充
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
更多更新日志可在Github上查看
|
||||||
|
问题反馈、功能建议请查看「关于」页面。
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/utils/extension.dart';
|
||||||
import '../../utils/storage.dart';
|
import '../../utils/storage.dart';
|
||||||
import '../constants.dart';
|
import '../constants.dart';
|
||||||
|
|
||||||
@ -12,55 +13,75 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
this.src,
|
this.src,
|
||||||
required this.width,
|
required this.width,
|
||||||
required this.height,
|
required this.height,
|
||||||
this.cacheW,
|
|
||||||
this.cacheH,
|
|
||||||
this.type,
|
this.type,
|
||||||
this.fadeOutDuration,
|
this.fadeOutDuration,
|
||||||
this.fadeInDuration,
|
this.fadeInDuration,
|
||||||
// 图片质量 默认1%
|
// 图片质量 默认1%
|
||||||
this.quality,
|
this.quality,
|
||||||
|
this.origAspectRatio,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String? src;
|
final String? src;
|
||||||
final double? width;
|
final double width;
|
||||||
final double? height;
|
final double height;
|
||||||
final double? cacheW;
|
|
||||||
final double? cacheH;
|
|
||||||
final String? type;
|
final String? type;
|
||||||
final Duration? fadeOutDuration;
|
final Duration? fadeOutDuration;
|
||||||
final Duration? fadeInDuration;
|
final Duration? fadeInDuration;
|
||||||
final int? quality;
|
final int? quality;
|
||||||
|
final double? origAspectRatio;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final double pr = MediaQuery.of(context).devicePixelRatio;
|
final String imageUrl =
|
||||||
final int picQuality =
|
'${src!.startsWith('//') ? 'https:${src!}' : src!}@${quality ?? 100}q.webp';
|
||||||
setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10) as int;
|
int? memCacheWidth, memCacheHeight;
|
||||||
|
double aspectRatio = (width / height).toDouble();
|
||||||
|
|
||||||
// double pr = 2;
|
void setMemCacheSizes() {
|
||||||
return src != ''
|
if (aspectRatio > 1) {
|
||||||
|
memCacheHeight = height.cacheSize(context);
|
||||||
|
} else if (aspectRatio < 1) {
|
||||||
|
memCacheWidth = width.cacheSize(context);
|
||||||
|
} else {
|
||||||
|
if (origAspectRatio != null && origAspectRatio! > 1) {
|
||||||
|
memCacheWidth = width.cacheSize(context);
|
||||||
|
} else if (origAspectRatio != null && origAspectRatio! < 1) {
|
||||||
|
memCacheHeight = height.cacheSize(context);
|
||||||
|
} else {
|
||||||
|
memCacheWidth = width.cacheSize(context);
|
||||||
|
memCacheHeight = height.cacheSize(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMemCacheSizes();
|
||||||
|
|
||||||
|
if (memCacheWidth == null && memCacheHeight == null) {
|
||||||
|
memCacheWidth = width.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return src != '' && src != null
|
||||||
? ClipRRect(
|
? ClipRRect(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.antiAlias,
|
||||||
borderRadius: BorderRadius.circular(type == 'avatar'
|
borderRadius: BorderRadius.circular(
|
||||||
? 50
|
type == 'avatar'
|
||||||
: type == 'emote'
|
? 50
|
||||||
? 0
|
: type == 'emote'
|
||||||
: StyleString.imgRadius.x),
|
? 0
|
||||||
|
: StyleString.imgRadius.x,
|
||||||
|
),
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl:
|
imageUrl: imageUrl,
|
||||||
'${src!.startsWith('//') ? 'https:${src!}' : src!}@${quality ?? picQuality}q.webp',
|
width: width,
|
||||||
width: width ?? double.infinity,
|
height: height,
|
||||||
height: height ?? double.infinity,
|
memCacheWidth: memCacheWidth,
|
||||||
maxWidthDiskCache: ((cacheW ?? width!) * pr).toInt(),
|
memCacheHeight: memCacheHeight,
|
||||||
// maxHeightDiskCache: (cacheH ?? height!).toInt(),
|
|
||||||
memCacheWidth: ((cacheW ?? width!) * pr).toInt(),
|
|
||||||
// memCacheHeight: (cacheH ?? height!).toInt(),
|
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
fadeOutDuration:
|
fadeOutDuration:
|
||||||
fadeOutDuration ?? const Duration(milliseconds: 200),
|
fadeOutDuration ?? const Duration(milliseconds: 120),
|
||||||
fadeInDuration:
|
fadeInDuration:
|
||||||
fadeInDuration ?? const Duration(milliseconds: 200),
|
fadeInDuration ?? const Duration(milliseconds: 120),
|
||||||
// filterQuality: FilterQuality.high,
|
filterQuality: FilterQuality.high,
|
||||||
errorWidget: (BuildContext context, String url, Object error) =>
|
errorWidget: (BuildContext context, String url, Object error) =>
|
||||||
placeholder(context),
|
placeholder(context),
|
||||||
placeholder: (BuildContext context, String url) =>
|
placeholder: (BuildContext context, String url) =>
|
||||||
@ -72,9 +93,9 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
|
|
||||||
Widget placeholder(BuildContext context) {
|
Widget placeholder(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: width ?? double.infinity,
|
width: width,
|
||||||
height: height ?? double.infinity,
|
height: height,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.antiAlias,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.onInverseSurface.withOpacity(0.4),
|
color: Theme.of(context).colorScheme.onInverseSurface.withOpacity(0.4),
|
||||||
borderRadius: BorderRadius.circular(type == 'avatar'
|
borderRadius: BorderRadius.circular(type == 'avatar'
|
||||||
@ -84,13 +105,16 @@ class NetworkImgLayer extends StatelessWidget {
|
|||||||
: StyleString.imgRadius.x),
|
: StyleString.imgRadius.x),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
type == 'avatar'
|
type == 'avatar'
|
||||||
? 'assets/images/noface.jpeg'
|
? 'assets/images/noface.jpeg'
|
||||||
: 'assets/images/loading.png',
|
: 'assets/images/loading.png',
|
||||||
width: 300,
|
width: width,
|
||||||
height: 300,
|
height: height,
|
||||||
)),
|
cacheWidth: width.cacheSize(context),
|
||||||
|
cacheHeight: height.cacheSize(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,7 +69,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
final double width = (boxConstraints.maxWidth -
|
final double width = (boxConstraints.maxWidth -
|
||||||
StyleString.cardSpace *
|
StyleString.cardSpace *
|
||||||
6 /
|
6 /
|
||||||
MediaQuery.of(context).textScaleFactor) /
|
MediaQuery.textScalerOf(context).scale(1.0)) /
|
||||||
2;
|
2;
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(minHeight: 88),
|
constraints: const BoxConstraints(minHeight: 88),
|
||||||
|
|||||||
@ -326,7 +326,8 @@ class VideoStat extends StatelessWidget {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
fontSize: MediaQuery.textScalerOf(context)
|
||||||
|
.scale(Theme.of(context).textTheme.labelSmall!.fontSize!),
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -185,7 +185,7 @@ class Api {
|
|||||||
static const String searchDefault = '/x/web-interface/wbi/search/default';
|
static const String searchDefault = '/x/web-interface/wbi/search/default';
|
||||||
|
|
||||||
// 搜索关键词
|
// 搜索关键词
|
||||||
static const String serachSuggest =
|
static const String searchSuggest =
|
||||||
'https://s.search.bilibili.com/main/suggest';
|
'https://s.search.bilibili.com/main/suggest';
|
||||||
|
|
||||||
// 分类搜索
|
// 分类搜索
|
||||||
@ -467,4 +467,7 @@ class Api {
|
|||||||
/// page_size
|
/// page_size
|
||||||
static const getSeasonDetailApi =
|
static const getSeasonDetailApi =
|
||||||
'/x/polymer/web-space/seasons_archives_list';
|
'/x/polymer/web-space/seasons_archives_list';
|
||||||
|
|
||||||
|
/// 获取未读动态数
|
||||||
|
static const getUnreadDynamic = '/x/web-interface/dynamic/entrance';
|
||||||
}
|
}
|
||||||
|
|||||||
17
lib/http/common.dart
Normal file
17
lib/http/common.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'index.dart';
|
||||||
|
|
||||||
|
class CommonHttp {
|
||||||
|
static Future unReadDynamic() async {
|
||||||
|
var res = await Request().get(Api.getUnreadDynamic,
|
||||||
|
data: {'alltype_offset': 0, 'video_offset': '', 'article_offset': 0});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true, 'data': res.data['data']['dyn_basic_infos']};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'data': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ import 'package:dio/io.dart';
|
|||||||
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
|
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
|
||||||
// import 'package:dio_http2_adapter/dio_http2_adapter.dart';
|
// import 'package:dio_http2_adapter/dio_http2_adapter.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
import '../utils/storage.dart';
|
import '../utils/storage.dart';
|
||||||
import '../utils/utils.dart';
|
import '../utils/utils.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
@ -77,10 +78,11 @@ class Request {
|
|||||||
static setOptionsHeaders(userInfo, bool status) {
|
static setOptionsHeaders(userInfo, bool status) {
|
||||||
if (status) {
|
if (status) {
|
||||||
dio.options.headers['x-bili-mid'] = userInfo.mid.toString();
|
dio.options.headers['x-bili-mid'] = userInfo.mid.toString();
|
||||||
|
dio.options.headers['x-bili-aurora-eid'] =
|
||||||
|
IdUtils.genAuroraEid(userInfo.mid);
|
||||||
}
|
}
|
||||||
dio.options.headers['env'] = 'prod';
|
dio.options.headers['env'] = 'prod';
|
||||||
dio.options.headers['app-key'] = 'android64';
|
dio.options.headers['app-key'] = 'android64';
|
||||||
dio.options.headers['x-bili-aurora-eid'] = 'UlMFQVcABlAH';
|
|
||||||
dio.options.headers['x-bili-aurora-zone'] = 'sh001';
|
dio.options.headers['x-bili-aurora-zone'] = 'sh001';
|
||||||
dio.options.headers['referer'] = 'https://www.bilibili.com/';
|
dio.options.headers['referer'] = 'https://www.bilibili.com/';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,14 +70,14 @@ class ApiInterceptor extends Interceptor {
|
|||||||
case DioExceptionType.sendTimeout:
|
case DioExceptionType.sendTimeout:
|
||||||
return '发送请求超时,请检查网络设置';
|
return '发送请求超时,请检查网络设置';
|
||||||
case DioExceptionType.unknown:
|
case DioExceptionType.unknown:
|
||||||
final String res = await checkConect();
|
final String res = await checkConnect();
|
||||||
return '$res \n 网络异常,请稍后重试!';
|
return '$res \n 网络异常,请稍后重试!';
|
||||||
// default:
|
// default:
|
||||||
// return 'Dio异常';
|
// return 'Dio异常';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<String> checkConect() async {
|
static Future<String> checkConnect() async {
|
||||||
final ConnectivityResult connectivityResult =
|
final ConnectivityResult connectivityResult =
|
||||||
await Connectivity().checkConnectivity();
|
await Connectivity().checkConnectivity();
|
||||||
if (connectivityResult == ConnectivityResult.mobile) {
|
if (connectivityResult == ConnectivityResult.mobile) {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class SearchHttp {
|
|||||||
|
|
||||||
// 获取搜索建议
|
// 获取搜索建议
|
||||||
static Future searchSuggest({required term}) async {
|
static Future searchSuggest({required term}) async {
|
||||||
var res = await Request().get(Api.serachSuggest,
|
var res = await Request().get(Api.searchSuggest,
|
||||||
data: {'term': term, 'main_ver': 'v1', 'highlight': term});
|
data: {'term': term, 'main_ver': 'v1', 'highlight': term});
|
||||||
if (res.data is String) {
|
if (res.data is String) {
|
||||||
Map<String, dynamic> resultMap = json.decode(res.data);
|
Map<String, dynamic> resultMap = json.decode(res.data);
|
||||||
|
|||||||
@ -158,9 +158,8 @@ class MyApp extends StatelessWidget {
|
|||||||
return FlutterSmartDialog(
|
return FlutterSmartDialog(
|
||||||
toastBuilder: (String msg) => CustomToast(msg: msg),
|
toastBuilder: (String msg) => CustomToast(msg: msg),
|
||||||
child: MediaQuery(
|
child: MediaQuery(
|
||||||
data: MediaQuery.of(context).copyWith(
|
data: MediaQuery.of(context)
|
||||||
textScaleFactor:
|
.copyWith(textScaler: TextScaler.linear(textScale)),
|
||||||
MediaQuery.of(context).textScaleFactor * textScale),
|
|
||||||
child: child!,
|
child: child!,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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 = [
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
import 'package:hive/hive.dart';
|
|
||||||
|
|
||||||
part 'result.g.dart';
|
|
||||||
|
|
||||||
@HiveType(typeId: 0)
|
|
||||||
class RecVideoItemAppModel {
|
class RecVideoItemAppModel {
|
||||||
RecVideoItemAppModel({
|
RecVideoItemAppModel({
|
||||||
this.id,
|
this.id,
|
||||||
@ -27,47 +22,27 @@ class RecVideoItemAppModel {
|
|||||||
this.adInfo,
|
this.adInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
@HiveField(0)
|
|
||||||
int? id;
|
int? id;
|
||||||
@HiveField(1)
|
|
||||||
int? aid;
|
int? aid;
|
||||||
@HiveField(2)
|
|
||||||
String? bvid;
|
String? bvid;
|
||||||
@HiveField(3)
|
|
||||||
int? cid;
|
int? cid;
|
||||||
@HiveField(4)
|
|
||||||
String? pic;
|
String? pic;
|
||||||
@HiveField(5)
|
|
||||||
RcmdStat? stat;
|
RcmdStat? stat;
|
||||||
@HiveField(6)
|
|
||||||
int? duration;
|
int? duration;
|
||||||
@HiveField(7)
|
|
||||||
String? title;
|
String? title;
|
||||||
@HiveField(8)
|
|
||||||
int? isFollowed;
|
int? isFollowed;
|
||||||
@HiveField(9)
|
|
||||||
RcmdOwner? owner;
|
RcmdOwner? owner;
|
||||||
@HiveField(10)
|
|
||||||
RcmdReason? rcmdReason;
|
RcmdReason? rcmdReason;
|
||||||
@HiveField(11)
|
|
||||||
String? goto;
|
String? goto;
|
||||||
@HiveField(12)
|
|
||||||
int? param;
|
int? param;
|
||||||
@HiveField(13)
|
|
||||||
String? uri;
|
String? uri;
|
||||||
@HiveField(14)
|
|
||||||
String? talkBack;
|
String? talkBack;
|
||||||
// 番剧
|
// 番剧
|
||||||
@HiveField(15)
|
|
||||||
String? bangumiView;
|
String? bangumiView;
|
||||||
@HiveField(16)
|
|
||||||
String? bangumiFollow;
|
String? bangumiFollow;
|
||||||
@HiveField(17)
|
|
||||||
String? bangumiBadge;
|
String? bangumiBadge;
|
||||||
|
|
||||||
@HiveField(18)
|
|
||||||
String? cardType;
|
String? cardType;
|
||||||
@HiveField(19)
|
|
||||||
Map? adInfo;
|
Map? adInfo;
|
||||||
|
|
||||||
RecVideoItemAppModel.fromJson(Map<String, dynamic> json) {
|
RecVideoItemAppModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -116,18 +91,14 @@ class RecVideoItemAppModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiveType(typeId: 1)
|
|
||||||
class RcmdStat {
|
class RcmdStat {
|
||||||
RcmdStat({
|
RcmdStat({
|
||||||
this.view,
|
this.view,
|
||||||
this.like,
|
this.like,
|
||||||
this.danmu,
|
this.danmu,
|
||||||
});
|
});
|
||||||
@HiveField(0)
|
|
||||||
String? view;
|
String? view;
|
||||||
@HiveField(1)
|
|
||||||
String? like;
|
String? like;
|
||||||
@HiveField(2)
|
|
||||||
String? danmu;
|
String? danmu;
|
||||||
|
|
||||||
RcmdStat.fromJson(Map<String, dynamic> json) {
|
RcmdStat.fromJson(Map<String, dynamic> json) {
|
||||||
@ -136,13 +107,10 @@ class RcmdStat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiveType(typeId: 2)
|
|
||||||
class RcmdOwner {
|
class RcmdOwner {
|
||||||
RcmdOwner({this.name, this.mid});
|
RcmdOwner({this.name, this.mid});
|
||||||
|
|
||||||
@HiveField(0)
|
|
||||||
String? name;
|
String? name;
|
||||||
@HiveField(1)
|
|
||||||
int? mid;
|
int? mid;
|
||||||
|
|
||||||
RcmdOwner.fromJson(Map<String, dynamic> json) {
|
RcmdOwner.fromJson(Map<String, dynamic> json) {
|
||||||
@ -155,13 +123,11 @@ class RcmdOwner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiveType(typeId: 8)
|
|
||||||
class RcmdReason {
|
class RcmdReason {
|
||||||
RcmdReason({
|
RcmdReason({
|
||||||
this.content,
|
this.content,
|
||||||
});
|
});
|
||||||
|
|
||||||
@HiveField(0)
|
|
||||||
String? content;
|
String? content;
|
||||||
|
|
||||||
RcmdReason.fromJson(Map<String, dynamic> json) {
|
RcmdReason.fromJson(Map<String, dynamic> json) {
|
||||||
|
|||||||
@ -1,209 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'result.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// TypeAdapterGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
class RecVideoItemAppModelAdapter extends TypeAdapter<RecVideoItemAppModel> {
|
|
||||||
@override
|
|
||||||
final int typeId = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
RecVideoItemAppModel read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return RecVideoItemAppModel(
|
|
||||||
id: fields[0] as int?,
|
|
||||||
aid: fields[1] as int?,
|
|
||||||
bvid: fields[2] as String?,
|
|
||||||
cid: fields[3] as int?,
|
|
||||||
pic: fields[4] as String?,
|
|
||||||
stat: fields[5] as RcmdStat?,
|
|
||||||
duration: fields[6] as int?,
|
|
||||||
title: fields[7] as String?,
|
|
||||||
isFollowed: fields[8] as int?,
|
|
||||||
owner: fields[9] as RcmdOwner?,
|
|
||||||
rcmdReason: fields[10] as RcmdReason?,
|
|
||||||
goto: fields[11] as String?,
|
|
||||||
param: fields[12] as int?,
|
|
||||||
uri: fields[13] as String?,
|
|
||||||
talkBack: fields[14] as String?,
|
|
||||||
bangumiView: fields[15] as String?,
|
|
||||||
bangumiFollow: fields[16] as String?,
|
|
||||||
bangumiBadge: fields[17] as String?,
|
|
||||||
cardType: fields[18] as String?,
|
|
||||||
adInfo: (fields[19] as Map?)?.cast<dynamic, dynamic>(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, RecVideoItemAppModel obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(20)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.id)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.aid)
|
|
||||||
..writeByte(2)
|
|
||||||
..write(obj.bvid)
|
|
||||||
..writeByte(3)
|
|
||||||
..write(obj.cid)
|
|
||||||
..writeByte(4)
|
|
||||||
..write(obj.pic)
|
|
||||||
..writeByte(5)
|
|
||||||
..write(obj.stat)
|
|
||||||
..writeByte(6)
|
|
||||||
..write(obj.duration)
|
|
||||||
..writeByte(7)
|
|
||||||
..write(obj.title)
|
|
||||||
..writeByte(8)
|
|
||||||
..write(obj.isFollowed)
|
|
||||||
..writeByte(9)
|
|
||||||
..write(obj.owner)
|
|
||||||
..writeByte(10)
|
|
||||||
..write(obj.rcmdReason)
|
|
||||||
..writeByte(11)
|
|
||||||
..write(obj.goto)
|
|
||||||
..writeByte(12)
|
|
||||||
..write(obj.param)
|
|
||||||
..writeByte(13)
|
|
||||||
..write(obj.uri)
|
|
||||||
..writeByte(14)
|
|
||||||
..write(obj.talkBack)
|
|
||||||
..writeByte(15)
|
|
||||||
..write(obj.bangumiView)
|
|
||||||
..writeByte(16)
|
|
||||||
..write(obj.bangumiFollow)
|
|
||||||
..writeByte(17)
|
|
||||||
..write(obj.bangumiBadge)
|
|
||||||
..writeByte(18)
|
|
||||||
..write(obj.cardType)
|
|
||||||
..writeByte(19)
|
|
||||||
..write(obj.adInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is RecVideoItemAppModelAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RcmdStatAdapter extends TypeAdapter<RcmdStat> {
|
|
||||||
@override
|
|
||||||
final int typeId = 1;
|
|
||||||
|
|
||||||
@override
|
|
||||||
RcmdStat read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return RcmdStat(
|
|
||||||
view: fields[0] as String?,
|
|
||||||
like: fields[1] as String?,
|
|
||||||
danmu: fields[2] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, RcmdStat obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(3)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.view)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.like)
|
|
||||||
..writeByte(2)
|
|
||||||
..write(obj.danmu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is RcmdStatAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RcmdOwnerAdapter extends TypeAdapter<RcmdOwner> {
|
|
||||||
@override
|
|
||||||
final int typeId = 2;
|
|
||||||
|
|
||||||
@override
|
|
||||||
RcmdOwner read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return RcmdOwner(
|
|
||||||
name: fields[0] as String?,
|
|
||||||
mid: fields[1] as int?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, RcmdOwner obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(2)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.name)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is RcmdOwnerAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RcmdReasonAdapter extends TypeAdapter<RcmdReason> {
|
|
||||||
@override
|
|
||||||
final int typeId = 8;
|
|
||||||
|
|
||||||
@override
|
|
||||||
RcmdReason read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return RcmdReason(
|
|
||||||
content: fields[0] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, RcmdReason obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(1)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is RcmdReasonAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
@ -86,6 +86,14 @@ class _AboutPageState extends State<AboutPage> {
|
|||||||
style: subTitleStyle,
|
style: subTitleStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
onTap: () => _aboutController.webSiteUrl(),
|
||||||
|
title: const Text('访问官网'),
|
||||||
|
trailing: Text(
|
||||||
|
'https://pilipalanet.mysxl.cn',
|
||||||
|
style: subTitleStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => _aboutController.panDownload(),
|
onTap: () => _aboutController.panDownload(),
|
||||||
title: const Text('网盘下载'),
|
title: const Text('网盘下载'),
|
||||||
@ -244,4 +252,12 @@ class AboutController extends GetxController {
|
|||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 官网
|
||||||
|
webSiteUrl() {
|
||||||
|
launchUrl(
|
||||||
|
Uri.parse('https://pilipalanet.mysxl.cn'),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -224,7 +224,7 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
// 列数
|
// 列数
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
mainAxisExtent: Get.size.width / 3 / 0.65 +
|
mainAxisExtent: Get.size.width / 3 / 0.65 +
|
||||||
32 * MediaQuery.of(context).textScaleFactor,
|
MediaQuery.textScalerOf(context).scale(32.0),
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// 内容
|
// 内容
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
import 'package:pilipala/pages/preview/index.dart';
|
import 'package:pilipala/pages/preview/index.dart';
|
||||||
@ -48,6 +49,13 @@ class _ContentState extends State<Content> {
|
|||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (context, BoxConstraints box) {
|
builder: (context, BoxConstraints box) {
|
||||||
|
double maxWidth = box.maxWidth.truncateToDouble();
|
||||||
|
double maxHeight = box.maxWidth * 0.6; // 设置最大高度
|
||||||
|
double height = maxWidth *
|
||||||
|
0.5 *
|
||||||
|
(pictureItem.height != null && pictureItem.width != null
|
||||||
|
? pictureItem.height! / pictureItem.width!
|
||||||
|
: 1);
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
@ -58,18 +66,29 @@ class _ContentState extends State<Content> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(top: 4),
|
padding: const EdgeInsets.only(top: 4),
|
||||||
child: NetworkImgLayer(
|
constraints: BoxConstraints(maxHeight: maxHeight),
|
||||||
src: pictureItem.url,
|
|
||||||
width: box.maxWidth / 2,
|
width: box.maxWidth / 2,
|
||||||
height: box.maxWidth *
|
height: height,
|
||||||
0.5 *
|
child: Stack(
|
||||||
(pictureItem.height != null && pictureItem.width != null
|
children: [
|
||||||
? pictureItem.height! / pictureItem.width!
|
Positioned.fill(
|
||||||
: 1),
|
child: NetworkImgLayer(
|
||||||
),
|
src: pictureItem.url,
|
||||||
),
|
width: maxWidth / 2,
|
||||||
|
height: height,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height > maxHeight
|
||||||
|
? const PBadge(
|
||||||
|
text: '长图',
|
||||||
|
right: 8,
|
||||||
|
bottom: 8,
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
],
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -83,6 +102,7 @@ class _ContentState extends State<Content> {
|
|||||||
list.add(
|
list.add(
|
||||||
LayoutBuilder(
|
LayoutBuilder(
|
||||||
builder: (context, BoxConstraints box) {
|
builder: (context, BoxConstraints box) {
|
||||||
|
double maxWidth = box.maxWidth.truncateToDouble();
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
@ -95,8 +115,10 @@ class _ContentState extends State<Content> {
|
|||||||
},
|
},
|
||||||
child: NetworkImgLayer(
|
child: NetworkImgLayer(
|
||||||
src: pics[i].url,
|
src: pics[i].url,
|
||||||
width: box.maxWidth,
|
width: maxWidth,
|
||||||
height: box.maxWidth,
|
height: maxWidth,
|
||||||
|
origAspectRatio:
|
||||||
|
pics[i].width!.toInt() / pics[i].height!.toInt(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -107,7 +129,7 @@ class _ContentState extends State<Content> {
|
|||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (context, BoxConstraints box) {
|
builder: (context, BoxConstraints box) {
|
||||||
double maxWidth = box.maxWidth;
|
double maxWidth = box.maxWidth.truncateToDouble();
|
||||||
double crossCount = len < 3 ? 2 : 3;
|
double crossCount = len < 3 ? 2 : 3;
|
||||||
double height = maxWidth /
|
double height = maxWidth /
|
||||||
crossCount *
|
crossCount *
|
||||||
|
|||||||
@ -5,15 +5,17 @@ import 'package:get/get.dart';
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/models/common/tab_type.dart';
|
import 'package:pilipala/models/common/tab_type.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
import '../../http/index.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 +23,9 @@ 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;
|
||||||
|
RxString defaultSearch = ''.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -28,19 +33,13 @@ 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);
|
||||||
|
if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) {
|
||||||
|
searchDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRefresh() {
|
void onRefresh() {
|
||||||
@ -62,4 +61,49 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void searchDefault() async {
|
||||||
|
var res = await Request().get(Api.searchDefault);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
defaultSearch.value = res.data['data']['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/pages/mine/index.dart';
|
import 'package:pilipala/pages/mine/index.dart';
|
||||||
import 'package:pilipala/pages/search/index.dart';
|
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import './controller.dart';
|
import './controller.dart';
|
||||||
|
|
||||||
@ -46,6 +46,13 @@ class _HomePageState extends State<HomePage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
|
Brightness currentBrightness = MediaQuery.of(context).platformBrightness;
|
||||||
|
// 设置状态栏图标的亮度
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||||
|
statusBarIconBrightness: currentBrightness == Brightness.light
|
||||||
|
? Brightness.dark
|
||||||
|
: Brightness.light,
|
||||||
|
));
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
extendBody: true,
|
extendBody: true,
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
@ -82,7 +89,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,
|
||||||
@ -129,9 +140,10 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
curve: Curves.easeInOutCubicEmphasized,
|
curve: Curves.easeInOutCubicEmphasized,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
height: snapshot.data ? top + 52 : top,
|
height: snapshot.data ? top + 52 : top,
|
||||||
padding: EdgeInsets.fromLTRB(14, top, 14, 0),
|
padding: EdgeInsets.fromLTRB(14, top + 6, 14, 0),
|
||||||
child: UserInfoWidget(
|
child: UserInfoWidget(
|
||||||
top: top,
|
top: top,
|
||||||
|
ctr: ctr,
|
||||||
userLogin: isUserLoggedIn,
|
userLogin: isUserLoggedIn,
|
||||||
userFace: ctr?.userFace.value,
|
userFace: ctr?.userFace.value,
|
||||||
callback: () => callback!(),
|
callback: () => callback!(),
|
||||||
@ -150,18 +162,20 @@ class UserInfoWidget extends StatelessWidget {
|
|||||||
required this.userLogin,
|
required this.userLogin,
|
||||||
required this.userFace,
|
required this.userFace,
|
||||||
required this.callback,
|
required this.callback,
|
||||||
|
required this.ctr,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final double top;
|
final double top;
|
||||||
final RxBool userLogin;
|
final RxBool userLogin;
|
||||||
final String? userFace;
|
final String? userFace;
|
||||||
final VoidCallback? callback;
|
final VoidCallback? callback;
|
||||||
|
final HomeController? ctr;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const SearchBar(),
|
SearchBar(ctr: ctr),
|
||||||
if (userLogin.value) ...[
|
if (userLogin.value) ...[
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
ClipRect(
|
ClipRect(
|
||||||
@ -242,17 +256,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();
|
||||||
@ -263,34 +266,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,
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -338,11 +337,15 @@ class CustomChip extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SearchBar extends StatelessWidget {
|
class SearchBar extends StatelessWidget {
|
||||||
const SearchBar({super.key});
|
const SearchBar({
|
||||||
|
Key? key,
|
||||||
|
required this.ctr,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final HomeController? ctr;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final SSearchController searchController = Get.put(SSearchController());
|
|
||||||
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -356,7 +359,10 @@ class SearchBar extends StatelessWidget {
|
|||||||
color: colorScheme.onSecondaryContainer.withOpacity(0.05),
|
color: colorScheme.onSecondaryContainer.withOpacity(0.05),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
splashColor: colorScheme.primaryContainer.withOpacity(0.3),
|
splashColor: colorScheme.primaryContainer.withOpacity(0.3),
|
||||||
onTap: () => Get.toNamed('/search'),
|
onTap: () => Get.toNamed(
|
||||||
|
'/search',
|
||||||
|
parameters: {'hintText': ctr!.defaultSearch.value},
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(width: 14),
|
const SizedBox(width: 14),
|
||||||
@ -365,14 +371,12 @@ class SearchBar extends StatelessWidget {
|
|||||||
color: colorScheme.onSecondaryContainer,
|
color: colorScheme.onSecondaryContainer,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Obx(
|
||||||
child: Obx(
|
() => Text(
|
||||||
() => Text(
|
ctr!.defaultSearch.value,
|
||||||
searchController.defaultSearch.value,
|
maxLines: 1,
|
||||||
maxLines: 1,
|
overflow: TextOverflow.ellipsis,
|
||||||
overflow: TextOverflow.ellipsis,
|
style: TextStyle(color: colorScheme.outline),
|
||||||
style: TextStyle(color: colorScheme.outline),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -162,8 +162,9 @@ class _LivePageState extends State<LivePage>
|
|||||||
crossAxisCount: crossAxisCount,
|
crossAxisCount: crossAxisCount,
|
||||||
mainAxisExtent:
|
mainAxisExtent:
|
||||||
Get.size.width / crossAxisCount / StyleString.aspectRatio +
|
Get.size.width / crossAxisCount / StyleString.aspectRatio +
|
||||||
(crossAxisCount == 1 ? 48 : 68) *
|
MediaQuery.textScalerOf(context).scale(
|
||||||
MediaQuery.of(context).textScaleFactor,
|
(crossAxisCount == 1 ? 48 : 68),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/http/common.dart';
|
||||||
import 'package:pilipala/pages/dynamics/index.dart';
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
import 'package:pilipala/pages/home/view.dart';
|
import 'package:pilipala/pages/home/view.dart';
|
||||||
import 'package:pilipala/pages/media/index.dart';
|
import 'package:pilipala/pages/media/index.dart';
|
||||||
@ -27,6 +29,7 @@ class MainController extends GetxController {
|
|||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
'label': "首页",
|
'label': "首页",
|
||||||
|
'count': 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'icon': const Icon(
|
'icon': const Icon(
|
||||||
@ -38,6 +41,7 @@ class MainController extends GetxController {
|
|||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
'label': "动态",
|
'label': "动态",
|
||||||
|
'count': 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'icon': const Icon(
|
'icon': const Icon(
|
||||||
@ -49,6 +53,7 @@ class MainController extends GetxController {
|
|||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
'label': "媒体库",
|
'label': "媒体库",
|
||||||
|
'count': 0,
|
||||||
}
|
}
|
||||||
].obs;
|
].obs;
|
||||||
final StreamController<bool> bottomBarStream =
|
final StreamController<bool> bottomBarStream =
|
||||||
@ -56,6 +61,10 @@ class MainController extends GetxController {
|
|||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
DateTime? _lastPressedAt;
|
DateTime? _lastPressedAt;
|
||||||
late bool hideTabBar;
|
late bool hideTabBar;
|
||||||
|
late PageController pageController;
|
||||||
|
int selectedIndex = 0;
|
||||||
|
Box userInfoCache = GStrorage.userInfo;
|
||||||
|
RxBool userLogin = false.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -64,17 +73,47 @@ class MainController extends GetxController {
|
|||||||
Utils.checkUpdata();
|
Utils.checkUpdata();
|
||||||
}
|
}
|
||||||
hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true);
|
hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true);
|
||||||
|
var userInfo = userInfoCache.get('userInfoCache');
|
||||||
|
userLogin.value = userInfo != null;
|
||||||
|
getUnreadDynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> onBackPressed(BuildContext context) {
|
void onBackPressed(BuildContext context) {
|
||||||
if (_lastPressedAt == null ||
|
if (_lastPressedAt == null ||
|
||||||
DateTime.now().difference(_lastPressedAt!) >
|
DateTime.now().difference(_lastPressedAt!) >
|
||||||
const Duration(seconds: 2)) {
|
const Duration(seconds: 2)) {
|
||||||
// 两次点击时间间隔超过2秒,重新记录时间戳
|
// 两次点击时间间隔超过2秒,重新记录时间戳
|
||||||
_lastPressedAt = DateTime.now();
|
_lastPressedAt = DateTime.now();
|
||||||
|
if (selectedIndex != 0) {
|
||||||
|
pageController.jumpTo(0);
|
||||||
|
}
|
||||||
SmartDialog.showToast("再按一次退出Pili");
|
SmartDialog.showToast("再按一次退出Pili");
|
||||||
return Future.value(false); // 不退出应用
|
return; // 不退出应用
|
||||||
}
|
}
|
||||||
return Future.value(true); // 退出应用
|
SystemNavigator.pop(); // 退出应用
|
||||||
|
}
|
||||||
|
|
||||||
|
void getUnreadDynamic() async {
|
||||||
|
if (!userLogin.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int dynamicItemIndex =
|
||||||
|
navigationBars.indexWhere((item) => item['label'] == "动态");
|
||||||
|
var res = await CommonHttp.unReadDynamic();
|
||||||
|
var data = res['data'];
|
||||||
|
if (dynamicItemIndex != -1) {
|
||||||
|
navigationBars[dynamicItemIndex]['count'] =
|
||||||
|
data == null ? 0 : data.length; // 修改 count 属性为新的值
|
||||||
|
}
|
||||||
|
navigationBars.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearUnread() async {
|
||||||
|
int dynamicItemIndex =
|
||||||
|
navigationBars.indexWhere((item) => item['label'] == "动态");
|
||||||
|
if (dynamicItemIndex != -1) {
|
||||||
|
navigationBars[dynamicItemIndex]['count'] = 0; // 修改 count 属性为新的值
|
||||||
|
}
|
||||||
|
navigationBars.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,8 +24,6 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
|||||||
final DynamicsController _dynamicController = Get.put(DynamicsController());
|
final DynamicsController _dynamicController = Get.put(DynamicsController());
|
||||||
final MediaController _mediaController = Get.put(MediaController());
|
final MediaController _mediaController = Get.put(MediaController());
|
||||||
|
|
||||||
PageController? _pageController;
|
|
||||||
int selectedIndex = 0;
|
|
||||||
int? _lastSelectTime; //上次点击时间
|
int? _lastSelectTime; //上次点击时间
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
late bool enableMYBar;
|
late bool enableMYBar;
|
||||||
@ -34,13 +32,14 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
|
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
_pageController = PageController(initialPage: selectedIndex);
|
_mainController.pageController =
|
||||||
|
PageController(initialPage: _mainController.selectedIndex);
|
||||||
enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
|
enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIndex(int value) async {
|
void setIndex(int value) async {
|
||||||
feedBack();
|
feedBack();
|
||||||
_pageController!.jumpToPage(value);
|
_mainController.pageController.jumpToPage(value);
|
||||||
var currentPage = _mainController.pages[value];
|
var currentPage = _mainController.pages[value];
|
||||||
if (currentPage is HomePage) {
|
if (currentPage is HomePage) {
|
||||||
if (_homeController.flag) {
|
if (_homeController.flag) {
|
||||||
@ -68,6 +67,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
|||||||
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
|
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
}
|
}
|
||||||
_dynamicController.flag = true;
|
_dynamicController.flag = true;
|
||||||
|
_mainController.clearUnread();
|
||||||
} else {
|
} else {
|
||||||
_dynamicController.flag = false;
|
_dynamicController.flag = false;
|
||||||
}
|
}
|
||||||
@ -94,14 +94,17 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
|||||||
localCache.put('sheetHeight', sheetHeight);
|
localCache.put('sheetHeight', sheetHeight);
|
||||||
localCache.put('statusBarHeight', statusBarHeight);
|
localCache.put('statusBarHeight', statusBarHeight);
|
||||||
return PopScope(
|
return PopScope(
|
||||||
onPopInvoked: (bool status) => _mainController.onBackPressed(context),
|
canPop: false,
|
||||||
|
onPopInvoked: (bool didPop) async {
|
||||||
|
_mainController.onBackPressed(context);
|
||||||
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
extendBody: true,
|
extendBody: true,
|
||||||
body: PageView(
|
body: PageView(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
controller: _pageController,
|
controller: _mainController.pageController,
|
||||||
onPageChanged: (index) {
|
onPageChanged: (index) {
|
||||||
selectedIndex = index;
|
_mainController.selectedIndex = index;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
children: _mainController.pages,
|
children: _mainController.pages,
|
||||||
@ -116,36 +119,48 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
|
|||||||
curve: Curves.easeInOutCubicEmphasized,
|
curve: Curves.easeInOutCubicEmphasized,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
offset: Offset(0, snapshot.data ? 0 : 1),
|
offset: Offset(0, snapshot.data ? 0 : 1),
|
||||||
child: enableMYBar
|
child: Obx(
|
||||||
? NavigationBar(
|
() => enableMYBar
|
||||||
onDestinationSelected: (value) => setIndex(value),
|
? NavigationBar(
|
||||||
selectedIndex: selectedIndex,
|
onDestinationSelected: (value) => setIndex(value),
|
||||||
destinations: <Widget>[
|
selectedIndex: _mainController.selectedIndex,
|
||||||
..._mainController.navigationBars.map((e) {
|
destinations: <Widget>[
|
||||||
return NavigationDestination(
|
..._mainController.navigationBars.map((e) {
|
||||||
icon: e['icon'],
|
return NavigationDestination(
|
||||||
selectedIcon: e['selectIcon'],
|
icon: Badge(
|
||||||
label: e['label'],
|
label: Text(e['count'].toString()),
|
||||||
);
|
padding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
|
||||||
}).toList(),
|
isLabelVisible: e['count'] > 0,
|
||||||
],
|
child: e['icon'],
|
||||||
)
|
),
|
||||||
: BottomNavigationBar(
|
selectedIcon: e['selectIcon'],
|
||||||
currentIndex: selectedIndex,
|
label: e['label'],
|
||||||
onTap: (value) => setIndex(value),
|
);
|
||||||
iconSize: 16,
|
}).toList(),
|
||||||
selectedFontSize: 12,
|
],
|
||||||
unselectedFontSize: 12,
|
)
|
||||||
items: [
|
: BottomNavigationBar(
|
||||||
..._mainController.navigationBars.map((e) {
|
currentIndex: _mainController.selectedIndex,
|
||||||
return BottomNavigationBarItem(
|
onTap: (value) => setIndex(value),
|
||||||
icon: e['icon'],
|
iconSize: 16,
|
||||||
activeIcon: e['selectIcon'],
|
selectedFontSize: 12,
|
||||||
label: e['label'],
|
unselectedFontSize: 12,
|
||||||
);
|
items: [
|
||||||
}).toList(),
|
..._mainController.navigationBars.map((e) {
|
||||||
],
|
return BottomNavigationBarItem(
|
||||||
),
|
icon: Badge(
|
||||||
|
label: Text(e['count'].toString()),
|
||||||
|
padding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
|
||||||
|
isLabelVisible: e['count'] > 0,
|
||||||
|
child: e['icon'],
|
||||||
|
),
|
||||||
|
activeIcon: e['selectIcon'],
|
||||||
|
label: e['label'],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -163,7 +163,7 @@ class _MediaPageState extends State<MediaPage>
|
|||||||
// const SizedBox(height: 10),
|
// const SizedBox(height: 10),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 200 * MediaQuery.of(context).textScaleFactor,
|
height: MediaQuery.textScalerOf(context).scale(200),
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
|||||||
@ -13,7 +13,6 @@ class RcmdController extends GetxController {
|
|||||||
// RxList<RecVideoItemModel> webVideoList = <RecVideoItemModel>[].obs;
|
// RxList<RecVideoItemModel> webVideoList = <RecVideoItemModel>[].obs;
|
||||||
bool isLoadingMore = true;
|
bool isLoadingMore = true;
|
||||||
OverlayEntry? popupDialog;
|
OverlayEntry? popupDialog;
|
||||||
Box recVideo = GStrorage.recVideo;
|
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
RxInt crossAxisCount = 2.obs;
|
RxInt crossAxisCount = 2.obs;
|
||||||
late bool enableSaveLastData;
|
late bool enableSaveLastData;
|
||||||
@ -25,15 +24,6 @@ class RcmdController extends GetxController {
|
|||||||
super.onInit();
|
super.onInit();
|
||||||
crossAxisCount.value =
|
crossAxisCount.value =
|
||||||
setting.get(SettingBoxKey.customRows, defaultValue: 2);
|
setting.get(SettingBoxKey.customRows, defaultValue: 2);
|
||||||
// 读取app端缓存内容
|
|
||||||
// if (recVideo.get('cacheList') != null &&
|
|
||||||
// recVideo.get('cacheList').isNotEmpty) {
|
|
||||||
// List<RecVideoItemAppModel> list = [];
|
|
||||||
// for (var i in recVideo.get('cacheList')) {
|
|
||||||
// list.add(i);
|
|
||||||
// }
|
|
||||||
// videoList.value = list;
|
|
||||||
// }
|
|
||||||
enableSaveLastData =
|
enableSaveLastData =
|
||||||
setting.get(SettingBoxKey.enableSaveLastData, defaultValue: false);
|
setting.get(SettingBoxKey.enableSaveLastData, defaultValue: false);
|
||||||
defaultRcmdType =
|
defaultRcmdType =
|
||||||
@ -84,10 +74,6 @@ class RcmdController extends GetxController {
|
|||||||
} else if (type == 'onLoad') {
|
} else if (type == 'onLoad') {
|
||||||
videoList.addAll(res['data']);
|
videoList.addAll(res['data']);
|
||||||
}
|
}
|
||||||
// 目前仅支持app端系列保存缓存
|
|
||||||
if (defaultRcmdType != 'web') {
|
|
||||||
recVideo.put('cacheList', res['data']);
|
|
||||||
}
|
|
||||||
_currentPage += 1;
|
_currentPage += 1;
|
||||||
// 若videoList数量太小,可能会影响翻页,此时再次请求
|
// 若videoList数量太小,可能会影响翻页,此时再次请求
|
||||||
// 为避免请求到的数据太少时还在反复请求,要求本次返回数据大于1条才触发
|
// 为避免请求到的数据太少时还在反复请求,要求本次返回数据大于1条才触发
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
|
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/http/index.dart';
|
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/models/search/hot.dart';
|
import 'package:pilipala/models/search/hot.dart';
|
||||||
import 'package:pilipala/models/search/suggest.dart';
|
import 'package:pilipala/models/search/suggest.dart';
|
||||||
@ -27,9 +26,6 @@ class SSearchController extends GetxController {
|
|||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) {
|
|
||||||
searchDefault();
|
|
||||||
}
|
|
||||||
// 其他页面跳转过来
|
// 其他页面跳转过来
|
||||||
if (Get.parameters.keys.isNotEmpty) {
|
if (Get.parameters.keys.isNotEmpty) {
|
||||||
if (Get.parameters['keyword'] != null) {
|
if (Get.parameters['keyword'] != null) {
|
||||||
@ -130,12 +126,4 @@ class SSearchController extends GetxController {
|
|||||||
historyList.refresh();
|
historyList.refresh();
|
||||||
histiryWord.put('cacheList', []);
|
histiryWord.put('cacheList', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
void searchDefault() async {
|
|
||||||
var res = await Request().get(Api.searchDefault);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
searchKeyWord.value =
|
|
||||||
hintText = defaultSearch.value = res.data['data']['name'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,10 +26,9 @@ Widget searchArticlePanel(BuildContext context, ctr, list) {
|
|||||||
StyleString.safeSpace, 5, StyleString.safeSpace, 5),
|
StyleString.safeSpace, 5, StyleString.safeSpace, 5),
|
||||||
child: LayoutBuilder(builder: (context, boxConstraints) {
|
child: LayoutBuilder(builder: (context, boxConstraints) {
|
||||||
double width = (boxConstraints.maxWidth -
|
double width = (boxConstraints.maxWidth -
|
||||||
StyleString.cardSpace *
|
StyleString.cardSpace *
|
||||||
6 /
|
6 /
|
||||||
MediaQuery.of(context).textScaleFactor) /
|
MediaQuery.textScalerOf(context).scale(2.0));
|
||||||
2;
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(minHeight: 88),
|
constraints: const BoxConstraints(minHeight: 88),
|
||||||
height: width / StyleString.aspectRatio,
|
height: width / StyleString.aspectRatio,
|
||||||
|
|||||||
@ -17,7 +17,7 @@ Widget searchLivePanel(BuildContext context, ctr, list) {
|
|||||||
mainAxisSpacing: StyleString.cardSpace + 3,
|
mainAxisSpacing: StyleString.cardSpace + 3,
|
||||||
mainAxisExtent:
|
mainAxisExtent:
|
||||||
MediaQuery.sizeOf(context).width / 2 / StyleString.aspectRatio +
|
MediaQuery.sizeOf(context).width / 2 / StyleString.aspectRatio +
|
||||||
66 * MediaQuery.of(context).textScaleFactor),
|
MediaQuery.textScalerOf(context).scale(66.0)),
|
||||||
itemCount: list.length,
|
itemCount: list.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return LiveItem(liveItem: list![index]);
|
return LiveItem(liveItem: list![index]);
|
||||||
|
|||||||
@ -67,11 +67,11 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
|
|||||||
TextSpan(
|
TextSpan(
|
||||||
text: i['text'],
|
text: i['text'],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context)
|
fontSize: MediaQuery.textScalerOf(context)
|
||||||
|
.scale(Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.titleSmall!
|
.titleSmall!
|
||||||
.fontSize! *
|
.fontSize!),
|
||||||
MediaQuery.of(context).textScaleFactor,
|
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: i['type'] == 'em'
|
color: i['type'] == 'em'
|
||||||
? Theme.of(context).colorScheme.primary
|
? Theme.of(context).colorScheme.primary
|
||||||
|
|||||||
@ -90,7 +90,7 @@ class SearchVideoPanel extends StatelessWidget {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||||
),
|
),
|
||||||
onPressed: () => controller.onShowFilterDialog(),
|
onPressed: () => controller.onShowFilterDialog(ctr),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.filter_list_outlined,
|
Icons.filter_list_outlined,
|
||||||
size: 18,
|
size: 18,
|
||||||
@ -175,7 +175,7 @@ class VideoPanelController extends GetxController {
|
|||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowFilterDialog() {
|
onShowFilterDialog(searchPanelCtr) {
|
||||||
SmartDialog.show(
|
SmartDialog.show(
|
||||||
animationType: SmartAnimationType.centerFade_otherSlide,
|
animationType: SmartAnimationType.centerFade_otherSlide,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@ -199,7 +199,8 @@ class VideoPanelController extends GetxController {
|
|||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
SmartDialog.showToast("「${i['label']}」的筛选结果");
|
SmartDialog.showToast("「${i['label']}」的筛选结果");
|
||||||
SearchPanelController ctr =
|
SearchPanelController ctr =
|
||||||
Get.find<SearchPanelController>(tag: 'video');
|
Get.find<SearchPanelController>(
|
||||||
|
tag: 'video${searchPanelCtr.keyword!}');
|
||||||
ctr.duration.value = i['value'];
|
ctr.duration.value = i['value'];
|
||||||
SmartDialog.showLoading(msg: 'loooad');
|
SmartDialog.showLoading(msg: 'loooad');
|
||||||
await ctr.onRefresh();
|
await ctr.onRefresh();
|
||||||
|
|||||||
@ -86,7 +86,8 @@ class _SearchResultPageState extends State<SearchResultPage>
|
|||||||
onTap: (index) {
|
onTap: (index) {
|
||||||
if (index == _searchResultController!.tabIndex) {
|
if (index == _searchResultController!.tabIndex) {
|
||||||
Get.find<SearchPanelController>(
|
Get.find<SearchPanelController>(
|
||||||
tag: SearchType.values[index].type)
|
tag: SearchType.values[index].type +
|
||||||
|
_searchResultController!.keyword!)
|
||||||
.animateToTop();
|
.animateToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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'),
|
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,
|
||||||
|
|||||||
@ -9,7 +9,8 @@ import './controller.dart';
|
|||||||
|
|
||||||
class RelatedVideoPanel extends StatelessWidget {
|
class RelatedVideoPanel extends StatelessWidget {
|
||||||
final ReleatedController _releatedController =
|
final ReleatedController _releatedController =
|
||||||
Get.put(ReleatedController(), tag: Get.arguments['heroTag']);
|
Get.put(ReleatedController(), tag: Get.arguments?['heroTag']);
|
||||||
|
RelatedVideoPanel({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@ -849,6 +849,13 @@ InlineSpan buildContent(
|
|||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (BuildContext context, BoxConstraints box) {
|
builder: (BuildContext context, BoxConstraints box) {
|
||||||
|
double maxHeight = box.maxWidth * 0.6; // 设置最大高度
|
||||||
|
// double width = (box.maxWidth / 2).truncateToDouble();
|
||||||
|
double height = ((box.maxWidth /
|
||||||
|
2 *
|
||||||
|
pictureItem['img_height'] /
|
||||||
|
pictureItem['img_width']))
|
||||||
|
.truncateToDouble();
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
@ -859,15 +866,28 @@ InlineSpan buildContent(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(top: 4),
|
padding: const EdgeInsets.only(top: 4),
|
||||||
child: NetworkImgLayer(
|
constraints: BoxConstraints(maxHeight: maxHeight),
|
||||||
src: pictureItem['img_src'],
|
width: box.maxWidth / 2,
|
||||||
width: box.maxWidth / 2,
|
height: height,
|
||||||
height: box.maxWidth *
|
child: Stack(
|
||||||
0.5 *
|
children: [
|
||||||
pictureItem['img_height'] /
|
Positioned.fill(
|
||||||
pictureItem['img_width'],
|
child: NetworkImgLayer(
|
||||||
|
src: pictureItem['img_src'],
|
||||||
|
width: box.maxWidth / 2,
|
||||||
|
height: height,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height > maxHeight
|
||||||
|
? const PBadge(
|
||||||
|
text: '长图',
|
||||||
|
right: 8,
|
||||||
|
bottom: 8,
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,12 +2,10 @@ import 'dart:async';
|
|||||||
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';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:pilipala/http/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
import 'package:pilipala/models/common/reply_type.dart';
|
import 'package:pilipala/models/common/reply_type.dart';
|
||||||
import 'package:pilipala/models/video/reply/item.dart';
|
import 'package:pilipala/models/video/reply/item.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
|
||||||
|
|
||||||
class VideoReplyNewDialog extends StatefulWidget {
|
class VideoReplyNewDialog extends StatefulWidget {
|
||||||
final int? oid;
|
final int? oid;
|
||||||
@ -34,25 +32,16 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
final TextEditingController _replyContentController = TextEditingController();
|
final TextEditingController _replyContentController = TextEditingController();
|
||||||
final FocusNode replyContentFocusNode = FocusNode();
|
final FocusNode replyContentFocusNode = FocusNode();
|
||||||
final GlobalKey _formKey = GlobalKey<FormState>();
|
final GlobalKey _formKey = GlobalKey<FormState>();
|
||||||
double _keyboardHeight = 0.0; // 键盘高度
|
|
||||||
final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间
|
|
||||||
bool ableClean = false;
|
|
||||||
Timer? timer;
|
|
||||||
Box localCache = GStrorage.localCache;
|
|
||||||
late double sheetHeight;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// 监听输入框聚焦
|
// 监听输入框聚焦
|
||||||
// replyContentFocusNode.addListener(_onFocus);
|
// replyContentFocusNode.addListener(_onFocus);
|
||||||
_replyContentController.addListener(_printLatestValue);
|
|
||||||
// 界面观察者 必须
|
// 界面观察者 必须
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
// 自动聚焦
|
// 自动聚焦
|
||||||
_autoFocus();
|
_autoFocus();
|
||||||
|
|
||||||
sheetHeight = localCache.get('sheetHeight');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_autoFocus() async {
|
_autoFocus() async {
|
||||||
@ -62,12 +51,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_printLatestValue() {
|
|
||||||
setState(() {
|
|
||||||
ableClean = _replyContentController.text != '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future submitReplyAdd() async {
|
Future submitReplyAdd() async {
|
||||||
feedBack();
|
feedBack();
|
||||||
String message = _replyContentController.text;
|
String message = _replyContentController.text;
|
||||||
@ -90,24 +73,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeMetrics() {
|
|
||||||
super.didChangeMetrics();
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
// 键盘高度
|
|
||||||
final viewInsets = EdgeInsets.fromViewPadding(
|
|
||||||
View.of(context).viewInsets, View.of(context).devicePixelRatio);
|
|
||||||
_debouncer.run(() {
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_keyboardHeight =
|
|
||||||
_keyboardHeight == 0.0 ? viewInsets.bottom : _keyboardHeight;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
@ -117,8 +82,10 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
double keyboardHeight = EdgeInsets.fromViewPadding(
|
||||||
|
View.of(context).viewInsets, View.of(context).devicePixelRatio)
|
||||||
|
.bottom;
|
||||||
return Container(
|
return Container(
|
||||||
height: 500,
|
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
@ -130,26 +97,32 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxHeight: 200,
|
||||||
|
minHeight: 120,
|
||||||
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 6, right: 15, left: 15, bottom: 10),
|
top: 12, right: 15, left: 15, bottom: 10),
|
||||||
child: Form(
|
child: SingleChildScrollView(
|
||||||
key: _formKey,
|
child: Form(
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
key: _formKey,
|
||||||
child: TextField(
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
controller: _replyContentController,
|
child: TextField(
|
||||||
minLines: 1,
|
controller: _replyContentController,
|
||||||
maxLines: null,
|
minLines: 1,
|
||||||
autofocus: false,
|
maxLines: null,
|
||||||
focusNode: replyContentFocusNode,
|
autofocus: false,
|
||||||
decoration: const InputDecoration(
|
focusNode: replyContentFocusNode,
|
||||||
hintText: "输入回复内容",
|
decoration: const InputDecoration(
|
||||||
border: InputBorder.none,
|
hintText: "输入回复内容",
|
||||||
hintStyle: TextStyle(
|
border: InputBorder.none,
|
||||||
fontSize: 14,
|
hintStyle: TextStyle(
|
||||||
)),
|
fontSize: 14,
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
)),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -168,22 +141,23 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
width: 36,
|
width: 36,
|
||||||
height: 36,
|
height: 36,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
FocusScope.of(context)
|
FocusScope.of(context)
|
||||||
.requestFocus(replyContentFocusNode);
|
.requestFocus(replyContentFocusNode);
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.keyboard,
|
icon: Icon(Icons.keyboard,
|
||||||
size: 22,
|
size: 22,
|
||||||
color: Theme.of(context).colorScheme.onBackground),
|
color: Theme.of(context).colorScheme.onBackground),
|
||||||
highlightColor:
|
highlightColor:
|
||||||
Theme.of(context).colorScheme.onInverseSurface,
|
Theme.of(context).colorScheme.onInverseSurface,
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
MaterialStateProperty.resolveWith((states) {
|
MaterialStateProperty.resolveWith((states) {
|
||||||
return Theme.of(context).highlightColor;
|
return Theme.of(context).highlightColor;
|
||||||
}),
|
}),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
TextButton(
|
TextButton(
|
||||||
@ -196,7 +170,7 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: _keyboardHeight,
|
height: keyboardHeight,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -204,22 +178,3 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef DebounceCallback = void Function();
|
|
||||||
|
|
||||||
class Debouncer {
|
|
||||||
DebounceCallback? callback;
|
|
||||||
final int? milliseconds;
|
|
||||||
Timer? _timer;
|
|
||||||
|
|
||||||
Debouncer({this.milliseconds});
|
|
||||||
|
|
||||||
run(DebounceCallback callback) {
|
|
||||||
if (_timer != null) {
|
|
||||||
_timer!.cancel();
|
|
||||||
}
|
|
||||||
_timer = Timer(Duration(milliseconds: milliseconds!), () {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -122,6 +122,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
plPlayerController!.triggerFullScreen(status: false);
|
plPlayerController!.triggerFullScreen(status: false);
|
||||||
}
|
}
|
||||||
shutdownTimerService.handleWaitingFinished();
|
shutdownTimerService.handleWaitingFinished();
|
||||||
|
|
||||||
/// 顺序播放 列表循环
|
/// 顺序播放 列表循环
|
||||||
if (plPlayerController!.playRepeat != PlayRepeat.pause &&
|
if (plPlayerController!.playRepeat != PlayRepeat.pause &&
|
||||||
plPlayerController!.playRepeat != PlayRepeat.singleCycle) {
|
plPlayerController!.playRepeat != PlayRepeat.singleCycle) {
|
||||||
@ -234,7 +235,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
videoIntroController.isPaused = false;
|
videoIntroController.isPaused = false;
|
||||||
if (_extendNestCtr.position.pixels == 0 && autoplay) {
|
if (_extendNestCtr.position.pixels == 0 && autoplay) {
|
||||||
await Future.delayed(const Duration(milliseconds: 300));
|
await Future.delayed(const Duration(milliseconds: 300));
|
||||||
plPlayerController!.seekTo(videoDetailController.defaultST);
|
plPlayerController?.seekTo(videoDetailController.defaultST);
|
||||||
plPlayerController?.play();
|
plPlayerController?.play();
|
||||||
}
|
}
|
||||||
plPlayerController?.addStatusLister(playerListener);
|
plPlayerController?.addStatusLister(playerListener);
|
||||||
@ -308,7 +309,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
body: ExtendedNestedScrollView(
|
body: ExtendedNestedScrollView(
|
||||||
controller: _extendNestCtr,
|
controller: _extendNestCtr,
|
||||||
headerSliverBuilder:
|
headerSliverBuilder:
|
||||||
(BuildContext _context, bool innerBoxIsScrolled) {
|
(BuildContext context, bool innerBoxIsScrolled) {
|
||||||
return <Widget>[
|
return <Widget>[
|
||||||
Obx(
|
Obx(
|
||||||
() => SliverAppBar(
|
() => SliverAppBar(
|
||||||
@ -418,7 +419,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Obx(
|
Obx(
|
||||||
() => Visibility(
|
() => Visibility(
|
||||||
visible: videoDetailController
|
visible: videoDetailController
|
||||||
|
|||||||
@ -621,7 +621,7 @@ class PlPlayerController {
|
|||||||
if (duration.value.inSeconds != 0) {
|
if (duration.value.inSeconds != 0) {
|
||||||
if (type != 'slider') {
|
if (type != 'slider') {
|
||||||
/// 拖动进度条调节时,不等待第一帧,防止抖动
|
/// 拖动进度条调节时,不等待第一帧,防止抖动
|
||||||
await _videoPlayerController!.stream.buffer.first;
|
await _videoPlayerController?.stream.buffer.first;
|
||||||
}
|
}
|
||||||
await _videoPlayerController?.seek(position);
|
await _videoPlayerController?.seek(position);
|
||||||
// if (playerStatus.stopped) {
|
// if (playerStatus.stopped) {
|
||||||
@ -786,7 +786,7 @@ class PlPlayerController {
|
|||||||
volume.value = volumeNew;
|
volume.value = volumeNew;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FlutterVolumeController.showSystemUI = false;
|
FlutterVolumeController.updateShowSystemUI(false);
|
||||||
await FlutterVolumeController.setVolume(volumeNew);
|
await FlutterVolumeController.setVolume(volumeNew);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(err);
|
print(err);
|
||||||
@ -1086,12 +1086,13 @@ class PlPlayerController {
|
|||||||
localCache.put(LocalCacheKey.danmakuOpacity, opacityVal);
|
localCache.put(LocalCacheKey.danmakuOpacity, opacityVal);
|
||||||
localCache.put(LocalCacheKey.danmakuFontScale, fontSizeVal);
|
localCache.put(LocalCacheKey.danmakuFontScale, fontSizeVal);
|
||||||
localCache.put(LocalCacheKey.danmakuDuration, danmakuDurationVal);
|
localCache.put(LocalCacheKey.danmakuDuration, danmakuDurationVal);
|
||||||
|
if (_videoPlayerController != null) {
|
||||||
var pp = _videoPlayerController!.platform as NativePlayer;
|
var pp = _videoPlayerController!.platform as NativePlayer;
|
||||||
await pp.setProperty('audio-files', '');
|
await pp.setProperty('audio-files', '');
|
||||||
removeListeners();
|
removeListeners();
|
||||||
await _videoPlayerController?.dispose();
|
await _videoPlayerController?.dispose();
|
||||||
_videoPlayerController = null;
|
_videoPlayerController = null;
|
||||||
|
}
|
||||||
_instance = null;
|
_instance = null;
|
||||||
// 关闭所有视频页面恢复亮度
|
// 关闭所有视频页面恢复亮度
|
||||||
resetBrightness();
|
resetBrightness();
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
|
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -130,7 +129,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
setting.get(SettingBoxKey.enableBackgroundPlay, defaultValue: false);
|
setting.get(SettingBoxKey.enableBackgroundPlay, defaultValue: false);
|
||||||
Future.microtask(() async {
|
Future.microtask(() async {
|
||||||
try {
|
try {
|
||||||
FlutterVolumeController.showSystemUI = true;
|
FlutterVolumeController.updateShowSystemUI(true);
|
||||||
_ctr.volumeValue.value = (await FlutterVolumeController.getVolume())!;
|
_ctr.volumeValue.value = (await FlutterVolumeController.getVolume())!;
|
||||||
FlutterVolumeController.addListener((double value) {
|
FlutterVolumeController.addListener((double value) {
|
||||||
if (mounted && !_ctr.volumeInterceptEventStream.value) {
|
if (mounted && !_ctr.volumeInterceptEventStream.value) {
|
||||||
@ -154,7 +153,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
Future<void> setVolume(double value) async {
|
Future<void> setVolume(double value) async {
|
||||||
try {
|
try {
|
||||||
FlutterVolumeController.showSystemUI = false;
|
FlutterVolumeController.updateShowSystemUI(false);
|
||||||
await FlutterVolumeController.setVolume(value);
|
await FlutterVolumeController.setVolume(value);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
_ctr.volumeValue.value = value;
|
_ctr.volumeValue.value = value;
|
||||||
@ -703,7 +702,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@ -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/recommend_setting.dart';
|
import '../pages/setting/recommend_setting.dart';
|
||||||
import '../pages/setting/play_setting.dart';
|
import '../pages/setting/play_setting.dart';
|
||||||
@ -114,6 +115,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()),
|
||||||
// 屏幕帧率
|
// 屏幕帧率
|
||||||
|
|||||||
7
lib/utils/extension.dart
Normal file
7
lib/utils/extension.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
extension ImageExtension on num {
|
||||||
|
int cacheSize(BuildContext context) {
|
||||||
|
return (this * MediaQuery.of(context).devicePixelRatio).round();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
// ignore_for_file: constant_identifier_names
|
// ignore_for_file: constant_identifier_names
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -72,4 +73,19 @@ class IdUtils {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eid生成
|
||||||
|
static String? genAuroraEid(int uid) {
|
||||||
|
if (uid == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String uidString = uid.toString();
|
||||||
|
List<int> resultBytes = List.generate(
|
||||||
|
uidString.length,
|
||||||
|
(i) => uidString.codeUnitAt(i) ^ "ad1va46a7lza".codeUnitAt(i % 12),
|
||||||
|
);
|
||||||
|
String auroraEid = base64Url.encode(resultBytes);
|
||||||
|
auroraEid = auroraEid.replaceAll(RegExp(r'=*$', multiLine: true), '');
|
||||||
|
return auroraEid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,13 +3,11 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:pilipala/models/home/rcmd/result.dart';
|
|
||||||
import 'package:pilipala/models/model_owner.dart';
|
import 'package:pilipala/models/model_owner.dart';
|
||||||
import 'package:pilipala/models/search/hot.dart';
|
import 'package:pilipala/models/search/hot.dart';
|
||||||
import 'package:pilipala/models/user/info.dart';
|
import 'package:pilipala/models/user/info.dart';
|
||||||
|
|
||||||
class GStrorage {
|
class GStrorage {
|
||||||
static late final Box<dynamic> recVideo;
|
|
||||||
static late final Box<dynamic> userInfo;
|
static late final Box<dynamic> userInfo;
|
||||||
static late final Box<dynamic> historyword;
|
static late final Box<dynamic> historyword;
|
||||||
static late final Box<dynamic> localCache;
|
static late final Box<dynamic> localCache;
|
||||||
@ -21,13 +19,6 @@ class GStrorage {
|
|||||||
final String path = dir.path;
|
final String path = dir.path;
|
||||||
await Hive.initFlutter('$path/hive');
|
await Hive.initFlutter('$path/hive');
|
||||||
regAdapter();
|
regAdapter();
|
||||||
// 首页推荐视频
|
|
||||||
recVideo = await Hive.openBox(
|
|
||||||
'recVideo',
|
|
||||||
compactionStrategy: (int entries, int deletedEntries) {
|
|
||||||
return deletedEntries > 12;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
// 登录用户信息
|
// 登录用户信息
|
||||||
userInfo = await Hive.openBox(
|
userInfo = await Hive.openBox(
|
||||||
'userInfo',
|
'userInfo',
|
||||||
@ -54,10 +45,6 @@ class GStrorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void regAdapter() {
|
static void regAdapter() {
|
||||||
Hive.registerAdapter(RecVideoItemAppModelAdapter());
|
|
||||||
Hive.registerAdapter(RcmdReasonAdapter());
|
|
||||||
Hive.registerAdapter(RcmdStatAdapter());
|
|
||||||
Hive.registerAdapter(RcmdOwnerAdapter());
|
|
||||||
Hive.registerAdapter(OwnerAdapter());
|
Hive.registerAdapter(OwnerAdapter());
|
||||||
Hive.registerAdapter(UserInfoDataAdapter());
|
Hive.registerAdapter(UserInfoDataAdapter());
|
||||||
Hive.registerAdapter(LevelInfoAdapter());
|
Hive.registerAdapter(LevelInfoAdapter());
|
||||||
@ -73,8 +60,6 @@ class GStrorage {
|
|||||||
static Future<void> close() async {
|
static Future<void> close() async {
|
||||||
// user.compact();
|
// user.compact();
|
||||||
// user.close();
|
// user.close();
|
||||||
recVideo.compact();
|
|
||||||
recVideo.close();
|
|
||||||
userInfo.compact();
|
userInfo.compact();
|
||||||
userInfo.close();
|
userInfo.close();
|
||||||
historyword.compact();
|
historyword.compact();
|
||||||
@ -151,7 +136,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 {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.16+1016
|
version: 1.0.17+1017
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.19.6 <3.0.0"
|
sdk: ">=2.19.6 <3.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user