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 createState() => _UploadPostScreenState(); } class _UploadPostScreenState extends State { EchoBoardController? echoBoardController; @override void initState() { if (!Get.isRegistered()) { Get.put(EchoBoardController()); } echoBoardController = Get.find(); 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"; } }