import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:onufitness/constants/color_constant.dart'; import 'package:onufitness/constants/text_constant.dart'; import 'package:onufitness/screens/echoboard/controllers/echoboard_controller.dart'; import 'package:onufitness/screens/chat/views/chat_inside_screen.dart'; import 'package:onufitness/services/logger_service.dart'; import 'package:onufitness/utils/custom_sneakbar.dart'; import 'package:onufitness/widgets/appbars/custom_appbar.dart'; class ChatUserSearchScreen extends StatefulWidget { const ChatUserSearchScreen({super.key}); @override State createState() => _ChatUserSearchScreenState(); } class _ChatUserSearchScreenState extends State { final EchoBoardController controller = Get.find(); final ScrollController _scrollController = ScrollController(); final logger = LoggerService(); @override void initState() { super.initState(); _scrollController.addListener(_onScroll); WidgetsBinding.instance.addPostFrameCallback((_) { controller.fetchExclusiveConnections(refresh: true); }); } void _onScroll() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 300) { if (controller.hasMoreDataConnection.value && !controller.isConnectionPaginationLoading.value) { controller.fetchExclusiveConnections(); } } } Future _onRefresh() async { await controller.fetchExclusiveConnections(refresh: true); return Future.value(); } void onConnectionTap({ required String? agoraGroupId, required String? connectedUserId, required String? userName, required String? groupName, required String? groupImage, required String? userProfilePic, }) { // ---------- GROUP CHAT ---------- if (agoraGroupId != null && agoraGroupId.isNotEmpty) { if (groupName == null || groupName.isEmpty) { customSnackbar( title: "Group Info Missing", message: "Group name not found.", duration: 2, ); return; } Get.to( () => ChatDetailScreen( targetUserId: agoraGroupId, targetUserName: groupName, targetUserAvatar: groupImage, isGroupMessage: true, ), ); return; } // ---------- 1-1 CHAT ---------- final cleanedUserId = connectedUserId?.replaceAll('-', ''); if (cleanedUserId == null || cleanedUserId.isEmpty) { customSnackbar( title: "Chat Not Available", message: "Chat window is not available.", duration: 2, ); return; } if (userName == null || userName.isEmpty) { customSnackbar( title: "User Info Missing", message: "User name not found.", duration: 2, ); return; } Get.to( () => ChatDetailScreen( targetUserId: cleanedUserId, targetUserName: userName, targetUserAvatar: userProfilePic, ), ); } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: CustomAppBar( title: 'Select Connection', textColor: appbarTextColor, titleFontSize: appBarHeardingText, backgroundColor: Color(primaryColor), leading: IconButton( icon: Icon(Icons.arrow_back_ios, color: Colors.black), onPressed: () { Get.back(); }, ), ), body: Column( children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( padding: EdgeInsets.all(10.sp), child: TextField( controller: controller.connectionSearchController, decoration: InputDecoration( hintText: 'Search for members', hintStyle: TextStyle( fontWeight: FontWeight.w600, color: greyBorderColor, ), prefixIcon: const Padding( padding: EdgeInsets.only(left: 20), child: Icon(Icons.search), ), suffixIcon: IconButton( icon: const Padding( padding: EdgeInsets.only(right: 10), child: Icon(Icons.close), ), onPressed: () => controller.clearSearch(), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(30), borderSide: BorderSide.none, ), filled: true, fillColor: textFieldFillColor, ), onChanged: (newValue) { controller.connectionSearchValue.value = newValue; }, onSubmitted: (_) { controller.fetchExclusiveConnections(refresh: true); }, ), ), const SizedBox(height: 12), ], ), ), Expanded( child: Obx( () => controller.isConnectionsFetchLoading.value && controller.exclusiveConnections.data?.items == null ? const Center( child: CircularProgressIndicator(color: Colors.black), ) : controller.exclusiveConnections.data?.items == null || controller.exclusiveConnections.data!.items!.isEmpty ? Center( child: RefreshIndicator( onRefresh: _onRefresh, child: ListView( physics: const AlwaysScrollableScrollPhysics(), children: [ SizedBox(height: 150.h), Center(child: Text('No connections found')), ], ), ), ) : RefreshIndicator( backgroundColor: Colors.white, color: Colors.black, onRefresh: _onRefresh, child: ListView.builder( physics: const AlwaysScrollableScrollPhysics(), controller: _scrollController, padding: EdgeInsets.symmetric(horizontal: 16.w), itemCount: controller .exclusiveConnections .data! .items! .length + (controller.isConnectionPaginationLoading.value ? 1 : 0), itemBuilder: (_, i) { if (i == controller .exclusiveConnections .data! .items! .length) { return const Padding( padding: EdgeInsets.symmetric(vertical: 16.0), child: Center( child: CircularProgressIndicator( backgroundColor: Colors.white, color: Colors.black, ), ), ); } final connection = controller.exclusiveConnections.data!.items![i]; return SingleConnectionTile( name: connection.tribeId != null ? connection.tribeName ?? 'Unknown Tribe' : connection.fullName ?? 'Unknown User', type: connection.tribeId != null ? 'group' : 'user', members: connection.totalMemberCount, imageUrl: connection.tribeId != null ? connection.tribeImage ?? connection.adminProfilePicture! : connection.profilePicture ?? '', onTap: () { onConnectionTap( agoraGroupId: connection.agoraGroupID, connectedUserId: connection.connectedUserId, userName: connection.fullName, groupName: connection.tribeName, groupImage: connection.tribeImage, userProfilePic: connection.profilePicture, ); }, ); }, ), ), ), ), ], ), ); } } class SingleConnectionTile extends StatelessWidget { final String name; final String type; final int? members; final String imageUrl; final VoidCallback onTap; const SingleConnectionTile({ required this.name, required this.type, this.members, required this.imageUrl, required this.onTap, super.key, }); @override Widget build(BuildContext context) { return ListTile( onTap: onTap, contentPadding: EdgeInsets.symmetric(vertical: 4.h, horizontal: 8.w), leading: type == 'group' ? Stack( clipBehavior: Clip.none, children: [ // Admin profile picture CircleAvatar( radius: 30.r, backgroundColor: Colors.grey[300], backgroundImage: imageUrl.isNotEmpty ? NetworkImage(imageUrl) : null, child: imageUrl.isEmpty ? Icon( Icons.person, size: 25.sp, color: Color(darkGreyColor), ) : null, ), // +N badge Positioned( right: -8.r, top: -8.r, child: Container( width: 40.r, height: 40.r, decoration: BoxDecoration( color: const Color(0xFFDBF403), shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2), ), alignment: Alignment.center, child: Text( '+${(members ?? 1) - 1}', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.bold, color: Colors.black, ), ), ), ), ], ) : CircleAvatar( radius: 30.r, backgroundImage: imageUrl.isNotEmpty ? NetworkImage(imageUrl) : null, backgroundColor: Colors.grey[300], child: imageUrl.isEmpty ? Icon( Icons.person, size: 30.sp, color: Colors.grey[600], ) : null, ), title: Text( name, style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w500), ), subtitle: type == 'group' ? Text( '${members ?? 0} members', style: TextStyle(fontSize: 12.sp, color: Colors.grey), ) : null, trailing: Icon(Icons.arrow_forward_ios, color: Colors.grey, size: 16.sp), ); } }