2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
import 'package:flutter_svg/svg.dart';
|
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
import 'package:get/get_rx/src/rx_typedefs/rx_typedefs.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:loopin/IM/controller/im_user_info_controller.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:loopin/IM/im_service.dart';
|
2025-09-17 11:51:54 +08:00
|
|
|
|
import 'package:loopin/api/common_api.dart';
|
2025-09-18 16:13:37 +08:00
|
|
|
|
import 'package:loopin/api/video_api.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:loopin/components/custom_sticky_header.dart';
|
2025-09-13 17:01:01 +08:00
|
|
|
|
import 'package:loopin/components/my_confirm.dart';
|
2025-09-18 16:13:37 +08:00
|
|
|
|
import 'package:loopin/components/my_qrcode.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:loopin/components/network_or_asset_image.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:loopin/components/only_down_scroll_physics.dart';
|
|
|
|
|
import 'package:loopin/controller/video_module_controller.dart';
|
2025-09-22 14:41:47 +08:00
|
|
|
|
import 'package:loopin/pages/my/merchant/balance/balance.dart';
|
|
|
|
|
import 'package:loopin/pages/my/merchant/balance/controller.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:loopin/service/http.dart';
|
2025-09-18 16:13:37 +08:00
|
|
|
|
import 'package:loopin/utils/index.dart';
|
|
|
|
|
import 'package:loopin/utils/scan_code_type.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:nested_scroll_view_plus/nested_scroll_view_plus.dart';
|
|
|
|
|
import 'package:shirne_dialog/shirne_dialog.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_info.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
import '../../utils/common.dart';
|
|
|
|
|
|
|
|
|
|
class PageParams {
|
|
|
|
|
int page;
|
|
|
|
|
int pageSize;
|
|
|
|
|
bool isLoading;
|
2025-08-26 17:38:59 +08:00
|
|
|
|
RxBool hasMore;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
int total;
|
|
|
|
|
bool isInitLoading;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
PageParams({
|
|
|
|
|
this.page = 1,
|
|
|
|
|
this.pageSize = 10,
|
|
|
|
|
this.isLoading = false,
|
2025-08-26 17:38:59 +08:00
|
|
|
|
bool hasMore = true,
|
2025-08-21 10:50:38 +08:00
|
|
|
|
this.total = 0,
|
|
|
|
|
this.isInitLoading = true,
|
2025-08-26 17:38:59 +08:00
|
|
|
|
}) : hasMore = hasMore.obs;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
|
|
|
|
|
void init() {
|
|
|
|
|
page = 1;
|
|
|
|
|
pageSize = 10;
|
|
|
|
|
isLoading = false;
|
2025-08-26 17:38:59 +08:00
|
|
|
|
hasMore.value = true;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
total = 0;
|
|
|
|
|
isInitLoading = true;
|
|
|
|
|
}
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MyPage extends StatefulWidget {
|
|
|
|
|
const MyPage({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
State<MyPage> createState() => MyPageState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
|
|
|
|
|
late RxInt currentTabIndex = 0.obs;
|
|
|
|
|
late RxList items = [].obs;
|
|
|
|
|
late RxList favoriteItems = [].obs;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
RxBool isLogin = Common.isLogin().obs;
|
|
|
|
|
//用户基本信息
|
|
|
|
|
// late Rx<V2TimUserFullInfo?> userInfo = Rx<V2TimUserFullInfo?>(null);
|
|
|
|
|
|
|
|
|
|
ImUserInfoController? imUserInfoController;
|
|
|
|
|
|
|
|
|
|
// 关注,互关,粉丝数量
|
|
|
|
|
late Rx<V2TimFollowInfo?> followInfo = Rx<V2TimFollowInfo?>(null);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
RxBool get shouldFixHeader => (currentTabIndex.value == 0 && items.isEmpty) || (currentTabIndex.value == 1 && favoriteItems.isEmpty) ? true.obs : false.obs;
|
|
|
|
|
|
|
|
|
|
List tabList = [
|
2025-08-21 10:50:38 +08:00
|
|
|
|
{'name': "作品"},
|
2025-07-21 15:46:30 +08:00
|
|
|
|
{'name': "喜欢"},
|
|
|
|
|
];
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
PageParams itemsParams = PageParams();
|
|
|
|
|
PageParams favoriteParams = PageParams();
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
late TabController tabController;
|
|
|
|
|
late ScrollController scrollController;
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
RxDouble positions = 0.0.obs;
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
late Callback tabListener;
|
|
|
|
|
late Callback scrollListener;
|
2025-09-17 11:51:54 +08:00
|
|
|
|
late int vlogLikeCount = 0; // 点赞数量
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
RxBool isPinned = false.obs; // 是否吸顶
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
initControllers();
|
|
|
|
|
|
|
|
|
|
scrollListener = () {
|
|
|
|
|
final pos = scrollController.position;
|
|
|
|
|
final isNearBottom = pos.pixels >= pos.maxScrollExtent - 100;
|
|
|
|
|
|
|
|
|
|
if (!isNearBottom) return;
|
|
|
|
|
|
2025-08-26 17:38:59 +08:00
|
|
|
|
if (currentTabIndex.value == 0 && !itemsParams.isLoading && itemsParams.hasMore.value) {
|
2025-07-21 15:46:30 +08:00
|
|
|
|
loadData(0);
|
2025-08-26 17:38:59 +08:00
|
|
|
|
} else if (currentTabIndex.value == 1 && !favoriteParams.isLoading && favoriteParams.hasMore.value) {
|
2025-07-21 15:46:30 +08:00
|
|
|
|
loadData(1);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
scrollController.addListener(scrollListener);
|
|
|
|
|
|
|
|
|
|
tabListener = () {
|
|
|
|
|
currentTabIndex.value = tabController.index;
|
|
|
|
|
if (tabController.index == 0 && items.isEmpty) {
|
|
|
|
|
loadData(0);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
scrollInnerList();
|
2025-07-21 15:46:30 +08:00
|
|
|
|
} else if (tabController.index == 1 && favoriteItems.isEmpty) {
|
|
|
|
|
loadData(1);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
scrollInnerList();
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
tabController.addListener(tabListener);
|
2025-09-17 15:07:05 +08:00
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// loadData(0);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
tabController.removeListener(tabListener);
|
|
|
|
|
scrollController.removeListener(scrollListener);
|
|
|
|
|
|
|
|
|
|
tabController.dispose();
|
|
|
|
|
scrollController.dispose();
|
|
|
|
|
super.dispose();
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-18 16:13:37 +08:00
|
|
|
|
// 获取用户的所有视频的点赞数量
|
2025-09-17 11:51:54 +08:00
|
|
|
|
void getUserLikesCount() async {
|
|
|
|
|
try {
|
|
|
|
|
final resData = await Http.get(CommonApi.accountInfo);
|
2025-09-18 16:13:37 +08:00
|
|
|
|
if (resData != null && resData['code'] == 200) {
|
|
|
|
|
vlogLikeCount = resData['data']['vlogLikeCount'] ?? 0;
|
2025-09-17 11:51:54 +08:00
|
|
|
|
}
|
2025-09-18 16:13:37 +08:00
|
|
|
|
} catch (e) {}
|
2025-09-17 11:51:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// 添加控制子列表滚动的方法
|
|
|
|
|
void scrollInnerList([double? offset]) async {
|
|
|
|
|
if (isPinned.value) {
|
|
|
|
|
// 如果已经吸顶,先给父滚动权限
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
|
isPinned.value = false;
|
|
|
|
|
// 直接滚动到指定位置
|
|
|
|
|
scrollController.jumpTo(positions.value);
|
|
|
|
|
// 重置滚动位置
|
|
|
|
|
positions.value = 0.0;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> loadData([int? tabIndex]) async {
|
2025-07-21 15:46:30 +08:00
|
|
|
|
final index = tabIndex ?? currentTabIndex.value;
|
|
|
|
|
if (index == 0) {
|
2025-08-26 17:38:59 +08:00
|
|
|
|
if (itemsParams.isLoading || !itemsParams.hasMore.value) return;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
itemsParams.isLoading = true;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// itemsParams.isInitLoading = true;
|
|
|
|
|
|
2025-08-26 17:38:59 +08:00
|
|
|
|
final res = await Http.post(VideoApi.myPublicList, data: {
|
|
|
|
|
"userId": imUserInfoController?.userID.value,
|
|
|
|
|
"yesOrNo": 0,
|
|
|
|
|
"current": itemsParams.page,
|
|
|
|
|
"size": itemsParams.pageSize,
|
|
|
|
|
});
|
|
|
|
|
final obj = res['data'];
|
|
|
|
|
final total = obj['total'];
|
|
|
|
|
final row = obj['records'] ?? [];
|
|
|
|
|
logger.i(res['data']);
|
|
|
|
|
// 判断是否还有更多数据
|
|
|
|
|
logger.e(items.length);
|
|
|
|
|
// 添加新数据,触发响应式更新
|
|
|
|
|
items.addAll(row);
|
|
|
|
|
logger.e(obj);
|
|
|
|
|
if (items.length >= total) {
|
|
|
|
|
itemsParams.hasMore.value = false;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
2025-08-26 17:38:59 +08:00
|
|
|
|
// 页码加一
|
|
|
|
|
itemsParams.page++;
|
|
|
|
|
//
|
|
|
|
|
itemsParams.isLoading = false;
|
|
|
|
|
itemsParams.isInitLoading = false;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
} else if (index == 1) {
|
2025-08-26 17:38:59 +08:00
|
|
|
|
if (favoriteParams.isLoading || !favoriteParams.hasMore.value) return;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
favoriteParams.isLoading = true;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// favoriteParams.isInitLoading = true;
|
|
|
|
|
|
2025-08-26 17:38:59 +08:00
|
|
|
|
final res = await Http.post(VideoApi.myLikedList, data: {
|
|
|
|
|
"userId": imUserInfoController?.userID.value,
|
|
|
|
|
"yesOrNo": 0,
|
|
|
|
|
"current": favoriteParams.page,
|
|
|
|
|
"size": favoriteParams.pageSize,
|
|
|
|
|
});
|
|
|
|
|
final obj = res['data'];
|
|
|
|
|
final total = obj['total'];
|
|
|
|
|
final row = obj['records'] ?? [];
|
|
|
|
|
favoriteItems.addAll(row);
|
|
|
|
|
|
|
|
|
|
if (favoriteItems.length >= total) {
|
|
|
|
|
favoriteParams.hasMore.value = false;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
2025-08-26 17:38:59 +08:00
|
|
|
|
|
|
|
|
|
favoriteParams.page++;
|
|
|
|
|
favoriteParams.isLoading = false;
|
|
|
|
|
favoriteParams.isInitLoading = false;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initControllers() {
|
|
|
|
|
tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this);
|
|
|
|
|
scrollController = ScrollController();
|
2025-08-21 10:50:38 +08:00
|
|
|
|
if (Common.isLogin()) {
|
|
|
|
|
imUserInfoController = Get.find<ImUserInfoController>();
|
|
|
|
|
}
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化页面数据
|
2025-08-21 10:50:38 +08:00
|
|
|
|
void refreshData([int? tabIndex]) async {
|
2025-07-21 15:46:30 +08:00
|
|
|
|
if (!mounted) {
|
|
|
|
|
logger.i('未挂载');
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-08-21 10:50:38 +08:00
|
|
|
|
isLogin.value = Common.isLogin();
|
2025-07-21 15:46:30 +08:00
|
|
|
|
if (!Common.isLogin()) return;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
final idx = tabIndex ?? currentTabIndex.value;
|
|
|
|
|
// 恢复位置
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
|
scrollInnerList();
|
|
|
|
|
});
|
2025-07-21 15:46:30 +08:00
|
|
|
|
items.clear();
|
|
|
|
|
favoriteItems.clear();
|
2025-08-21 10:50:38 +08:00
|
|
|
|
itemsParams.init();
|
|
|
|
|
favoriteParams.init();
|
|
|
|
|
// currentTabIndex.value = 0;
|
2025-07-21 15:46:30 +08:00
|
|
|
|
selfInfo();
|
2025-09-17 15:07:05 +08:00
|
|
|
|
getUserLikesCount();
|
2025-08-21 10:50:38 +08:00
|
|
|
|
loadData(idx);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取当前登录用户基本信息
|
|
|
|
|
void selfInfo() async {
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// imUserInfoController = Get.find<ImUserInfoController>();
|
2025-08-26 17:38:59 +08:00
|
|
|
|
if (!Get.isRegistered<ImUserInfoController>()) {
|
|
|
|
|
logger.e('用户信息controller未注册');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
final res = await ImService.instance.getUserFollowInfo(userIDList: [imUserInfoController?.userID.value ?? '']);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
if (res.success) {
|
|
|
|
|
//这里少个点赞,从服务端获取
|
|
|
|
|
// followersCount粉丝,多少人关注了我,mutualFollowersCount互关,followingCount我关注了多少人
|
|
|
|
|
followInfo.value = res.data!.first;
|
|
|
|
|
logger.i(followInfo.value!.toJson());
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-18 16:13:37 +08:00
|
|
|
|
// 删除当前用户发布的视频
|
2025-09-18 15:33:14 +08:00
|
|
|
|
// 删除当前用户发布的视频
|
2025-09-15 17:18:10 +08:00
|
|
|
|
void deletePersonalVideo(videoId) async {
|
2025-09-18 16:13:37 +08:00
|
|
|
|
logger.i('删除视频$videoId');
|
2025-09-15 17:18:10 +08:00
|
|
|
|
try {
|
2025-09-18 16:13:37 +08:00
|
|
|
|
final res = await Http.post('${VideoApi.deleteVideo}?id=$videoId', data: {});
|
|
|
|
|
logger.i('删除成功响应$res');
|
|
|
|
|
if (res != null && res['code'] == 200) {
|
2025-09-18 15:33:14 +08:00
|
|
|
|
MyDialog.toast('删除成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200)));
|
|
|
|
|
loadData(0);
|
|
|
|
|
}
|
2025-09-18 16:13:37 +08:00
|
|
|
|
} catch (e) {}
|
2025-09-15 17:18:10 +08:00
|
|
|
|
}
|
2025-09-18 15:33:14 +08:00
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
// 二维码名片弹窗
|
|
|
|
|
void qrcodeAlertDialog(BuildContext context) {
|
2025-09-22 14:41:47 +08:00
|
|
|
|
final role = imUserInfoController?.role.value ?? 0;
|
|
|
|
|
final isLeader = Utils.hasRole(role, 5);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
builder: (context) {
|
|
|
|
|
return UnconstrainedBox(
|
|
|
|
|
constrainedAxis: Axis.vertical,
|
|
|
|
|
child: SizedBox(
|
|
|
|
|
width: 350.0,
|
|
|
|
|
child: AlertDialog(
|
|
|
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
|
2025-09-22 14:41:47 +08:00
|
|
|
|
backgroundColor: Colors.white,
|
2025-07-21 15:46:30 +08:00
|
|
|
|
surfaceTintColor: Colors.white,
|
|
|
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
|
|
|
|
|
content: Padding(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
2025-09-22 14:41:47 +08:00
|
|
|
|
MyQrcode(
|
|
|
|
|
prefix: QrTypeCode.tgm,
|
|
|
|
|
text: isLeader ? '推广码' : '',
|
|
|
|
|
),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 退出登录弹窗
|
|
|
|
|
void showLogoutDialog(BuildContext context) {
|
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
builder: (context) {
|
|
|
|
|
return AlertDialog(
|
|
|
|
|
content: const Text('确认退出当前账号吗?', style: TextStyle(fontSize: 16.0)),
|
|
|
|
|
backgroundColor: Colors.white,
|
|
|
|
|
surfaceTintColor: Colors.white,
|
|
|
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
|
|
|
|
|
elevation: 2.0,
|
|
|
|
|
actionsPadding: const EdgeInsets.all(15.0),
|
|
|
|
|
actions: [
|
|
|
|
|
TextButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
Get.back();
|
|
|
|
|
},
|
|
|
|
|
child: const Text('取消', style: TextStyle(color: Colors.black54)),
|
|
|
|
|
),
|
|
|
|
|
TextButton(onPressed: handleLogout, child: const Text('退出登录', style: TextStyle(color: Colors.red))),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 退出登录
|
|
|
|
|
void handleLogout() async {
|
|
|
|
|
final loginRes = await ImService.instance.logout();
|
|
|
|
|
if (loginRes.success) {
|
|
|
|
|
// 清除存储信息
|
|
|
|
|
Common.logout();
|
|
|
|
|
// 初始化视频
|
|
|
|
|
final videoController = Get.find<VideoModuleController>();
|
|
|
|
|
videoController.init();
|
|
|
|
|
Get.back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// 如果没登录,直接返回一个登录提示页面
|
|
|
|
|
return Obx(() {
|
|
|
|
|
if (!isLogin.value) {
|
|
|
|
|
return SizedBox();
|
|
|
|
|
} else {
|
|
|
|
|
return Scaffold(
|
|
|
|
|
backgroundColor: const Color(0xFFFAF6F9),
|
2025-08-26 17:38:59 +08:00
|
|
|
|
body: NestedScrollViewPlus(
|
|
|
|
|
controller: scrollController,
|
|
|
|
|
physics: shouldFixHeader.value
|
|
|
|
|
? OnlyDownScrollPhysics(parent: AlwaysScrollableScrollPhysics())
|
|
|
|
|
: isPinned.value
|
|
|
|
|
? NeverScrollableScrollPhysics()
|
|
|
|
|
: AlwaysScrollableScrollPhysics(),
|
|
|
|
|
// physics: shouldFixHeader.value ? OnlyDownScrollPhysics(parent: AlwaysScrollableScrollPhysics()) : AlwaysScrollableScrollPhysics(),
|
|
|
|
|
overscrollBehavior: OverscrollBehavior.outer,
|
|
|
|
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
|
|
|
|
return [
|
|
|
|
|
SliverAppBar(
|
|
|
|
|
backgroundColor: Colors.transparent,
|
|
|
|
|
surfaceTintColor: Colors.transparent,
|
|
|
|
|
expandedHeight: 180.0,
|
|
|
|
|
collapsedHeight: 120.0,
|
|
|
|
|
pinned: true,
|
|
|
|
|
stretch: true,
|
|
|
|
|
onStretchTrigger: () async {
|
|
|
|
|
logger.i('触发 stretch 拉伸');
|
|
|
|
|
// 加载刷新逻辑
|
|
|
|
|
},
|
|
|
|
|
actions: [
|
|
|
|
|
// _buildIcon('assets/images/svg/service.svg', () {
|
|
|
|
|
// logger.i('点击客服按钮');
|
|
|
|
|
// }),
|
|
|
|
|
const SizedBox(width: 8.0),
|
|
|
|
|
_buildIcon('assets/images/svg/setting.svg', () {
|
|
|
|
|
logger.i('点击设置按钮');
|
|
|
|
|
Get.toNamed('/setting');
|
|
|
|
|
}),
|
|
|
|
|
const SizedBox(width: 10.0),
|
|
|
|
|
],
|
|
|
|
|
flexibleSpace: _buildFlexibleSpace(),
|
|
|
|
|
),
|
|
|
|
|
SliverToBoxAdapter(
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.all(10.0),
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
2025-09-03 11:25:31 +08:00
|
|
|
|
const SizedBox(height: 10),
|
2025-08-26 17:38:59 +08:00
|
|
|
|
Obx(() => _buildStatsCard()),
|
2025-09-03 11:25:31 +08:00
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
|
Obx(() => _buildInfoDesc(context)),
|
2025-08-26 17:38:59 +08:00
|
|
|
|
const SizedBox(height: 10.0),
|
|
|
|
|
_buildOrderCard(context),
|
|
|
|
|
const SizedBox(height: 10.0),
|
|
|
|
|
],
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
|
|
|
|
),
|
2025-08-26 17:38:59 +08:00
|
|
|
|
),
|
|
|
|
|
SliverPersistentHeader(
|
|
|
|
|
pinned: true,
|
|
|
|
|
delegate: CustomStickyHeader(
|
|
|
|
|
isPinned: isPinned,
|
|
|
|
|
positions: positions,
|
|
|
|
|
child: PreferredSize(
|
|
|
|
|
preferredSize: const Size.fromHeight(48.0),
|
|
|
|
|
child: Container(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
child: TabBar(
|
|
|
|
|
controller: tabController,
|
|
|
|
|
tabs: tabList.map((item) {
|
|
|
|
|
return Tab(
|
|
|
|
|
child: Badge.count(
|
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
|
count: item['badge'] ?? 0,
|
|
|
|
|
isLabelVisible: item['badge'] != null,
|
|
|
|
|
alignment: Alignment.topRight,
|
|
|
|
|
offset: const Offset(14, -6),
|
|
|
|
|
child: Text(item['name'], style: const TextStyle(fontWeight: FontWeight.bold)),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}).toList(),
|
|
|
|
|
isScrollable: false,
|
|
|
|
|
overlayColor: WidgetStateProperty.all(Colors.transparent),
|
|
|
|
|
unselectedLabelColor: Colors.black87,
|
|
|
|
|
labelColor: const Color(0xFFFF5000),
|
|
|
|
|
indicator: const UnderlineTabIndicator(borderSide: BorderSide(color: Color(0xFFFF5000), width: 2.0)),
|
|
|
|
|
indicatorSize: TabBarIndicatorSize.tab,
|
|
|
|
|
unselectedLabelStyle: const TextStyle(fontSize: 16.0, fontFamily: 'Microsoft YaHei'),
|
|
|
|
|
labelStyle: const TextStyle(fontSize: 18.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.bold),
|
|
|
|
|
dividerHeight: 0,
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
|
|
|
labelPadding: const EdgeInsets.symmetric(horizontal: 15.0),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2025-08-26 17:38:59 +08:00
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
},
|
|
|
|
|
body: TabBarView(
|
|
|
|
|
controller: tabController,
|
|
|
|
|
children: [
|
|
|
|
|
// Tab 1:
|
|
|
|
|
_buildGridTab(0),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
2025-08-26 17:38:59 +08:00
|
|
|
|
// Tab 2:
|
|
|
|
|
_buildGridTab(1)
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 空状态提示
|
|
|
|
|
Widget emptyTip(String text) {
|
|
|
|
|
return CustomScrollView(
|
|
|
|
|
physics: const OnlyDownScrollPhysics(),
|
|
|
|
|
slivers: [
|
|
|
|
|
SliverFillRemaining(
|
|
|
|
|
hasScrollBody: false,
|
|
|
|
|
child: Align(
|
|
|
|
|
alignment: Alignment.topCenter,
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.only(top: 50.0),
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
|
|
|
|
Image.asset('assets/images/empty.png', width: 100.0),
|
|
|
|
|
const SizedBox(height: 8.0),
|
|
|
|
|
Text(
|
|
|
|
|
text,
|
|
|
|
|
style: const TextStyle(color: Colors.grey, fontSize: 13.0),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 11:25:31 +08:00
|
|
|
|
Widget _buildInfoDesc(BuildContext context) {
|
|
|
|
|
final tx = imUserInfoController?.signature;
|
|
|
|
|
if (tx == null || tx.isEmpty) {
|
|
|
|
|
return const SizedBox.shrink();
|
|
|
|
|
}
|
|
|
|
|
return Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
|
|
|
boxShadow: [BoxShadow(color: Colors.black.withAlpha(10), offset: const Offset(0.0, 1.0), blurRadius: 2.0, spreadRadius: 0.0)],
|
|
|
|
|
),
|
|
|
|
|
clipBehavior: Clip.antiAlias,
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Container(
|
|
|
|
|
padding: const EdgeInsets.all(12),
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
|
|
),
|
|
|
|
|
child: Text(
|
|
|
|
|
'${imUserInfoController!.signature}',
|
|
|
|
|
style: const TextStyle(fontSize: 16),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
Widget _buildGridTab(int tabIndex) {
|
|
|
|
|
final listToShow = tabIndex == 0 ? items : favoriteItems;
|
2025-08-21 10:50:38 +08:00
|
|
|
|
PageParams params = tabIndex == 0 ? itemsParams : favoriteParams;
|
|
|
|
|
if (params.isInitLoading) {
|
|
|
|
|
return Center(child: CircularProgressIndicator());
|
|
|
|
|
}
|
2025-07-21 15:46:30 +08:00
|
|
|
|
if (listToShow.isEmpty) {
|
|
|
|
|
return emptyTip('暂无相关数据');
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
return Obx(() {
|
|
|
|
|
return CustomScrollView(
|
|
|
|
|
// physics: !isPinned.value ? NeverScrollableScrollPhysics() : AlwaysScrollableScrollPhysics(),
|
|
|
|
|
// physics: AlwaysScrollableScrollPhysics(),
|
|
|
|
|
key: PageStorageKey('myindex_$tabIndex'),
|
|
|
|
|
slivers: [
|
|
|
|
|
SliverPadding(
|
|
|
|
|
padding: EdgeInsets.all(10.0),
|
|
|
|
|
sliver: SliverGrid(
|
|
|
|
|
delegate: SliverChildBuilderDelegate(
|
|
|
|
|
(context, index) {
|
|
|
|
|
return Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.blue[100 * ((index % 8) + 1)],
|
|
|
|
|
borderRadius: BorderRadius.circular(10.0),
|
|
|
|
|
),
|
|
|
|
|
alignment: Alignment.center,
|
2025-09-18 16:13:37 +08:00
|
|
|
|
child: _buildVdCard(listToShow[index], tabIndex),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
childCount: listToShow.length,
|
|
|
|
|
),
|
|
|
|
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
|
|
|
crossAxisCount: 3,
|
|
|
|
|
crossAxisSpacing: 10.0,
|
|
|
|
|
mainAxisSpacing: 10.0,
|
|
|
|
|
childAspectRatio: 0.6,
|
|
|
|
|
),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
),
|
|
|
|
|
SliverToBoxAdapter(
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 20.0),
|
|
|
|
|
child: Center(
|
2025-08-26 17:38:59 +08:00
|
|
|
|
child: params.hasMore.value ? CircularProgressIndicator() : Text('没有更多数据了'),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
|
|
|
|
),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-18 16:13:37 +08:00
|
|
|
|
Widget _buildVdCard(item, tabIndex) {
|
2025-08-21 10:50:38 +08:00
|
|
|
|
return InkWell(
|
|
|
|
|
onTap: () {
|
|
|
|
|
//去视频详情
|
2025-09-09 10:57:52 +08:00
|
|
|
|
Get.toNamed('/videoDetail', arguments: {'videoId': item['id']});
|
2025-08-21 10:50:38 +08:00
|
|
|
|
},
|
|
|
|
|
onLongPress: () {
|
2025-09-18 16:13:37 +08:00
|
|
|
|
if (tabIndex == 0) {
|
|
|
|
|
// 个人发布作品可以长按删除
|
2025-09-15 17:18:10 +08:00
|
|
|
|
showModalBottomSheet(
|
2025-09-18 16:13:37 +08:00
|
|
|
|
context: Get.context!,
|
|
|
|
|
backgroundColor: Colors.white,
|
|
|
|
|
shape: const RoundedRectangleBorder(
|
|
|
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
|
|
|
|
),
|
|
|
|
|
builder: (context) {
|
|
|
|
|
return SafeArea(
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
children: [
|
|
|
|
|
// ListTile(
|
|
|
|
|
// leading: const Icon(Icons.lock, color: Colors.black),
|
|
|
|
|
// title: const Text('设为私密', style: TextStyle(color: Colors.black)),
|
|
|
|
|
// onTap: () {
|
|
|
|
|
// Navigator.pop(context);
|
|
|
|
|
// // TODO: 修改为私密逻辑
|
|
|
|
|
// },
|
|
|
|
|
// ),
|
|
|
|
|
ListTile(
|
|
|
|
|
leading: const Icon(Icons.delete, color: Colors.redAccent),
|
|
|
|
|
title: const Text('删除视频', style: TextStyle(color: Colors.redAccent)),
|
|
|
|
|
onTap: () async {
|
|
|
|
|
Get.back();
|
|
|
|
|
final confirmed = await ConfirmDialog.show(
|
|
|
|
|
title: "提示",
|
|
|
|
|
content: "确认要删除吗?",
|
|
|
|
|
);
|
|
|
|
|
if (confirmed == true) {
|
|
|
|
|
Get.back();
|
|
|
|
|
deletePersonalVideo(item['id']);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
2025-09-15 17:18:10 +08:00
|
|
|
|
}
|
2025-08-21 10:50:38 +08:00
|
|
|
|
},
|
|
|
|
|
child: Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
borderRadius: BorderRadius.circular(12.0),
|
|
|
|
|
color: Colors.grey[900],
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
child: Stack(
|
|
|
|
|
children: [
|
|
|
|
|
/// 视频缩略图
|
|
|
|
|
ClipRRect(
|
|
|
|
|
borderRadius: BorderRadius.circular(12.0),
|
2025-09-13 17:01:01 +08:00
|
|
|
|
child: NetworkOrAssetImage(
|
|
|
|
|
imageUrl: item['cover'] ?? item['firstFrameImg'] ?? '',
|
|
|
|
|
placeholderAsset: 'assets/images/bk.jpg',
|
2025-08-21 10:50:38 +08:00
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
height: double.infinity,
|
|
|
|
|
),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
|
|
|
|
|
/// 右下角的点赞数
|
|
|
|
|
Positioned(
|
|
|
|
|
right: 8,
|
|
|
|
|
bottom: 8,
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
const Icon(Icons.favorite, color: Colors.white, size: 16),
|
|
|
|
|
const SizedBox(width: 4),
|
|
|
|
|
Text(
|
|
|
|
|
'${item['likeCounts'] ?? 0}',
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
fontSize: 12,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildIcon(String assetPath, VoidCallback onTap) {
|
|
|
|
|
return InkWell(
|
|
|
|
|
onTap: onTap,
|
|
|
|
|
child: Container(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
|
|
|
|
|
decoration: BoxDecoration(color: Colors.black.withAlpha((0.3 * 255).round()), borderRadius: BorderRadius.circular(20.0)),
|
|
|
|
|
child: SvgPicture.asset(assetPath, height: 20.0, width: 20.0, colorFilter: const ColorFilter.mode(Colors.white70, BlendMode.srcIn)),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildFlexibleSpace() {
|
|
|
|
|
return LayoutBuilder(
|
2025-08-26 17:38:59 +08:00
|
|
|
|
builder: (context, constraints) {
|
|
|
|
|
final double maxHeight = 180;
|
|
|
|
|
final double minHeight = 120;
|
|
|
|
|
final currentHeight = constraints.maxHeight;
|
|
|
|
|
double ratio = ((currentHeight - minHeight) / (maxHeight - minHeight)).clamp(0.0, 1.0);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
return Stack(
|
|
|
|
|
fit: StackFit.expand,
|
|
|
|
|
children: [
|
2025-08-26 17:38:59 +08:00
|
|
|
|
// 背景图 Obx
|
|
|
|
|
Obx(() {
|
|
|
|
|
final bgUrl = imUserInfoController?.customInfo['coverBg'] ?? '';
|
|
|
|
|
return NetworkOrAssetImage(
|
|
|
|
|
imageUrl: bgUrl,
|
|
|
|
|
placeholderAsset: 'assets/images/bk.jpg',
|
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
|
);
|
|
|
|
|
}),
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
Positioned(
|
2025-08-26 17:38:59 +08:00
|
|
|
|
left: 15,
|
2025-07-21 15:46:30 +08:00
|
|
|
|
bottom: 0,
|
2025-08-26 17:38:59 +08:00
|
|
|
|
right: 15,
|
2025-07-21 15:46:30 +08:00
|
|
|
|
child: Container(
|
2025-08-26 17:38:59 +08:00
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
child: Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
2025-08-26 17:38:59 +08:00
|
|
|
|
children: [
|
|
|
|
|
// 头像 Obx
|
|
|
|
|
Obx(() {
|
|
|
|
|
final faceUrl = imUserInfoController?.faceUrl.value ?? '';
|
|
|
|
|
return ClipOval(
|
|
|
|
|
child: NetworkOrAssetImage(
|
|
|
|
|
imageUrl: faceUrl,
|
|
|
|
|
width: 80,
|
|
|
|
|
height: 80,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}),
|
|
|
|
|
const SizedBox(width: 15),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
Expanded(
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
2025-08-26 17:38:59 +08:00
|
|
|
|
// 昵称 Obx
|
2025-09-18 16:13:37 +08:00
|
|
|
|
Obx(
|
|
|
|
|
() {
|
|
|
|
|
final nickname = imUserInfoController?.nickname.value ?? '';
|
|
|
|
|
return Container(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.black.withAlpha(76),
|
|
|
|
|
borderRadius: BorderRadius.circular(20),
|
|
|
|
|
),
|
|
|
|
|
child: Text(
|
|
|
|
|
nickname.isNotEmpty ? nickname : '昵称',
|
2025-09-22 14:41:47 +08:00
|
|
|
|
// '啊啊啊啊啊啊啊啊',
|
2025-09-18 16:13:37 +08:00
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontSize: 20,
|
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
),
|
2025-08-21 10:50:38 +08:00
|
|
|
|
),
|
2025-09-18 16:13:37 +08:00
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
// 团长的二维码
|
2025-09-22 14:41:47 +08:00
|
|
|
|
// Obx(
|
|
|
|
|
// () {
|
|
|
|
|
// // MERCHANT(2, "商家"),
|
|
|
|
|
// // AGENT(3, "代理"),
|
|
|
|
|
// // PLATFORM(4, "平台"),
|
|
|
|
|
// // REFERENCE(5, "团长")
|
|
|
|
|
// final role = imUserInfoController?.role.value;
|
|
|
|
|
// final isLeader = Utils.hasRole(role ?? 0, 5);
|
|
|
|
|
// if (!isLeader) {
|
|
|
|
|
// return Row(children: [
|
|
|
|
|
// SizedBox(width: 8),
|
|
|
|
|
// //
|
|
|
|
|
// InkWell(
|
|
|
|
|
// onTap: () => qrcodeAlertDialog(context),
|
|
|
|
|
// child: Container(
|
|
|
|
|
// padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
|
|
|
|
// decoration: BoxDecoration(
|
|
|
|
|
// color: Colors.black.withAlpha(176),
|
|
|
|
|
// borderRadius: BorderRadius.circular(20),
|
|
|
|
|
// ),
|
|
|
|
|
// child: Row(
|
|
|
|
|
// children: [
|
|
|
|
|
// Icon(
|
|
|
|
|
// Icons.qr_code_outlined,
|
|
|
|
|
// size: 18,
|
|
|
|
|
// color: FStyle.secondaryColor,
|
|
|
|
|
// ),
|
|
|
|
|
// SizedBox(width: 4),
|
|
|
|
|
// Text(
|
|
|
|
|
// '团长邀请码',
|
|
|
|
|
// style: TextStyle(
|
|
|
|
|
// fontSize: 12,
|
|
|
|
|
// fontWeight: FontWeight.bold,
|
|
|
|
|
// color: FStyle.secondaryColor, // 彩色文字
|
|
|
|
|
// ),
|
|
|
|
|
// )
|
|
|
|
|
// ],
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// ),
|
|
|
|
|
// ]);
|
|
|
|
|
// } else {
|
|
|
|
|
// return const SizedBox();
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// ),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
],
|
|
|
|
|
),
|
2025-08-26 17:38:59 +08:00
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
|
// 用户ID Obx
|
|
|
|
|
Obx(() {
|
|
|
|
|
final userId = imUserInfoController?.userID.value ?? '';
|
|
|
|
|
return Container(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.black.withAlpha(76),
|
|
|
|
|
borderRadius: BorderRadius.circular(20),
|
|
|
|
|
),
|
|
|
|
|
child: InkWell(
|
|
|
|
|
onTap: () {
|
|
|
|
|
Clipboard.setData(ClipboardData(text: userId));
|
|
|
|
|
MyDialog.toast(
|
|
|
|
|
'ID已复制',
|
|
|
|
|
icon: const Icon(Icons.check_circle),
|
|
|
|
|
style: ToastStyle(backgroundColor: Colors.green.withAlpha(200)),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
child: Text('ID:$userId', style: const TextStyle(fontSize: 12, color: Colors.white)),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildStatsCard() {
|
|
|
|
|
return Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
|
|
|
boxShadow: [BoxShadow(color: Colors.black.withAlpha(10), offset: const Offset(0.0, 1.0), blurRadius: 2.0, spreadRadius: 0.0)],
|
|
|
|
|
),
|
|
|
|
|
clipBehavior: Clip.antiAlias,
|
|
|
|
|
child: Padding(
|
2025-08-21 10:50:38 +08:00
|
|
|
|
padding: const EdgeInsets.all(10.0),
|
|
|
|
|
child: Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
|
|
|
children: [
|
2025-09-17 11:51:54 +08:00
|
|
|
|
// '已售${Utils.graceNumber(int.tryParse(vlogLikeCount?.toString() ?? '0') ?? 0)}',
|
2025-09-18 16:13:37 +08:00
|
|
|
|
Column(children: [
|
|
|
|
|
Text(Utils.graceNumber(vlogLikeCount), style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
|
|
|
|
|
SizedBox(height: 3.0),
|
|
|
|
|
Text('获赞')
|
|
|
|
|
]),
|
2025-09-03 11:25:31 +08:00
|
|
|
|
GestureDetector(
|
|
|
|
|
onTap: () async {
|
|
|
|
|
// 互相关注
|
|
|
|
|
await Get.toNamed('/eachFlow');
|
|
|
|
|
refreshData();
|
|
|
|
|
},
|
|
|
|
|
child: Column(children: [
|
|
|
|
|
Text('${followInfo.value?.mutualFollowersCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
|
|
|
|
|
SizedBox(height: 3.0),
|
|
|
|
|
Text('互关')
|
|
|
|
|
]),
|
|
|
|
|
),
|
|
|
|
|
GestureDetector(
|
|
|
|
|
onTap: () async {
|
|
|
|
|
// 关注
|
|
|
|
|
await Get.toNamed('/flow');
|
|
|
|
|
refreshData();
|
|
|
|
|
},
|
|
|
|
|
child: Column(children: [
|
|
|
|
|
Text('${followInfo.value?.followingCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
|
|
|
|
|
SizedBox(height: 3.0),
|
|
|
|
|
Text('关注')
|
|
|
|
|
]),
|
|
|
|
|
),
|
|
|
|
|
GestureDetector(
|
|
|
|
|
onTap: () async {
|
|
|
|
|
await Get.toNamed('/fans');
|
|
|
|
|
refreshData();
|
|
|
|
|
},
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'${followInfo.value?.followersCount ?? 0}',
|
|
|
|
|
style: const TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 3.0),
|
|
|
|
|
const Text('粉丝'),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
)
|
2025-08-21 10:50:38 +08:00
|
|
|
|
],
|
|
|
|
|
)),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildOrderCard(BuildContext context) {
|
2025-09-22 14:41:47 +08:00
|
|
|
|
final role = imUserInfoController?.role.value ?? 0;
|
|
|
|
|
final isLeader = Utils.hasRole(role, 5);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
return Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
borderRadius: BorderRadius.circular(15.0),
|
|
|
|
|
boxShadow: [BoxShadow(color: Colors.black.withAlpha(10), offset: const Offset(0.0, 1.0), blurRadius: 2.0, spreadRadius: 0.0)],
|
|
|
|
|
),
|
|
|
|
|
clipBehavior: Clip.antiAlias,
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
|
|
|
|
GestureDetector(
|
|
|
|
|
child: Container(
|
|
|
|
|
padding: const EdgeInsets.all(10.0),
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Image.asset('assets/images/more.png', width: 16.0),
|
|
|
|
|
const SizedBox(width: 5.0),
|
|
|
|
|
const Text('常用功能', style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold)),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
const Spacer(),
|
|
|
|
|
const Text('全部', style: TextStyle(color: Colors.grey, fontSize: 12.0)),
|
|
|
|
|
const Icon(Icons.arrow_forward_ios_rounded, color: Colors.grey, size: 12.0),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
2025-09-11 16:42:35 +08:00
|
|
|
|
onTap: () {
|
|
|
|
|
Get.toNamed('/functions');
|
|
|
|
|
},
|
2025-07-21 15:46:30 +08:00
|
|
|
|
),
|
|
|
|
|
Padding(
|
|
|
|
|
padding: const EdgeInsets.all(10.0),
|
|
|
|
|
child: Row(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
|
|
|
children: [
|
|
|
|
|
_buildOrderIcon('assets/images/ico_order.png', '订单', () {
|
2025-09-12 17:23:08 +08:00
|
|
|
|
Get.toNamed('/myOrder');
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}),
|
2025-09-22 14:41:47 +08:00
|
|
|
|
_buildOrderIcon('assets/images/ico_dhx.png', '余额', () {
|
|
|
|
|
Get.put(BalanceController());
|
|
|
|
|
Get.to(() => Balance());
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}),
|
2025-09-22 14:41:47 +08:00
|
|
|
|
_buildOrderIcon('assets/images/ico_tgm.png', isLeader ? '推广码' : '好友码', () {
|
|
|
|
|
qrcodeAlertDialog(context);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
}),
|
2025-09-22 14:41:47 +08:00
|
|
|
|
_buildOrderIcon('assets/images/icon_logout.png', '退出登录', () {
|
|
|
|
|
showLogoutDialog(context);
|
2025-08-26 17:38:59 +08:00
|
|
|
|
}),
|
2025-07-21 15:46:30 +08:00
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget _buildOrderIcon(String assetPath, String label, VoidCallback onTap) {
|
|
|
|
|
return GestureDetector(
|
|
|
|
|
onTap: onTap,
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
|
|
|
|
Image.asset(assetPath, width: 24.0),
|
|
|
|
|
const SizedBox(height: 3.0),
|
|
|
|
|
Text(label),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|