Compare commits

..

5 Commits

Author SHA1 Message Date
bggRGjQaUbCoE
5dd3ff32b6 fix: view forwarded dyn
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 22:00:55 +08:00
bggRGjQaUbCoE
a48d262637 mod: show member coin/like archives(web)
Closes #265

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 20:55:41 +08:00
bggRGjQaUbCoE
b5d17b5161 mod: pay coins page
related #245

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 20:34:06 +08:00
bggRGjQaUbCoE
980733ba22 fix: member contribute page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 19:49:39 +08:00
bggRGjQaUbCoE
7043fdc35d mod: debug logout
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-02-16 15:09:53 +08:00
25 changed files with 368 additions and 291 deletions

View File

@@ -35,44 +35,7 @@ class VideoCardV extends StatelessWidget {
String goto = videoItem.goto;
switch (goto) {
case 'bangumi':
// if (videoItem.bangumiBadge == '电影') {
// SmartDialog.showToast('暂不支持电影观看');
// return;
// }
Utils.viewBangumi(epId: videoItem.param);
// SmartDialog.showLoading(msg: '资源获取中');
// var result = await SearchHttp.bangumiInfo(seasonId: null, epId: epId);
// SmartDialog.dismiss();
// if (result['status']) {
// var bangumiDetail = result['data'];
// EpisodeItem episode = result['data'].episodes.first;
// int? epId = result['data'].userStatus?.progress?.lastEpId;
// if (epId == null) {
// epId = episode.epId;
// } else {
// for (var item in result['data'].episodes) {
// if (item.epId == epId) {
// episode = item;
// break;
// }
// }
// }
// String bvid = episode.bvid!;
// int cid = episode.cid!;
// String pic = episode.cover!;
// String seasonId = bangumiDetail.seasonId;
// dynamic heroTag = Utils.makeHeroTag(cid);
// Get.toNamed(
// '/video?bvid=$bvid&cid=$cid&seasonId=$seasonId&epId=$epId',
// arguments: {
// 'pic': pic,
// 'heroTag': heroTag,
// 'videoType': SearchType.media_bangumi,
// },
// );
// } else {
// SmartDialog.showToast(result['msg']);
// }
break;
case 'av':
String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid);

View File

@@ -21,47 +21,8 @@ class VideoCardVMemberHome extends StatelessWidget {
String goto = videoItem.goto ?? '';
switch (goto) {
case 'bangumi':
// if (videoItem.bangumiBadge == '电影') {
// SmartDialog.showToast('暂不支持电影观看');
// return;
// }
// int epId = videoItem.param;
Utils.viewBangumi(epId: videoItem.param);
// SmartDialog.showLoading(msg: '资源获取中');
// var result = await SearchHttp.bangumiInfo(seasonId: null, epId: epId);
// SmartDialog.dismiss();
// if (result['status']) {
// var bangumiDetail = result['data'];
// EpisodeItem episode = result['data'].episodes.first;
// int? epId = result['data'].userStatus?.progress?.lastEpId;
// if (epId == null) {
// epId = episode.epId;
// } else {
// for (var item in result['data'].episodes) {
// if (item.epId == epId) {
// episode = item;
// break;
// }
// }
// }
// String bvid = episode.bvid!;
// int cid = episode.cid!;
// String pic = episode.cover!;
// String seasonId = bangumiDetail.seasonId;
// dynamic heroTag = Utils.makeHeroTag(cid);
// Get.toNamed(
// '/video?bvid=$bvid&cid=$cid&seasonId=$seasonId&epId=$epId',
// arguments: {
// 'pic': pic,
// 'heroTag': heroTag,
// 'videoType': SearchType.media_bangumi,
// },
// );
// } else {
// SmartDialog.showToast(result['msg']);
// }
// break;
break;
case 'av':
if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) {
if (Utils.viewPgcFromUri(videoItem.uri!)) {

View File

@@ -598,7 +598,7 @@ class MemberHttp {
}
// 最近投币
static Future getRecentCoinVideo({required int mid}) async {
static Future<LoadingState> getRecentCoinVideo({required int mid}) async {
Map params = await WbiSign().makSign({
'mid': mid,
'gaia_source': 'main_web',
@@ -615,23 +615,16 @@ class MemberHttp {
},
);
if (res.data['code'] == 0) {
return {
'status': true,
'data': res.data['data']
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
.toList(),
};
return LoadingState.success(res.data['data']
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
.toList());
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
return LoadingState.error(res.data['message']);
}
}
// 最近点赞
static Future getRecentLikeVideo({required int mid}) async {
static Future<LoadingState> getRecentLikeVideo({required int mid}) async {
Map params = await WbiSign().makSign({
'mid': mid,
'gaia_source': 'main_web',
@@ -648,16 +641,11 @@ class MemberHttp {
},
);
if (res.data['code'] == 0) {
return {
'status': true,
'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
};
return LoadingState.success(res.data['data']['list']
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
.toList());
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
return LoadingState.error(res.data['message']);
}
}

View File

@@ -35,47 +35,23 @@ class DynamicItemModel {
Map? basic;
dynamic idStr;
ItemModulesModel? modules;
ItemOrigModel? orig;
DynamicItemModel? orig;
String? type;
bool? visible;
bool? isForwarded;
DynamicItemModel.fromJson(Map<String, dynamic> json) {
basic = json['basic'];
idStr = json['id_str'];
modules = ItemModulesModel.fromJson(json['modules']);
orig = json['orig'] != null ? ItemOrigModel.fromJson(json['orig']) : null;
orig =
json['orig'] != null ? DynamicItemModel.fromJson(json['orig']) : null;
orig?.isForwarded = true;
type = json['type'];
visible = json['visible'];
}
}
class ItemOrigModel {
ItemOrigModel({
this.basic,
this.isStr,
this.modules,
this.type,
this.visible,
this.idStr,
});
Map? basic;
String? isStr;
ItemModulesModel? modules;
String? type;
bool? visible;
dynamic idStr;
ItemOrigModel.fromJson(Map<String, dynamic> json) {
basic = json['basic'];
isStr = json['is_str'];
modules = ItemModulesModel.fromJson(json['modules']);
type = json['type'];
visible = json['visible'];
idStr = json['id_str'];
}
}
// 单个动态详情
class ItemModulesModel {
ItemModulesModel({

View File

@@ -1,5 +1,6 @@
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/storage.dart';
@@ -12,7 +13,7 @@ class DynamicDetailController extends ReplyController {
DynamicDetailController(this.oid, this.type);
int? oid;
int? type;
dynamic item;
late DynamicItemModel item;
int? floor;
late final horizontalPreview = GStorage.horizontalPreview;

View File

@@ -474,15 +474,19 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
_dynamicDetailController
.item
.modules
.moduleStat
.forward
?.moduleStat
?.forward
?.count ??
'0') ??
0;
_dynamicDetailController.item.modules
?.moduleStat ??= ModuleStatModel();
_dynamicDetailController.item.modules!
.moduleStat?.forward ??= ForWard();
_dynamicDetailController
.item
.modules
.moduleStat
.modules!
.moduleStat!
.forward!
.count = (count + 1).toString();
if (btnContext.mounted) {
@@ -507,12 +511,12 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
),
label: Text(
_dynamicDetailController.item.modules
.moduleStat.forward!.count !=
?.moduleStat?.forward?.count !=
null
? Utils.numFormat(_dynamicDetailController
.item
.modules
.moduleStat
.modules!
.moduleStat!
.forward!
.count)
: '转发',
@@ -553,17 +557,24 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
},
),
icon: Icon(
_dynamicDetailController
.item.modules.moduleStat.like!.status!
_dynamicDetailController.item.modules
?.moduleStat?.like?.status ==
true
? FontAwesomeIcons.solidThumbsUp
: FontAwesomeIcons.thumbsUp,
size: 16,
color: _dynamicDetailController
.item.modules.moduleStat.like!.status!
color: _dynamicDetailController.item.modules
?.moduleStat?.like?.status ==
true
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
semanticLabel: _dynamicDetailController
.item.modules.moduleStat.like!.status!
.item
.modules
?.moduleStat
?.like
?.status ==
true
? "已赞"
: "点赞",
),
@@ -582,15 +593,24 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
},
child: Text(
_dynamicDetailController.item.modules
.moduleStat.like!.count !=
?.moduleStat?.like?.count !=
null
? Utils.numFormat(
_dynamicDetailController.item
.modules.moduleStat.like!.count)
_dynamicDetailController
.item
.modules!
.moduleStat!
.like!
.count)
: '点赞',
style: TextStyle(
color: _dynamicDetailController.item
.modules.moduleStat.like!.status!
color: _dynamicDetailController
.item
.modules
?.moduleStat
?.like
?.status ==
true
? Theme.of(context)
.colorScheme
.primary

View File

@@ -1,6 +1,5 @@
import 'package:PiliPlus/common/widgets/radio_widget.dart';
import 'package:PiliPlus/http/index.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:cached_network_image/cached_network_image.dart';
@@ -98,7 +97,7 @@ class AuthorPanel extends StatelessWidget {
),
child: Row(
children: [
Text(item is ItemOrigModel
Text(item.isForwarded == true
? Utils.dateFormat(item.modules.moduleAuthor.pubTs)
: item.modules.moduleAuthor.pubTime),
if (item.modules.moduleAuthor.pubTime != '' &&

View File

@@ -162,37 +162,38 @@ Widget forWard(item, context, source, callback, {floor = 1}) {
// 文章
case 'DYNAMIC_TYPE_ARTICLE':
return switch (item) {
ItemOrigModel() => articlePanel(item, context, callback, floor: floor),
DynamicItemModel() => item.modules?.moduleDynamic?.major?.blocked !=
null
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (item.modules?.moduleDynamic?.major?.blocked?['title'] !=
null)
Text(
'${item.modules?.moduleDynamic?.major?.blocked!['title']}',
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
),
if (item.modules?.moduleDynamic?.major
?.blocked?['hint_message'] !=
null)
Text(
'${item.modules?.moduleDynamic?.major?.blocked!['hint_message']}',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
),
)
],
),
)
: const SizedBox.shrink(),
DynamicItemModel() => item.isForwarded == true
? articlePanel(item, context, callback, floor: floor)
: item.modules?.moduleDynamic?.major?.blocked != null
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (item.modules?.moduleDynamic?.major
?.blocked?['title'] !=
null)
Text(
'${item.modules?.moduleDynamic?.major?.blocked!['title']}',
style: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
),
if (item.modules?.moduleDynamic?.major
?.blocked?['hint_message'] !=
null)
Text(
'${item.modules?.moduleDynamic?.major?.blocked!['hint_message']}',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
),
)
],
),
)
: const SizedBox.shrink(),
_ => const SizedBox.shrink(),
};
// return Container(

View File

@@ -1,5 +1,4 @@
// 视频or合集
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPlus/common/constants.dart';
@@ -159,7 +158,7 @@ Widget videoSeasonWidget(item, context, type, {floor = 1}) {
if (richNodes != null) Text.rich(richNodes),
const SizedBox(height: 6),
],
if (item is ItemOrigModel)
if (item.isForwarded == true)
buildCover()
else
Padding(

View File

@@ -254,10 +254,10 @@ class MemberController extends GetxController {
// 请求投币视频
Future getRecentCoinVideo() async {
if (userInfo == null) return;
var res = await MemberHttp.getRecentCoinVideo(mid: mid!);
recentCoinsList.value = res['data'];
return res;
// if (userInfo == null) return;
// var res = await MemberHttp.getRecentCoinVideo(mid: mid!);
// recentCoinsList.value = res['data'];
// return res;
}
// 跳转查看动态

View File

@@ -77,57 +77,54 @@ class _MemberContributeState extends State<MemberContribute>
child: TabBarView(
physics: const NeverScrollableScrollPhysics(),
controller: _controller.tabController,
children: _controller.items!
.map(
(item) => switch (item.param) {
'video' => MemberVideo(
type: ContributeType.video,
heroTag: widget.heroTag,
mid: widget.mid,
title: item.title,
),
'charging_video' => MemberVideo(
type: ContributeType.charging,
heroTag: widget.heroTag,
mid: widget.mid,
title: item.title,
),
'article' => MemberArticle(
heroTag: widget.heroTag,
mid: widget.mid,
),
'audio' => MemberAudio(heroTag: widget.heroTag),
'season_video' => MemberVideo(
type: ContributeType.season,
heroTag: widget.heroTag,
mid: widget.mid,
seasonId: item.seasonId,
title: item.title,
),
'series' => MemberVideo(
type: ContributeType.series,
heroTag: widget.heroTag,
mid: widget.mid,
seriesId: item.seriesId,
title: item.title,
),
'ugcSeason' => SeasonSeriesPage(
mid: widget.mid,
heroTag: widget.heroTag,
),
_ => Center(child: Text(item.title!))
},
)
.toList(),
children: _controller.items!.map(_getPageFromType).toList(),
),
),
],
)
: MemberVideo(
type: ContributeType.video,
heroTag: widget.heroTag,
mid: widget.mid,
title: '视频',
);
: _controller.items?.isNotEmpty == true
? _getPageFromType(_controller.items!.first)
: const SizedBox.shrink();
}
Widget _getPageFromType(item) {
return switch (item.param) {
'video' => MemberVideo(
type: ContributeType.video,
heroTag: widget.heroTag,
mid: widget.mid,
title: item.title,
),
'charging_video' => MemberVideo(
type: ContributeType.charging,
heroTag: widget.heroTag,
mid: widget.mid,
title: item.title,
),
'article' => MemberArticle(
heroTag: widget.heroTag,
mid: widget.mid,
),
'audio' => MemberAudio(heroTag: widget.heroTag),
'season_video' => MemberVideo(
type: ContributeType.season,
heroTag: widget.heroTag,
mid: widget.mid,
seasonId: item.seasonId,
title: item.title,
),
'series' => MemberVideo(
type: ContributeType.series,
heroTag: widget.heroTag,
mid: widget.mid,
seriesId: item.seriesId,
title: item.title,
),
'ugcSeason' => SeasonSeriesPage(
mid: widget.mid,
heroTag: widget.heroTag,
),
_ => Center(child: Text(item.title!))
};
}
}

View File

@@ -29,36 +29,25 @@ class MemberContributeCtr extends CommonController
super.onInit();
Tab2 contribute =
_ctr.tab2!.firstWhere((item) => item.param == 'contribute');
if (contribute.items?.isNullOrEmpty == false &&
contribute.items!.length > 1) {
if (contribute.items?.isNullOrEmpty == false) {
items = contribute.items;
// if (_ctr.ugcSeasonCount != null) {
// int currentSeasonCount =
// items!.where((item) => item.param == 'season_video').length;
// if (currentSeasonCount < _ctr.ugcSeasonCount!) {
// items!.add(
// Item(
// param: 'ugcSeason',
// title: '全部合集/列表',
// ),
// );
// }
// }
// show if exist
if (_ctr.hasSeasonOrSeries == true) {
items!.add(
Item(
param: 'ugcSeason',
title: '全部合集/列表',
),
if (contribute.items!.length > 1) {
// show if exist
if (_ctr.hasSeasonOrSeries == true) {
items!.add(
Item(
param: 'ugcSeason',
title: '全部合集/列表',
),
);
}
tabs = items!.map((item) => Tab(text: item.title)).toList();
tabController = TabController(
vsync: this,
length: items!.length,
initialIndex: max(0, initialIndex ?? 0),
);
}
tabs = items!.map((item) => Tab(text: item.title)).toList();
tabController = TabController(
vsync: this,
length: items!.length,
initialIndex: max(0, initialIndex ?? 0),
);
}
}

View File

@@ -10,6 +10,8 @@ import 'package:PiliPlus/models/space/item.dart';
import 'package:PiliPlus/pages/bangumi/widgets/bangumi_card_v_member_home.dart';
import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute_ctr.dart';
import 'package:PiliPlus/pages/member/new/controller.dart';
import 'package:PiliPlus/pages/member_coin/index.dart';
import 'package:PiliPlus/pages/member_like/index.dart';
import 'package:PiliPlus/utils/grid.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -271,6 +273,21 @@ class _MemberHomeState extends State<MemberHome>
}
_ctr.tabController?.animateTo(index);
} else {
if (param == 'coinArchive') {
Get.to(MemberCoinPage(
mid: _ctr.mid,
name: _ctr.username,
));
return;
}
if (param == 'likeArchive') {
Get.to(MemberLikePage(
mid: _ctr.mid,
name: _ctr.username,
));
return;
}
// TODO
SmartDialog.showToast('view $param');
}

View File

@@ -23,7 +23,7 @@ extension MemberTabTypeExt on MemberTabType {
class MemberControllerNew extends CommonController
with GetTickerProviderStateMixin {
MemberControllerNew({required this.mid});
int? mid;
int mid;
RxDouble scrollRatio = 0.0.obs;
String? username;
int? ownerMid;
@@ -154,7 +154,7 @@ class MemberControllerNew extends CommonController
void _onBlock() async {
dynamic res = await VideoHttp.relationMod(
mid: mid ?? -1,
mid: mid,
act: relation.value != -1 ? 5 : 6,
reSrc: 11,
);

View File

@@ -26,7 +26,7 @@ class MemberPageNew extends StatefulWidget {
class _MemberPageNewState extends State<MemberPageNew>
with TickerProviderStateMixin {
int? _mid;
late final int _mid;
late final String _heroTag;
late final MemberControllerNew _userController;
final _key = GlobalKey<ExtendedNestedScrollViewState>();
@@ -161,16 +161,16 @@ class _MemberPageNewState extends State<MemberPageNew>
() => MemberContribute(
heroTag: _heroTag,
initialIndex: _userController.contributeInitialIndex.value,
mid: _mid ?? -1,
mid: _mid,
),
),
'bangumi' => MemberBangumi(
heroTag: _heroTag,
mid: _mid ?? -1,
mid: _mid,
),
'favorite' => MemberFavorite(
heroTag: _heroTag,
mid: _mid ?? -1,
mid: _mid,
),
_ => Center(child: Text(item.title ?? '')),
};

View File

@@ -1,3 +1,18 @@
import 'package:get/get.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/member.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
class MemberCoinController extends GetxController {}
class MemberCoinController extends CommonController {
final dynamic mid;
MemberCoinController({this.mid});
@override
void onInit() {
super.onInit();
queryData();
}
@override
Future<LoadingState> customGetData() =>
MemberHttp.getRecentCoinVideo(mid: mid);
}

View File

@@ -1,15 +1,75 @@
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/member_coin/controller.dart';
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
import 'package:PiliPlus/utils/grid.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class MemberCoinPage extends StatefulWidget {
const MemberCoinPage({super.key});
const MemberCoinPage({
super.key,
required this.mid,
this.name,
});
final dynamic mid;
final String? name;
@override
State<MemberCoinPage> createState() => _MemberCoinPageState();
}
class _MemberCoinPageState extends State<MemberCoinPage> {
late final _ownerMid = GStorage.ownerMid;
late final _ctr = Get.put(
MemberCoinController(mid: widget.mid),
tag: Utils.makeHeroTag(widget.mid),
);
@override
Widget build(BuildContext context) {
return Scaffold();
return Scaffold(
appBar: AppBar(
title: Text('${widget.mid == _ownerMid ? '' : '${widget.name}'}'),
),
body: Obx(() => _buildBody(_ctr.loadingState.value)),
);
}
Widget _buildBody(LoadingState loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? GridView.builder(
padding: EdgeInsets.only(
top: StyleString.safeSpace - 5,
left: StyleString.safeSpace,
right: StyleString.safeSpace,
bottom: MediaQuery.paddingOf(context).bottom + 80,
),
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.smallCardWidth,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent: MediaQuery.textScalerOf(context).scale(75),
),
itemCount: loadingState.response.length,
itemBuilder: (context, index) {
return MemberCoinsItem(coinItem: loadingState.response[index]);
},
)
: scrollErrorWidget(callback: _ctr.onReload),
Error() => scrollErrorWidget(
errMsg: loadingState.errMsg,
callback: _ctr.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
}

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPlus/common/constants.dart';
@@ -19,7 +20,6 @@ class MemberCoinsItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
elevation: 0,
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: InkWell(
@@ -34,7 +34,13 @@ class MemberCoinsItem extends StatelessWidget {
},
);
},
onLongPress: () => imageSaveDialog(
context: context,
title: coinItem.title,
cover: coinItem.pic,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: StyleString.aspectRatio,
@@ -62,10 +68,11 @@ class MemberCoinsItem extends StatelessWidget {
Padding(
padding: const EdgeInsets.fromLTRB(5, 6, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
coinItem.title!,
'${coinItem.title}\n',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),

View File

@@ -1,3 +1,18 @@
import 'package:get/get.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/member.dart';
import 'package:PiliPlus/pages/common/common_controller.dart';
class MemberLikeController extends GetxController {}
class MemberLikeController extends CommonController {
final dynamic mid;
MemberLikeController({this.mid});
@override
void onInit() {
super.onInit();
queryData();
}
@override
Future<LoadingState> customGetData() =>
MemberHttp.getRecentLikeVideo(mid: mid);
}

View File

@@ -1,15 +1,75 @@
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
import 'package:PiliPlus/pages/member_like/controller.dart';
import 'package:PiliPlus/utils/grid.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class MemberLikePage extends StatefulWidget {
const MemberLikePage({super.key});
const MemberLikePage({
super.key,
required this.mid,
this.name,
});
final dynamic mid;
final String? name;
@override
State<MemberLikePage> createState() => _MemberLikePageState();
}
class _MemberLikePageState extends State<MemberLikePage> {
late final _ownerMid = GStorage.ownerMid;
late final _ctr = Get.put(
MemberLikeController(mid: widget.mid),
tag: Utils.makeHeroTag(widget.mid),
);
@override
Widget build(BuildContext context) {
return Scaffold();
return Scaffold(
appBar: AppBar(
title: Text('${widget.mid == _ownerMid ? '' : '${widget.name}'}'),
),
body: Obx(() => _buildBody(_ctr.loadingState.value)),
);
}
Widget _buildBody(LoadingState loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? GridView.builder(
padding: EdgeInsets.only(
top: StyleString.safeSpace - 5,
left: StyleString.safeSpace,
right: StyleString.safeSpace,
bottom: MediaQuery.paddingOf(context).bottom + 80,
),
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.smallCardWidth,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent: MediaQuery.textScalerOf(context).scale(75),
),
itemCount: loadingState.response.length,
itemBuilder: (context, index) {
return MemberCoinsItem(coinItem: loadingState.response[index]);
},
)
: scrollErrorWidget(callback: _ctr.onReload),
Error() => scrollErrorWidget(
errMsg: loadingState.errMsg,
callback: _ctr.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
}

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/build_config.dart';
import 'package:PiliPlus/pages/about/index.dart';
import 'package:PiliPlus/pages/setting/extra_setting.dart';
import 'package:PiliPlus/pages/setting/play_setting.dart';
@@ -203,15 +204,20 @@ class _SettingPageState extends State<SettingPage> {
),
),
),
// TextButton(
// onPressed: () async {
// await LoginUtils.onLogout();
// _isLogin.value = false;
// SmartDialog.dismiss();
// Get.back();
// },
// child: const Text('仅登出'),
// ),
if (BuildConfig.isDebug)
TextButton(
onPressed: () {
Get.back();
_isLogin.value = false;
LoginUtils.onLogout();
},
child: Text(
'仅登出',
style: TextStyle(
color: Theme.of(context).colorScheme.error,
),
),
),
TextButton(
onPressed: () async {
SmartDialog.showLoading();

View File

@@ -106,7 +106,8 @@ class _PayCoinsPageState extends State<PayCoinsPage>
: Row(
children: [
const Spacer(),
Expanded(child: _buildBody(isV)),
Expanded(flex: 3, child: _buildBody(isV)),
const Spacer(),
],
);
});

View File

@@ -32,9 +32,7 @@ import '../pages/live_room/view.dart';
import '../pages/login/index.dart';
import '../pages/media/index.dart';
import '../pages/member_archive/index.dart';
import '../pages/member_coin/index.dart';
import '../pages/member_dynamics/index.dart';
import '../pages/member_like/index.dart';
import '../pages/member_search/index.dart';
import '../pages/member_seasons/index.dart';
import '../pages/msg_feed_top/sys_msg/view.dart';
@@ -154,9 +152,9 @@ class Routes {
CustomGetPage(
name: '/memberArchive', page: () => const MemberArchivePage()),
// 用户最近投币
CustomGetPage(name: '/memberCoin', page: () => const MemberCoinPage()),
// CustomGetPage(name: '/memberCoin', page: () => const MemberCoinPage()),
// 用户最近喜欢
CustomGetPage(name: '/memberLike', page: () => const MemberLikePage()),
// CustomGetPage(name: '/memberLike', page: () => const MemberLikePage()),
// 用户专栏
CustomGetPage(
name: '/memberSeasons', page: () => const MemberSeasonsPage()),

View File

@@ -34,6 +34,8 @@ class GStorage {
static bool get isLogin => userInfo.get('userInfoCache') != null;
static get ownerMid => GStorage.userInfo.get('userInfoCache')?.mid;
static List<double> get speedList => List<double>.from(
video.get(
VideoBoxKey.speedsList,

View File

@@ -51,9 +51,11 @@ class Utils {
feedBack();
String dynamicId = item.idStr!;
// 1 已点赞 2 不喜欢 0 未操作
item.modules?.moduleStat ??= ModuleStatModel();
item.modules?.moduleStat.like ??= Like();
Like like = item.modules.moduleStat.like;
int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0');
bool status = like.status!;
bool status = like.status ?? false;
int up = status ? 2 : 1;
var res = await DynamicsHttp.likeDynamic(dynamicId: dynamicId, up: up);
if (res['status']) {