flutter/lib/pages/my/index.dart

808 lines
28 KiB
Dart
Raw Normal View History

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-08-21 10:50:38 +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-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-08-21 10:50:38 +08:00
import 'package:loopin/service/http.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;
bool 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,
this.hasMore = true,
2025-08-21 10:50:38 +08:00
this.total = 0,
this.isInitLoading = true,
2025-07-21 15:46:30 +08:00
});
2025-08-21 10:50:38 +08:00
void init() {
page = 1;
pageSize = 10;
isLoading = false;
hasMore = true;
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-08-21 10:50:38 +08:00
RxBool isPinned = false.obs; // 是否吸顶
2025-07-21 15:46:30 +08:00
@override
void initState() {
super.initState();
2025-08-21 10:50:38 +08:00
2025-07-21 15:46:30 +08:00
initControllers();
scrollListener = () {
final pos = scrollController.position;
final isNearBottom = pos.pixels >= pos.maxScrollExtent - 100;
if (!isNearBottom) return;
if (currentTabIndex.value == 0 && !itemsParams.isLoading && itemsParams.hasMore) {
loadData(0);
} else if (currentTabIndex.value == 1 && !favoriteParams.isLoading && favoriteParams.hasMore) {
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-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-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) {
if (itemsParams.isLoading || !itemsParams.hasMore) return;
itemsParams.isLoading = true;
2025-08-21 10:50:38 +08:00
// itemsParams.isInitLoading = true;
try {
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['rows'];
logger.i(res['data']);
// 判断是否还有更多数据
if (items.length >= total) {
itemsParams.hasMore = false;
}
// 添加新数据,触发响应式更新
items.addAll(row);
// 页码加一
itemsParams.page++;
} finally {
itemsParams.isLoading = false;
itemsParams.isInitLoading = false;
2025-07-21 15:46:30 +08:00
}
} else if (index == 1) {
if (favoriteParams.isLoading || !favoriteParams.hasMore) return;
favoriteParams.isLoading = true;
2025-08-21 10:50:38 +08:00
// favoriteParams.isInitLoading = true;
try {
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['rows'];
if (favoriteItems.length >= total) {
itemsParams.hasMore = false;
}
favoriteItems.addAll(row);
favoriteParams.page++;
} finally {
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-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>();
final res = await ImService.instance.getUserFollowInfo(userIDList: [imUserInfoController!.userID.value]);
if (res.success) {
//这里少个点赞,从服务端获取
// followersCount粉丝多少人关注了我,mutualFollowersCount互关,followingCount我关注了多少人
followInfo.value = res.data!.first;
logger.i(followInfo.value!.toJson());
2025-07-21 15:46:30 +08:00
}
}
// 二维码名片弹窗
void qrcodeAlertDialog(BuildContext context) {
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),
backgroundColor: const Color(0xff07c160),
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: [
Image.asset('assets/images/pic1.jpg', width: 250.0, fit: BoxFit.contain),
const SizedBox(height: 15.0),
const Text('扫一扫,加好友',
style: TextStyle(
color: Colors.white38,
fontSize: 14.0,
)),
],
),
),
),
),
);
},
);
}
// 退出登录弹窗
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),
body: Obx(() {
return 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),
2025-07-21 15:46:30 +08:00
],
2025-08-21 10:50:38 +08:00
flexibleSpace: _buildFlexibleSpace(),
2025-07-21 15:46:30 +08:00
),
2025-08-21 10:50:38 +08:00
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Obx(() => _buildStatsCard()),
const SizedBox(height: 10.0),
_buildOrderCard(context),
const SizedBox(height: 10.0),
],
2025-07-21 15:46:30 +08:00
),
),
),
2025-08-21 10:50:38 +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),
),
),
),
),
),
];
},
body: TabBarView(
controller: tabController,
children: [
// Tab 1:
_buildGridTab(0),
2025-07-21 15:46:30 +08:00
2025-08-21 10:50:38 +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),
),
],
),
),
),
),
],
);
}
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,
child: _buildVdCard(listToShow[index]),
);
},
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(
child: params.hasMore ? const CircularProgressIndicator() : const Text('没有更多数据了'),
),
2025-07-21 15:46:30 +08:00
),
),
2025-08-21 10:50:38 +08:00
],
);
});
}
Widget _buildVdCard(item) {
return InkWell(
onTap: () {
//去视频详情
},
onLongPress: () {
showModalBottomSheet(
context: Get.context!,
backgroundColor: Colors.black.withOpacity(0.8),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: const Icon(Icons.lock, color: Colors.white),
title: const Text('设为私密', style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
// TODO: 修改为私密逻辑
},
),
ListTile(
leading: const Icon(Icons.delete, color: Colors.redAccent),
title: const Text('删除视频', style: TextStyle(color: Colors.redAccent)),
onTap: () {
Navigator.pop(context);
// TODO: 删除逻辑
},
),
],
);
},
);
},
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),
child: Image.network(
item['cover'] ?? item['firstFrameImg'],
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(
builder: (BuildContext context, BoxConstraints constraints) {
final double maxHeight = 180.0;
2025-08-21 10:50:38 +08:00
final double minHeight = 120.0;
2025-07-21 15:46:30 +08:00
final double currentHeight = constraints.maxHeight;
double ratio = (currentHeight - minHeight) / (maxHeight - minHeight);
ratio = ratio.clamp(0.0, 1.0);
return Stack(
fit: StackFit.expand,
children: [
2025-08-21 10:50:38 +08:00
Positioned.fill(
child: Opacity(
opacity: 1.0,
child: NetworkOrAssetImage(imageUrl: imUserInfoController?.customInfo['coverBg'], placeholderAsset: 'assets/images/bk.jpg'),
),
),
2025-07-21 15:46:30 +08:00
Positioned(
left: 15.0,
bottom: 0,
right: 15.0,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
2025-08-21 10:50:38 +08:00
ClipOval(
child: Obx(() {
final faceUrl = imUserInfoController?.faceUrl.value;
return ClipRRect(
borderRadius: BorderRadius.circular(30),
child: NetworkOrAssetImage(
imageUrl: faceUrl,
width: 80,
height: 80,
),
);
}),
),
2025-07-21 15:46:30 +08:00
const SizedBox(width: 15.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
2025-08-21 10:50:38 +08:00
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
decoration: BoxDecoration(color: Colors.black.withAlpha((0.3 * 255).round()), borderRadius: BorderRadius.circular(20.0)),
child: Obx(
() => Text(
imUserInfoController!.nickname.value.isNotEmpty == true ? imUserInfoController!.nickname.value : '昵称',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold, fontFamily: 'Arial', color: Colors.white),
),
)),
2025-07-21 15:46:30 +08:00
const SizedBox(width: 8.0),
InkWell(
onTap: () {
qrcodeAlertDialog(context);
},
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: const Icon(Icons.qr_code_outlined, size: 18.0, color: Colors.white),
),
),
],
),
const SizedBox(height: 8.0),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
decoration: BoxDecoration(color: Colors.black.withAlpha((0.3 * 255).round()), borderRadius: BorderRadius.circular(20.0)),
child: InkWell(
onTap: () {
2025-08-21 10:50:38 +08:00
logger.i('点击id');
Clipboard.setData(ClipboardData(text: imUserInfoController!.userID.value));
2025-07-21 15:46:30 +08:00
MyDialog.toast('ID已复制', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200)));
},
2025-08-21 10:50:38 +08:00
child: Text('ID:${imUserInfoController!.userID.value}', style: TextStyle(fontSize: 12.0, 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: [
Column(children: [Text('9999', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), SizedBox(height: 3.0), Text('获赞')]),
Column(children: [
Text('${followInfo.value?.mutualFollowersCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
SizedBox(height: 3.0),
Text('互关')
]),
Column(children: [
Text('${followInfo.value?.followingCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
SizedBox(height: 3.0),
Text('关注')
]),
Column(children: [
Text('${followInfo.value?.followersCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
SizedBox(height: 3.0),
Text('粉丝')
]),
],
)),
2025-07-21 15:46:30 +08:00
);
}
Widget _buildOrderCard(BuildContext context) {
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),
],
),
),
onTap: () {},
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildOrderIcon('assets/images/ico_order.png', '订单', () {
Get.toNamed('/order');
}),
2025-08-21 10:50:38 +08:00
_buildOrderIcon('assets/images/ico_dhx.png', '余额logout', () {
2025-07-21 15:46:30 +08:00
showLogoutDialog(context);
}),
2025-08-21 10:50:38 +08:00
_buildOrderIcon('assets/images/ico_sh.png', '提现vloger', () {
Get.toNamed('/vloger');
}),
2025-07-21 15:46:30 +08:00
_buildOrderIcon('assets/images/ico_tgm.png', '推广码', () {}),
],
),
),
],
),
);
}
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),
],
),
);
}
}