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/rise/controllers/create_challenge_controller.dart'; import 'package:onufitness/screens/echoboard/widget/exclusive_connection_tile.dart'; import 'package:onufitness/screens/rise/controllers/rise_controller.dart'; class MembersSelectionPopup extends StatefulWidget { final int selectedChallengeId; final bool isChallengePrivacyUpdate; final int? currentVisibilityId; final RiseController? riseController; const MembersSelectionPopup({ super.key, required this.selectedChallengeId, this.isChallengePrivacyUpdate = false, this.currentVisibilityId, this.riseController, }); @override State createState() => _MembersSelectionPopupState(); } class _MembersSelectionPopupState extends State { final CreateChallengeController controller = Get.put( CreateChallengeController(), ); final ScrollController _scrollController = ScrollController(); RxBool isChallengePrivayOpen = false.obs; @override void initState() { super.initState(); _scrollController.addListener(_onScroll); controller.fetchExclusiveConnections( refresh: true, challengeId: widget.selectedChallengeId, ); // Initialize visibility ID if it's a privacy update if (widget.isChallengePrivacyUpdate && widget.currentVisibilityId != null) { controller.challengeVisibilityId.value = widget.currentVisibilityId!; } WidgetsBinding.instance.addPostFrameCallback((_) { isChallengePrivayOpen.value = widget.isChallengePrivacyUpdate; }); } void _onScroll() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200) { if (controller.hasMoreDataConnection.value && !controller.isConnectionPaginationLoading.value) { controller.fetchExclusiveConnections( challengeId: widget.selectedChallengeId, ); } } } @override void dispose() { _scrollController.removeListener(_onScroll); controller.selectedConnections.clear(); controller.selectedConnections.refresh(); super.dispose(); } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Text( widget.isChallengePrivacyUpdate ? "Update Challenge Visibility" : "Select Members and Groups", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.sp), ), ), SizedBox(height: 15.h), Divider(), SizedBox(height: 15.h), // Privacy Radio Buttons (only for privacy update)............................................ if (widget.isChallengePrivacyUpdate) ...[ challengeVisibilitySection(), SizedBox(height: 15.h), Divider(), SizedBox(height: 15.h), ], //............................................................................................ // Show search and member list only if exclusive or not privacy update........................ Obx(() { bool showMembersList = !isChallengePrivayOpen.value || controller.challengeVisibilityId.value == 3; if (!showMembersList) { return Container( padding: EdgeInsets.symmetric(vertical: 40.h), child: Center( child: Column( children: [ Icon(Icons.public, size: 48.sp, color: Colors.grey), SizedBox(height: 12.h), Text( 'Public challenges are visible to everyone', style: TextStyle( fontSize: 14.sp, color: greyTextColor1, ), textAlign: TextAlign.center, ), ], ), ), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.isChallengePrivacyUpdate) Padding( padding: EdgeInsets.only(bottom: 10.h), child: Text( "Select Members and Groups", style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14.sp, ), ), ), TextField( controller: controller.connectionSearchController, onChanged: (value) { controller.connectionSearchValue.value = value; }, onSubmitted: (_) { controller.fetchExclusiveConnections( refresh: true, challengeId: widget.selectedChallengeId, ); }, decoration: InputDecoration( hintText: 'Search members...', suffixIcon: IconButton( icon: Icon(Icons.close), onPressed: controller.clearSearch, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), borderSide: BorderSide(color: lightGreyColor), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8.r), borderSide: BorderSide(color: lightGreyColor), ), filled: true, fillColor: textFieldFillColor, ), ), SizedBox(height: 12.h), Container( height: 300.h, decoration: BoxDecoration( border: Border.all(color: Colors.grey[300]!), borderRadius: BorderRadius.circular(8.r), ), child: Obx(() { if (controller.isConnectionsFetchLoading.value && controller.exclusiveConnections.data?.items == null) { return Center(child: CircularProgressIndicator()); } final items = controller.exclusiveConnections.data?.items ?? []; if (items.isEmpty) { return Center(child: Text("No members found")); } return ListView.builder( controller: _scrollController, padding: EdgeInsets.all(8.w), itemCount: items.length + (controller.isConnectionPaginationLoading.value ? 1 : 0), itemBuilder: (context, index) { if (index == items.length) { return Padding( padding: EdgeInsets.symmetric(vertical: 16.h), child: Center(child: CircularProgressIndicator()), ); } final connection = items[index]; final String itemId = connection.tribeId != null ? 'tribe_${connection.tribeId}' : 'user_${connection.connectedUserId}'; return Obx(() { final isSelected = controller.selectedIds.contains( itemId, ); return ExclusiveConnectionTile( 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.adminProfilePicture ?? '' : connection.profilePicture ?? '', isSelected: isSelected, onTap: () { controller.exclusiveConnectionToggleSelection( tribeId: connection.tribeId, connectedUserId: connection.connectedUserId, ); }, isLocked: connection.isAdded!, ); }); }, ); }), ), ], ); }), //............................................................................................ SizedBox(height: 16.h), Row( children: [ Expanded( child: ElevatedButton( onPressed: () => Get.back(), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), padding: EdgeInsets.symmetric(vertical: 14.h), ), child: Text( 'Cancel', style: TextStyle( fontSize: regularSizeText, fontWeight: FontWeight.w600, ), ), ), ), SizedBox(width: 16.w), Expanded( child: Obx( () => ElevatedButton( onPressed: () { if (widget.isChallengePrivacyUpdate) { // Call update privacy API controller .updateChallengePrivacy( selectedChallengeId: widget.selectedChallengeId, ) .then((value) async { if (value) { Future.delayed(Duration(milliseconds: 500), () { Get.back(); }); // Refresh the list after privacy update await widget.riseController! .fetchCreatedChallenges(isRefresh: true); } }); } else { // Call add participant API controller .addParticipentToChallenge( selectedChallengeId: widget.selectedChallengeId, ) .then((value) { if (value) { Future.delayed(Duration(milliseconds: 600), () { Get.back(); }); } }); } }, style: ElevatedButton.styleFrom( backgroundColor: (widget.isChallengePrivacyUpdate ? controller.isUpdatePrivacyLoading.value : controller.isAddPrticipentLoading.value) ? lightGreyColor : Color(primaryColor), foregroundColor: Colors.black, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), padding: EdgeInsets.symmetric(vertical: 14.h), ), child: (widget.isChallengePrivacyUpdate ? controller.isUpdatePrivacyLoading.value : controller.isAddPrticipentLoading.value) ? SizedBox( height: 20.h, width: 20.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2.0, ), ) : Text( widget.isChallengePrivacyUpdate ? 'Update' : 'Add People', style: TextStyle( fontSize: regularSizeText, fontWeight: FontWeight.w600, ), ), ), ), ), ], ), SizedBox(height: 20.h), Container( color: Colors.white, padding: EdgeInsetsDirectional.only( bottom: MediaQuery.of(context).viewPadding.bottom, ), ), ], ), ); } //......................................................................................................... // Privacy visibility section widget....................................................................... //......................................................................................................... Widget challengeVisibilitySection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Obx(() { return Column( children: [ RadioListTile( title: Text( 'Public', style: TextStyle( fontSize: regularSizeText, fontWeight: FontWeight.w500, ), ), subtitle: Text( 'Anyone can join this challenge.', style: TextStyle(fontSize: 12.sp, color: greyTextColor1), ), value: 1, groupValue: controller.challengeVisibilityId.value, activeColor: Color(primaryColor), onChanged: (int? value) { if (value != null) { controller.challengeVisibilityId.value = value; // Clear selected connections when switching to public if (value == 1) { controller.selectedConnections.clear(); controller.selectedIds.clear(); } } }, contentPadding: EdgeInsets.zero, ), RadioListTile( title: Text( 'Exclusive', style: TextStyle( fontSize: regularSizeText, fontWeight: FontWeight.w500, ), ), subtitle: Text( 'Only selected members can join this challenge.', style: TextStyle(fontSize: 12.sp, color: greyTextColor1), ), value: 3, groupValue: controller.challengeVisibilityId.value, activeColor: Color(primaryColor), onChanged: (int? value) { if (value != null) { controller.challengeVisibilityId.value = value; } }, contentPadding: EdgeInsets.zero, ), ], ); }), ], ); } }