1107 lines
45 KiB
Dart
1107 lines
45 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
import 'package:awesome_snackbar_content/awesome_snackbar_content.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:onufitness/constants/api_enum_constant.dart';
|
|
import 'package:onufitness/constants/constant.dart';
|
|
import 'package:onufitness/environment/environment_config.dart';
|
|
import 'package:onufitness/screens/echoboard/controllers/connection_and_tribe_controller.dart';
|
|
import 'package:onufitness/screens/echoboard/controllers/echoboard_controller.dart';
|
|
import 'package:onufitness/screens/echoboard/controllers/like_comment_controller.dart';
|
|
import 'package:onufitness/screens/echoboard/controllers/rating_reviews.controller.dart';
|
|
import 'package:onufitness/screens/echoboard/views/single_post_screen.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/image_zoom.dart';
|
|
import 'package:onufitness/screens/echoboard/models/post_model.dart';
|
|
import 'package:onufitness/screens/echoboard/views/social_rating_reviews_screen.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/Like/reaction_popup.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/comment_bottomsheet.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/connection_request_respond_bottom_sheet.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/post_three_dot_bottom_sheet.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/profile_badge_bottomsheet.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/social_user_profile_shimmer.dart';
|
|
import 'package:onufitness/screens/u_vault/controllers/uvault_video_controller.dart';
|
|
import 'package:onufitness/services/local_storage_services/shared_services.dart';
|
|
import 'package:onufitness/widgets/appbars/custom_appbar.dart';
|
|
import 'package:onufitness/widgets/Buttons/custom_submit_button.dart';
|
|
import 'package:onufitness/constants/asset_constants.dart';
|
|
import 'package:onufitness/constants/color_constant.dart';
|
|
import 'package:onufitness/constants/text_constant.dart';
|
|
import 'package:onufitness/screens/echoboard/controllers/profile_controller.dart';
|
|
import 'package:onufitness/screens/echoboard/widget/post_card.dart';
|
|
import 'package:onufitness/utils/helper_function.dart';
|
|
import 'package:onufitness/widgets/Buttons/custom_social_login_button.dart';
|
|
import 'package:onufitness/widgets/others/new_custom_sneakbar.dart';
|
|
import 'package:share_plus/share_plus.dart';
|
|
|
|
class UserSocialProfileScreen extends StatefulWidget {
|
|
const UserSocialProfileScreen({super.key});
|
|
|
|
@override
|
|
State<UserSocialProfileScreen> createState() =>
|
|
_UserSocialProfileScreenState();
|
|
}
|
|
|
|
class _UserSocialProfileScreenState extends State<UserSocialProfileScreen> {
|
|
ReviewsController reviewsController = Get.put(ReviewsController());
|
|
final ScrollController _verticalScrollController = ScrollController();
|
|
final ScrollController _horizontalScrollController = ScrollController();
|
|
final socialConnectionController = Get.find<SocialConnectionController>();
|
|
ProfileController profileController = Get.find<ProfileController>();
|
|
EchoBoardController? echoBoardController;
|
|
late LikeCommentController likeCommentController;
|
|
|
|
// Track like requests to prevent multiple simultaneous calls.............................................................
|
|
final Set<String> _processingLikes = <String>{};
|
|
final Set<String> _processingComments = <String>{};
|
|
|
|
//........................................................................................................................
|
|
|
|
@override
|
|
void initState() {
|
|
if (!Get.isRegistered<EchoBoardController>()) {
|
|
Get.put(EchoBoardController());
|
|
}
|
|
echoBoardController = Get.find<EchoBoardController>();
|
|
if (!Get.isRegistered<LikeCommentController>()) {
|
|
Get.put(LikeCommentController());
|
|
}
|
|
likeCommentController = Get.find<LikeCommentController>();
|
|
if (!Get.isRegistered<UvaultController>()) {
|
|
Get.put(UvaultController());
|
|
}
|
|
super.initState();
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_loadData();
|
|
});
|
|
_verticalScrollController.addListener(_verticalScrollListener);
|
|
_horizontalScrollController.addListener(_horizontalScrollListener);
|
|
}
|
|
|
|
void _verticalScrollListener() {
|
|
if (_verticalScrollController.position.pixels ==
|
|
_verticalScrollController.position.maxScrollExtent) {
|
|
if (!reviewsController.isLoadingMore.value &&
|
|
!reviewsController.reachedEnd.value) {
|
|
reviewsController.loadMoreReviews();
|
|
}
|
|
}
|
|
}
|
|
|
|
void _horizontalScrollListener() {
|
|
if (_horizontalScrollController.position.pixels >
|
|
_horizontalScrollController.position.maxScrollExtent - 200.w) {
|
|
if (!profileController.isLoadingMoreRecentActivity.value &&
|
|
profileController.hasMoreRecentActivities.value) {
|
|
profileController.fetchRecentActivity(loadMore: true);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _loadData() async {
|
|
await Future.wait([
|
|
profileController.getUserSocialProfileInfo(),
|
|
profileController.fetchRecentActivity(),
|
|
]);
|
|
|
|
if (profileController.userSocialProfile.value.data != null) {
|
|
final userId = profileController.selectedUserId.toString();
|
|
reviewsController.revieweeId.value = userId;
|
|
await reviewsController.getUserReviews();
|
|
}
|
|
}
|
|
|
|
Future<void> handleLikePressed(SocialPostItem post) async {
|
|
final postIdStr = post.postId.toString();
|
|
|
|
if (_processingLikes.contains(postIdStr)) return;
|
|
_processingLikes.add(postIdStr);
|
|
|
|
final wasLiked = post.postReactionTypeId != null;
|
|
|
|
profileController.updatePostReaction(
|
|
postIdStr,
|
|
1, // reactionTypeId
|
|
wasLiked,
|
|
);
|
|
likeCommentController.updatePostReaction(
|
|
postIdStr,
|
|
1, // reactionTypeId
|
|
wasLiked,
|
|
);
|
|
|
|
// Step 2: API Call
|
|
likeCommentController
|
|
.submitPostReaction(
|
|
postId: postIdStr,
|
|
reactionTypeId: 1,
|
|
isDeleteReaction: wasLiked,
|
|
)
|
|
.then((success) {
|
|
if (!success) {
|
|
// Step 3: Revert on failure - Revert BOTH controllers
|
|
|
|
profileController.updatePostReaction(
|
|
postIdStr,
|
|
post.postReactionTypeId ?? 1, // Revert to original reaction type
|
|
!wasLiked, // Invert the removal flag
|
|
);
|
|
likeCommentController.updatePostReaction(
|
|
postIdStr,
|
|
post.postReactionTypeId ?? 1, // Revert to original reaction type
|
|
!wasLiked, // Invert the removal flag
|
|
);
|
|
}
|
|
})
|
|
.whenComplete(() {
|
|
_processingLikes.remove(postIdStr);
|
|
});
|
|
}
|
|
|
|
//........................................................................
|
|
|
|
Future<void> handleLongPress(
|
|
SocialPostItem post,
|
|
GlobalKey likeButtonKey,
|
|
) async {
|
|
final postIdStr = post.postId.toString();
|
|
|
|
if (_processingLikes.contains(postIdStr)) return;
|
|
|
|
showReactions(
|
|
context: context,
|
|
buttonKey: likeButtonKey,
|
|
onReactionSelected: (reaction, reactionTypeID) async {
|
|
if (_processingLikes.contains(postIdStr)) return;
|
|
|
|
_processingLikes.add(postIdStr);
|
|
|
|
// Step 1: Optimistic UI Update - Update BOTH controllers
|
|
likeCommentController.updatePostReaction(
|
|
postIdStr,
|
|
reactionTypeID,
|
|
false,
|
|
);
|
|
|
|
profileController.updatePostReaction(postIdStr, reactionTypeID, false);
|
|
|
|
// Step 2: API Call
|
|
likeCommentController
|
|
.submitPostReaction(
|
|
postId: postIdStr,
|
|
reactionTypeId: reactionTypeID,
|
|
isDeleteReaction: false,
|
|
)
|
|
.then((success) {
|
|
if (!success) {
|
|
// Step 3: Revert to previous state if failed
|
|
likeCommentController.updatePostReaction(
|
|
postIdStr,
|
|
post.postReactionTypeId ?? 1,
|
|
false,
|
|
);
|
|
profileController.updatePostReaction(
|
|
postIdStr,
|
|
post.postReactionTypeId ?? 1,
|
|
false,
|
|
);
|
|
}
|
|
})
|
|
.whenComplete(() {
|
|
_processingLikes.remove(postIdStr);
|
|
});
|
|
},
|
|
);
|
|
} //........................................................................................................................
|
|
|
|
Future<void> handleCommentPressed(SocialPostItem post) async {
|
|
final postIdStr = post.postId.toString();
|
|
|
|
// Prevent multiple comment bottom sheets from opening
|
|
if (_processingComments.contains(postIdStr)) return;
|
|
|
|
_processingComments.add(postIdStr);
|
|
|
|
try {
|
|
likeCommentController.postId.value = postIdStr;
|
|
|
|
if (mounted) {
|
|
showCommentsBottomSheet(context, postIdStr, likeCommentController);
|
|
}
|
|
} finally {
|
|
_processingComments.remove(postIdStr);
|
|
}
|
|
}
|
|
|
|
//........................................................................................................................
|
|
|
|
void showRemoveFriendDialog(BuildContext context, dynamic userProfile) {
|
|
showDialog(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return AlertDialog(
|
|
backgroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15.r),
|
|
side: BorderSide(color: Color(primaryColor), width: 2),
|
|
),
|
|
title: Container(
|
|
padding: EdgeInsets.all(8.sp),
|
|
decoration: BoxDecoration(
|
|
color: Color(primaryColor).withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(10.r),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.person_remove,
|
|
color: deeperShadeOfprimaryColor,
|
|
size: 24.sp,
|
|
),
|
|
SizedBox(width: 10.w),
|
|
Text(
|
|
'Remove Friend',
|
|
style: TextStyle(
|
|
fontSize: largeSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
color: deeperShadeOfprimaryColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
content: Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 10.h),
|
|
child: Text(
|
|
'Are you sure you want to remove ${userProfile?.fullName ?? 'this user'} from your friends list?',
|
|
style: TextStyle(
|
|
fontSize: mediumSizeText,
|
|
color: Color(darkGreyColor),
|
|
height: 1.4,
|
|
),
|
|
),
|
|
),
|
|
actionsPadding: EdgeInsets.symmetric(
|
|
horizontal: 16.w,
|
|
vertical: 10.h,
|
|
),
|
|
actions: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
border: Border.all(
|
|
color: Color(darkGreyColor).withValues(alpha: 0.3),
|
|
),
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
child: TextButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
},
|
|
style: TextButton.styleFrom(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: 20.w,
|
|
vertical: 10.h,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
),
|
|
child: Text(
|
|
'Cancel',
|
|
style: TextStyle(
|
|
color: Color(darkGreyColor),
|
|
fontSize: mediumSizeText,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 10.w),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
colors: [
|
|
deeperShadeOfprimaryColor,
|
|
deeperShadeOfprimaryColor,
|
|
],
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
),
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Color(primaryColor).withValues(alpha: 0.3),
|
|
blurRadius: 4,
|
|
offset: Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: TextButton(
|
|
onPressed: () async {
|
|
Get.back();
|
|
|
|
await socialConnectionController
|
|
.removeFriend(connectionId: userProfile!.userId!)
|
|
.then((value) {
|
|
if (value) {
|
|
userProfile.connectionStatus = ApiEnum.notConnected;
|
|
socialConnectionController.update([
|
|
'connectionStatus-${userProfile.userId}',
|
|
]);
|
|
}
|
|
});
|
|
},
|
|
style: TextButton.styleFrom(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: 20.w,
|
|
vertical: 10.h,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8.r),
|
|
),
|
|
),
|
|
child: Text(
|
|
'Remove',
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: mediumSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_verticalScrollController.removeListener(_verticalScrollListener);
|
|
_verticalScrollController.dispose();
|
|
_horizontalScrollController.removeListener(_horizontalScrollListener);
|
|
_horizontalScrollController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: CustomAppBar(
|
|
textColor: appbarTextColor,
|
|
titleFontSize: appBarHeardingText,
|
|
backgroundColor: Colors.white,
|
|
title: "Profile",
|
|
leading: IconButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
},
|
|
icon: Icon(Icons.arrow_back_ios),
|
|
),
|
|
),
|
|
body: RefreshIndicator(
|
|
backgroundColor: Colors.white,
|
|
color: Colors.black,
|
|
onRefresh: () async {
|
|
reviewsController.resetPagination();
|
|
profileController.resetRecentActivityPagination();
|
|
await _loadData();
|
|
},
|
|
child: SingleChildScrollView(
|
|
controller: _verticalScrollController,
|
|
physics: const AlwaysScrollableScrollPhysics(),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Obx(() {
|
|
if (profileController.isProfileLoading.value) {
|
|
return socialProfileShimmer();
|
|
}
|
|
return profileHeader(profileController);
|
|
}),
|
|
SizedBox(height: 20.h),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Text(
|
|
'Recent Activity',
|
|
style: TextStyle(
|
|
fontSize: largeSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 10.h),
|
|
Obx(() {
|
|
if (profileController.isRecentAcrivityLoading.value) {
|
|
return recentActivityShimmer();
|
|
}
|
|
|
|
if (profileController.posts.isEmpty) {
|
|
return Container(
|
|
height: 100.h,
|
|
alignment: Alignment.center,
|
|
child: Text(
|
|
'No recent activities',
|
|
style: TextStyle(fontSize: smallSizeText),
|
|
),
|
|
);
|
|
}
|
|
|
|
return SingleChildScrollView(
|
|
controller: _horizontalScrollController,
|
|
scrollDirection: Axis.horizontal,
|
|
child: Obx(() {
|
|
final postCards =
|
|
profileController.posts.map((post) {
|
|
final GlobalKey likeButtonKeyProfile =
|
|
GlobalKey();
|
|
return Padding(
|
|
padding: EdgeInsets.all(15.sp),
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(15.r),
|
|
border: Border.all(
|
|
color: containerBorderColor,
|
|
width: 2,
|
|
),
|
|
),
|
|
width: 300.w,
|
|
child: Padding(
|
|
padding: EdgeInsets.all(10.sp),
|
|
child: PostCard(
|
|
key: ValueKey(
|
|
'post_${post.postId}_${post.poll?.pollPostId}',
|
|
),
|
|
post: post,
|
|
onProfilePressed: () {},
|
|
onPostTap: () {
|
|
Get.to(
|
|
() => SinglePostPage(
|
|
postId: post.postId.toString(),
|
|
isComingFromShare: false,
|
|
tribeId: 0,
|
|
),
|
|
);
|
|
},
|
|
onLikePressed:
|
|
() => handleLikePressed(post),
|
|
likeButtonKey: likeButtonKeyProfile,
|
|
onLikeLongPressed:
|
|
() => handleLongPress(
|
|
post,
|
|
likeButtonKeyProfile,
|
|
),
|
|
onCommentPressed:
|
|
() => handleCommentPressed(post),
|
|
|
|
onSharePressed: () async {
|
|
log(post.postId.toString());
|
|
final encodedPostId = base64Url.encode(
|
|
utf8.encode(post.postId.toString()),
|
|
);
|
|
final webUrl =
|
|
EnvironmentConfigFactory.getConfig()
|
|
.webUrl;
|
|
final shareUrl =
|
|
"https://$webUrl/post-link?postId=$encodedPostId";
|
|
final content = shareUrl;
|
|
|
|
await SharePlus.instance.share(
|
|
ShareParams(
|
|
text: content,
|
|
subject: 'Check out this post!',
|
|
),
|
|
);
|
|
},
|
|
onMorePressed: () {
|
|
final bool isMyPost =
|
|
post.userId ==
|
|
SharedServices.getUserDetails()
|
|
?.data
|
|
?.userId;
|
|
|
|
PostMoreOptionsBottomSheet.show(
|
|
context: context,
|
|
postId: post.postId.toString(),
|
|
isMyPost: isMyPost,
|
|
post: post,
|
|
);
|
|
},
|
|
onPollOptionSelected: (
|
|
pollId,
|
|
optionId,
|
|
) async {
|
|
log(
|
|
"Poll option selected: pollId=$pollId, optionId=$optionId",
|
|
);
|
|
echoBoardController!
|
|
.submitPollVote(pollId, optionId)
|
|
.then((response) {
|
|
if (response != null) {
|
|
log(
|
|
"response------------------>>>> ${jsonEncode(response)}",
|
|
);
|
|
echoBoardController!
|
|
.updatePostWithPollResults(
|
|
response,
|
|
selectedOptionId:
|
|
optionId,
|
|
);
|
|
}
|
|
});
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}).toList();
|
|
|
|
if (profileController
|
|
.isLoadingMoreRecentActivity
|
|
.value) {
|
|
postCards.add(
|
|
Padding(
|
|
padding: EdgeInsets.only(right: 16.w),
|
|
child: SizedBox(
|
|
width: 25.w,
|
|
height: 25.h,
|
|
child: const Center(
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return Row(children: postCards);
|
|
}),
|
|
);
|
|
}),
|
|
],
|
|
),
|
|
SizedBox(height: 20.h),
|
|
Obx(() {
|
|
final userProfile =
|
|
profileController.userSocialProfile.value.data;
|
|
|
|
if (profileController.isProfileLoading.value ||
|
|
userProfile == null) {
|
|
return SizedBox.shrink();
|
|
}
|
|
|
|
final isCoach =
|
|
userProfile.userTypeName == ApiEnum.coachUserRole;
|
|
final isConnected =
|
|
userProfile.connectionStatus == ApiEnum.accepted;
|
|
final userName = userProfile.fullName ?? "User";
|
|
|
|
if (!isCoach) return SizedBox.shrink();
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Text(
|
|
'Ratings & Reviews',
|
|
style: TextStyle(
|
|
fontSize: largeSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 10.h),
|
|
reviewsController.isLoading.value
|
|
? ratingsShimmer()
|
|
: RatingStatsWidget(
|
|
avgRating: reviewsController.averageRating.value,
|
|
totalReviews: reviewsController.totalReviews.value,
|
|
userName: userName,
|
|
),
|
|
reviewsController.isLoading.value
|
|
? reviewsShimmer()
|
|
: isConnected &&
|
|
isCoach &&
|
|
SharedServices.getLoginDetails()?.data?.userRole ==
|
|
ApiEnum.traineeUserRole
|
|
? Padding(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: 16.w,
|
|
vertical: 16.h,
|
|
),
|
|
child: CustomSubmitButton(
|
|
height: isTablet ? 50.h : 45.h,
|
|
text: "Write a Review",
|
|
onPressed: () {
|
|
showDialog(
|
|
context: context,
|
|
builder:
|
|
(context) => ReviewInputDialog(
|
|
onSubmit:
|
|
(rating, review) => reviewsController
|
|
.submitReview(rating, review),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
)
|
|
: SizedBox.shrink(), // Fallback widget when not connected
|
|
|
|
Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Text(
|
|
'Reviews',
|
|
style: TextStyle(
|
|
fontSize: largeSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 10.h),
|
|
if (reviewsController.isLoading.value)
|
|
reviewsShimmer()
|
|
else if (reviewsController.reviews.isEmpty)
|
|
SizedBox(
|
|
height: 200.h,
|
|
child: Center(
|
|
child: Text(
|
|
'No reviews yet',
|
|
style: TextStyle(
|
|
fontSize: mediumSizeText,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
),
|
|
)
|
|
else
|
|
ListView.builder(
|
|
shrinkWrap: true,
|
|
physics: NeverScrollableScrollPhysics(),
|
|
itemCount:
|
|
reviewsController.isLoadingMore.value
|
|
? reviewsController.reviews.length + 1
|
|
: reviewsController.reviews.length,
|
|
itemBuilder: (context, index) {
|
|
if (index < reviewsController.reviews.length) {
|
|
return ReviewCard(
|
|
review: reviewsController.reviews[index],
|
|
);
|
|
} else {
|
|
return Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(16.sp),
|
|
child: const CircularProgressIndicator(
|
|
color: Colors.black,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
),
|
|
],
|
|
);
|
|
}),
|
|
SizedBox(height: 40.h),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
//.......................................................................................................
|
|
//.......................................................................................................
|
|
//.......................................................................................................
|
|
Widget profileHeader(ProfileController controller) {
|
|
// Get the user profile data..........................................................................
|
|
final userProfile = controller.userSocialProfile.value.data;
|
|
|
|
return Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
InkWell(
|
|
onTap: () {
|
|
userProfile?.profilePicture != null &&
|
|
userProfile!.profilePicture!.isNotEmpty
|
|
? Get.to(
|
|
() => ImageZoomWidget(
|
|
imageUrl: userProfile.profilePicture!,
|
|
),
|
|
)
|
|
: () {};
|
|
},
|
|
child: CircleAvatar(
|
|
radius: 30.r,
|
|
backgroundImage:
|
|
userProfile?.profilePicture != null &&
|
|
userProfile!.profilePicture!.isNotEmpty
|
|
? NetworkImage(userProfile.profilePicture!)
|
|
: AssetImage(AssetConstants.dummyUserImage)
|
|
as ImageProvider,
|
|
),
|
|
),
|
|
SizedBox(width: 20.w),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
userProfile?.fullName ?? 'User Name',
|
|
style: TextStyle(
|
|
fontSize: largeSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
'${userProfile?.totalConnection ?? 0} Friends',
|
|
style: TextStyle(fontSize: smallSizeText),
|
|
),
|
|
SizedBox(width: 10.w),
|
|
Text(
|
|
"•",
|
|
style: TextStyle(
|
|
fontSize: smallSizeText + 2,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
SizedBox(width: 10.w),
|
|
GestureDetector(
|
|
onTap: () {
|
|
showBadgesBottomSheet(
|
|
context: context,
|
|
userID: userProfile!.userId!,
|
|
profileController: profileController,
|
|
);
|
|
},
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: 12.w,
|
|
vertical: 4.h,
|
|
),
|
|
decoration: BoxDecoration(
|
|
color: Color(primaryColor).withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(30.r),
|
|
border: Border.all(
|
|
color: deeperShadeOfprimaryColor,
|
|
width: 1,
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Image.asset(
|
|
AssetConstants.goalAchievementsReward,
|
|
height: 18.h,
|
|
width: 18.w,
|
|
),
|
|
SizedBox(width: 5.w),
|
|
Text(
|
|
'Badges',
|
|
style: TextStyle(
|
|
fontSize: smallSizeText,
|
|
fontWeight: FontWeight.bold,
|
|
color: deeperShadeOfprimaryColor,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 5.h),
|
|
Text(
|
|
userProfile?.country ?? "",
|
|
style: TextStyle(
|
|
fontSize: smallSizeText,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
SizedBox(height: 10.h),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 10.h),
|
|
Text(
|
|
userProfile?.aboutMe?.toString() ??
|
|
"I'm someone who's curious by nature, always eager to learn, connect, and grow 🎯. I enjoy finding creative solutions, working with great people, and contributing to meaningful projects 🎉",
|
|
),
|
|
|
|
SizedBox(height: 10.h),
|
|
|
|
Row(
|
|
children: [
|
|
GetBuilder<SocialConnectionController>(
|
|
init: SocialConnectionController(),
|
|
id: 'connectionStatus-${userProfile?.userId}',
|
|
builder: (controller) {
|
|
if (userProfile?.connectionStatus == ApiEnum.pending) {
|
|
return Container(
|
|
height: isTablet ? 45.h : 40.h,
|
|
width: isTablet ? 0.3.sw : 0.35.sw,
|
|
decoration: BoxDecoration(
|
|
color: greyTextColor1.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(30.r),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"Pending",
|
|
style: TextStyle(
|
|
color: greyTextColor2,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
} else if (userProfile?.connectionStatus ==
|
|
ApiEnum.Requested) {
|
|
return Obx(
|
|
() => CustomSocialLoginButton(
|
|
isLoading:
|
|
socialConnectionController
|
|
.isRespondingToConnection
|
|
.value,
|
|
height: isTablet ? 45.h : 40.h,
|
|
width: isTablet ? 0.3.sw : 0.35.sw,
|
|
text: "Respond",
|
|
borderSide: BorderSide(color: Colors.black),
|
|
backgroundColor: Colors.black,
|
|
textColor: Colors.white,
|
|
onPressed: () {
|
|
ConnectionResponseBottomSheet.show(
|
|
context: context,
|
|
userProfile: userProfile!,
|
|
onResponse: (bool accepted) async {
|
|
if (accepted) {
|
|
await socialConnectionController
|
|
.respondToConnectionRequest(
|
|
userProfile.userId!,
|
|
ApiEnum.accepted,
|
|
)
|
|
.then((value) {
|
|
if (value) {
|
|
userProfile.connectionStatus =
|
|
ApiEnum.accepted;
|
|
socialConnectionController.update([
|
|
'connectionStatus-${userProfile.userId}',
|
|
]);
|
|
}
|
|
});
|
|
} else {
|
|
await socialConnectionController
|
|
.respondToConnectionRequest(
|
|
userProfile.userId!,
|
|
ApiEnum.rejected,
|
|
)
|
|
.then((value) {
|
|
if (value) {
|
|
userProfile.connectionStatus =
|
|
ApiEnum.notConnected;
|
|
socialConnectionController.update([
|
|
'connectionStatus-${userProfile.userId}',
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
);
|
|
},
|
|
),
|
|
);
|
|
} else if (userProfile?.connectionStatus ==
|
|
ApiEnum.notConnected &&
|
|
(userProfile?.userId !=
|
|
SharedServices.getLoginDetails()?.data?.userId)) {
|
|
return Obx(
|
|
() => CustomSocialLoginButton(
|
|
isLoading:
|
|
socialConnectionController
|
|
.singleSendConnectionRequestLoading
|
|
.value,
|
|
height: isTablet ? 45.h : 40.h,
|
|
width: isTablet ? 0.3.sw : 0.35.sw,
|
|
text: "Add Friend",
|
|
borderSide: BorderSide(color: Color(darkGreyColor)),
|
|
textColor: Colors.black,
|
|
onPressed: () async {
|
|
await socialConnectionController
|
|
.sendConnectionRequest(userProfile!.userId!)
|
|
.then((value) {
|
|
if (value) {
|
|
userProfile.connectionStatus =
|
|
ApiEnum.pending;
|
|
socialConnectionController.update([
|
|
'connectionStatus-${userProfile.userId}',
|
|
]);
|
|
}
|
|
});
|
|
},
|
|
),
|
|
);
|
|
} else if ((userProfile?.connectionStatus ==
|
|
ApiEnum.accepted &&
|
|
userProfile?.userId !=
|
|
SharedServices.getLoginDetails()?.data?.userId)) {
|
|
return Obx(
|
|
() => CustomSocialLoginButton(
|
|
isLoading:
|
|
socialConnectionController
|
|
.isRemoveConnectionLoading
|
|
.value,
|
|
height: isTablet ? 45.h : 40.h,
|
|
width: isTablet ? 0.3.sw : 0.35.sw,
|
|
text: "Remove Friend",
|
|
fontSize: verySmallSizeText,
|
|
borderSide: BorderSide(color: Color(darkGreyColor)),
|
|
textColor: Colors.black,
|
|
onPressed: () async {
|
|
showRemoveFriendDialog(context, userProfile);
|
|
},
|
|
),
|
|
);
|
|
} else {
|
|
return SizedBox.shrink();
|
|
}
|
|
},
|
|
),
|
|
|
|
SizedBox(width: 10.w),
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
children: [
|
|
_socialMediaIcon(
|
|
imageLink: AssetConstants.facebookLogo,
|
|
onPressed: () async {
|
|
if (userProfile?.facebookSocialLink != null &&
|
|
userProfile!.facebookSocialLink!.isNotEmpty) {
|
|
final Uri url = Uri.parse(
|
|
userProfile.facebookSocialLink!,
|
|
);
|
|
await launchAnylUrl(url);
|
|
} else {
|
|
AwesomeCustomSnackbar.show(
|
|
context: context,
|
|
title: 'No Link Available',
|
|
message:
|
|
'Facebook link is not available for this user',
|
|
contentType: ContentType.warning,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
SizedBox(width: 5.w),
|
|
_socialMediaIcon(
|
|
imageLink: AssetConstants.instagramLogo,
|
|
onPressed: () async {
|
|
if (userProfile?.instagramSocialLink != null &&
|
|
userProfile!.instagramSocialLink!.isNotEmpty) {
|
|
final Uri url = Uri.parse(
|
|
userProfile.instagramSocialLink!,
|
|
);
|
|
await launchAnylUrl(url);
|
|
} else {
|
|
AwesomeCustomSnackbar.show(
|
|
context: context,
|
|
title: 'No Link Available',
|
|
message:
|
|
'Instagram link is not available for this user',
|
|
contentType: ContentType.warning,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
SizedBox(width: 5.w),
|
|
_socialMediaIcon(
|
|
imageLink: AssetConstants.linkedInLogo,
|
|
onPressed: () async {
|
|
if (userProfile?.linkedInSocialLink != null &&
|
|
userProfile!.linkedInSocialLink!.isNotEmpty) {
|
|
final Uri url = Uri.parse(
|
|
userProfile.linkedInSocialLink!,
|
|
);
|
|
await launchAnylUrl(url);
|
|
} else {
|
|
AwesomeCustomSnackbar.show(
|
|
context: context,
|
|
title: 'No Link Available',
|
|
message:
|
|
'LinkedIn link is not available for this user',
|
|
contentType: ContentType.warning,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
SizedBox(width: 5.w),
|
|
_socialMediaIcon(
|
|
imageLink: AssetConstants.twitterLogo,
|
|
onPressed: () async {
|
|
if (userProfile?.twitterSocialLink != null &&
|
|
userProfile!.twitterSocialLink!.isNotEmpty) {
|
|
final Uri url = Uri.parse(
|
|
userProfile.twitterSocialLink!,
|
|
);
|
|
await launchAnylUrl(url);
|
|
} else {
|
|
AwesomeCustomSnackbar.show(
|
|
context: context,
|
|
title: 'No Link Available',
|
|
message:
|
|
'Twitter link is not available for this user',
|
|
contentType: ContentType.warning,
|
|
);
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _socialMediaIcon({
|
|
required String imageLink,
|
|
required Function() onPressed,
|
|
}) {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
border: Border.all(color: lightGreyColor),
|
|
),
|
|
child: IconButton(
|
|
icon: Image.asset(
|
|
imageLink,
|
|
height: isTablet ? 25.h : 20.h,
|
|
width: isTablet ? 25.w : 20.w,
|
|
),
|
|
onPressed: onPressed,
|
|
),
|
|
);
|
|
}
|
|
|
|
//........................................................................
|
|
}
|