Привет, я пытаюсь загрузить видео из своего приложения, когда я впервые запускаю приложение и выполняю загрузку, все в порядке, но при второй загрузке выдается ошибка
Bad state: Stream has already been listed to
это мой видеоконтроллер для загрузки
import 'dart:async';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:get/get.dart';
import 'package:video_compress/video_compress.dart';
import 'package:viwaad_1/constants.dart';
import 'package:viwaad_1/models/videos.dart';
class UploadVideoContoller extends GetxController {
var compressionProgress = 0.0.obs; // Progress observable
var uploadProgress = 0.0.obs;
// StreamController and StreamSubscription to manage compression progress
StreamController? _progressController;
StreamSubscription? _progressSubscription;
// Method to handle video compression
Future _compressVideo(String videoPath) async {
try {
// Clean up any previous compression progress
await _cancelPreviousCompressionProgress();
// Show Snackbar to indicate compression started
Get.snackbar(
'Compression Started',
'Compressing video...',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
// Set logging level (optional)
VideoCompress.setLogLevel(0);
compressionProgress.value = 0.0;
// Create a new StreamController for the new compression task
_progressController = StreamController();
// Start video compression
final compressTask = VideoCompress.compressVideo(
videoPath,
quality: VideoQuality.MediumQuality,
deleteOrigin: false,
);
// Listen for progress updates
VideoCompress.compressProgress$.subscribe((progress) {
// Only feed progress to controller if it's valid
if (_progressController != null && !_progressController!.isClosed) {
_progressController!.add(progress / 100); // Normalize progress to 0-1 range
}
});
// Listen to the progress updates stream
_progressSubscription = _progressController!.stream.listen((progress) {
compressionProgress.value = progress; // Update progress observable
});
// Wait for the compression task to complete
final compressedVideo = await compressTask;
// Close the progress controller stream
await _progressController!.close();
// Show completion Snackbar
Get.snackbar(
'Compression Complete',
'The video has been compressed successfully!',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
return compressedVideo?.file;
} catch (e) {
// Handle any errors that occur during compression
Get.snackbar(
'Compression Error',
'An error occurred during video compression: $e',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
return null;
}
}
// Method to clean up previous progress stream and subscription
Future _cancelPreviousCompressionProgress() async {
if (_progressSubscription != null) {
await _progressSubscription!.cancel();
_progressSubscription = null;
}
if (_progressController != null) {
await _progressController!.close();
_progressController = null;
}
}
// Method to upload compressed video to Firebase Storage
Future _uploadVideoToStorage(String id, String videoPath) async {
File? compressedVideo = await _compressVideo(videoPath);
if (compressedVideo == null) throw "Compression failed.";
try {
Reference ref = FirebaseStorage.instance.ref().child('videos').child(id);
UploadTask uploadTask = ref.putFile(compressedVideo);
// Monitor upload progress
uploadTask.snapshotEvents.listen((TaskSnapshot snapshot) {
uploadProgress.value = snapshot.bytesTransferred / snapshot.totalBytes;
});
// Wait for upload to complete
TaskSnapshot snapshot = await uploadTask;
return await snapshot.ref.getDownloadURL();
} catch (e) {
throw "Error uploading video: $e";
}
}
// Method to get a thumbnail for the video
Future _getThumbnail(String videoPath) async {
return await VideoCompress.getFileThumbnail(videoPath);
}
// Method to upload video thumbnail to Firebase Storage
Future _uploadImageToStorage(String id, String videoPath) async {
File thumbnail = await _getThumbnail(videoPath);
Reference ref = firebaseStorage.ref().child('thumbnails').child(id);
UploadTask uploadTask = ref.putFile(thumbnail);
TaskSnapshot snap = await uploadTask;
return await snap.ref.getDownloadURL();
}
// Main method to upload video and associated metadata
Future uploadVideo(String songName, String caption, String videoPath) async {
try {
// Clean up any previous progress before starting new upload
await _cancelPreviousCompressionProgress();
String uid = firebaseAuth.currentUser!.uid;
DocumentSnapshot userDoc = await firestore.collection('users').doc(uid).get();
String len = "${firebaseAuth.currentUser!.uid}_${DateTime.now().millisecondsSinceEpoch}";
String videoUrl = await _uploadVideoToStorage("Video $len", videoPath);
String thumbnail = await _uploadImageToStorage("Video $len", videoPath);
String profilePhoto = (userDoc.data() as Map)['profilePhoto'];
// Create video metadata object
Video video = Video(
uid: uid,
id: "Video $len",
likes: [],
commentCount: 0,
shareCount: 0,
songName: songName,
caption: caption,
videoUrl: videoUrl,
thumbnail: thumbnail,
profilePhoto: profilePhoto,
);
// Upload video metadata to Firestore
await firestore.collection('videos').doc("Video $len").set(video.toJson());
} catch (e) {
// Handle upload errors
String uid = firebaseAuth.currentUser?.uid ?? 'Unknown UID';
Get.snackbar(
'Error Uploading Video',
'Error: $e\nUser UID: $uid',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
}
}
@override
void onClose() {
// Ensure that previous compression progress is cleaned up when the controller is disposed
_cancelPreviousCompressionProgress();
super.onClose();
}
}
а это экран загрузки
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:viwaad_1/controllers/upload_video_contoller.dart';
import 'package:viwaad_1/views/widgets/text_input_field.dart';
class ConfirmScreen extends StatefulWidget {
final File videoFile;
final String videoPath;
const ConfirmScreen({Key? key, required this.videoFile, required this.videoPath}) : super(key: key);
@override
_ConfirmScreenState createState() => _ConfirmScreenState();
}
class _ConfirmScreenState extends State {
late VideoPlayerController _controller;
final TextEditingController _songController = TextEditingController();
final TextEditingController _captionController = TextEditingController();
final UploadVideoContoller _uploadVideoContoller = Get.put(UploadVideoContoller(), permanent: false);
bool _isUploading = false;
@override
void initState() {
super.initState();
// Initialize VideoPlayerController
_controller = VideoPlayerController.file(widget.videoFile)
..initialize().then((_) {
setState(() {
_controller.play();
_controller.setVolume(1);
_controller.setLooping(true);
});
});
}
@override
void dispose() {
_controller.dispose(); // Dispose the video controller
_uploadVideoContoller.onClose(); // Ensure the controller handles cleanup
super.dispose();
}
void startUpload() {
setState(() {
_isUploading = true;
_uploadVideoContoller.compressionProgress.value = 0.0;
_uploadVideoContoller.uploadProgress.value = 0.0;
});
_uploadVideoContoller.uploadVideo(
_songController.text,
_captionController.text,
widget.videoPath,
).then((_) {
setState(() {
_isUploading = false;
});
Get.snackbar(
'Upload Complete',
'Video successfully uploaded',
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 5),
);
// Navigate back after Snackbar duration
Future.delayed(const Duration(seconds: 1), () {
if (mounted) {
Navigator.of(context).pop();
}
});
}).catchError((e) {
setState(() {
_isUploading = false;
});
Get.snackbar(
'Upload Failed',
'Error: $e',
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 3),
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 30),
SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height / 1.5,
child: VideoPlayer(_controller),
),
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
// Song Name Input
TextInputField(
controller: _songController,
labelText: 'Song Name',
icon: Icons.music_note,
),
const SizedBox(height: 10),
// Caption Input
TextInputField(
controller: _captionController,
labelText: 'Caption',
icon: Icons.closed_caption,
),
const SizedBox(height: 10),
// Upload Progress or Button
_isUploading
? Obx(() {
double progress = _uploadVideoContoller.compressionProgress.value < 1.0
? _uploadVideoContoller.compressionProgress.value
: _uploadVideoContoller.uploadProgress.value;
String progressLabel = _uploadVideoContoller.compressionProgress.value < 1.0
? 'Compression Progress'
: 'Upload Progress';
return Column(
children: [
Text(
'$progressLabel: ${(100 * progress).toStringAsFixed(0)}%',
style: const TextStyle(fontSize: 16),
),
LinearProgressIndicator(
value: progress,
minHeight: 8,
),
const SizedBox(height: 20),
],
);
})
: ElevatedButton(
onPressed: startUpload, // Start upload when pressed
child: const Text(
'Share',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
],
),
),
],
),
),
);
}
}
это предыдущий экран. Я не знаю, есть ли здесь проблема, но я просто предоставляю дополнительную информацию
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:viwaad_1/views/screens/cofirm_image_screen.dart';
import 'package:viwaad_1/views/screens/confirm_screen.dart';
import 'package:viwaad_1/views/widgets/icons_add_screen.dart';
class AddScreen extends StatelessWidget {
const AddScreen({super.key});
//Image
pickImage(ImageSource src, BuildContext context) async {
final image = await ImagePicker().pickImage(source: src);
if (image != null) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ConfirmImageScreen(
imageFile: File(image.path),
imagePath: image.path,
)));
}
}
showImageOptionsDialog(BuildContext context) {
return showDialog(
context: context,
builder: (context) => SimpleDialog(
children: [
SimpleDialogOption(
onPressed: () => pickImage(ImageSource.gallery, context),
child: Row(
children: const [
Icon(Icons.image),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Gallery',
style: TextStyle(fontSize: 20),
),
)
],
),
),
SimpleDialogOption(
onPressed: () => pickImage(ImageSource.camera, context),
child: Row(
children: const [
Icon(Icons.camera_alt),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Camera',
style: TextStyle(fontSize: 20),
),
)
],
),
),
SimpleDialogOption(
onPressed: () => Navigator.of(context).pop(),
child: Row(
children: const [
Icon(Icons.cancel),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Cancel',
style: TextStyle(fontSize: 20),
),
)
],
),
)
],
));
}
//Video
pickVideo(ImageSource src, BuildContext context) async {
final video = await ImagePicker().pickVideo(source: src);
if (video != null) {
// Close the dialog first before navigating to the next screen
Navigator.of(context).pop();
// Navigate to the confirm screen after picking the video
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ConfirmScreen(
videoFile: File(video.path),
videoPath: video.path,
),
));
}
}
showVideoOptionsDialog(BuildContext context) {
return showDialog(
context: context,
builder: (context) => SimpleDialog(
children: [
SimpleDialogOption(
onPressed: () => pickVideo(ImageSource.gallery, context),
child: Row(
children: const [
Icon(Icons.image),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Gallery', style: TextStyle(fontSize: 20)),
)
],
),
),
SimpleDialogOption(
onPressed: () => pickVideo(ImageSource.camera, context),
child: Row(
children: const [
Icon(Icons.camera_alt),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Camera', style: TextStyle(fontSize: 20)),
)
],
),
),
SimpleDialogOption(
onPressed: () => Navigator.of(context).pop(),
child: Row(
children: const [
Icon(Icons.cancel),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Cancel', style: TextStyle(fontSize: 20)),
)
],
),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 35),
decoration: BoxDecoration(
color: Colors.grey[300], // Container background color
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Post New Viwaad',
style: TextStyle(
color: Colors.grey[800],
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 25),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconWithLabel(
icon: Icons.text_snippet,
label: 'Add text',
onTap: () {
print("Add text tapped!");
},
),
IconWithLabel(
icon: Icons.camera_alt,
label: 'Add pics',
onTap: () => showImageOptionsDialog(context),
),
IconWithLabel(
icon: Icons.videocam,
label: 'Add vid',
onTap: () => showVideoOptionsDialog(context),
),
],
),
SizedBox(height: 15),
],
),
),
),
],
),
);
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... s-listener
Плохое состояние: поток уже прослушивался прослушивателем прогресса сжатия. ⇐ Android
Форум для тех, кто программирует под Android
1736325468
Anonymous
Привет, я пытаюсь загрузить видео из своего приложения, когда я впервые запускаю приложение и выполняю загрузку, все в порядке, но при второй загрузке выдается ошибка
Bad state: Stream has already been listed to
это мой видеоконтроллер для загрузки
import 'dart:async';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:get/get.dart';
import 'package:video_compress/video_compress.dart';
import 'package:viwaad_1/constants.dart';
import 'package:viwaad_1/models/videos.dart';
class UploadVideoContoller extends GetxController {
var compressionProgress = 0.0.obs; // Progress observable
var uploadProgress = 0.0.obs;
// StreamController and StreamSubscription to manage compression progress
StreamController? _progressController;
StreamSubscription? _progressSubscription;
// Method to handle video compression
Future _compressVideo(String videoPath) async {
try {
// Clean up any previous compression progress
await _cancelPreviousCompressionProgress();
// Show Snackbar to indicate compression started
Get.snackbar(
'Compression Started',
'Compressing video...',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
// Set logging level (optional)
VideoCompress.setLogLevel(0);
compressionProgress.value = 0.0;
// Create a new StreamController for the new compression task
_progressController = StreamController();
// Start video compression
final compressTask = VideoCompress.compressVideo(
videoPath,
quality: VideoQuality.MediumQuality,
deleteOrigin: false,
);
// Listen for progress updates
VideoCompress.compressProgress$.subscribe((progress) {
// Only feed progress to controller if it's valid
if (_progressController != null && !_progressController!.isClosed) {
_progressController!.add(progress / 100); // Normalize progress to 0-1 range
}
});
// Listen to the progress updates stream
_progressSubscription = _progressController!.stream.listen((progress) {
compressionProgress.value = progress; // Update progress observable
});
// Wait for the compression task to complete
final compressedVideo = await compressTask;
// Close the progress controller stream
await _progressController!.close();
// Show completion Snackbar
Get.snackbar(
'Compression Complete',
'The video has been compressed successfully!',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
return compressedVideo?.file;
} catch (e) {
// Handle any errors that occur during compression
Get.snackbar(
'Compression Error',
'An error occurred during video compression: $e',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
return null;
}
}
// Method to clean up previous progress stream and subscription
Future _cancelPreviousCompressionProgress() async {
if (_progressSubscription != null) {
await _progressSubscription!.cancel();
_progressSubscription = null;
}
if (_progressController != null) {
await _progressController!.close();
_progressController = null;
}
}
// Method to upload compressed video to Firebase Storage
Future _uploadVideoToStorage(String id, String videoPath) async {
File? compressedVideo = await _compressVideo(videoPath);
if (compressedVideo == null) throw "Compression failed.";
try {
Reference ref = FirebaseStorage.instance.ref().child('videos').child(id);
UploadTask uploadTask = ref.putFile(compressedVideo);
// Monitor upload progress
uploadTask.snapshotEvents.listen((TaskSnapshot snapshot) {
uploadProgress.value = snapshot.bytesTransferred / snapshot.totalBytes;
});
// Wait for upload to complete
TaskSnapshot snapshot = await uploadTask;
return await snapshot.ref.getDownloadURL();
} catch (e) {
throw "Error uploading video: $e";
}
}
// Method to get a thumbnail for the video
Future _getThumbnail(String videoPath) async {
return await VideoCompress.getFileThumbnail(videoPath);
}
// Method to upload video thumbnail to Firebase Storage
Future _uploadImageToStorage(String id, String videoPath) async {
File thumbnail = await _getThumbnail(videoPath);
Reference ref = firebaseStorage.ref().child('thumbnails').child(id);
UploadTask uploadTask = ref.putFile(thumbnail);
TaskSnapshot snap = await uploadTask;
return await snap.ref.getDownloadURL();
}
// Main method to upload video and associated metadata
Future uploadVideo(String songName, String caption, String videoPath) async {
try {
// Clean up any previous progress before starting new upload
await _cancelPreviousCompressionProgress();
String uid = firebaseAuth.currentUser!.uid;
DocumentSnapshot userDoc = await firestore.collection('users').doc(uid).get();
String len = "${firebaseAuth.currentUser!.uid}_${DateTime.now().millisecondsSinceEpoch}";
String videoUrl = await _uploadVideoToStorage("Video $len", videoPath);
String thumbnail = await _uploadImageToStorage("Video $len", videoPath);
String profilePhoto = (userDoc.data() as Map)['profilePhoto'];
// Create video metadata object
Video video = Video(
uid: uid,
id: "Video $len",
likes: [],
commentCount: 0,
shareCount: 0,
songName: songName,
caption: caption,
videoUrl: videoUrl,
thumbnail: thumbnail,
profilePhoto: profilePhoto,
);
// Upload video metadata to Firestore
await firestore.collection('videos').doc("Video $len").set(video.toJson());
} catch (e) {
// Handle upload errors
String uid = firebaseAuth.currentUser?.uid ?? 'Unknown UID';
Get.snackbar(
'Error Uploading Video',
'Error: $e\nUser UID: $uid',
snackPosition: SnackPosition.TOP,
duration: Duration(seconds: 3),
);
}
}
@override
void onClose() {
// Ensure that previous compression progress is cleaned up when the controller is disposed
_cancelPreviousCompressionProgress();
super.onClose();
}
}
а это экран загрузки
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:viwaad_1/controllers/upload_video_contoller.dart';
import 'package:viwaad_1/views/widgets/text_input_field.dart';
class ConfirmScreen extends StatefulWidget {
final File videoFile;
final String videoPath;
const ConfirmScreen({Key? key, required this.videoFile, required this.videoPath}) : super(key: key);
@override
_ConfirmScreenState createState() => _ConfirmScreenState();
}
class _ConfirmScreenState extends State {
late VideoPlayerController _controller;
final TextEditingController _songController = TextEditingController();
final TextEditingController _captionController = TextEditingController();
final UploadVideoContoller _uploadVideoContoller = Get.put(UploadVideoContoller(), permanent: false);
bool _isUploading = false;
@override
void initState() {
super.initState();
// Initialize VideoPlayerController
_controller = VideoPlayerController.file(widget.videoFile)
..initialize().then((_) {
setState(() {
_controller.play();
_controller.setVolume(1);
_controller.setLooping(true);
});
});
}
@override
void dispose() {
_controller.dispose(); // Dispose the video controller
_uploadVideoContoller.onClose(); // Ensure the controller handles cleanup
super.dispose();
}
void startUpload() {
setState(() {
_isUploading = true;
_uploadVideoContoller.compressionProgress.value = 0.0;
_uploadVideoContoller.uploadProgress.value = 0.0;
});
_uploadVideoContoller.uploadVideo(
_songController.text,
_captionController.text,
widget.videoPath,
).then((_) {
setState(() {
_isUploading = false;
});
Get.snackbar(
'Upload Complete',
'Video successfully uploaded',
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 5),
);
// Navigate back after Snackbar duration
Future.delayed(const Duration(seconds: 1), () {
if (mounted) {
Navigator.of(context).pop();
}
});
}).catchError((e) {
setState(() {
_isUploading = false;
});
Get.snackbar(
'Upload Failed',
'Error: $e',
snackPosition: SnackPosition.TOP,
duration: const Duration(seconds: 3),
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 30),
SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height / 1.5,
child: VideoPlayer(_controller),
),
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
// Song Name Input
TextInputField(
controller: _songController,
labelText: 'Song Name',
icon: Icons.music_note,
),
const SizedBox(height: 10),
// Caption Input
TextInputField(
controller: _captionController,
labelText: 'Caption',
icon: Icons.closed_caption,
),
const SizedBox(height: 10),
// Upload Progress or Button
_isUploading
? Obx(() {
double progress = _uploadVideoContoller.compressionProgress.value < 1.0
? _uploadVideoContoller.compressionProgress.value
: _uploadVideoContoller.uploadProgress.value;
String progressLabel = _uploadVideoContoller.compressionProgress.value < 1.0
? 'Compression Progress'
: 'Upload Progress';
return Column(
children: [
Text(
'$progressLabel: ${(100 * progress).toStringAsFixed(0)}%',
style: const TextStyle(fontSize: 16),
),
LinearProgressIndicator(
value: progress,
minHeight: 8,
),
const SizedBox(height: 20),
],
);
})
: ElevatedButton(
onPressed: startUpload, // Start upload when pressed
child: const Text(
'Share',
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
],
),
),
],
),
),
);
}
}
это предыдущий экран. Я не знаю, есть ли здесь проблема, но я просто предоставляю дополнительную информацию
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:viwaad_1/views/screens/cofirm_image_screen.dart';
import 'package:viwaad_1/views/screens/confirm_screen.dart';
import 'package:viwaad_1/views/widgets/icons_add_screen.dart';
class AddScreen extends StatelessWidget {
const AddScreen({super.key});
//Image
pickImage(ImageSource src, BuildContext context) async {
final image = await ImagePicker().pickImage(source: src);
if (image != null) {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ConfirmImageScreen(
imageFile: File(image.path),
imagePath: image.path,
)));
}
}
showImageOptionsDialog(BuildContext context) {
return showDialog(
context: context,
builder: (context) => SimpleDialog(
children: [
SimpleDialogOption(
onPressed: () => pickImage(ImageSource.gallery, context),
child: Row(
children: const [
Icon(Icons.image),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Gallery',
style: TextStyle(fontSize: 20),
),
)
],
),
),
SimpleDialogOption(
onPressed: () => pickImage(ImageSource.camera, context),
child: Row(
children: const [
Icon(Icons.camera_alt),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Camera',
style: TextStyle(fontSize: 20),
),
)
],
),
),
SimpleDialogOption(
onPressed: () => Navigator.of(context).pop(),
child: Row(
children: const [
Icon(Icons.cancel),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Cancel',
style: TextStyle(fontSize: 20),
),
)
],
),
)
],
));
}
//Video
pickVideo(ImageSource src, BuildContext context) async {
final video = await ImagePicker().pickVideo(source: src);
if (video != null) {
// Close the dialog first before navigating to the next screen
Navigator.of(context).pop();
// Navigate to the confirm screen after picking the video
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ConfirmScreen(
videoFile: File(video.path),
videoPath: video.path,
),
));
}
}
showVideoOptionsDialog(BuildContext context) {
return showDialog(
context: context,
builder: (context) => SimpleDialog(
children: [
SimpleDialogOption(
onPressed: () => pickVideo(ImageSource.gallery, context),
child: Row(
children: const [
Icon(Icons.image),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Gallery', style: TextStyle(fontSize: 20)),
)
],
),
),
SimpleDialogOption(
onPressed: () => pickVideo(ImageSource.camera, context),
child: Row(
children: const [
Icon(Icons.camera_alt),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Camera', style: TextStyle(fontSize: 20)),
)
],
),
),
SimpleDialogOption(
onPressed: () => Navigator.of(context).pop(),
child: Row(
children: const [
Icon(Icons.cancel),
Padding(
padding: EdgeInsets.all(8.0),
child: Text('Cancel', style: TextStyle(fontSize: 20)),
)
],
),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 35),
decoration: BoxDecoration(
color: Colors.grey[300], // Container background color
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Post New Viwaad',
style: TextStyle(
color: Colors.grey[800],
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 25),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconWithLabel(
icon: Icons.text_snippet,
label: 'Add text',
onTap: () {
print("Add text tapped!");
},
),
IconWithLabel(
icon: Icons.camera_alt,
label: 'Add pics',
onTap: () => showImageOptionsDialog(context),
),
IconWithLabel(
icon: Icons.videocam,
label: 'Add vid',
onTap: () => showVideoOptionsDialog(context),
),
],
),
SizedBox(height: 15),
],
),
),
),
],
),
);
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79338426/bad-state-stream-has-already-been-listened-to-compression-progress-listener[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия