422 lines
16 KiB
Dart
422 lines
16 KiB
Dart
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<MembersSelectionPopup> createState() => _MembersSelectionPopupState();
|
|
}
|
|
|
|
class _MembersSelectionPopupState extends State<MembersSelectionPopup> {
|
|
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<int>(
|
|
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<int>(
|
|
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,
|
|
),
|
|
],
|
|
);
|
|
}),
|
|
],
|
|
);
|
|
}
|
|
}
|