diff --git a/README.md b/README.md
index 6d2c1d56..46f6d986 100644
--- a/README.md
+++ b/README.md
@@ -3,16 +3,23 @@
+
PiliPala
+
+
+
+
+
+
使用Flutter开发的BiliBili第三方客户端
-
-

-

-

-
-

-
+
+

+

+

+
+

+
## 开发环境
diff --git a/change_log/1.0.12.1114.md b/change_log/1.0.12.1114.md
new file mode 100644
index 00000000..55553286
--- /dev/null
+++ b/change_log/1.0.12.1114.md
@@ -0,0 +1,11 @@
+## 1.0.12
+
+
+### 修复
++ iOS端视频播放时没有声音
++ 超过6分钟弹幕不显示
++ 视频详情页网络异常
+
+
+更多更新日志可在Github上查看
+问题反馈、功能建议请查看「关于」页面。
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 9d796293..c794b953 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,6 +1,12 @@
PODS:
- appscheme (1.0.4):
- Flutter
+ - audio_service (0.0.1):
+ - Flutter
+ - audio_session (0.0.1):
+ - Flutter
+ - auto_orientation (0.0.1):
+ - Flutter
- connectivity_plus (0.0.1):
- Flutter
- ReachabilitySwift
@@ -56,6 +62,9 @@ PODS:
DEPENDENCIES:
- appscheme (from `.symlinks/plugins/appscheme/ios`)
+ - audio_service (from `.symlinks/plugins/audio_service/ios`)
+ - audio_session (from `.symlinks/plugins/audio_session/ios`)
+ - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- Flutter (from `Flutter`)
@@ -88,6 +97,12 @@ SPEC REPOS:
EXTERNAL SOURCES:
appscheme:
:path: ".symlinks/plugins/appscheme/ios"
+ audio_service:
+ :path: ".symlinks/plugins/audio_service/ios"
+ audio_session:
+ :path: ".symlinks/plugins/audio_session/ios"
+ auto_orientation:
+ :path: ".symlinks/plugins/auto_orientation/ios"
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
device_info_plus:
@@ -135,8 +150,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
appscheme: b1c3f8862331cb20430cf9e0e4af85dbc1572ad8
+ audio_service: f509d65da41b9521a61f1c404dd58651f265a567
+ audio_session: 4f3e461722055d21515cf3261b64c973c062f345
+ auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
- device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
+ device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
@@ -145,17 +163,17 @@ SPEC CHECKSUMS:
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
- package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
+ package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
- share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
+ share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
- url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
+ url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
@@ -163,4 +181,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b
-COCOAPODS: 1.12.1
+COCOAPODS: 1.14.3
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index eeb03bef..c0883366 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -157,7 +157,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1300;
+ LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index c87d15a3..a6b826db 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
[
+ if (contentWidget != null)
+ Expanded(
+ child: contentWidget!,
+ )
+ else
+ Spacer(),
+ if (bottomWidget != null) bottomWidget!,
+ ],
+ ),
+ ),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart
index 6d4fa61a..551f4063 100644
--- a/lib/common/widgets/video_card_h.dart
+++ b/lib/common/widgets/video_card_h.dart
@@ -17,6 +17,10 @@ class VideoCardH extends StatelessWidget {
final Function()? longPress;
final Function()? longPressEnd;
final String source;
+ final bool showOwner;
+ final bool showView;
+ final bool showDanmaku;
+ final bool showPubdate;
const VideoCardH({
Key? key,
@@ -24,6 +28,10 @@ class VideoCardH extends StatelessWidget {
this.longPress,
this.longPressEnd,
this.source = 'normal',
+ this.showOwner = true,
+ this.showView = true,
+ this.showDanmaku = true,
+ this.showPubdate = false,
}) : super(key: key);
@override
@@ -103,7 +111,14 @@ class VideoCardH extends StatelessWidget {
},
),
),
- VideoContent(videoItem: videoItem, source: source)
+ VideoContent(
+ videoItem: videoItem,
+ source: source,
+ showOwner: showOwner,
+ showView: showView,
+ showDanmaku: showDanmaku,
+ showPubdate: showPubdate,
+ )
],
),
);
@@ -119,8 +134,20 @@ class VideoContent extends StatelessWidget {
// ignore: prefer_typing_uninitialized_variables
final videoItem;
final String source;
- const VideoContent(
- {super.key, required this.videoItem, this.source = 'normal'});
+ final bool showOwner;
+ final bool showView;
+ final bool showDanmaku;
+ final bool showPubdate;
+
+ const VideoContent({
+ super.key,
+ required this.videoItem,
+ this.source = 'normal',
+ this.showOwner = true,
+ this.showView = true,
+ this.showDanmaku = true,
+ this.showPubdate = false,
+ });
@override
Widget build(BuildContext context) {
@@ -179,34 +206,40 @@ class VideoContent extends StatelessWidget {
// ),
// ),
// const SizedBox(height: 4),
- Row(
- children: [
- Text(
- videoItem.owner.name,
- style: TextStyle(
- fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
- color: Theme.of(context).colorScheme.outline,
+ if (showPubdate)
+ Text(
+ Utils.dateFormat(videoItem.pubdate!),
+ style: TextStyle(
+ fontSize: 11, color: Theme.of(context).colorScheme.outline),
+ ),
+ if (showOwner)
+ Row(
+ children: [
+ Text(
+ videoItem.owner.name,
+ style: TextStyle(
+ fontSize:
+ Theme.of(context).textTheme.labelMedium!.fontSize,
+ color: Theme.of(context).colorScheme.outline,
+ ),
),
- ),
- ],
- ),
+ ],
+ ),
Row(
children: [
- StatView(
- theme: 'gray',
- view: videoItem.stat.view,
- ),
- const SizedBox(width: 8),
- StatDanMu(
- theme: 'gray',
- danmu: videoItem.stat.danmaku,
- ),
- // Text(
- // Utils.dateFormat(videoItem.pubdate!),
- // style: TextStyle(
- // fontSize: 11,
- // color: Theme.of(context).colorScheme.outline),
- // )
+ if (showView) ...[
+ StatView(
+ theme: 'gray',
+ view: videoItem.stat.view,
+ ),
+ const SizedBox(width: 8),
+ ],
+ if (showDanmaku)
+ StatDanMu(
+ theme: 'gray',
+ danmu: videoItem.stat.danmaku,
+ ),
+
const Spacer(),
// SizedBox(
// width: 20,
diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart
index 39358fda..fa15a75c 100644
--- a/lib/common/widgets/video_card_v.dart
+++ b/lib/common/widgets/video_card_v.dart
@@ -333,8 +333,10 @@ class VideoStat extends StatelessWidget {
color: Theme.of(context).colorScheme.outline,
),
children: [
- TextSpan(text: '${videoItem.stat.view}观看'),
- TextSpan(text: ' • ${videoItem.stat.danmu}弹幕'),
+ if (videoItem.stat.view != '-')
+ TextSpan(text: '${videoItem.stat.view}观看'),
+ if (videoItem.stat.danmu != '-')
+ TextSpan(text: ' • ${videoItem.stat.danmu}弹幕'),
],
),
);
diff --git a/lib/http/api.dart b/lib/http/api.dart
index 59c6892e..9584f108 100644
--- a/lib/http/api.dart
+++ b/lib/http/api.dart
@@ -215,7 +215,7 @@ class Api {
// 粉丝
// vmid 用户id pn 页码 ps 每页个数,最大50 order: desc
// order_type 排序规则 最近访问传空,最常访问传 attention
- static const String fans = 'https://api.bilibili.com/x/relation/fans';
+ static const String fans = '/x/relation/fans';
// 直播
// ?page=1&page_size=30&platform=web
@@ -312,6 +312,10 @@ class Api {
static const String webDanmaku = '/x/v2/dm/web/seg.so';
+ //发送视频弹幕
+ //https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/action.md
+ static const String shootDanmaku = '/x/v2/dm/post';
+
// up主分组
static const String followUpTag = '/x/relation/tags';
@@ -405,4 +409,49 @@ class Api {
/// local_id
static const getWebKey =
'https://passport.bilibili.com/x/passport-login/web/key';
+
+ /// cookie转access_key
+ static const cookieToKey =
+ 'https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/confirm';
+
+ /// 申请二维码(TV端)
+ static const getTVCode =
+ 'https://passport.snm0516.aisee.tv/x/passport-tv-login/qrcode/auth_code';
+
+ ///扫码登录(TV端)
+ static const qrcodePoll =
+ 'https://passport.bilibili.com/x/passport-tv-login/qrcode/poll';
+
+ /// 置顶视频
+ static const getTopVideoApi = '/x/space/top/arc';
+
+ /// 主页 - 最近投币的视频
+ /// vmid
+ /// gaia_source = main_web
+ /// web_location
+ /// w_rid
+ /// wts
+ static const getRecentCoinVideoApi = '/x/space/coin/video';
+
+ /// 最近点赞的视频
+ static const getRecentLikeVideoApi = '/x/space/like/video';
+
+ /// 最近追番
+ static const getRecentBangumiApi = '/x/space/bangumi/follow/list';
+
+ /// 用户专栏
+ static const getMemberSeasonsApi = '/x/polymer/web-space/home/seasons_series';
+
+ /// 获赞数 播放数
+ /// mid
+ static const getMemberViewApi = '/x/space/upstat';
+
+ /// 查询某个专栏
+ /// mid
+ /// season_id
+ /// sort_reverse
+ /// page_num
+ /// page_size
+ static const getSeasonDetailApi =
+ '/x/polymer/web-space/seasons_archives_list';
}
diff --git a/lib/http/danmaku.dart b/lib/http/danmaku.dart
index 87f08d8b..e34320e7 100644
--- a/lib/http/danmaku.dart
+++ b/lib/http/danmaku.dart
@@ -24,4 +24,72 @@ class DanmakaHttp {
);
return DmSegMobileReply.fromBuffer(response.data);
}
+ static Future shootDanmaku({
+ int type = 1,//弹幕类选择(1:视频弹幕 2:漫画弹幕)
+ required int oid,// 视频cid
+ required String msg,//弹幕文本(长度小于 100 字符)
+ int mode = 1,// 弹幕类型(1:滚动弹幕 4:底端弹幕 5:顶端弹幕 6:逆向弹幕(不能使用) 7:高级弹幕 8:代码弹幕(不能使用) 9:BAS弹幕(pool必须为2))
+ // String? aid,// 稿件avid
+ // String? bvid,// bvid与aid必须有一个
+ required String bvid,
+ int? progress,// 弹幕出现在视频内的时间(单位为毫秒,默认为0)
+ int? color,// 弹幕颜色(默认白色,16777215)
+ int? fontsize,// 弹幕字号(默认25)
+ int? pool,// 弹幕池选择(0:普通池 1:字幕池 2:特殊池(代码/BAS弹幕)默认普通池,0)
+ //int? rnd,// 当前时间戳*1000000(若无此项,则发送弹幕冷却时间限制为90s;若有此项,则发送弹幕冷却时间限制为5s)
+ int? colorful,//60001:专属渐变彩色(需要会员)
+ int? checkbox_type,//是否带 UP 身份标识(0:普通;4:带有标识)
+ // String? csrf,//CSRF Token(位于 Cookie) Cookie 方式必要
+ // String? access_key,// APP 登录 Token APP 方式必要
+ }) async {
+ // 构建参数对象
+ // assert(aid != null || bvid != null);
+ // assert(csrf != null || access_key != null);
+ assert(msg.length < 100);
+ // 构建参数对象
+ var params = {
+ 'type': type,
+ 'oid': oid,
+ 'msg': msg,
+ 'mode': mode,
+ //'aid': aid,
+ 'bvid': bvid,
+ 'progress': progress,
+ 'color': color,
+ 'fontsize': fontsize,
+ 'pool': pool,
+ 'rnd': DateTime.now().microsecondsSinceEpoch,
+ 'colorful': colorful,
+ 'checkbox_type': checkbox_type,
+ 'csrf': await Request.getCsrf(),
+ // 'access_key': access_key,
+ }..removeWhere((key, value) => value == null);
+
+ var response = await Request().post(
+ Api.shootDanmaku,
+ data: params,
+ options: Options(
+ contentType: Headers.formUrlEncodedContentType,
+ ),
+ );
+ if (response.statusCode != 200) {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': '弹幕发送失败,状态码:${response.statusCode}',
+ };
+ }
+ if (response.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': response.data['data'],
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': "${response.data['code']}: ${response.data['message']}",
+ };
+ }
+ }
}
diff --git a/lib/http/init.dart b/lib/http/init.dart
index 6a60dca0..1e55be38 100644
--- a/lib/http/init.dart
+++ b/lib/http/init.dart
@@ -115,30 +115,24 @@ class Request {
idleTimeout: const Duration(milliseconds: 10000),
onClientCreate: (_, config) => config.onBadCertificate = (_) => true,
),
- )
+ );
- /// 设置代理
- ..httpClientAdapter = IOHttpClientAdapter(
+ /// 设置代理
+ if (enableSystemProxy) {
+ dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
final client = HttpClient();
// Config the client.
client.findProxy = (uri) {
- if (enableSystemProxy) {
- print('🌹:$systemProxyHost');
- print('🌹:$systemProxyPort');
-
- // return 'PROXY host:port';
- return 'PROXY $systemProxyHost:$systemProxyPort';
- } else {
- // 不设置代理
- return 'DIRECT';
- }
+ // return 'PROXY host:port';
+ return 'PROXY $systemProxyHost:$systemProxyPort';
};
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return client;
},
);
+ }
//添加拦截器
dio.interceptors.add(ApiInterceptor());
diff --git a/lib/http/member.dart b/lib/http/member.dart
index a48dbffd..20826451 100644
--- a/lib/http/member.dart
+++ b/lib/http/member.dart
@@ -1,9 +1,16 @@
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:hive/hive.dart';
+import 'package:pilipala/common/constants.dart';
import 'package:pilipala/http/index.dart';
import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/models/follow/result.dart';
import 'package:pilipala/models/member/archive.dart';
+import 'package:pilipala/models/member/coin.dart';
import 'package:pilipala/models/member/info.dart';
+import 'package:pilipala/models/member/seasons.dart';
import 'package:pilipala/models/member/tags.dart';
+import 'package:pilipala/utils/storage.dart';
+import 'package:pilipala/utils/utils.dart';
import 'package:pilipala/utils/wbi_sign.dart';
class MemberHttp {
@@ -215,4 +222,243 @@ class MemberHttp {
};
}
}
+
+ // 获取up置顶
+ static Future getTopVideo(String? vmid) async {
+ var res = await Request().get(Api.getTopVideoApi);
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': res.data['data']
+ .map((e) => MemberTagItemModel.fromJson(e))
+ .toList()
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 获取uo专栏
+ static Future getMemberSeasons(int? mid, int? pn, int? ps) async {
+ var res = await Request().get(Api.getMemberSeasonsApi, data: {
+ 'mid': mid,
+ 'page_num': pn,
+ 'page_size': ps,
+ });
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 最近投币
+ static Future getRecentCoinVideo({required int mid}) async {
+ Map params = await WbiSign().makSign({
+ 'mid': mid,
+ 'gaia_source': 'main_web',
+ 'web_location': 333.999,
+ });
+ var res = await Request().get(
+ Api.getRecentCoinVideoApi,
+ data: {
+ 'vmid': mid,
+ 'gaia_source': 'main_web',
+ 'web_location': 333.999,
+ 'w_rid': params['w_rid'],
+ 'wts': params['wts'],
+ },
+ );
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': res.data['data']
+ .map((e) => MemberCoinsDataModel.fromJson(e))
+ .toList(),
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 最近点赞
+ static Future getRecentLikeVideo({required int mid}) async {
+ Map params = await WbiSign().makSign({
+ 'mid': mid,
+ 'gaia_source': 'main_web',
+ 'web_location': 333.999,
+ });
+ var res = await Request().get(
+ Api.getRecentLikeVideoApi,
+ data: {
+ 'vmid': mid,
+ 'gaia_source': 'main_web',
+ 'web_location': 333.999,
+ 'w_rid': params['w_rid'],
+ 'wts': params['wts'],
+ },
+ );
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 查看某个专栏
+ static Future getSeasonDetail({
+ required int mid,
+ required int seasonId,
+ bool sortReverse = false,
+ required int pn,
+ required int ps,
+ }) async {
+ var res = await Request().get(
+ Api.getSeasonDetailApi,
+ data: {
+ 'mid': mid,
+ 'season_id': seasonId,
+ 'sort_reverse': sortReverse,
+ 'page_num': pn,
+ 'page_size': ps,
+ },
+ );
+ if (res.data['code'] == 0) {
+ try {
+ return {
+ 'status': true,
+ 'data': MemberSeasonsList.fromJson(res.data['data'])
+ };
+ } catch (err) {
+ print(err);
+ }
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 获取TV authCode
+ static Future getTVCode() async {
+ SmartDialog.showLoading();
+ var params = {
+ 'appkey': Constants.appKey,
+ 'local_id': '0',
+ 'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
+ };
+ String sign = Utils.appSign(
+ params,
+ Constants.appKey,
+ Constants.appSec,
+ );
+ var res = await Request()
+ .post(Api.getTVCode, queryParameters: {...params, 'sign': sign});
+ if (res.data['code'] == 0) {
+ return {
+ 'status': true,
+ 'data': res.data['data']['auth_code'],
+ 'msg': '操作成功'
+ };
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 获取access_key
+ static Future cookieToKey() async {
+ var authCodeRes = await getTVCode();
+ if (authCodeRes['status']) {
+ var res = await Request().post(Api.cookieToKey, queryParameters: {
+ 'auth_code': authCodeRes['data'],
+ 'build': 708200,
+ 'csrf': await Request.getCsrf(),
+ });
+ await Future.delayed(const Duration(milliseconds: 300));
+ await qrcodePoll(authCodeRes['data']);
+ if (res.data['code'] == 0) {
+ return {'status': true, 'data': [], 'msg': '操作成功'};
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+ }
+
+ static Future qrcodePoll(authCode) async {
+ var params = {
+ 'appkey': Constants.appKey,
+ 'auth_code': authCode.toString(),
+ 'local_id': '0',
+ 'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
+ };
+ String sign = Utils.appSign(
+ params,
+ Constants.appKey,
+ Constants.appSec,
+ );
+ var res = await Request()
+ .post(Api.qrcodePoll, queryParameters: {...params, 'sign': sign});
+ SmartDialog.dismiss();
+ if (res.data['code'] == 0) {
+ String accessKey = res.data['data']['access_token'];
+ Box localCache = GStrorage.localCache;
+ Box userInfoCache = GStrorage.userInfo;
+ var userInfo = userInfoCache.get('userInfoCache');
+ localCache.put(
+ LocalCacheKey.accessKey, {'mid': userInfo.mid, 'value': accessKey});
+ return {'status': true, 'data': [], 'msg': '操作成功'};
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
+
+ // 获取up播放数、点赞数
+ static Future memberView({required int mid}) async {
+ var res = await Request().get(Api.getMemberViewApi, data: {'mid': mid});
+ if (res.data['code'] == 0) {
+ return {'status': true, 'data': res.data['data']};
+ } else {
+ return {
+ 'status': false,
+ 'data': [],
+ 'msg': res.data['message'],
+ };
+ }
+ }
}
diff --git a/lib/http/user.dart b/lib/http/user.dart
index 1ab465e0..f439b815 100644
--- a/lib/http/user.dart
+++ b/lib/http/user.dart
@@ -199,7 +199,7 @@ class UserHttp {
}
}
- // 获取用户凭证
+ // 获取用户凭证 失效
static Future thirdLogin() async {
var res = await Request().get(
'https://passport.bilibili.com/login/app/third',
diff --git a/lib/models/home/rcmd/result.dart b/lib/models/home/rcmd/result.dart
index 94ed0727..a2a8006d 100644
--- a/lib/models/home/rcmd/result.dart
+++ b/lib/models/home/rcmd/result.dart
@@ -118,7 +118,7 @@ class RcmdStat {
RcmdStat.fromJson(Map json) {
view = json["cover_left_text_1"];
- danmu = json['cover_left_text_2'];
+ danmu = json['cover_left_text_2'] ?? '-';
}
}
diff --git a/lib/models/member/coin.dart b/lib/models/member/coin.dart
new file mode 100644
index 00000000..701131f1
--- /dev/null
+++ b/lib/models/member/coin.dart
@@ -0,0 +1,89 @@
+class MemberCoinsDataModel {
+ MemberCoinsDataModel({
+ this.aid,
+ this.bvid,
+ this.cid,
+ this.coins,
+ this.copyright,
+ this.ctime,
+ this.desc,
+ this.duration,
+ this.owner,
+ this.pic,
+ this.pubLocation,
+ this.pubdate,
+ this.resourceType,
+ this.state,
+ this.subtitle,
+ this.time,
+ this.title,
+ this.tname,
+ this.videos,
+ this.view,
+ this.danmaku,
+ });
+
+ int? aid;
+ String? bvid;
+ int? cid;
+ int? coins;
+ int? copyright;
+ int? ctime;
+ String? desc;
+ int? duration;
+ Owner? owner;
+ String? pic;
+ String? pubLocation;
+ int? pubdate;
+ String? resourceType;
+ int? state;
+ String? subtitle;
+ int? time;
+ String? title;
+ String? tname;
+ int? videos;
+ int? view;
+ int? danmaku;
+
+ MemberCoinsDataModel.fromJson(Map json) {
+ aid = json['aid'];
+ bvid = json['bvid'];
+ cid = json['cid'];
+ coins = json['coins'];
+ copyright = json['copyright'];
+ ctime = json['ctime'];
+ desc = json['desc'];
+ duration = json['duration'];
+ owner = Owner.fromJson(json['owner']);
+ pic = json['pic'];
+ pubLocation = json['pub_location'];
+ pubdate = json['pubdate'];
+ resourceType = json['resource_type'];
+ state = json['state'];
+ subtitle = json['subtitle'];
+ time = json['time'];
+ title = json['title'];
+ tname = json['tname'];
+ videos = json['videos'];
+ view = json['stat']['view'];
+ danmaku = json['stat']['danmaku'];
+ }
+}
+
+class Owner {
+ Owner({
+ this.mid,
+ this.name,
+ this.face,
+ });
+
+ int? mid;
+ String? name;
+ String? face;
+
+ Owner.fromJson(Map json) {
+ mid = json['mid'];
+ name = json['name'];
+ face = json['face'];
+ }
+}
diff --git a/lib/models/member/seasons.dart b/lib/models/member/seasons.dart
new file mode 100644
index 00000000..70230367
--- /dev/null
+++ b/lib/models/member/seasons.dart
@@ -0,0 +1,108 @@
+class MemberSeasonsDataModel {
+ MemberSeasonsDataModel({
+ this.page,
+ this.seasonsList,
+ });
+
+ Map? page;
+ List? seasonsList;
+
+ MemberSeasonsDataModel.fromJson(Map json) {
+ page = json['page'];
+ seasonsList = json['seasons_list'] != null
+ ? json['seasons_list']
+ .map((e) => MemberSeasonsList.fromJson(e))
+ .toList()
+ : [];
+ }
+}
+
+class MemberSeasonsList {
+ MemberSeasonsList({
+ this.archives,
+ this.meta,
+ this.recentAids,
+ this.page,
+ });
+
+ List? archives;
+ MamberMeta? meta;
+ List? recentAids;
+ Map? page;
+
+ MemberSeasonsList.fromJson(Map json) {
+ archives = json['archives'] != null
+ ? json['archives']
+ .map((e) => MemberArchiveItem.fromJson(e))
+ .toList()
+ : [];
+ meta = MamberMeta.fromJson(json['meta']);
+ page = json['page'];
+ }
+}
+
+class MemberArchiveItem {
+ MemberArchiveItem({
+ this.aid,
+ this.bvid,
+ this.ctime,
+ this.duration,
+ this.pic,
+ this.cover,
+ this.pubdate,
+ this.view,
+ this.title,
+ });
+
+ int? aid;
+ String? bvid;
+ int? ctime;
+ int? duration;
+ String? pic;
+ String? cover;
+ int? pubdate;
+ int? view;
+ String? title;
+
+ MemberArchiveItem.fromJson(Map json) {
+ aid = json['aid'];
+ bvid = json['bvid'];
+ ctime = json['ctime'];
+ duration = json['duration'];
+ pic = json['pic'];
+ cover = json['pic'];
+ pubdate = json['pubdate'];
+ view = json['stat']['view'];
+ title = json['title'];
+ }
+}
+
+class MamberMeta {
+ MamberMeta({
+ this.cover,
+ this.description,
+ this.mid,
+ this.name,
+ this.ptime,
+ this.seasonId,
+ this.total,
+ });
+
+ String? cover;
+ String? description;
+ int? mid;
+ String? name;
+ int? ptime;
+ int? seasonId;
+ int? total;
+
+ MamberMeta.fromJson(Map json) {
+ cover = json['cover'];
+ description = json['description'];
+ mid = json['mid'];
+ name = json['name'];
+ ptime = json['ptime'];
+ seasonId = json['season_id'];
+ total = json['total'];
+ }
+}
diff --git a/lib/models/video/play/url.dart b/lib/models/video/play/url.dart
index 71894406..4c43cb00 100644
--- a/lib/models/video/play/url.dart
+++ b/lib/models/video/play/url.dart
@@ -1,5 +1,3 @@
-import 'dart:developer';
-
import 'package:pilipala/models/video/play/quality.dart';
class PlayUrlModel {
diff --git a/lib/pages/about/index.dart b/lib/pages/about/index.dart
index 31808e1c..17eabee5 100644
--- a/lib/pages/about/index.dart
+++ b/lib/pages/about/index.dart
@@ -1,6 +1,3 @@
-import 'dart:io';
-
-import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -34,11 +31,6 @@ class _AboutPageState extends State {
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
- Divider(
- thickness: 8,
- height: 10,
- color: Theme.of(context).colorScheme.onInverseSurface,
- ),
Image.asset(
'assets/images/logo/logo_android_2.png',
width: 150,
@@ -83,9 +75,9 @@ class _AboutPageState extends State {
// ),
// ),
Divider(
- thickness: 8,
+ thickness: 1,
height: 30,
- color: Theme.of(context).colorScheme.onInverseSurface,
+ color: Theme.of(context).colorScheme.outlineVariant,
),
ListTile(
onTap: () => _aboutController.githubUrl(),
@@ -134,11 +126,6 @@ class _AboutPageState extends State {
title: const Text('赞助'),
trailing: Icon(Icons.arrow_forward_ios, size: 16, color: outline),
),
- Divider(
- thickness: 8,
- height: 30,
- color: Theme.of(context).colorScheme.onInverseSurface,
- ),
],
),
),
diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart
index af47d7da..62842075 100644
--- a/lib/pages/bangumi/introduction/view.dart
+++ b/lib/pages/bangumi/introduction/view.dart
@@ -5,7 +5,6 @@ import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/badge.dart';
-import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/common/widgets/stat/danmu.dart';
import 'package:pilipala/common/widgets/stat/view.dart';
diff --git a/lib/pages/bangumi/view.dart b/lib/pages/bangumi/view.dart
index e48715eb..a2e8ae0f 100644
--- a/lib/pages/bangumi/view.dart
+++ b/lib/pages/bangumi/view.dart
@@ -6,6 +6,7 @@ import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/http_error.dart';
+import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/main/index.dart';
import 'package:pilipala/pages/rcmd/view.dart';
@@ -35,6 +36,8 @@ class _BangumiPageState extends State
scrollController = _bangumidController.scrollController;
StreamController mainStream =
Get.find().bottomBarStream;
+ StreamController searchBarStream =
+ Get.find().searchBarStream;
_futureBuilderFuture = _bangumidController.queryBangumiListFeed();
_futureBuilderFutureFollow = _bangumidController.queryBangumiFollow();
scrollController.addListener(
@@ -51,8 +54,10 @@ class _BangumiPageState extends State
scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
mainStream.add(true);
+ searchBarStream.add(true);
} else if (direction == ScrollDirection.reverse) {
mainStream.add(false);
+ searchBarStream.add(false);
}
},
);
diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart
index 317d47e9..4f5527ff 100644
--- a/lib/pages/danmaku/view.dart
+++ b/lib/pages/danmaku/view.dart
@@ -95,8 +95,12 @@ class _PlDanmakuState extends State {
// 根据position判断是否有已缓存弹幕。没有则请求对应段
int segIndex = (currentPosition / (6 * 60 * 1000)).ceil();
segIndex = segIndex < 1 ? 1 : segIndex;
- if (ctr.dmSegList[segIndex - 1].elems.isEmpty &&
- !ctr.hasrequestSeg.contains(segIndex - 1)) {
+ print('🌹🌹: ${segIndex}');
+ print('🌹🌹: ${ctr.dmSegList.length}');
+ print('🌹🌹: ${ctr.hasrequestSeg.contains(segIndex - 1)}');
+ if (segIndex - 1 >= ctr.dmSegList.length ||
+ (ctr.dmSegList[segIndex - 1].elems.isEmpty &&
+ !ctr.hasrequestSeg.contains(segIndex - 1))) {
ctr.hasrequestSeg.add(segIndex - 1);
ctr.currentSegIndex = segIndex;
EasyThrottle.throttle('follow', const Duration(seconds: 1), () {
diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart
index cad4bbd7..facb89c9 100644
--- a/lib/pages/dynamics/view.dart
+++ b/lib/pages/dynamics/view.dart
@@ -231,6 +231,15 @@ class _DynamicsPageState extends State
}
},
),
+ SliverToBoxAdapter(
+ child: Container(
+ height: 6,
+ color: Theme.of(context)
+ .colorScheme
+ .onInverseSurface
+ .withOpacity(0.5),
+ ),
+ ),
FutureBuilder(
future: _futureBuilderFuture,
builder: (context, snapshot) {
diff --git a/lib/pages/dynamics/widgets/rich_node_panel.dart b/lib/pages/dynamics/widgets/rich_node_panel.dart
index a66772a4..8b7dcd69 100644
--- a/lib/pages/dynamics/widgets/rich_node_panel.dart
+++ b/lib/pages/dynamics/widgets/rich_node_panel.dart
@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
-import 'package:pilipala/models/dynamics/result.dart';
-import 'package:pilipala/pages/preview/index.dart';
// 富文本
InlineSpan richNode(item, context) {
@@ -11,13 +9,11 @@ InlineSpan richNode(item, context) {
TextStyle authorStyle =
TextStyle(color: Theme.of(context).colorScheme.primary);
List spanChilds = [];
- String contentType = 'desc';
dynamic richTextNodes;
if (item.modules.moduleDynamic.desc != null) {
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
} else if (item.modules.moduleDynamic.major != null) {
- contentType = 'major';
// 动态页面 richTextNodes 层级可能与主页动态层级不同
richTextNodes =
item.modules.moduleDynamic.major.opus.summary.richTextNodes;
diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart
index 3db6c357..8a2c5dac 100644
--- a/lib/pages/dynamics/widgets/up_panel.dart
+++ b/lib/pages/dynamics/widgets/up_panel.dart
@@ -56,67 +56,73 @@ class _UpPanelState extends State {
floating: true,
pinned: false,
delegate: _SliverHeaderDelegate(
- height: 90,
- child: Container(
- height: 90,
- color: Theme.of(context).colorScheme.background,
- child: Row(
- children: [
- Expanded(
- child: ListView(
- scrollDirection: Axis.horizontal,
- controller: scrollController,
- children: [
- const SizedBox(width: 10),
- if (liveList.isNotEmpty) ...[
- for (int i = 0; i < liveList.length; i++) ...[
- upItemBuild(liveList[i], i)
- ],
- VerticalDivider(
- indent: 20,
- endIndent: 40,
- width: 26,
- color: Theme.of(context)
- .colorScheme
- .primary
- .withOpacity(0.5),
- ),
- ],
- for (int i = 0; i < upList.length; i++) ...[
- upItemBuild(upList[i], i)
- ],
- const SizedBox(width: 10),
- ],
- ),
- ),
- Material(
- child: InkWell(
- onTap: () => {
- feedBack(),
- Get.toNamed('/follow?mid=${userInfo.mid}')
- },
- child: Container(
- height: 100,
- padding: const EdgeInsets.only(left: 10, right: 10),
- color: Theme.of(context)
- .colorScheme
- .secondaryContainer
- .withOpacity(0.3),
- child: Center(
+ height: 124,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ color: Theme.of(context).colorScheme.background,
+ padding: const EdgeInsets.only(left: 16, right: 16),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ const Text('最新关注'),
+ GestureDetector(
+ onTap: () {
+ feedBack();
+ Get.toNamed('/follow?mid=${userInfo.mid}');
+ },
+ child: Container(
+ padding: const EdgeInsets.only(top: 5, bottom: 5),
child: Text(
- '全部',
+ '查看全部',
style: TextStyle(
- color: Theme.of(context)
- .colorScheme
- .onSecondaryContainer),
+ color: Theme.of(context).colorScheme.outline),
),
),
),
- ),
+ ],
),
- ],
- )),
- ),
+ ),
+ Container(
+ height: 90,
+ color: Theme.of(context).colorScheme.background,
+ child: Row(
+ children: [
+ Expanded(
+ child: ListView(
+ scrollDirection: Axis.horizontal,
+ controller: scrollController,
+ children: [
+ const SizedBox(width: 10),
+ if (liveList.isNotEmpty) ...[
+ for (int i = 0; i < liveList.length; i++) ...[
+ upItemBuild(liveList[i], i)
+ ],
+ VerticalDivider(
+ indent: 20,
+ endIndent: 40,
+ width: 26,
+ color: Theme.of(context)
+ .colorScheme
+ .primary
+ .withOpacity(0.5),
+ ),
+ ],
+ for (int i = 0; i < upList.length; i++) ...[
+ upItemBuild(upList[i], i)
+ ],
+ const SizedBox(width: 10),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ )),
);
}
diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart
index 3f9e4f3c..ac9cc01b 100644
--- a/lib/pages/follow/widgets/follow_item.dart
+++ b/lib/pages/follow/widgets/follow_item.dart
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
-import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/follow/result.dart';
diff --git a/lib/pages/follow/widgets/owner_follow_list.dart b/lib/pages/follow/widgets/owner_follow_list.dart
index 0dcd785d..ccc11c44 100644
--- a/lib/pages/follow/widgets/owner_follow_list.dart
+++ b/lib/pages/follow/widgets/owner_follow_list.dart
@@ -1,5 +1,3 @@
-import 'dart:math';
-
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart
index b80affc8..a83e118b 100644
--- a/lib/pages/history/widgets/item.dart
+++ b/lib/pages/history/widgets/item.dart
@@ -11,7 +11,6 @@ import 'package:pilipala/models/bangumi/info.dart';
import 'package:pilipala/models/common/business_type.dart';
import 'package:pilipala/models/common/search_type.dart';
import 'package:pilipala/models/live/item.dart';
-import 'package:pilipala/pages/history/index.dart';
import 'package:pilipala/pages/history_search/index.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/id_utils.dart';
diff --git a/lib/pages/history_search/view.dart b/lib/pages/history_search/view.dart
index 809e6d67..5bde691d 100644
--- a/lib/pages/history_search/view.dart
+++ b/lib/pages/history_search/view.dart
@@ -131,7 +131,6 @@ class _HistorySearchPageState extends State {
onChoose: null,
onUpdateMultiple: () => null,
);
- ;
}
},
)
diff --git a/lib/pages/home/controller.dart b/lib/pages/home/controller.dart
index 4239096c..5b722527 100644
--- a/lib/pages/home/controller.dart
+++ b/lib/pages/home/controller.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
@@ -15,6 +17,10 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
RxBool userLogin = false.obs;
RxString userFace = ''.obs;
var userInfo;
+ Box setting = GStrorage.setting;
+ late final StreamController searchBarStream =
+ StreamController.broadcast();
+ late bool hideSearchBar;
@override
void onInit() {
@@ -33,6 +39,8 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
length: tabs.length,
vsync: this,
);
+ hideSearchBar =
+ setting.get(SettingBoxKey.hideSearchBar, defaultValue: true);
}
void onRefresh() {
diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart
index dc55b4f5..e119cbcb 100644
--- a/lib/pages/home/view.dart
+++ b/lib/pages/home/view.dart
@@ -1,7 +1,8 @@
+import 'dart:async';
+
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
-import 'package:pilipala/pages/main/index.dart';
import 'package:pilipala/pages/mine/index.dart';
import 'package:pilipala/pages/search/index.dart';
import 'package:pilipala/utils/feed_back.dart';
@@ -18,11 +19,17 @@ class _HomePageState extends State
with AutomaticKeepAliveClientMixin, TickerProviderStateMixin {
final HomeController _homeController = Get.put(HomeController());
List videoList = [];
- Stream stream = Get.find().bottomBarStream.stream;
+ late Stream stream;
@override
bool get wantKeepAlive => true;
+ @override
+ void initState() {
+ super.initState();
+ stream = _homeController.searchBarStream.stream;
+ }
+
showUserBottonSheet() {
feedBack();
showModalBottomSheet(
@@ -46,7 +53,9 @@ class _HomePageState extends State
body: Column(
children: [
CustomAppBar(
- stream: stream,
+ stream: _homeController.hideSearchBar
+ ? stream
+ : StreamController.broadcast().stream,
ctr: _homeController,
callback: showUserBottonSheet,
),
@@ -65,6 +74,7 @@ class _HomePageState extends State
dividerColor: Colors.transparent,
enableFeedback: true,
splashBorderRadius: BorderRadius.circular(10),
+ tabAlignment: TabAlignment.center,
onTap: (value) {
feedBack();
if (_homeController.initialIndex == value) {
@@ -118,7 +128,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
duration: const Duration(milliseconds: 500),
height: snapshot.data
? MediaQuery.of(context).padding.top + 52
- : MediaQuery.of(context).padding.top,
+ : MediaQuery.of(context).padding.top - 10,
child: Container(
padding: EdgeInsets.only(
left: 20,
diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart
index 16ee4348..4b098063 100644
--- a/lib/pages/hot/view.dart
+++ b/lib/pages/hot/view.dart
@@ -9,6 +9,7 @@ import 'package:pilipala/common/widgets/overlay_pop.dart';
import 'package:pilipala/common/skeleton/video_card_h.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/video_card_h.dart';
+import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/hot/controller.dart';
import 'package:pilipala/pages/main/index.dart';
@@ -35,6 +36,8 @@ class _HotPageState extends State with AutomaticKeepAliveClientMixin {
scrollController = _hotController.scrollController;
StreamController mainStream =
Get.find().bottomBarStream;
+ StreamController searchBarStream =
+ Get.find().searchBarStream;
scrollController.addListener(
() {
if (scrollController.position.pixels >=
@@ -49,8 +52,10 @@ class _HotPageState extends State with AutomaticKeepAliveClientMixin {
scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
mainStream.add(true);
+ searchBarStream.add(true);
} else if (direction == ScrollDirection.reverse) {
mainStream.add(false);
+ searchBarStream.add(false);
}
},
);
diff --git a/lib/pages/html/view.dart b/lib/pages/html/view.dart
index 64fabff8..478626af 100644
--- a/lib/pages/html/view.dart
+++ b/lib/pages/html/view.dart
@@ -9,7 +9,6 @@ import 'package:pilipala/common/widgets/html_render.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/common/reply_type.dart';
-import 'package:pilipala/pages/mine/index.dart';
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
import 'package:pilipala/pages/video/detail/replyNew/index.dart';
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
diff --git a/lib/pages/live/view.dart b/lib/pages/live/view.dart
index 1fbff63c..302d226d 100644
--- a/lib/pages/live/view.dart
+++ b/lib/pages/live/view.dart
@@ -9,6 +9,7 @@ import 'package:pilipala/common/skeleton/video_card_v.dart';
import 'package:pilipala/common/widgets/animated_dialog.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/overlay_pop.dart';
+import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/main/index.dart';
import 'package:pilipala/pages/rcmd/index.dart';
@@ -38,6 +39,8 @@ class _LivePageState extends State
scrollController = _liveController.scrollController;
StreamController mainStream =
Get.find().bottomBarStream;
+ StreamController searchBarStream =
+ Get.find().searchBarStream;
scrollController.addListener(
() {
if (scrollController.position.pixels >=
@@ -52,8 +55,10 @@ class _LivePageState extends State
scrollController.position.userScrollDirection;
if (direction == ScrollDirection.forward) {
mainStream.add(true);
+ searchBarStream.add(true);
} else if (direction == ScrollDirection.reverse) {
mainStream.add(false);
+ searchBarStream.add(false);
}
},
);
@@ -67,6 +72,7 @@ class _LivePageState extends State
@override
Widget build(BuildContext context) {
+ super.build(context);
return Container(
clipBehavior: Clip.hardEdge,
margin: const EdgeInsets.only(
diff --git a/lib/pages/liveRoom/view.dart b/lib/pages/liveRoom/view.dart
index 36b1f979..125460b9 100644
--- a/lib/pages/liveRoom/view.dart
+++ b/lib/pages/liveRoom/view.dart
@@ -52,7 +52,6 @@ class _LiveRoomPageState extends State {
@override
Widget build(BuildContext context) {
- final videoHeight = MediaQuery.of(context).size.width * 9 / 16;
Widget childWhenDisabled = Scaffold(
primary: true,
appBar: AppBar(
diff --git a/lib/pages/liveRoom/widgets/bottom_control.dart b/lib/pages/liveRoom/widgets/bottom_control.dart
index 49343bb1..7347a8fc 100644
--- a/lib/pages/liveRoom/widgets/bottom_control.dart
+++ b/lib/pages/liveRoom/widgets/bottom_control.dart
@@ -3,7 +3,6 @@ import 'dart:io';
import 'package:floating/floating.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/models/video/play/url.dart';
import 'package:pilipala/pages/liveRoom/index.dart';
@@ -43,10 +42,6 @@ class _BottomControlState extends State {
@override
Widget build(BuildContext context) {
- const textStyle = TextStyle(
- color: Colors.white,
- fontSize: 12,
- );
return AppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart
index 1d296105..a322c5f3 100644
--- a/lib/pages/main/controller.dart
+++ b/lib/pages/main/controller.dart
@@ -55,6 +55,7 @@ class MainController extends GetxController {
StreamController.broadcast();
Box setting = GStrorage.setting;
DateTime? _lastPressedAt;
+ late bool hideTabBar;
@override
void onInit() {
@@ -62,6 +63,7 @@ class MainController extends GetxController {
if (setting.get(SettingBoxKey.autoUpdate, defaultValue: false)) {
Utils.checkUpdata();
}
+ hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true);
}
Future onBackPressed(BuildContext context) {
diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart
index ee8d3829..fef5620d 100644
--- a/lib/pages/main/view.dart
+++ b/lib/pages/main/view.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
@@ -113,8 +115,8 @@ class _MainAppState extends State with SingleTickerProviderStateMixin {
MediaQuery.of(context).size.width * 9 / 16;
localCache.put('sheetHeight', sheetHeight);
localCache.put('statusBarHeight', statusBarHeight);
- return WillPopScope(
- onWillPop: () => _mainController.onBackPressed(context),
+ return PopScope(
+ onPopInvoked: (bool status) => _mainController.onBackPressed(context),
child: Scaffold(
extendBody: true,
body: FadeTransition(
@@ -142,7 +144,9 @@ class _MainAppState extends State with SingleTickerProviderStateMixin {
),
),
bottomNavigationBar: StreamBuilder(
- stream: _mainController.bottomBarStream.stream,
+ stream: _mainController.hideTabBar
+ ? _mainController.bottomBarStream.stream
+ : StreamController.broadcast().stream,
initialData: true,
builder: (context, AsyncSnapshot snapshot) {
return AnimatedSlide(
diff --git a/lib/pages/member/archive/index.dart b/lib/pages/member/archive/index.dart
deleted file mode 100644
index 8be45429..00000000
--- a/lib/pages/member/archive/index.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-library archive_panel;
-
-export './controller.dart';
-export 'index.dart';
diff --git a/lib/pages/member/archive/view.dart b/lib/pages/member/archive/view.dart
deleted file mode 100644
index f34a396c..00000000
--- a/lib/pages/member/archive/view.dart
+++ /dev/null
@@ -1,240 +0,0 @@
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import 'package:loading_more_list/loading_more_list.dart';
-import 'package:pilipala/common/widgets/video_card_h.dart';
-import 'package:pilipala/models/member/archive.dart';
-import 'package:pilipala/pages/member/archive/index.dart';
-import 'package:pilipala/utils/utils.dart';
-import 'package:pull_to_refresh_notification/pull_to_refresh_notification.dart';
-
-class ArchivePanel extends StatefulWidget {
- final int? mid;
- const ArchivePanel({super.key, this.mid});
-
- @override
- State createState() => _ArchivePanelState();
-}
-
-class _ArchivePanelState extends State
- with AutomaticKeepAliveClientMixin {
- DateTime lastRefreshTime = DateTime.now();
- late final LoadMoreListSource source;
- late final ArchiveController _archiveController;
-
- @override
- bool get wantKeepAlive => true;
-
- @override
- void initState() {
- super.initState();
- print('🐶🐶: ${widget.mid}');
- _archiveController = Get.put(ArchiveController(widget.mid),
- tag: Utils.makeHeroTag(widget.mid));
- source = LoadMoreListSource(_archiveController);
- }
-
- @override
- Widget build(BuildContext context) {
- super.build(context);
- return PullToRefreshNotification(
- onRefresh: () async {
- await Future.delayed(const Duration(seconds: 1));
- return true;
- },
- maxDragOffset: 50,
- child: GlowNotificationWidget(
- Column(
- children: [
- // 下拉刷新指示器
- // PullToRefreshContainer(
- // (PullToRefreshScrollNotificationInfo? info) {
- // return PullToRefreshHeader(info, lastRefreshTime);
- // },
- // ),
- Padding(
- padding:
- const EdgeInsets.only(left: 14, top: 8, bottom: 8, right: 8),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- const Text('排序方式'),
- SizedBox(
- height: 35,
- width: 85,
- child: TextButton(
- style: ButtonStyle(
- padding: MaterialStateProperty.all(EdgeInsets.zero),
- ),
- onPressed: () {
- // _archiveController.order = 'click';
- // _archiveController.pn = 1;
- _archiveController.toggleSort();
- source.refresh(true);
- // LoadMoreListSource().loadData();
- },
- child: Obx(
- () => AnimatedSwitcher(
- duration: const Duration(milliseconds: 400),
- transitionBuilder:
- (Widget child, Animation animation) {
- return ScaleTransition(
- scale: animation, child: child);
- },
- child: Text(
- _archiveController.currentOrder['label']!,
- key: ValueKey(
- _archiveController.currentOrder['label']!),
- ),
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- Expanded(
- child: LoadingMoreList(
- ListConfig(
- sourceList: source,
- itemBuilder:
- (BuildContext c, VListItemModel item, int index) {
- if (index == 0) {
- return Column(
- children: [
- const SizedBox(height: 6),
- VideoCardH(videoItem: item)
- ],
- );
- } else {
- return VideoCardH(videoItem: item);
- }
- },
- indicatorBuilder: _buildIndicator,
- ),
- ),
- )
- ],
- ),
- showGlowLeading: false,
- ),
- );
- }
-
- Widget _buildIndicator(BuildContext context, IndicatorStatus status) {
- TextStyle style =
- TextStyle(fontSize: 13, color: Theme.of(context).colorScheme.outline);
- Widget? widget;
- switch (status) {
- case IndicatorStatus.none:
- widget = Container(height: 0.0);
- break;
- case IndicatorStatus.loadingMoreBusying:
- widget = Text('加载中...', style: style);
- widget = _setbackground(false, widget, height: 60.0);
- break;
- case IndicatorStatus.fullScreenBusying:
- widget = Text('加载中...', style: style);
- widget = _setbackground(true, widget);
- break;
- case IndicatorStatus.error:
-
- /// TODO 异常逻辑
- widget = Text('没有更多了', style: style);
- widget = _setbackground(false, widget);
-
- widget = GestureDetector(
- onTap: () {},
- child: widget,
- );
-
- break;
- case IndicatorStatus.fullScreenError:
-
- /// TODO 异常逻辑
- widget = Text('没有更多了', style: style);
- widget = _setbackground(true, widget);
- widget = GestureDetector(
- onTap: () {},
- child: widget,
- );
- break;
- case IndicatorStatus.noMoreLoad:
- widget = Text('没有更多了', style: style);
- widget = _setbackground(false, widget, height: 60.0);
- break;
- case IndicatorStatus.empty:
- widget = Text('用户没有投稿', style: style);
- widget = _setbackground(true, widget);
- break;
- }
- return widget;
- }
-
- Widget _setbackground(bool full, Widget widget, {double height = 100}) {
- widget = Padding(
- padding: height == double.infinity
- ? EdgeInsets.zero
- : EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
- child: Container(
- width: double.infinity,
- height: height,
- color: Theme.of(context).colorScheme.background,
- alignment: Alignment.center,
- child: widget,
- ),
- );
- return widget;
- }
-
- Widget getIndicator(BuildContext context) {
- final TargetPlatform platform = Theme.of(context).platform;
- return platform == TargetPlatform.iOS
- ? const CupertinoActivityIndicator(
- animating: true,
- radius: 16.0,
- )
- : CircularProgressIndicator(
- strokeWidth: 2.0,
- valueColor:
- AlwaysStoppedAnimation(Theme.of(context).primaryColor),
- );
- }
-}
-
-class LoadMoreListSource extends LoadingMoreBase {
- late ArchiveController ctr;
- LoadMoreListSource(this.ctr);
- bool forceRefresh = false;
-
- @override
- Future loadData([bool isloadMoreAction = false]) async {
- bool isSuccess = false;
- var res = await ctr.getMemberArchive();
- if (res['status']) {
- if (ctr.pn == 2) {
- clear();
- }
- addAll(res['data'].list.vlist);
- }
- if (length < res['data'].page['count']) {
- isSuccess = true;
- } else {
- isSuccess = false;
- }
- return isSuccess;
- }
-
- @override
- Future refresh([bool clearBeforeRequest = false]) async {
- // _hasMore = true;
- // pageindex = 1;
- // //force to refresh list when you don't want clear list before request
- // //for the case, if your list already has 20 items.
- forceRefresh = !clearBeforeRequest;
- var result = await super.refresh(clearBeforeRequest);
-
- forceRefresh = false;
- return result;
- }
-}
diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart
index 0d40ec65..14ede4d3 100644
--- a/lib/pages/member/controller.dart
+++ b/lib/pages/member/controller.dart
@@ -6,6 +6,7 @@ import 'package:pilipala/http/member.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/member/archive.dart';
+import 'package:pilipala/models/member/coin.dart';
import 'package:pilipala/models/member/info.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:share_plus/share_plus.dart';
@@ -13,16 +14,17 @@ import 'package:share_plus/share_plus.dart';
class MemberController extends GetxController {
late int mid;
Rx memberInfo = MemberInfoModel().obs;
- Map? userStat;
+ late Map userStat;
RxString face = ''.obs;
String? heroTag;
Box userInfoCache = GStrorage.userInfo;
late int ownerMid;
// 投稿列表
RxList? archiveList = [VListItemModel()].obs;
- var userInfo;
+ dynamic userInfo;
RxInt attribute = (-1).obs;
RxString attributeText = '关注'.obs;
+ RxList recentCoinsList = [].obs;
@override
void onInit() {
@@ -38,6 +40,7 @@ class MemberController extends GetxController {
// 获取用户信息
Future