Merge branch 'main' into fix

This commit is contained in:
guozhigq
2024-10-31 23:24:47 +08:00
16 changed files with 427 additions and 19 deletions

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/member.dart';
import 'package:pilipala/models/member/archive.dart';
import 'package:pilipala/utils/global_data_cache.dart';
class MemberArchiveController extends GetxController {
final ScrollController scrollController = ScrollController();
@ -17,12 +18,18 @@ class MemberArchiveController extends GetxController {
].obs;
RxList<VListItemModel> archivesList = <VListItemModel>[].obs;
RxBool isLoading = false.obs;
late int ownerMid;
RxBool isOwner = false.obs;
@override
void onInit() {
super.onInit();
mid = int.parse(Get.parameters['mid']!);
currentOrder.value = orderList.first;
ownerMid = GlobalDataCache().userInfo != null
? GlobalDataCache().userInfo!.mid!
: -1;
isOwner.value = mid == -1 || mid == ownerMid;
}
// 获取用户投稿

View File

@ -51,8 +51,9 @@ class _MemberArchivePageState extends State<MemberArchivePage> {
centerTitle: false,
title: Obx(
() => Text(
'的投稿 - ${_memberArchivesController.currentOrder['label']}',
style: Theme.of(context).textTheme.titleMedium),
'${_memberArchivesController.isOwner.value ? '' : 'Ta'}的投稿 - ${_memberArchivesController.currentOrder['label']}',
style: Theme.of(context).textTheme.titleMedium,
),
),
actions: [
// Obx(

View File

@ -3,6 +3,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/member.dart';
import 'package:pilipala/models/member/article.dart';
import 'package:pilipala/utils/global_data_cache.dart';
class MemberArticleController extends GetxController {
final ScrollController scrollController = ScrollController();
@ -12,11 +13,17 @@ class MemberArticleController extends GetxController {
bool hasMore = true;
RxBool isLoading = false.obs;
RxList<MemberArticleItemModel> articleList = <MemberArticleItemModel>[].obs;
late int ownerMid;
RxBool isOwner = false.obs;
@override
void onInit() {
super.onInit();
mid = int.parse(Get.parameters['mid']!);
ownerMid = GlobalDataCache().userInfo != null
? GlobalDataCache().userInfo!.mid!
: -1;
isOwner.value = mid == -1 || mid == ownerMid;
}
Future getMemberArticle(type) async {

View File

@ -50,7 +50,12 @@ class _MemberArticlePageState extends State<MemberArticlePage> {
appBar: AppBar(
titleSpacing: 0,
centerTitle: false,
title: const Text('Ta的图文', style: TextStyle(fontSize: 16)),
title: Obx(
() => Text(
'${_memberArticleController.isOwner.value ? '' : 'Ta'}的图文',
style: Theme.of(context).textTheme.titleMedium,
),
),
),
body: FutureBuilder(
future: _futureBuilderFuture,

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/member.dart';
import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/utils/global_data_cache.dart';
class MemberDynamicsController extends GetxController {
final ScrollController scrollController = ScrollController();
@ -10,11 +11,17 @@ class MemberDynamicsController extends GetxController {
int count = 0;
bool hasMore = true;
RxList<DynamicItemModel> dynamicsList = <DynamicItemModel>[].obs;
late int ownerMid;
RxBool isOwner = false.obs;
@override
void onInit() {
super.onInit();
mid = int.parse(Get.parameters['mid']!);
ownerMid = GlobalDataCache().userInfo != null
? GlobalDataCache().userInfo!.mid!
: -1;
isOwner.value = mid == -1 || mid == ownerMid;
}
Future getMemberDynamic(type) async {

View File

@ -56,7 +56,12 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage> {
appBar: AppBar(
titleSpacing: 0,
centerTitle: false,
title: Text('他的动态', style: Theme.of(context).textTheme.titleMedium),
title: Obx(
() => Text(
'${_memberDynamicController.isOwner.value ? '' : 'Ta'}的动态',
style: Theme.of(context).textTheme.titleMedium,
),
),
),
body: CustomScrollView(
controller: _memberDynamicController.scrollController,

View File

@ -1,3 +1,27 @@
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/msg.dart';
import 'package:pilipala/models/msg/at.dart';
class MessageAtController extends GetxController {}
class MessageAtController extends GetxController {
Cursor? cursor;
RxList<MessageAtItems> atItems = <MessageAtItems>[].obs;
Future queryMessageAt({String type = 'init'}) async {
if (cursor != null && cursor!.isEnd == true) {
return {};
}
var res = await MsgHttp.messageAt();
if (res['status']) {
cursor = res['data'].cursor;
if (type == 'init') {
atItems.value = res['data'].items;
} else {
atItems.addAll(res['data'].items);
}
} else {
SmartDialog.showToast(res['msg']);
}
return res;
}
}

View File

@ -1,4 +1,14 @@
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/common/widgets/no_data.dart';
import 'package:pilipala/models/msg/at.dart';
import 'package:pilipala/pages/message/utils/index.dart';
import 'package:pilipala/utils/utils.dart';
import 'controller.dart';
class MessageAtPage extends StatefulWidget {
const MessageAtPage({super.key});
@ -8,12 +18,179 @@ class MessageAtPage extends StatefulWidget {
}
class _MessageAtPageState extends State<MessageAtPage> {
final MessageAtController _messageAtCtr = Get.put(MessageAtController());
late Future _futureBuilderFuture;
final ScrollController scrollController = ScrollController();
@override
void initState() {
super.initState();
_futureBuilderFuture = _messageAtCtr.queryMessageAt();
scrollController.addListener(
() async {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200) {
EasyThrottle.throttle('follow', const Duration(seconds: 1), () {
_messageAtCtr.queryMessageAt(type: 'onLoad');
});
}
},
);
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('@我的'),
),
body: RefreshIndicator(
onRefresh: () async {
await _messageAtCtr.queryMessageAt(type: 'init');
},
child: FutureBuilder(
future: _futureBuilderFuture,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final Map<String, dynamic>? data = snapshot.data;
if (data != null && data['status']) {
final RxList<MessageAtItems> atItems = _messageAtCtr.atItems;
return Obx(
() => atItems.isEmpty
? const CustomScrollView(slivers: [NoData()])
: ListView.separated(
controller: scrollController,
itemBuilder: (context, index) => AtItem(
item: atItems[index],
index: index,
messageAtCtr: _messageAtCtr,
),
itemCount: atItems.length,
separatorBuilder: (BuildContext context, int index) {
return Divider(
indent: 66,
endIndent: 14,
height: 1,
color: Colors.grey.withOpacity(0.1),
);
},
),
);
} else {
// 请求错误
return HttpError(
errMsg: data?['msg'] ?? '请求异常',
fn: () {
setState(() {
_futureBuilderFuture = _messageAtCtr.queryMessageAt();
});
},
isInSliver: false,
);
}
} else {
return const SizedBox();
}
},
),
),
);
}
}
class AtItem extends StatelessWidget {
final MessageAtItems item;
final int index;
final MessageAtController messageAtCtr;
const AtItem({
super.key,
required this.item,
required this.index,
required this.messageAtCtr,
});
@override
Widget build(BuildContext context) {
Color outline = Theme.of(context).colorScheme.outline;
final User user = item.user!;
final String heroTag = Utils.makeHeroTag(user.mid);
final Uri uri = Uri.parse(item.item!.uri!);
/// bilibili://
final Uri nativeUri = Uri.parse(item.item!.nativeUri!);
final String type = item.item!.type!;
return InkWell(
onTap: () async {
MessageUtils.onClickMessage(context, uri, nativeUri, type);
},
child: Padding(
padding: const EdgeInsets.all(14),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
Get.toNamed('/member?mid=${item.user!.mid}',
arguments: {'face': item.user!.avatar, 'heroTag': heroTag});
},
child: Hero(
tag: heroTag,
child: NetworkImgLayer(
width: 42,
height: 42,
type: 'avatar',
src: item.user!.avatar,
),
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text.rich(TextSpan(children: [
TextSpan(text: item.user!.nickname!),
const TextSpan(text: ' '),
if (item.item!.type! == 'reply')
TextSpan(
text: '在评论中@了我',
style: TextStyle(color: outline),
),
])),
const SizedBox(height: 6),
Text(item.item!.sourceContent!),
const SizedBox(height: 4),
Text(
Utils.dateFormat(item.atTime!, formatType: 'detail'),
style: TextStyle(color: outline),
),
],
),
),
const SizedBox(width: 25),
if (item.item!.type! == 'reply')
Container(
width: 60,
height: 80,
padding: const EdgeInsets.all(4),
child: Text(
item.item!.title!,
maxLines: 3,
style: const TextStyle(fontSize: 12, letterSpacing: 0.3),
overflow: TextOverflow.ellipsis,
),
),
],
),
),
);
}
}

View File

@ -18,7 +18,11 @@ class MessageLikeController extends GetxController {
id: params['id'], likeTime: params['likeTime']);
if (res['status']) {
cursor = res['data'].total.cursor;
likeItems.addAll(res['data'].total.items);
if (type == 'init') {
likeItems.value = res['data'].total.items;
} else {
likeItems.addAll(res['data'].total.items);
}
}
return res;
}

View File

@ -13,13 +13,20 @@ class MessageUtils {
BuildContext context, Uri uri, Uri nativeUri, String type) async {
final String path = uri.path;
final String bvid = path.split('/').last;
String? sourceType;
final String nativePath = nativeUri.path;
final String oid = nativePath.split('/').last;
String oid = nativePath.split('/').last;
final Map<String, String> queryParameters = nativeUri.queryParameters;
final String? argCid = queryParameters['cid'];
// final String? page = queryParameters['page'];
final String? commentRootId = queryParameters['comment_root_id'];
String? commentRootId = queryParameters['comment_root_id'];
// final String? commentSecondaryId = queryParameters['comment_secondary_id'];
if (nativePath.contains('detail')) {
// 动态详情
sourceType = 'opus';
oid = nativePath.split('/')[3];
commentRootId = nativePath.split('/')[4];
}
switch (type) {
case 'video':
case 'danmu':
@ -42,7 +49,12 @@ class MessageUtils {
case 'reply':
debugPrint('commentRootId: $oid, $commentRootId');
navigateToComment(
context, oid, commentRootId!, ReplyType.video, nativeUri);
context,
oid,
commentRootId!,
sourceType == 'opus' ? ReplyType.dynamics : ReplyType.video,
nativeUri,
);
break;
default:
break;

View File

@ -11,7 +11,7 @@ class VideoReplyReplyController extends GetxController {
int? aid;
// rpid 请求楼中楼回复
String? rpid;
ReplyType replyType = ReplyType.video;
ReplyType? replyType;
bool showRoot = false;
ReplyItemModel? rootReply;
RxList<ReplyItemModel> replyList = <ReplyItemModel>[].obs;
@ -40,7 +40,7 @@ class VideoReplyReplyController extends GetxController {
oid: aid!,
root: rpid!,
pageNum: currentPage,
type: replyType.index,
type: (replyType ?? ReplyType.video).index,
);
if (res['status']) {
final List<ReplyItemModel> replies = res['data'].replies;

View File

@ -73,11 +73,6 @@ class _WhisperPageState extends State<WhisperPage> {
..._whisperController.noticesList.map((element) {
return InkWell(
onTap: () {
if (['/messageAt']
.contains(element['path'])) {
SmartDialog.showToast('功能开发中');
return;
}
Get.toNamed(element['path']);
if (element['count'] > 0) {