import 'dart:async'; import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/ui_kit/theme/socialchat_theme.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_room_repository_imp.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart'; import 'package:yumi/shared/business_logic/models/res/room_res.dart'; import 'package:yumi/modules/index/main_route.dart'; import 'package:provider/provider.dart'; import 'package:yumi/ui_kit/components/socialchat_gradient_button.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:yumi/app/constants/sc_screen.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/business_logic/models/res/login_res.dart'; import 'package:yumi/shared/business_logic/usecases/sc_fixed_width_tabIndicator.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import '../../services/general/sc_app_general_manager.dart'; import '../../ui_kit/components/sc_compontent.dart'; import '../../ui_kit/components/sc_debounce_widget.dart'; import '../../ui_kit/components/sc_page_list.dart'; import '../../ui_kit/components/text/sc_text.dart'; ///搜索房间 class SearchPage extends SCPageList { @override _SearchPageState createState() => _SearchPageState(); } class _SearchPageState extends SCPageListState with SingleTickerProviderStateMixin { String search = ''; List historys = []; late TabController _tabController; bool enablePullUp = false; bool enablePullDown = false; late TextEditingController _textEditingController; @override void dispose() { super.dispose(); } @override void initState() { super.initState(); _loadHistory(); _tabController = TabController(vsync: this, length: 2); _textEditingController = TextEditingController(); _textEditingController.addListener(() { if (_textEditingController.text.isEmpty) { search = ""; _loadHistory(); } }); } @override Widget build(BuildContext context) { return Stack( children: [ Image.asset( "sc_images/person/sc_icon_edit_userinfo_bg.png", width: ScreenUtil().screenWidth, height: ScreenUtil().screenHeight, fit: BoxFit.fill, ), Scaffold( backgroundColor: SCGlobalConfig.businessLogicStrategy .getSearchPageScaffoldBackgroundColor(), body: Column( children: [ Container( height: kToolbarHeight + ScreenUtil().statusBarHeight, padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight), alignment: AlignmentDirectional.centerStart, child: Row( children: [ SizedBox(width: width(10)), SCDebounceWidget( child: Icon( Icons.chevron_left, color: SCGlobalConfig.businessLogicStrategy .getSearchPageBackIconColor(), size: 25.w, ), onTap: () { SCNavigatorUtils.goBack(context); }, ), Expanded( child: searchWidget( padding: EdgeInsets.symmetric(horizontal: 2.w), hint: SCAppLocalizations.of(context)!.pleaseEnterContent, controller: _textEditingController, borderColor: SCGlobalConfig.businessLogicStrategy .getSearchPageInputBorderColor(), textColor: SCGlobalConfig.businessLogicStrategy .getSearchPageInputTextColor(), ), ), socialchatGradientButton( text: SCAppLocalizations.of(context)!.search, radius: 25, textSize: 14.sp, textColor: SCGlobalConfig.businessLogicStrategy .getSearchPageButtonTextColor(), gradient: LinearGradient( colors: SCGlobalConfig.businessLogicStrategy .getSearchPageButtonGradient(), begin: Alignment.centerLeft, end: Alignment.centerRight, ), onPress: () { _reqSearch(); }, ), SizedBox(width: width(10)), ], ), ), search.isEmpty || search == "" ? _history() : _result(), ], ), ), ], ); } _history() { if (historys.isEmpty) { return mainEmpty(msg: SCAppLocalizations.of(context)!.noData); } else { return Expanded( child: Column( children: [ SizedBox(height: 20.w), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(width: width(15)), text( SCAppLocalizations.of(context)!.history, fontSize: 16.sp, textColor: SCGlobalConfig.businessLogicStrategy .getSearchPageHistoryTitleTextColor(), fontWeight: FontWeight.bold, ), Expanded(child: SizedBox(width: width(1))), GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { setState(() { historys.clear(); _saveHistory(""); }); }, child: Row( children: [ Image.asset( 'sc_images/general/sc_icon_delete.png', width: 17.w, ), //SizedBox(width: width(5),), //Text("清空", style: TextStyle(fontSize: 13.sp, color: Color(0xffaaaaaa)),), SizedBox(width: width(15)), ], ), ), ], ), SizedBox(height: height(10)), Expanded( child: Column( children: [ Row( children: [ SizedBox(width: 12.w), Expanded( child: Wrap( runSpacing: 10, spacing: 10, direction: Axis.horizontal, children: historys .asMap() .keys .map((e) => _historyItem(historys[e])) .toList(), ), ), SizedBox(width: 12.w), ], ), ], ), ), ], ), ); } } _saveHistory(String msg) async { historys.removeWhere((history) => history == msg || history.isEmpty); if (!historys.any((history) => history.startsWith(msg))) { if (msg.isNotEmpty) { historys.insert(0, msg); } } setState(() {}); DataPersistence.setSearchHistroy( AccountStorage().getCurrentUser()?.userProfile?.account ?? "", jsonEncode(historys), ); } _loadHistory() async { String json = DataPersistence.getSearchHistroy( AccountStorage().getCurrentUser()?.userProfile?.account ?? "", ); historys = List.from(jsonDecode(json)); setState(() {}); } Widget _historyItem(String history) { return GestureDetector( onTap: () { _textEditingController.text = history; _reqSearch(); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 6.w), decoration: BoxDecoration( color: SCGlobalConfig.businessLogicStrategy .getSearchPageHistoryItemBackgroundColor(), borderRadius: BorderRadius.circular(52.w), ), child: Text( history, style: TextStyle( fontSize: sp(13), color: SCGlobalConfig.businessLogicStrategy .getSearchPageHistoryItemTextColor(), fontWeight: FontWeight.w400, decoration: TextDecoration.none, ), ), ), ); } _result() { return Expanded( child: Column( children: [ Theme( data: ThemeData( brightness: Brightness.light, splashColor: Colors.transparent, highlightColor: Colors.transparent, ), child: Container( padding: EdgeInsets.symmetric(vertical: 1.w), decoration: BoxDecoration( // color: Colors.white, //border: Border(bottom: BorderSide(color: Color(0xffEEEEEE),width: 0.5.w)) ), child: TabBar( tabs: [ SCAppLocalizations.of(context)!.rooms, SCAppLocalizations.of(context)!.users, ].map((e) => Tab(text: e)).toList(), indicator: SCFixedWidthTabIndicator( width: 15.w, gradient: LinearGradient( colors: [ SCGlobalConfig.businessLogicStrategy .getSearchPageTabIndicatorGradientStartColor(), SCGlobalConfig.businessLogicStrategy .getSearchPageTabIndicatorGradientEndColor(), ], ), ), indicatorSize: TabBarIndicatorSize.label, // 控制指示器宽度 labelPadding: EdgeInsetsDirectional.only(start: 15, end: 15), isScrollable: true, tabAlignment: TabAlignment.start, controller: _tabController, labelColor: SCGlobalConfig.businessLogicStrategy .getSearchPageTabSelectedLabelColor(), dividerColor: SCGlobalConfig.businessLogicStrategy .getSearchPageTabDividerColor(), unselectedLabelColor: SCGlobalConfig.businessLogicStrategy .getSearchPageTabUnselectedLabelColor(), unselectedLabelStyle: SCGlobalConfig.businessLogicStrategy .getSearchPageTabUnselectedLabelStyle(), labelStyle: SCGlobalConfig.businessLogicStrategy .getSearchPageTabSelectedLabelStyle(), ), ), ), Expanded( child: TabBarView( controller: _tabController, children: [ SearchRoomList(search, (String text) { _saveHistory(text); }), SearchUserList(search, (String text) { _saveHistory(text); }), ], ), ), ], ), ); } void _reqSearch() { search = _textEditingController.text; setState(() {}); if (search.trim().isNotEmpty) { _saveHistory(search); } else { items.clear(); } } } class SearchRoomList extends StatefulWidget { final String text; Function(String text) saveHistroy; SearchRoomList(this.text, this.saveHistroy); @override _SearchRoomListState createState() => _SearchRoomListState(saveHistroy); } class _SearchRoomListState extends State { List? rooms; Function(String text) saveHistroy; Timer? _searchTimer; _SearchRoomListState(this.saveHistroy); @override void initState() { loadPage(); super.initState(); } @override void dispose() { _searchTimer?.cancel(); super.dispose(); } @override void didUpdateWidget(SearchRoomList oldWidget) { var oldText = oldWidget.text; var text = widget.text; if (oldText != text) { _searchTimer?.cancel(); _searchTimer = Timer(Duration(milliseconds: 550), () { loadPage(); }); } super.didUpdateWidget(oldWidget); } @override Widget build(BuildContext context) { if (rooms == null) { return Center(child: CupertinoActivityIndicator()); } else if (rooms!.length == 0) { return empty(); } return GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, // 每行2个 childAspectRatio: 1, // 宽高比 mainAxisSpacing: 10, crossAxisSpacing: 10, ), padding: EdgeInsets.all(10), itemCount: rooms!.length, itemBuilder: (context, index) { return buildItem(rooms![index]); }, ); } ///构建列表项 Widget buildItem(SocialChatRoomRes e) { //return roomItem(room: e,context: context); return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () async { if (context != null) { Provider.of( context, listen: false, ).joinVoiceRoomSession(context, e.id ?? ""); } }, child: Stack( alignment: Alignment.bottomCenter, children: [ Container( padding: EdgeInsets.all(3.w), decoration: BoxDecoration( image: DecorationImage( image: AssetImage("sc_images/index/sc_icon_room_bord.png"), fit: BoxFit.fill, ), ), child: netImage( url: e.roomCover ?? "", borderRadius: BorderRadius.circular(12.w), width: 200.w, height: 200.w, ), ), Container( padding: EdgeInsets.symmetric(vertical: 6.w), margin: EdgeInsets.symmetric(horizontal: 1.w), decoration: BoxDecoration( image: DecorationImage( image: AssetImage("sc_images/index/sc_icon_index_room_brd.png"), fit: BoxFit.fill, ), ), child: Row( children: [ SizedBox(width: 10.w), Consumer( builder: (_, provider, __) { return netImage( url: "${provider.findCountryByName(e.countryName ?? "")?.nationalFlag}", width: 20.w, height: 13.w, borderRadius: BorderRadius.circular(2.w), ); }, ), SizedBox(width: 5.w), Expanded( child: SizedBox( height: 21.w, child: text( e.roomName ?? "", fontSize: 15.sp, textColor: Color(0xffffffff), fontWeight: FontWeight.w400, ), // (roomRes.roomProfile?.roomName?.length ?? 0) > 10 // ? Marquee( // text: roomRes.roomProfile?.roomName ?? "", // style: TextStyle( // fontSize: 15.sp, // color: Color(0xffffffff), // fontWeight: FontWeight.w400, // decoration: TextDecoration.none, // ), // scrollAxis: Axis.horizontal, // crossAxisAlignment: CrossAxisAlignment.start, // blankSpace: 20.0, // velocity: 40.0, // pauseAfterRound: Duration(seconds: 1), // accelerationDuration: Duration(seconds: 1), // accelerationCurve: Curves.easeOut, // decelerationDuration: Duration( // milliseconds: 500, // ), // decelerationCurve: Curves.easeOut, // ) // : Text( // roomRes.roomProfile?.roomName ?? "", // maxLines: 1, // overflow: TextOverflow.ellipsis, // style: TextStyle( // fontSize: 15.sp, // color: Color(0xffffffff), // fontWeight: FontWeight.w400, // decoration: TextDecoration.none, // ), // ), ), ), SizedBox(width: 5.w), (e.extValues?.roomSetting?.password?.isEmpty ?? false) ? Image.asset( "sc_images/general/sc_icon_online_user.png", width: 14.w, height: 14.w, ) : Image.asset( "sc_images/index/sc_icon_room_suo.png", width: 20.w, height: 20.w, ), (e.extValues?.roomSetting?.password?.isEmpty ?? false) ? SizedBox(width: 3.w) : Container(height: 10.w), (e.extValues?.roomSetting?.password?.isEmpty ?? false) ? text(e.extValues?.memberQuantity ?? "0", fontSize: 12.sp) : Container(height: 10.w), SizedBox(width: 10.w), ], ), ), (e.roomGameIcon?.isNotEmpty ?? false) ? PositionedDirectional( top: 8.w, end: 8.w, child: netImage( url: e.roomGameIcon ?? "", width: 25.w, height: 25.w, borderRadius: BorderRadius.circular(4.w), ), ) : Container(), ], ), ); } loadPage() async { widget.saveHistroy(widget.text); try { rooms = await SCChatRoomRepository().searchRoom(widget.text); } catch (e) { } finally { setState(() {}); } } empty() { return mainEmpty(msg: SCAppLocalizations.of(context)!.noData); } } class SearchUserList extends SCPageList { final String text; Function(String text) saveHistroy; SearchUserList(this.text, this.saveHistroy); @override _SearchUserListState createState() => _SearchUserListState(saveHistroy); } class _SearchUserListState extends SCPageListState { Function(String text) saveHistroy; _SearchUserListState(this.saveHistroy); Timer? _searchTimer; @override void initState() { // TODO: implement initState backgroundColor = Colors.transparent; loadData(1); super.initState(); } @override void dispose() { _searchTimer?.cancel(); super.dispose(); } @override void didUpdateWidget(SCPageList oldWidget) { // TODO: implement didUpdateWidget var oldText = (oldWidget as SearchUserList).text; var text = (widget as SearchUserList).text; if (oldText != text) { _searchTimer?.cancel(); _searchTimer = Timer(Duration(milliseconds: 550), () { loadData(1); }); } super.didUpdateWidget(oldWidget); } @override Widget build(BuildContext context) { return buildList(context); } ///构建列表项 Widget buildItem(SocialChatUserProfile data) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { SCNavigatorUtils.push( context, "${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == data.id}&tageId=${data.id}", ); }, child: Container( padding: EdgeInsets.symmetric(vertical: 5.w), margin: EdgeInsets.symmetric(horizontal: 25.w), child: Row( children: [ head(url: data.userAvatar ?? "", width: 55.w), SizedBox(width: 2.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ xb( data.userSex, color: data.userSex == 1 ? Colors.blue : Colors.purpleAccent, ), SizedBox(width: 5.w), // richText( // txt: data.userNickname ?? "", // key: (widget as SearchUserList).text, // highlight: SocialChatTheme.primaryColor, // defaultColor: Colors.black, // ), Expanded( child: socialchatNickNameText( textColor: SCGlobalConfig.businessLogicStrategy .getSearchPageHistoryTitleTextColor(), data.userNickname ?? "", fontSize: 15.sp, type: data.getVIP()?.name ?? "", needScroll: (data.userNickname?.characters.length ?? 0) > 18, ), ), SizedBox(width: 5.w), // dj(data.level.toString()), ], ), GestureDetector( child: Container( child: text( "ID:${data.getID()}", fontSize: 12.sp, textColor: SCGlobalConfig.businessLogicStrategy .getSearchPageHistoryTitleTextColor(), fontWeight: FontWeight.bold, ), ), onTap: () { Clipboard.setData(ClipboardData(text: data.getID())); SCTts.show( SCAppLocalizations.of(context)!.copiedToClipboard, ); }, ), ], ), ), ], ), ), ); } @override loadPage({ required int page, required Function(List) onSuccess, Function? onErr, }) async { saveHistroy((widget as SearchUserList).text); SCAccountRepository() .searchUser((widget as SearchUserList).text) .then((data) { List users = []; users.add(data); onSuccess(users); }) .catchError((e) { if (onErr != null) { onErr(); } }); } @override empty() { return mainEmpty(msg: SCAppLocalizations.of(context)!.noData); } @override builderDivider() { return Divider( height: height(1), color: SocialChatTheme.dividerColor, indent: width(85), endIndent: width(15), ); } }