diff --git a/lib/pages/chat/index.dart b/lib/pages/chat/index.dart index 738c1ea..8ffc180 100644 --- a/lib/pages/chat/index.dart +++ b/lib/pages/chat/index.dart @@ -51,6 +51,7 @@ class ChatPageState extends State { // 长按坐标点 double posDX = 0.0; double posDY = 0.0; + late RxInt followed = 0.obs; // 是否关注 // 下拉刷新 Future handleRefresh() async { @@ -102,17 +103,37 @@ class ChatPageState extends State { Get.toNamed('/vloger', arguments: {'memberId': value}); } - // 处理推广码 + // 检测当前用户是否关注博主 + checkFollowType(memberId) async { + /// 0:不是好友也没有关注 + /// 1:你关注了对方(单向) + /// 2:对方关注了你(单向) + /// 3:互相关注(双向好友) + final res = await ImService.instance.checkFollowType(userIDList: [memberId]); + if (res.success) { + final followType = res.data?.first.followType ?? 0; + logger.i(res.data?.first.toJson()); + followed.value = followType; + logger.i(followed.value); + } + } + + + // 处理推广码,先调用IM互相关注逻辑,成功后在调用绑定关系接口 void _handlePromotionCode(String value) async { - try { - print('处理推广码111: $value'); - final res = await Http.post(ShopApi.bindSpreadCodeId, data: {"socialCode": value}); - if (res != null && res['code'] == 200) { - MyDialog.toast('推广码绑定失败', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200))); - Get.toNamed('/vloger', arguments: {'memberId': value}); - } - } catch (e) { - MyDialog.toast('推广码绑定失败'); + await checkFollowType(value); // 检查当前用户是否关注了团长 + if(followed.value == 0 || followed.value == 2){ + final res = await ImService.instance.followUser(userIDList: [value]); + if (res.success) { + followed.value = followed.value == 0 ? 1 : 3; + final res = await Http.post(ShopApi.bindSpreadCodeId, data: {"socialCode": value}); + if (res != null && res['code'] == 200) { + MyDialog.toast('推广码绑定成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200))); + Get.toNamed('/vloger', arguments: {'memberId': value}); + } + } + }else{ + Get.toNamed('/vloger', arguments: {'memberId': value}); } } diff --git a/lib/pages/my/index.dart b/lib/pages/my/index.dart index 91132ba..9abd1da 100644 --- a/lib/pages/my/index.dart +++ b/lib/pages/my/index.dart @@ -263,20 +263,121 @@ class MyPageState extends State with SingleTickerProviderStateMixin { } } - // 删除当前用户发布的视频 + // 删除当前用户发布的视频 void deletePersonalVideo(videoId) async { logger.i('删除视频${videoId}'); try { final res = await Http.post('${VideoApi.deleteVideo}?id=${videoId}', data: {}); logger.i('删除成功响应${res}'); if(res != null && res['code'] == 200){ - MyDialog.toast('删除成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200))); - loadData(0); - } + MyDialog.toast('删除成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200))); + loadData(0); + } } catch (e) { - + logger.e('删除视频失败: $e'); } } + + // 显示删除确认对话框 + void showDeleteConfirmDialog(String videoId) { + Get.dialog( + Dialog( + backgroundColor: Colors.white, + surfaceTintColor: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 图标 + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon( + Icons.delete_outline, + color: Colors.red, + size: 30, + ), + ), + SizedBox(height: 16), + + // 标题 + Text( + '删除视频', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + SizedBox(height: 8), + + // 描述 + Text( + '确认要删除这个视频吗?\n删除后将无法恢复', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Colors.grey[600], + height: 1.4, + ), + ), + SizedBox(height: 24), + + // 按钮区域 + Row( + children: [ + // 取消按钮 + Expanded( + child: OutlinedButton( + onPressed: () => Get.back(), + style: OutlinedButton.styleFrom( + backgroundColor: Colors.transparent, + foregroundColor: Colors.grey[700], + side: BorderSide(color: Colors.grey[300]!), + padding: EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text('取消'), + ), + ), + SizedBox(width: 12), + + // 确认按钮 + Expanded( + child: ElevatedButton( + onPressed: () { + Get.back(); + deletePersonalVideo(videoId); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: Text('确认删除'), + ), + ), + ], + ), + ], + ), + ), + ), + barrierDismissible: true, + ); + } // 二维码名片弹窗 void qrcodeAlertDialog(BuildContext context) { showDialog( @@ -614,14 +715,7 @@ class MyPageState extends State with SingleTickerProviderStateMixin { 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']); - } + showDeleteConfirmDialog(item['id']); }, ), ], diff --git a/lib/pages/my/vloger.dart b/lib/pages/my/vloger.dart index fbc4e99..127d48b 100644 --- a/lib/pages/my/vloger.dart +++ b/lib/pages/my/vloger.dart @@ -8,6 +8,7 @@ import 'package:loopin/service/http.dart'; import 'package:loopin/components/custom_sticky_header.dart'; import 'package:loopin/api/common_api.dart'; import 'package:loopin/api/video_api.dart'; +import 'package:loopin/utils/index.dart'; import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/only_down_scroll_physics.dart'; import 'package:loopin/styles/index.dart'; @@ -565,7 +566,7 @@ class MyPageState extends State with SingleTickerProviderStateMixin { 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('${Utils.graceNumber(vlogLikeCount)}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), SizedBox(height: 3.0), Text('获赞')]), Column(children: [ Text('${followInfo.value.followingCount}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), SizedBox(height: 3.0), diff --git a/lib/pages/search/search-result.dart b/lib/pages/search/search-result.dart index ddb877e..b23d861 100644 --- a/lib/pages/search/search-result.dart +++ b/lib/pages/search/search-result.dart @@ -509,6 +509,9 @@ class _SearchResultPageState extends State with SingleTickerPr } // 视频项构建 + // 视频项构建 +// 视频项构建 +// 视频项构建 Widget _buildVideoItem(Map video) { return GestureDetector( onTap: () { @@ -531,65 +534,71 @@ class _SearchResultPageState extends State with SingleTickerPr child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 视频封面 - 宽度100%,高度自适应 + // 视频封面 - 自适应高度 ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(_itemCornerRadius), topRight: Radius.circular(_itemCornerRadius), ), - child: Container( - width: double.infinity, - color: Colors.grey[200], - child: video['firstFrameImg'] != null && video['firstFrameImg'].toString().isNotEmpty - ? Image.network( - video['firstFrameImg'].toString(), - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - return Container( - height: 120, - alignment: Alignment.center, - child: const Icon( - Icons.videocam, - color: Colors.grey, - size: 40, // 设置一个合理的默认大小 - ), - ); - }, - ) - : Container( - height: 200, - alignment: Alignment.center, - child: LayoutBuilder( - builder: (context, constraints) { - return Icon( - Icons.videocam, - color: Colors.grey, + child: AspectRatio( + aspectRatio: 0.8, // 保持1:1.2的宽高比 + child: Container( + color: Colors.grey[200], + child: video['firstFrameImg'] != null && video['firstFrameImg'].toString().isNotEmpty + ? Image.network( + video['firstFrameImg'].toString(), + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.grey[200], + child: const Center( + child: Icon( + Icons.videocam, + color: Colors.grey, + size: 32, + ), + ), ); }, + ) + : Container( + color: Colors.grey[200], + child: const Center( + child: Icon( + Icons.videocam, + color: Colors.grey, + size: 32, + ), + ), ), - ), + ), ), ), - // 视频信息 - 固定在容器底部 + // 使用Expanded将信息区域推到底部 Expanded( child: Padding( - padding: const EdgeInsets.all(6), + padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, // 内容靠底部对齐 + mainAxisAlignment: MainAxisAlignment.spaceBetween, // 标题在上,用户信息在下 children: [ + // 标题区域 - 修改为最多1行 Text( video['title']?.toString() ?? '无标题', style: const TextStyle( fontSize: 11, fontWeight: FontWeight.w500, + height: 1.2, ), - maxLines: 1, // 改为 1,限制为单行 - overflow: TextOverflow.ellipsis, // 超出部分显示省略号 + maxLines: 1, // 修改为1行 + overflow: TextOverflow.ellipsis, ), - const SizedBox(height: 4), + // 用户信息区域 - 固定在底部 Row( children: [ + // 用户头像 Container( width: 18, height: 18, @@ -603,9 +612,12 @@ class _SearchResultPageState extends State with SingleTickerPr ) : null, ), - child: video['avatar'] == null || video['avatar'].toString().isEmpty ? const Icon(Icons.person, size: 10, color: Colors.grey) : null, + child: video['avatar'] == null || video['avatar'].toString().isEmpty + ? const Icon(Icons.person, size: 10, color: Colors.grey) + : null, ), - const SizedBox(width: 4), + const SizedBox(width: 6), + // 用户名 Expanded( child: Text( video['nickname']?.toString() ?? '未知作者', @@ -617,7 +629,7 @@ class _SearchResultPageState extends State with SingleTickerPr overflow: TextOverflow.ellipsis, ), ), - const SizedBox(width: 6), + // 点赞数 Row( children: [ const Icon(Icons.favorite_border, size: 10, color: Colors.grey), diff --git a/lib/pages/video/module/attention.dart b/lib/pages/video/module/attention.dart index 6bebdc6..90b7ff7 100644 --- a/lib/pages/video/module/attention.dart +++ b/lib/pages/video/module/attention.dart @@ -1295,7 +1295,7 @@ class _AttentionModuleState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '@${videoList[videoModuleController.videoPlayIndex.value]['commentUserNickname'] ?? '未知'}', + '@${videoList[videoModuleController.videoPlayIndex.value]['nickname'] ?? '未知'}', style: const TextStyle(color: Colors.white, fontSize: 16.0), ), LayoutBuilder( diff --git a/lib/pages/video/module/friend.dart b/lib/pages/video/module/friend.dart index 6e6cafe..cff5207 100644 --- a/lib/pages/video/module/friend.dart +++ b/lib/pages/video/module/friend.dart @@ -1300,7 +1300,7 @@ class _FriendModuleState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '@${videoList[videoModuleController.videoPlayIndex.value]['commentUserNickname'] ?? '未知'}', + '@${videoList[videoModuleController.videoPlayIndex.value]['nickname'] ?? '未知'}', style: const TextStyle(color: Colors.white, fontSize: 16.0), ), LayoutBuilder( diff --git a/lib/pages/video/module/recommend.dart b/lib/pages/video/module/recommend.dart index 8dc36c8..1180a8b 100644 --- a/lib/pages/video/module/recommend.dart +++ b/lib/pages/video/module/recommend.dart @@ -1301,7 +1301,7 @@ class _RecommendModuleState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '@${videoList[videoModuleController.videoPlayIndex.value]['commentUserNickname'] ?? '未知'}', + '@${videoList[videoModuleController.videoPlayIndex.value]['nickname'] ?? '未知'}', style: const TextStyle(color: Colors.white, fontSize: 16.0), ), LayoutBuilder(