diff --git a/example/lib/chat_bubble.dart b/example/lib/chat_bubble.dart index faf1f1d3..fa2aafc8 100644 --- a/example/lib/chat_bubble.dart +++ b/example/lib/chat_bubble.dart @@ -102,11 +102,18 @@ class _WaveBubbleState extends State { if (widget.index == null && widget.path == null && file?.path == null) { return; } + late final WaveformExtractionType waveformExtractionType; + if (widget.index != null) { + waveformExtractionType = widget.index!.isEven + ? WaveformExtractionType.extractAsync + : WaveformExtractionType.noExtraction; + } else { + waveformExtractionType = WaveformExtractionType.extractAsync; + } // Prepare player with extracting waveform if index is even. controller.preparePlayer( - path: widget.path ?? file!.path, - shouldExtractWaveform: widget.index?.isEven ?? true, - ); + path: widget.path ?? file!.path, + waveformExtractionType: waveformExtractionType); // Extracting waveform separately if index is odd. if (widget.index?.isOdd ?? false) { controller.waveformExtraction diff --git a/ios/Classes/WaveformExtractor.swift b/ios/Classes/WaveformExtractor.swift index c9d1e565..f74985e8 100644 --- a/ios/Classes/WaveformExtractor.swift +++ b/ios/Classes/WaveformExtractor.swift @@ -110,7 +110,7 @@ public class WaveformExtractor { ) } - let progress = Float(i - startIndex + 1) / Float(endIndex - startIndex) + progress = Float(i - startIndex + 1) / Float(endIndex - startIndex) await sendWaveformDataToFlutter( waveformStorage: waveformStorage, progress: progress, diff --git a/lib/audio_waveforms.dart b/lib/audio_waveforms.dart index cf60644a..fdfd1211 100644 --- a/lib/audio_waveforms.dart +++ b/lib/audio_waveforms.dart @@ -10,3 +10,4 @@ export 'src/controllers/recorder_controller.dart'; export 'src/models/android_encoder_settings.dart'; export 'src/models/ios_encoder_setting.dart'; export 'src/models/recorder_settings.dart'; +export 'src/enums/waveform_extraction_type.dart'; diff --git a/lib/src/audio_file_waveforms.dart b/lib/src/audio_file_waveforms.dart index 6a56f82a..550c16c8 100644 --- a/lib/src/audio_file_waveforms.dart +++ b/lib/src/audio_file_waveforms.dart @@ -46,7 +46,8 @@ class AudioFileWaveforms extends StatefulWidget { /// If decoration is used then use color in it. final Color? backgroundColor; - /// Duration for animation. Defaults to 500 milliseconds. + /// Duration for animation. If set to Duration.zero, no animation will occur. + /// Defaults to 500 milliseconds. final Duration animationDuration; /// Curve for animation. Defaults to Curves.easeIn @@ -144,18 +145,26 @@ class _AudioFileWaveformsState extends State void initState() { super.initState(); _initialiseVariables(); - _growingWaveController = AnimationController( - vsync: this, - duration: widget.animationDuration, - ); - _growAnimation = CurvedAnimation( - parent: _growingWaveController, - curve: widget.animationCurve, - ); - _growingWaveController - ..forward() - ..addListener(_updateGrowAnimationProgress); + if (widget.animationDuration == Duration.zero) { + _growAnimationProgress = 1.0; + } else { + _growingWaveController = AnimationController( + vsync: this, + duration: widget.animationDuration, + ); + _growAnimation = CurvedAnimation( + parent: _growingWaveController, + curve: widget.animationCurve, + ); + + _growingWaveController + ..forward() + ..addListener(_updateGrowAnimationProgress); + } + + _initializeAudioProgress(); + onCurrentDurationSubscription = playerController.onCurrentDurationChanged.listen((event) { _seekProgress.value = event; @@ -188,10 +197,50 @@ class _AudioFileWaveformsState extends State onCurrentExtractedWaveformData?.cancel(); onCompletionSubscription.cancel(); playerController.removeListener(_addWaveformDataFromController); - _growingWaveController.dispose(); + + if (widget.animationDuration != Duration.zero) { + _growingWaveController.dispose(); + } + super.dispose(); } + @override + void didUpdateWidget(AudioFileWaveforms oldWidget) { + super.didUpdateWidget(oldWidget); + + // Vérifier si les waveformData ont changé + if (widget.waveformData != oldWidget.waveformData) { + if (widget.waveformData.isNotEmpty) { + _addWaveformData(widget.waveformData); + } + } + + // Vérifier si d'autres propriétés importantes ont changé + if (widget.playerWaveStyle != oldWidget.playerWaveStyle || + widget.size != oldWidget.size || + widget.waveformType != oldWidget.waveformType) { + if (mounted) setState(() {}); + } + + // Mettre à jour les variables si nécessaire + if (widget.margin != oldWidget.margin || + widget.padding != oldWidget.padding || + widget.decoration != oldWidget.decoration || + widget.backgroundColor != oldWidget.backgroundColor || + widget.animationDuration != oldWidget.animationDuration || + widget.animationCurve != oldWidget.animationCurve || + widget.clipBehavior != oldWidget.clipBehavior) { + margin = widget.margin; + padding = widget.padding; + decoration = widget.decoration; + backgroundColor = widget.backgroundColor; + animationDuration = widget.animationDuration; + animationCurve = widget.animationCurve; + clipBehavior = widget.clipBehavior; + } + } + double _audioProgress = 0.0; double _cachedAudioProgress = 0.0; @@ -406,4 +455,16 @@ class _AudioFileWaveformsState extends State } }); } + + Future _initializeAudioProgress() async { + if (playerController.playerState == PlayerState.paused && + playerController.maxDuration > 0) { + final currentPosition = + await playerController.getDuration(DurationType.current); + if (currentPosition > 0) { + _seekProgress.value = currentPosition; + _updatePlayerPercent(); + } + } + } } diff --git a/lib/src/controllers/player_controller.dart b/lib/src/controllers/player_controller.dart index 55d349d0..dff91a17 100644 --- a/lib/src/controllers/player_controller.dart +++ b/lib/src/controllers/player_controller.dart @@ -127,7 +127,8 @@ class PlayerController extends ChangeNotifier { Future preparePlayer({ required String path, double? volume, - bool shouldExtractWaveform = true, + WaveformExtractionType waveformExtractionType = + WaveformExtractionType.noExtraction, int noOfSamples = 100, }) async { path = Uri.parse(path).path; @@ -143,20 +144,18 @@ class PlayerController extends ChangeNotifier { _setPlayerState(PlayerState.initialized); } - if (shouldExtractWaveform) { - waveformExtraction - .extractWaveformData( + if (waveformExtractionType != WaveformExtractionType.noExtraction) { + var extraction = waveformExtraction.extractWaveformData( path: path, noOfSamples: noOfSamples, - ) - .then( - (value) { + )..then((values) { waveformExtraction.waveformData ..clear() - ..addAll(value); - notifyListeners(); - }, - ); + ..addAll(values); + }); + if (waveformExtractionType == WaveformExtractionType.extractSync) { + await extraction; + } } notifyListeners(); } diff --git a/lib/src/controllers/waveform_extraction_controller.dart b/lib/src/controllers/waveform_extraction_controller.dart index a92b08b9..7225e90f 100644 --- a/lib/src/controllers/waveform_extraction_controller.dart +++ b/lib/src/controllers/waveform_extraction_controller.dart @@ -29,7 +29,7 @@ class WaveformExtractionController { /// This returns waveform data which can be used by [AudioFileWaveforms] /// to display waveforms. - List get waveformData => _waveformData.toList(); + List get waveformData => _waveformData; /// A stream to get current extracted waveform data. This stream will emit /// list of doubles which are waveform data point. diff --git a/lib/src/enums/waveform_extraction_type.dart b/lib/src/enums/waveform_extraction_type.dart new file mode 100644 index 00000000..2dfc13d7 --- /dev/null +++ b/lib/src/enums/waveform_extraction_type.dart @@ -0,0 +1,10 @@ +enum WaveformExtractionType { + /// No waveform extraction will be performed. + noExtraction, + + /// Extract waveform data asynchronously without waiting for the result. + extractAsync, + + /// Extract waveform data and wait until it's completed before continuing. + extractSync, +}