import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; import 'package:yumi/services/audio/rtm_manager.dart'; import 'package:provider/provider.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_value_callback.dart'; import 'package:tencent_cloud_chat_sdk/tencent_im_sdk_plugin.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; import 'package:yumi/app/config/business_logic_strategy.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/shared/data_sources/sources/local/data_persistence.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/ui_kit/theme/socialchat_theme.dart'; import 'package:yumi/ui_kit/widgets/msg/message_conversation_list_page.dart'; import 'package:yumi/ui_kit/widgets/sc_home_shell_background.dart'; import '../chat_route.dart'; ///消息 class SCMessagePage extends StatefulWidget { final bool isFromRoom; const SCMessagePage({super.key, this.isFromRoom = false}); @override State createState() => _MessagePageState(); } class _MessagePageState extends State { BusinessLogicStrategy get _strategy => SCGlobalConfig.businessLogicStrategy; bool showSystemAnnouncementTips = true; final TextEditingController _messageSearchController = TextEditingController(); final FocusNode _messageSearchFocusNode = FocusNode(); bool _isSearchingMessages = false; String _messageSearchText = ""; @override void initState() { super.initState(); showSystemAnnouncementTips = DataPersistence.getBool( "${AccountStorage().getCurrentUser()?.userProfile?.account}-ShowSystemAnnouncementTips", defaultValue: true, ); _checkLogin(); } void _checkLogin() async { V2TimValueCallback getLoginStatusRes = await TencentImSDKPlugin.v2TIMManager.getLoginStatus(); if (getLoginStatusRes.code == 0) { var status = getLoginStatusRes.data; // getLoginStatusRes.data为用户登录状态值 if (status == 1) { // 已登录 ///处理有时候拉不到最后一条消息 Provider.of( context, listen: false, ).initConversation().then((value) { Future.delayed(Duration(milliseconds: 550), () { Provider.of( context, listen: false, ).initConversation().then((value) { setState(() {}); }); }); }); } else if (status == 2) { // 登录中 } else if (status == 3) { // 未登录 Provider.of( context, listen: false, ).loginTencetRtm(context).then((value) { _checkLogin(); }); } setState(() {}); } } @override void dispose() { _messageSearchController.dispose(); _messageSearchFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ const Positioned.fill(child: SCHomeShellBackground()), if (widget.isFromRoom) Image.asset( _strategy.getMessagePageIndexMaskIcon(), width: ScreenUtil().screenWidth, fit: BoxFit.cover, ), Scaffold( backgroundColor: Colors.transparent, body: SafeArea( bottom: false, child: Column( children: [ _buildTopBar(), Expanded( child: Consumer( builder: (_, provider, __) { return Column( children: [ if (!_isSearchingMessages) _headMenu(provider), Expanded( child: Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), child: MessageConversationListPage( false, searchQuery: _messageSearchText, ), ), ), ], ); }, ), ), ], ), ), ), ], ); } Widget _buildTopBar() { return SizedBox( height: 44.w, child: Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), child: Row( children: [ Expanded( child: _isSearchingMessages ? _messageSearchField() : SCHomeShellGradientText( SCAppLocalizations.of(context)!.message, style: scHomeShellTitleStyle(), ), ), SCDebounceWidget( child: SizedBox( width: 38.w, height: 38.w, child: Center( child: _isSearchingMessages ? Icon(Icons.close, size: 22.w, color: Colors.white) : Image.asset( "sc_images/index/sc_icon_serach.png", width: 24.w, height: 24.w, ), ), ), onTap: () { if (_isSearchingMessages) { _stopMessageSearch(); } else { _startMessageSearch(); } }, ), ], ), ), ); } Widget _messageSearchField() { return Container( height: 36.w, alignment: AlignmentDirectional.center, decoration: BoxDecoration( color: const Color(0xff18F2B1).withValues(alpha: 0.1), borderRadius: BorderRadius.circular(20.w), ), child: Row( children: [ SizedBox(width: 10.w), Image.asset( "sc_images/index/sc_icon_serach2.png", width: 18.w, height: 18.w, color: const Color(0xff18F2B1), ), SizedBox(width: 6.w), Expanded( child: TextField( controller: _messageSearchController, focusNode: _messageSearchFocusNode, autofocus: true, cursorColor: SocialChatTheme.primaryLight, style: TextStyle(color: Colors.black, fontSize: 14.sp), decoration: InputDecoration( hintText: "${SCAppLocalizations.of(context)!.search} ID/${SCAppLocalizations.of(context)!.userName}", hintStyle: TextStyle(color: Colors.white54, fontSize: 13.sp), border: InputBorder.none, isDense: true, contentPadding: EdgeInsets.zero, ), onChanged: (value) { setState(() { _messageSearchText = value; }); }, ), ), ], ), ); } void _startMessageSearch() { setState(() { _isSearchingMessages = true; }); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { _messageSearchFocusNode.requestFocus(); } }); } void _stopMessageSearch() { _messageSearchController.clear(); _messageSearchFocusNode.unfocus(); setState(() { _isSearchingMessages = false; _messageSearchText = ""; }); } Widget _headMenu(RtmProvider provider) { return Container( margin: EdgeInsets.fromLTRB(10.w, 25.w, 10.w, 10.w), height: 114.w, decoration: BoxDecoration( borderRadius: BorderRadius.circular(14.w), border: Border.all( color: scHomeShellAccentColor.withValues(alpha: 0.2), width: 1.w, ), gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ const Color(0xFF111A1B).withValues(alpha: 0.86), const Color(0xFF2C4D42).withValues(alpha: 0.68), ], ), ), child: Row( children: [ _buildMessageShortcut( label: SCAppLocalizations.of(context)!.notifcation, icon: _strategy.getMessagePageNotificationMessageIcon(), unreadCount: provider.notifcationUnReadCount, onTap: () { provider.updateNotificationCount(0); SCNavigatorUtils.push( context, SCChatRouter.notifcation, replace: false, ); }, ), _buildMessageShortcut( label: SCAppLocalizations.of(context)!.activity, icon: _strategy.getMessagePageActivityMessageIcon(), unreadCount: provider.activityUnReadCount, onTap: () { provider.updateActivityCount(0); SCNavigatorUtils.push( context, SCChatRouter.activity, replace: false, ); }, ), _buildMessageShortcut( label: SCAppLocalizations.of(context)!.system, icon: _strategy.getMessagePageSystemMessageIcon(), unreadCount: provider.systemUnReadCount, onTap: () async { var conversation = provider.getPreferredSystemConversation(); provider.updateSystemCount(0); var bool = await provider.startConversation(conversation); if (!bool) return; var json = jsonEncode(conversation.toJson()); SCNavigatorUtils.push( context, "${SCChatRouter.systemChat}?conversation=${Uri.encodeComponent(json)}", ); }, ), ], ), ); } Widget _buildMessageShortcut({ required String label, required String icon, required int unreadCount, required VoidCallback onTap, }) { return Expanded( child: SCDebounceWidget( onTap: onTap, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Stack( clipBehavior: Clip.none, children: [ Image.asset(icon, width: 52.w, height: 52.w), if (unreadCount > 0) PositionedDirectional( top: -2.w, end: -6.w, child: _unreadBadge(unreadCount), ), ], ), SizedBox(height: 10.w), Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: Colors.white, fontSize: 14.sp, fontWeight: FontWeight.w700, height: 1.2, ), ), ], ), ), ); } Widget _unreadBadge(int unreadCount) { return Visibility( visible: unreadCount > 0, child: Container( padding: EdgeInsets.symmetric(horizontal: 6.w), alignment: Alignment.center, height: 18.w, constraints: BoxConstraints(minWidth: 18.w), decoration: BoxDecoration(color: Colors.red, shape: BoxShape.circle), child: Text( "${unreadCount > 99 ? '99+' : unreadCount}", style: TextStyle( fontSize: 10.sp, color: Color(0xffffffff), fontWeight: FontWeight.w400, decoration: TextDecoration.none, ), ), ), ); } }