/// 粉丝列表 library; import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:loopin/IM/controller/chat_controller.dart'; import 'package:loopin/IM/im_service.dart'; import 'package:loopin/behavior/custom_scroll_behavior.dart'; import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/styles/index.dart'; import 'package:loopin/utils/index.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_type_check_result.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart'; class UserWithFollow { final V2TimUserFullInfo userInfo; int followType; UserWithFollow({ required this.userInfo, this.followType = 0, }); } class Fans extends StatefulWidget { const Fans({super.key}); @override State createState() => FansState(); } class FansState extends State with SingleTickerProviderStateMixin { bool isLoading = false; // 是否在加载中 bool hasMore = true; // 是否还有更多数据 String page = ''; List dataList = []; ///------------------- @override void initState() { super.initState(); getData(); } // 分页获取陌粉丝数据 Future getData() async { /// 0:不是好友也没有关注 /// 1:你关注了对方(单向) /// 2:对方关注了你(单向) /// 3:互相关注(双向好友) final res = await ImService.instance.getMyFollowersList( nextCursor: page, ); if (res.success && res.data != null) { logger.i('获取成功:${res.data!.nextCursor}'); final userInfoList = res.data!.userFullInfoList ?? []; // 构建数据 List wrappedList = userInfoList.map((u) { return UserWithFollow(userInfo: u); }).toList(); // 获取id final userIDList = userInfoList.map((item) => item.userID).whereType().toList(); if (userIDList.isNotEmpty) { final shiRes = await ImService.instance.checkFollowType(userIDList: userIDList); if (shiRes.success && shiRes.data != null) { final shipResData = shiRes.data!; for (final uwf in wrappedList) { final userID = uwf.userInfo.userID; if (userID != null) { // 查找对应关系 final match = shipResData.firstWhere( (e) => e.userID == userID, orElse: () => V2TimFollowTypeCheckResult(userID: ''), ); if (match.userID?.isNotEmpty ?? false) { uwf.followType = match.followType ?? 0; } } } } } final isFinished = res.data!.nextCursor == null || res.data!.nextCursor!.isEmpty; if (isFinished) { setState(() { hasMore = false; }); // 加载没数据了 page = ''; } else { page = res.data!.nextCursor ?? ''; } logger.i('获取数据成功:$userInfoList'); setState(() { dataList.addAll(wrappedList); }); } else { logger.e('获取数据失败:${res.desc}'); } } // 下拉刷新 Future handleRefresh() async { dataList.clear(); page = ''; getData(); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( centerTitle: true, forceMaterialTransparency: true, bottom: PreferredSize( preferredSize: const Size.fromHeight(1.0), child: Container( color: Colors.grey[300], height: 1.0, ), ), title: const Text( '粉丝', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), actions: [], ), body: ScrollConfiguration( behavior: CustomScrollBehavior().copyWith(scrollbars: false), child: Column( children: [ Expanded( child: EasyRefresh.builder( callLoadOverOffset: 20, //触底距离 callRefreshOverOffset: 20, // 下拉距离 header: ClassicHeader( dragText: '下拉刷新', armedText: '释放刷新', readyText: '加载中...', processingText: '加载中...', processedText: '加载完成', failedText: '加载失败,请重试', messageText: '最后更新于 %T', ), footer: ClassicFooter( dragText: '加载更多', armedText: '释放加载', readyText: '加载中...', processingText: '加载中...', processedText: hasMore ? '加载完成' : '没有更多了~', failedText: '加载失败,请重试', messageText: '最后更新于 %T', ), onRefresh: () async { await handleRefresh(); }, onLoad: () async { if (hasMore) { await getData(); } }, childBuilder: (context, physics) { return ListView.builder( physics: physics, itemCount: dataList.length, itemBuilder: (context, index) { final item = dataList[index]; return Ink( key: ValueKey(item.userInfo.userID), child: Container( padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ // 左侧部分(头像 + 昵称 + 描述) Expanded( child: InkWell( onTap: () { Get.toNamed( '/vloger', arguments: {'memberId': item.userInfo.userID}, ); }, child: Row( children: [ ClipOval( child: NetworkOrAssetImage( imageUrl: item.userInfo.faceUrl, width: 50, height: 50, ), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.userInfo.nickName?.isNotEmpty == true ? item.userInfo.nickName! : '未知昵称', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.normal, ), ), if (item.userInfo.selfSignature?.isNotEmpty ?? false) ...[ const SizedBox(height: 2.0), Text( item.userInfo.selfSignature!, style: const TextStyle( color: Colors.grey, fontSize: 13.0, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ], ), ), ], ), ), ), SizedBox(width: 10), // 右侧按钮 TextButton( style: TextButton.styleFrom( backgroundColor: item.followType != 3 ? FStyle.primaryColor : Colors.grey, minimumSize: const Size(70, 32), padding: const EdgeInsets.symmetric(horizontal: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4), ), ), onPressed: () async { final ctl = Get.find(); final checkRes = await ImService.instance.checkFollowType(userIDList: [item.userInfo.userID!]); int realFollowType = 0; if (checkRes.success && checkRes.data != null) { realFollowType = checkRes.data!.first.followType ?? 0; if ([1, 3].contains(realFollowType)) { // 取关 final unRes = await ImService.instance.unfollowUser(userIDList: [item.userInfo.userID!]); if (unRes.success) { setState(() { item.followType = 2; }); ctl.mergeNoFriend(conversationID: 'c2c_${item.userInfo.userID!}'); } } else { // 关注 final res = await ImService.instance.followUser(userIDList: [item.userInfo.userID!]); if (res.success) { setState(() { item.followType = realFollowType == 0 ? 1 : realFollowType == 2 ? 3 : 0; }); final chatRes = await ImService.instance.followUser(userIDList: [item.userInfo.userID!]); if (chatRes.success) { final res = await ImService.instance.getConversation(conversationID: 'c2c_${item.userInfo.userID}'); if (res.success) { V2TimConversation conversation = res.data; if (conversation.conversationGroupList?.isNotEmpty ?? false) { await ImService.instance.deleteConversationsFromGroup( groupName: conversation.conversationGroupList!.first!, conversationIDList: [conversation.conversationID], ); ctl.updateNoFriendMenu(); } } } } } } }, child: Text( Utils.getTipText(item.followType), style: const TextStyle(color: Colors.white, fontSize: 14), ), ), ], ), ), ); }, ); }, ), ), ], ), ), ); } }