onufitness_mobile/lib/screens/echoboard/views/upload_post_screen.dart
2026-06-29 12:28:16 +05:30

601 lines
25 KiB
Dart

import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:onufitness/constants/asset_constants.dart';
import 'package:onufitness/constants/color_constant.dart';
import 'package:onufitness/constants/constant.dart';
import 'package:onufitness/constants/text_constant.dart';
import 'package:onufitness/screens/echoboard/controllers/echoboard_controller.dart';
import 'package:onufitness/screens/echoboard/views/create_poll_screen.dart';
import 'package:onufitness/screens/echoboard/widget/privecy_bottom_sheet.dart';
import 'package:onufitness/screens/streamming/screens/create_streem_screen.dart';
import 'package:onufitness/utils/custom_sneakbar.dart';
import 'package:onufitness/utils/helper_function.dart';
import 'package:onufitness/widgets/appbars/custom_appbar.dart';
import 'package:onufitness/widgets/Buttons/custom_submit_button.dart';
import 'package:onufitness/widgets/bottomsheet/common_upload_option_bottomsheet.dart';
import 'package:video_player/video_player.dart';
class UploadPostScreen extends StatefulWidget {
final bool isTribeEchoboard;
final int tribeId;
const UploadPostScreen({
super.key,
this.isTribeEchoboard = false,
this.tribeId = 0,
});
@override
State<UploadPostScreen> createState() => _UploadPostScreenState();
}
class _UploadPostScreenState extends State<UploadPostScreen> {
EchoBoardController? echoBoardController;
@override
void initState() {
if (!Get.isRegistered<EchoBoardController>()) {
Get.put(EchoBoardController());
}
echoBoardController = Get.find<EchoBoardController>();
echoBoardController!.captionCtrl = TextEditingController();
echoBoardController!.connectionSearchController = TextEditingController();
super.initState();
}
@override
void dispose() {
echoBoardController?.captionCtrl.dispose();
echoBoardController?.connectionSearchController.dispose();
echoBoardController!.removeMedia();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Colors.white,
appBar: CustomAppBar(
title: 'U Echo',
textColor: appbarTextColor,
titleFontSize: appBarHeardingText,
backgroundColor: Colors.white,
leading: IconButton(
icon: Icon(Icons.close, color: Colors.black, size: 24.r),
onPressed: Get.back,
),
actions: [
Row(
children: [
widget.isTribeEchoboard == false
? Obx(
() => InkWell(
onTap: () {
showPrivacyBottomSheet(context, echoBoardController!);
},
child: Row(
children: [
Text(
echoBoardController!.visibility.value,
style: TextStyle(
color: Colors.grey[700],
fontSize: smallSizeText,
),
),
Icon(
Icons.keyboard_arrow_down,
color: Colors.grey[700],
),
],
),
),
)
: Container(),
SizedBox(width: 16.w),
Obx(() {
final hasCaption =
echoBoardController!.captionText.value.trim().isNotEmpty;
final hasMedia =
echoBoardController!.mediaType.value != MediaType.none;
final isValid = hasCaption || hasMedia;
return CustomSubmitButton(
text: "Post",
backgroundColor: isValid ? Colors.black : Colors.grey[400]!,
textColor: Colors.white,
width: isTablet ? 120.w : 70.w,
height: 35.h,
fontSize: smallSizeText,
isLoading: echoBoardController!.isPostUploadLoading.value,
isDisable: !isValid,
onPressed: () async {
final success = await echoBoardController!.uploadPost(
tribeIdForTribeEchoboard: widget.tribeId,
);
if (success) {
if (widget.tribeId != 0) {
// For tribe echoboard
echoBoardController!.fetchPosts(
tribeId: widget.tribeId,
refresh: true,
);
}
if (widget.tribeId == 0) {
echoBoardController!.refreshPosts();
}
await Future.delayed(const Duration(seconds: 1));
Get.back(closeOverlays: true);
}
},
);
}),
SizedBox(width: 12.w),
],
),
],
),
body: Obx(
() => Column(
children: [
// Scrollable content area
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// TextField container
Container(
decoration: BoxDecoration(
border: Border.all(color: lightGreyColor),
borderRadius: BorderRadius.circular(10.r),
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: TextField(
controller: echoBoardController!.captionCtrl,
maxLines: 6,
style: TextStyle(fontSize: regularSizeText),
decoration: InputDecoration(
hintText: "What's on your mind?",
border: InputBorder.none,
hintStyle: TextStyle(fontSize: smallSizeText),
),
onChanged: (value) {
echoBoardController!.captionText.value = value;
},
),
),
),
SizedBox(height: 10.h),
// Media preview section
if (echoBoardController!.mediaType.value !=
MediaType.none)
Padding(
padding: EdgeInsets.symmetric(horizontal: 10.w),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap:
echoBoardController!.mediaType.value ==
MediaType.image
? () {
CommonUploadBottomSheet.show(
context: context,
title: "Upload Image From",
allowedFileTypes: [
'jpg',
'jpeg',
'png',
],
maxFileSizeMB: 50.0,
showCamera: true,
showGallery: true,
showDocument: true,
showRecordVideo: false,
onFileSelected: (
String filePath,
String fileName,
String fileExtension,
) {
log(
"Selected image path: $filePath",
);
// Set the selected image
echoBoardController!
.selectedImage
.value = File(filePath);
echoBoardController!
.clearVideo();
echoBoardController!
.mediaType
.value = MediaType.image;
},
onError: (String errorMessage) {
customSnackbar(
title: "Error",
message: errorMessage,
);
},
);
}
: () {
CommonUploadBottomSheet.show(
context: context,
title: "Upload Video From",
allowedFileTypes: [
'mp4',
'm4v',
'mov',
],
maxFileSizeMB: 500.0,
showCamera: false,
showGallery: true,
showDocument: true,
showRecordVideo: true,
onFileSelected: (
String filePath,
String fileName,
String fileExtension,
) async {
log(
"Selected video path: $filePath",
);
// Set the selected video
echoBoardController!
.selectedVideo
.value = File(filePath);
echoBoardController!
.selectedImage
.value = null;
echoBoardController!
.mediaType
.value = MediaType.video;
await echoBoardController!
.initializeVideoPlayer(
filePath,
);
},
onError: (String errorMessage) {
customSnackbar(
title: "Error",
message: errorMessage,
);
},
);
},
child: Container(
decoration: BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
padding: EdgeInsets.all(6.w),
child: Icon(
Icons.edit,
size: 20.r,
color: Colors.white,
),
),
),
SizedBox(width: 10.h),
GestureDetector(
onTap: echoBoardController!.removeMedia,
child: Container(
decoration: BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
padding: EdgeInsets.all(6.w),
child: Icon(
Icons.close,
size: 20.r,
color: Colors.white,
),
),
),
],
),
SizedBox(height: 20.h),
if (echoBoardController!.mediaType.value ==
MediaType.image)
_buildImagePreview(),
if (echoBoardController!.mediaType.value ==
MediaType.video)
_buildVideoPreview(),
],
),
),
],
),
),
),
),
// Bottom action bar - stays at bottom
if (echoBoardController!.mediaType.value == MediaType.none)
Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: double.infinity,
padding: EdgeInsets.only(
left: 15.w,
right: 15.w,
top: 10.h,
bottom: isTablet ? 40.h : 20.h,
),
decoration: BoxDecoration(color: Colors.white),
child: Row(
children: [
Image.asset(
AssetConstants.videoIconSocialWall,
width: 24.r,
height: 24.r,
color: Colors.black,
),
SizedBox(width: 10.w),
InkWell(
onTap: () {
Get.to(
() => CreateLiveStreamScreen(
tribeId: widget.tribeId,
),
);
},
child: Text(
'Start a spark',
style: TextStyle(
fontSize: mediumSizeText,
fontWeight: FontWeight.bold,
fontFamily: montserratFontFamily,
),
),
),
Spacer(),
IconButton(
onPressed: () {
Get.to(
() => PollCreationView(tribeID: widget.tribeId),
);
},
icon: Image.asset(
AssetConstants.createPollLogo,
width: 24.r,
height: 24.r,
color: greyTextColor1,
),
),
IconButton(
// onPressed: echoBoardController!.pickImage,
onPressed: () {
CommonUploadBottomSheet.show(
context: context,
title: "Upload Image From",
allowedFileTypes: ['jpg', 'jpeg', 'png'],
maxFileSizeMB: 50.0,
showCamera: true,
showGallery: true,
showDocument: true,
showRecordVideo: false,
onFileSelected: (
String filePath,
String fileName,
String fileExtension,
) {
log("Selected image path: $filePath");
// Set the selected image
echoBoardController!.selectedImage.value = File(
filePath,
);
echoBoardController!.clearVideo();
echoBoardController!.mediaType.value =
MediaType.image;
},
onError: (String errorMessage) {
customSnackbar(
title: "Error",
message: errorMessage,
);
},
);
},
icon: Image.asset(
AssetConstants.imageSocialWall,
width: 24.r,
height: 24.r,
color: greyTextColor1,
),
),
IconButton(
onPressed: () {
CommonUploadBottomSheet.show(
context: context,
title: "Upload Video From",
allowedFileTypes: ['mp4', 'm4v', 'mov'],
maxFileSizeMB: 500.0,
showCamera: false,
showGallery: true,
showDocument: true,
showRecordVideo: true,
onFileSelected: (
String filePath,
String fileName,
String fileExtension,
) async {
log("Selected video path: $filePath");
// Set the selected video
echoBoardController!.selectedVideo.value = File(
filePath,
);
echoBoardController!.selectedImage.value = null;
echoBoardController!.mediaType.value =
MediaType.video;
await echoBoardController!
.initializeVideoPlayer(filePath);
},
onError: (String errorMessage) {
customSnackbar(
title: "Error",
message: errorMessage,
);
},
);
},
icon: Image.asset(
AssetConstants.reelIconSocialWall,
width: 24.r,
height: 24.r,
color: greyTextColor1,
),
),
],
),
),
Container(
color: Colors.white,
padding: EdgeInsetsDirectional.only(
bottom: MediaQuery.of(context).viewPadding.bottom,
),
),
],
),
],
),
),
);
}
Widget _buildImagePreview() {
final image = echoBoardController?.selectedImage.value;
if (image == null || image.path.isEmpty) {
return const SizedBox.shrink();
}
return ClipRRect(
borderRadius: BorderRadius.circular(12.r),
child: Image.file(
File(image.path),
width: double.infinity,
height: 220.h,
fit: BoxFit.cover,
cacheWidth:
(MediaQuery.of(context).size.width *
MediaQuery.of(context).devicePixelRatio)
.clamp(720, 1600)
.round(),
),
);
}
Widget _buildVideoPreview() {
return Obx(() {
final controller = echoBoardController?.videoController.value;
if (controller == null ||
!echoBoardController!.isVideoInitialized.value ||
!controller.value.isInitialized) {
return Container(
width: double.infinity,
height: 220.h,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(12.r),
),
child: const Center(child: CircularProgressIndicator()),
);
}
return Stack(
alignment: Alignment.center,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12.r),
child: SizedBox(
width: double.infinity,
height: 220.h,
child: AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: VideoPlayer(controller),
),
),
),
/// Play / Pause Button
Positioned(
bottom: 10.h,
left: 10.w,
child: GestureDetector(
onTap: echoBoardController?.toggleVideoPlayback,
child: Container(
width: 40.r,
height: 40.r,
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.5),
shape: BoxShape.circle,
),
child: Icon(
echoBoardController?.isVideoPlaying.value == true
? Icons.pause
: Icons.play_arrow,
color: Colors.white,
size: 20.r,
),
),
),
),
/// Duration
Positioned(
bottom: 10.h,
right: 10.w,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.6),
borderRadius: BorderRadius.circular(4.r),
),
child: Text(
_formatDuration(controller.value.duration),
style: TextStyle(color: Colors.white, fontSize: smallSizeText),
),
),
),
],
);
});
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
String hours = twoDigits(duration.inHours);
String minutes = twoDigits(duration.inMinutes.remainder(60));
String seconds = twoDigits(duration.inSeconds.remainder(60));
return "$hours:$minutes:$seconds";
}
}