Flutter Audioplayers with Clip/Edit Function like Just_ Audio player - flutter

Whenever I record audio in my flutter app there's a noise at the start and the end of the clip due to tapping the start and stop buttons on my phone. Flutter's Just-Audio plugin has an Edit/Clip function that will remove these noises. IE:
await player.setClip(start: Duration(seconds: 10), end: Duration(seconds: 20));
But unfortunately, the Just-Audio plugin doesn't play quite right with my app. I've got a swiping pageview and each page has it's own player. Just-Audio doesn't seem to like this and acts as if each swiped page is the same player.
So I'm using the Audioplayers plugin which allows for multiple players. But the Audioplayer plugin doesn't have the Clip/Edit function that the Just-Audio plugin has. So can anyone see where I can get the same Clip/Edit function into the Audioplayers plugin?
Here's the Just Player plugin's function;
Future<Duration?> setClip({Duration? start, Duration? end}) async {
if (_disposed) return null;
_setPlatformActive(true)?.catchError((dynamic e) {});
final duration = await _load(
await _platform,
start == null && end == null
? _audioSource!
: ClippingAudioSource(
child: _audioSource as UriAudioSource,
start: start,
end: end,
));
return duration;
}
And here's a widget for the Audioplayers plugin;
import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:audioplayers/notifications.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class PlayerWidget extends StatefulWidget {
final String url;
final PlayerMode mode;
const PlayerWidget({
Key? key,
required this.url,
this.mode = PlayerMode.MEDIA_PLAYER,
}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _PlayerWidgetState(url, mode);
}
}
class _PlayerWidgetState extends State<PlayerWidget> {
String url;
PlayerMode mode;
late AudioPlayer _audioPlayer;
PlayerState? _audioPlayerState;
Duration? _duration;
Duration? _position;
PlayerState _playerState = PlayerState.STOPPED;
PlayingRoute _playingRouteState = PlayingRoute.SPEAKERS;
StreamSubscription? _durationSubscription;
StreamSubscription? _positionSubscription;
StreamSubscription? _playerCompleteSubscription;
StreamSubscription? _playerErrorSubscription;
StreamSubscription? _playerStateSubscription;
StreamSubscription<PlayerControlCommand>? _playerControlCommandSubscription;
bool get _isPlaying => _playerState == PlayerState.PLAYING;
bool get _isPaused => _playerState == PlayerState.PAUSED;
String get _durationText => _duration?.toString().split('.').first ?? '';
String get _positionText => _position?.toString().split('.').first ?? '';
bool get _isPlayingThroughEarpiece =>
_playingRouteState == PlayingRoute.EARPIECE;
_PlayerWidgetState(this.url, this.mode);
#override
void initState() {
super.initState();
_initAudioPlayer();
}
#override
void dispose() {
_audioPlayer.dispose();
_durationSubscription?.cancel();
_positionSubscription?.cancel();
_playerCompleteSubscription?.cancel();
_playerErrorSubscription?.cancel();
_playerStateSubscription?.cancel();
_playerControlCommandSubscription?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
key: const Key('play_button'),
onPressed: _isPlaying ? null : _play,
iconSize: 64.0,
icon: const Icon(Icons.play_arrow),
color: Colors.cyan,
),
IconButton(
key: const Key('pause_button'),
onPressed: _isPlaying ? _pause : null,
iconSize: 64.0,
icon: const Icon(Icons.pause),
color: Colors.cyan,
),
IconButton(
key: const Key('stop_button'),
onPressed: _isPlaying || _isPaused ? _stop : null,
iconSize: 64.0,
icon: const Icon(Icons.stop),
color: Colors.cyan,
),
IconButton(
onPressed: _earpieceOrSpeakersToggle,
iconSize: 64.0,
icon: _isPlayingThroughEarpiece
? const Icon(Icons.volume_up)
: const Icon(Icons.hearing),
color: Colors.cyan,
),
],
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Stack(
children: [
Slider(
onChanged: (v) {
final Position = v * _duration!.inMilliseconds;
_audioPlayer
.seek(Duration(milliseconds: Position.round()));
},
value: (_position != null &&
_duration != null &&
_position!.inMilliseconds > 0 &&
_position!.inMilliseconds <
_duration!.inMilliseconds)
? _position!.inMilliseconds / _duration!.inMilliseconds
: 0.0,
),
],
),
),
Text(
_position != null
? '$_positionText / $_durationText'
: _duration != null
? _durationText
: '',
style: const TextStyle(fontSize: 24.0),
),
],
),
Text('State: $_audioPlayerState'),
],
);
}
void _initAudioPlayer() {
_audioPlayer = AudioPlayer(mode: mode);
_durationSubscription = _audioPlayer.onDurationChanged.listen((duration) {
setState(() => _duration = duration);
if (Theme.of(context).platform == TargetPlatform.iOS) {
// optional: listen for notification updates in the background
_audioPlayer.notificationService.startHeadlessService();
// set at least title to see the notification bar on ios.
_audioPlayer.notificationService.setNotification(
title: 'App Name',
artist: 'Artist or blank',
albumTitle: 'Name or blank',
imageUrl: 'Image URL or blank',
forwardSkipInterval: const Duration(seconds: 30), // default is 30s
backwardSkipInterval: const Duration(seconds: 30), // default is 30s
duration: duration,
enableNextTrackButton: true,
enablePreviousTrackButton: true,
);
}
});
_positionSubscription =
_audioPlayer.onAudioPositionChanged.listen((p) => setState(() {
_position = p;
}));
_playerCompleteSubscription =
_audioPlayer.onPlayerCompletion.listen((event) {
_onComplete();
setState(() {
_position = _duration;
});
});
_playerErrorSubscription = _audioPlayer.onPlayerError.listen((msg) {
print('audioPlayer error : $msg');
setState(() {
_playerState = PlayerState.STOPPED;
_duration = const Duration();
_position = const Duration();
});
});
_playerControlCommandSubscription =
_audioPlayer.notificationService.onPlayerCommand.listen((command) {
print('command: $command');
});
_audioPlayer.onPlayerStateChanged.listen((state) {
if (mounted) {
setState(() {
_audioPlayerState = state;
});
}
});
_audioPlayer.onNotificationPlayerStateChanged.listen((state) {
if (mounted) {
setState(() => _audioPlayerState = state);
}
});
_playingRouteState = PlayingRoute.SPEAKERS;
}
Future<int> _play() async {
final playPosition = (_position != null &&
_duration != null &&
_position!.inMilliseconds > 0 &&
_position!.inMilliseconds < _duration!.inMilliseconds)
? _position
: null;
final result = await _audioPlayer.play(url, position: playPosition);
if (result == 1) {
setState(() => _playerState = PlayerState.PLAYING);
}
// default playback rate is 1.0
// this should be called after _audioPlayer.play() or _audioPlayer.resume()
// this can also be called everytime the user wants to change playback rate in the UI
_audioPlayer.setPlaybackRate();
return result;
}
Future<int> _pause() async {
final result = await _audioPlayer.pause();
if (result == 1) {
setState(() => _playerState = PlayerState.PAUSED);
}
return result;
}
Future<int> _earpieceOrSpeakersToggle() async {
final result = await _audioPlayer.earpieceOrSpeakersToggle();
if (result == 1) {
setState(() => _playingRouteState = _playingRouteState.toggle());
}
return result;
}
Future<int> _stop() async {
final result = await _audioPlayer.stop();
if (result == 1) {
setState(() {
_playerState = PlayerState.STOPPED;
_position = const Duration();
});
}
return result;
}
void _onComplete() {
setState(() => _playerState = PlayerState.STOPPED);
}
}

Related

flutter - how to create voice record in popup when click mic image using flutter?

mic image code
Center(
child: Padding(
padding: const EdgeInsets.only(top: 1),
child: IconButton(
iconSize: 45,
icon: Ink.image(
image: const AssetImage('assets/mic.png'),
),
onPressed: () {
// do something when the button is pressed
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
Recorder12Screen()),
);
// RecorderDialogScreen(context);
},
),
),
),
when click this mic image I want display voice recording page as a pop up window.
recording page image... my output
But I wanna like this
I my voice recording function has 2 pages
and this
2nd page is then the click pause button then display playback page
both pages I wanna display as pop up windows
1st page
2nd page
1st page code
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:kathana/screens/voiceRecord/voiceRecord12/recorder/feature_buttons_view.dart';
import 'package:provider/provider.dart';
import '../../../provider/sign_in_provider.dart';
class Recorder12Screen extends StatefulWidget {
#override
State<Recorder12Screen> createState() => _Recorder12ScreenState();
}
class _Recorder12ScreenState extends State<Recorder12Screen> {
String? downloadURL;
List<Reference> references = [];
#override
void initState() {
super.initState();
_onUploadComplete();
}
//snack bar for showing error
showSnackBar(String snackText, Duration d) {
final snackBar = SnackBar(content: Text(snackText), duration: d);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
#override
Widget build(BuildContext context) {
final sp = context.read<SignInProvider>();
return Scaffold(
body: Column(
children: [
Expanded(
flex: 2,
child: FeatureButtonsView(
onUploadComplete: _onUploadComplete,
),
),
Text(
"${sp.uid}",
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
],
),
);
}
Future<void> _onUploadComplete() async {
final sp = context.read<SignInProvider>();
FirebaseStorage firebaseStorage = FirebaseStorage.instance;
ListResult listResult = await firebaseStorage
.ref()
.child("${sp.uid}/records")
.child("voices")
.list();
setState(() {
references = listResult.items;
});
}
}
2nd page code
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_audio_recorder2/flutter_audio_recorder2.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import '../../../../provider/sign_in_provider.dart';
class FeatureButtonsView extends StatefulWidget {
final Function onUploadComplete;
FeatureButtonsView({
Key? key,
required this.onUploadComplete,
}) : super(key: key);
#override
_FeatureButtonsViewState createState() => _FeatureButtonsViewState();
String? userId;
}
class _FeatureButtonsViewState extends State<FeatureButtonsView> {
late bool _isPlaying;
late bool _isUploading;
late bool _isRecorded;
late bool _isRecording;
late AudioPlayer _audioPlayer;
late String _filePath;
late FlutterAudioRecorder2 _audioRecorder;
Future getData() async {
final sp = context.read<SignInProvider>();
sp.getDataFromSharedPreferences();
}
String downloadUrl = '';
Future<void> onsend() async {
//uploading to cloudfirestore
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final sp = context.read<SignInProvider>();
await firebaseFirestore
.collection("users")
.doc("${sp.uid}")
.collection("reco")
.add({'downloadURL': downloadUrl}).whenComplete(() =>
showSnackBar("Voice uploaded successful", Duration(seconds: 2)));
}
//snackbar for showing error
showSnackBar(String snackText, Duration d) {
final snackBar = SnackBar(content: Text(snackText), duration: d);
}
#override
void initState() {
super.initState();
_isPlaying = false;
_isUploading = false;
_isRecorded = false;
_isRecording = false;
_audioPlayer = AudioPlayer();
final sp = context.read<SignInProvider>();
FirebaseFirestore.instance
.collection("users")
.doc(sp.uid)
.get()
.then((value) {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Center(
child: _isRecorded
? _isUploading
? Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: LinearProgressIndicator()),
Text('Uplaoding to Firebase'),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.replay),
onPressed: _onRecordAgainButtonPressed,
),
IconButton(
icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
onPressed: _onPlayButtonPressed,
),
IconButton(
icon: Icon(Icons.upload_file, color: Colors.green),
onPressed: _onFileUploadButtonPressed,
),
],
)
: IconButton(
icon: _isRecording
? Icon(Icons.pause)
: Icon(Icons.fiber_manual_record),
onPressed: _onRecordButtonPressed,
),
);
}
Future<void> _onFileUploadButtonPressed() async {
FirebaseStorage firebaseStorage = FirebaseStorage.instance;
setState(() {
_isUploading = true;
});
try {
final sp = context.read<SignInProvider>();
Reference ref = firebaseStorage.ref().child("${sp.uid}/records1").child(
_filePath.substring(_filePath.lastIndexOf('/'), _filePath.length));
TaskSnapshot uploadedFile = await ref.putFile(File(_filePath));
if (uploadedFile.state == TaskState.success) {
downloadUrl = await ref.getDownloadURL();
}
widget.onUploadComplete();
onsend(); //send downloadURL after get it
} catch (error) {
print('Error occured while uplaoding to Firebase ${error.toString()}');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error occured while uplaoding'),
),
);
} finally {
setState(() {
_isUploading = false;
});
}
}
void _onRecordAgainButtonPressed() {
setState(() {
_isRecorded = false;
});
}
Future<void> _onRecordButtonPressed() async {
if (_isRecording) {
_audioRecorder.stop();
_isRecording = false;
_isRecorded = true;
} else {
_isRecorded = false;
_isRecording = true;
await _startRecording();
}
setState(() {});
}
void _onPlayButtonPressed() {
if (!_isPlaying) {
_isPlaying = true;
_audioPlayer.play(_filePath, isLocal: true);
_audioPlayer.onPlayerCompletion.listen((duration) {
setState(() {
_isPlaying = false;
});
});
} else {
_audioPlayer.pause();
_isPlaying = false;
}
setState(() {});
}
Future<void> _startRecording() async {
final bool? hasRecordingPermission =
await FlutterAudioRecorder2.hasPermissions;
if (hasRecordingPermission ?? false) {
Directory directory = await getApplicationDocumentsDirectory();
String filepath = directory.path +
'/' +
DateTime.now().millisecondsSinceEpoch.toString() +
'.aac';
_audioRecorder =
FlutterAudioRecorder2(filepath, audioFormat: AudioFormat.AAC);
await _audioRecorder.initialized;
_audioRecorder.start();
_filePath = filepath;
setState(() {});
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Center(child: Text('Please enable recording permission'))));
}
}
}
Those 2 pages, how convert to like as a popup?
My voice recording functions work perfectly I'm asking to convert those two material pages to like popup windows.
You can use this package for recording the voice :
dependencies:
flutter_sound: ^9.2.13

Connection lost - OnTap Text to play file => getting connection lost

I am trying to get the user to press a record button, to then speak. His memo is recorded and then when the user tap on the Text widget displaying the name of the audio file, the file should be read so he can listen again to what he has recorded.
When I try, I am getting connection lost and the simulator crash. I do not find what is the problem in my code. I guess it is because I am still new with Flutter. Your help is welcome as I am stuck with this for several days. Many thanks.
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_audio_recorder2/flutter_audio_recorder2.dart';
import 'package:path_provider/path_provider.dart';
enum RecordingState {
UnSet,
Set,
Recording,
Stopped,
}
void main66() => runApp(MyTest());
bool isRecording = false;
class MyTest extends StatelessWidget {
const MyTest({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
// backgroundColor: Colors.white,
body: HomeViewRecorder(),//HomeViewRecorder(),
),
);
}
}
class HomeViewRecorder extends StatefulWidget {
final String _title;
const HomeViewRecorder({Key key, String title}) : _title = title,
super(key: key);
#override
_HomeViewRecorderState createState() => _HomeViewRecorderState();
}
class _HomeViewRecorderState extends State<HomeViewRecorder> {
Directory appDirectory;
String records = '';
#override
void initState() {
super.initState();
getApplicationDocumentsDirectory().then((value) {
appDirectory = (value);
setState(() {
print(appDirectory);
});
});
}
void dispose() {
appDirectory.delete();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text('My recorder Test')),
body: Column(
children: [
Expanded(child:
InkWell(child: RecordListView(records:records)),
),
Center(child: Record_Widget(
onSaved:
_onRecordComplete)),
]
)
);
}
_onRecordComplete() {
records ='';
appDirectory.list().listen((onData) {
if (onData.path.contains('.aac')) records=(onData.path);
}).onDone(() {
setState(() {});
});
}
}
class RecordListView extends StatefulWidget {
final String records;
const RecordListView({
Key key,
this.records,
}) : super(key: key);
#override
_RecordListViewState createState() => _RecordListViewState();
}
class _RecordListViewState extends State<RecordListView> {
int _totalDuration;
int _currentDuration;
double _completedPercentage = 0.0;
bool _isPlaying = false;
int _selectedIndex = -1;
#override
Widget build(BuildContext context){
return Column(
children: [
widget.records.isEmpty?
Text('No records yet'): InkWell(child: Text(widget.records.split("/").last+DateTime.now().toString()),
onTap: _onPlay,),
],
);
}
Future<void> _onPlay({ String filePath, int index}) async {
AudioPlayer audioPlayer = AudioPlayer();
if (!_isPlaying) {
audioPlayer.play(filePath, isLocal: true);
setState(() {
_selectedIndex = index;
_completedPercentage = 0.0;
_isPlaying = true;
});
audioPlayer.onPlayerCompletion.listen((_) {
setState(() {
_isPlaying = false;
_completedPercentage = 0.0;
});
});
audioPlayer.onDurationChanged.listen((duration) {
setState(() {
_totalDuration = duration.inMicroseconds;
});
});
audioPlayer.onAudioPositionChanged.listen((duration) {
setState(() {
_currentDuration = duration.inMicroseconds;
_completedPercentage =
_currentDuration.toDouble() / _totalDuration.toDouble();
});
});
}
}
String _getDateFromFilePath({ String filePath}) {
String fromEpoch = filePath.substring(
filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
DateTime recordedDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(fromEpoch));
int year = recordedDate.year;
int month = recordedDate.month;
int day = recordedDate.day;
return ('$year-$month-$day');
}
}
class Record_Widget extends StatefulWidget {
final Function onSaved;
const Record_Widget({Key key,
this.onSaved,}) : super(key: key);
#override
_Record_WidgetState createState() => _Record_WidgetState();
}
class _Record_WidgetState extends State<Record_Widget> {
Directory appDirectory;
String records = '';
RecordingState _recordingState = RecordingState.UnSet;
// Recorder properties
FlutterAudioRecorder2 audioRecorder;
#override
void initState() {
super.initState();
FlutterAudioRecorder2.hasPermissions.then((hasPermission) {
if (hasPermission) {
_recordingState = RecordingState.Set;
}
});
}
#override
void dispose() {
_recordingState = RecordingState.UnSet;
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(100.0),
child: _RecordOrStopButton());
}
Container _RecordOrStopButton() {
return Container(
height: 90,
width: 90,
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: isRecording == false ?
_createRecordButton() : _createStopButton()),);
}
//Widget Button Record
Container _createRecordButton({IconData icon, Function onPressFunc}) {
return Container(child: ElevatedButton(
onPressed: () async {
await _onRecordButtonPressed();
setState(() {
_recordingState = RecordingState.Recording;
isRecording = true;
});
},
style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(
Colors.red), // <-- Button color
)));
}
//Widget Button Stop
Container _createStopButton() {
return Container(
padding: EdgeInsets.all(16),
width: 30.0,
height: 30.0,
child: ElevatedButton(
onPressed: () {
_onRecordButtonPressed();
setState(() {
isRecording = false;
});
},
style: ButtonStyle(
fixedSize: MaterialStateProperty.all(Size(10, 10)),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(color: Colors.red))),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(Colors.red),
),
));
}
Future<void> _onRecordButtonPressed() async {
switch (_recordingState) {
case RecordingState.Set:
await _recordVoice();
break;
case RecordingState.Recording:
await _stopRecording();
_recordingState = RecordingState.Stopped;
break;
case RecordingState.Stopped:
await _recordVoice();
break;
case RecordingState.UnSet:
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please allow recording from settings.'),
));
break;
}
}
_initRecorder() async {
Directory appDirectory = await getApplicationDocumentsDirectory();
String filePath = appDirectory.path +
'/' +
DateTime.now().millisecondsSinceEpoch.toString() +
'.aac';
audioRecorder =
FlutterAudioRecorder2(filePath, audioFormat: AudioFormat.AAC);
await audioRecorder.initialized;
}
_startRecording() async {
isRecording = true;
await audioRecorder.start();
await audioRecorder.current(channel: 0);
}
_stopRecording() async {
isRecording = false;
await audioRecorder.stop();
widget.onSaved();
}
Future<void> _recordVoice() async {
final hasPermission = await FlutterAudioRecorder2.hasPermissions;
if (hasPermission ?? false) {
await _initRecorder();
await _startRecording();
_recordingState = RecordingState.Recording;
} else {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please allow recording from settings.'),
));
}
}
}

Unhandled Exception: setState() called after dispose() - due to modal dissmissed

I have a modalBottomSheet. On it, I am displaying several widgets, especially an audioPlayer.
I have find out that when I press the play button, the audio file is playing, so far so good, but if I tap outside the modalBottomSheet, the modal is dismissed. I am OK to get the modal dismissed. But my problem is that when it is dismissed, the player which is running, is generating an exception.
Unhandled Exception: setState() called after dispose()
I do not want to make the Modal not dissmisible.
Please, can you advise? Many thanks.
import 'package:audioplayers/audioplayers.dart';
import 'package:audioplayers/audioplayers_api.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gtd_official_sharped_focused/Reusable%20Widget/Player_Audio/widgets/play_pause_button.dart';
class AudioPlayerWidget extends StatefulWidget {
final String url;
final bool isAsset;
final Duration currentTime;
final Duration totalTime;
final ValueChanged<Duration> onSeekBarMoved;
const AudioPlayerWidget({
Key key,
this.url,
this.isAsset = false,
this.currentTime,
this.totalTime,
this.onSeekBarMoved,
}) : super(key: key);
#override
_AudioPlayerWidgetState createState() => _AudioPlayerWidgetState();
}
class _AudioPlayerWidgetState extends State<AudioPlayerWidget> {
AudioPlayer _audioPlayer;
AudioCache _audioCache;
//variables for slider
Duration _duration = new Duration();
Duration _position = new Duration();
PlayerState _playerState = PlayerState.STOPPED;
bool get _isPlaying => _playerState == PlayerState.PLAYING;
bool get _isLocal => !widget.url.contains('https');
#override
void initState() {
_audioPlayer = AudioPlayer(mode: PlayerMode.MEDIA_PLAYER);
_audioCache = AudioCache(fixedPlayer: _audioPlayer);
_audioPlayer.onDurationChanged.listen((d) {setState(() {
_duration = d;
});});
_audioPlayer.onAudioPositionChanged.listen((p) {setState((){
_position = p;
});});
_audioPlayer.onPlayerCompletion.listen((event) {
setState(() {
_position = Duration(seconds: 0);
_playerState = PlayerState.STOPPED;
});
});
_audioPlayer.onPlayerError.listen((msg) {
print('audioPlayer error : $msg');
setState(() {
_playerState = PlayerState.STOPPED;
});
});
super.initState();
}
#override
void dispose() {
_audioPlayer.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Text(_position.toString().split('.')[0],style:TextStyle(fontSize: 16)),
),
Padding(
padding: const EdgeInsets.only(right:18.0),
child: Text(_duration.toString().split('.')[0],style:TextStyle(fontSize: 16)),
),
],),
_buildSliderBar(context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buttonBackWard10Seconds(),
PlayPauseButton(
isPlaying: _isPlaying,
onPlay: () => _playPause()
),
buttonForward10Seconds(),
//Do not delete iconButton below => for reference
/* IconButton(
onPressed: () => _stop(),
icon: Icon(
Icons.stop,
size: 40,
color: Colors.red,
),
),*/
],
),
],
);
}
//########################################################
_playPause() async {
if (_playerState == PlayerState.PLAYING) {
final playerResult = await _audioPlayer.pause();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PAUSED;
});
}
} else if (_playerState == PlayerState.PAUSED) {
final playerResult = await _audioPlayer.resume();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PLAYING;
});
}
} else {
if (widget.isAsset) {
_audioPlayer = await _audioCache.play(widget.url);
setState(() {
_playerState = PlayerState.PLAYING;
});
} else {
final playerResult = await _audioPlayer.play(widget.url, isLocal: _isLocal);
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.PLAYING;
});
}
}
}
}
void changeToSecond(int second){
Duration newDuration = Duration(seconds:second);
_audioPlayer.seek(newDuration);
}
_stop() async {
final playerResult = await _audioPlayer.stop();
if (playerResult == 1) {
setState(() {
_playerState = PlayerState.STOPPED;
});
}
}
//###############################################################
Slider _buildSliderBar(BuildContext context) {
return Slider(
value: _position.inSeconds.toDouble(),
min: 0.0,
max: _duration.inSeconds.toDouble(), //_sliderValue,
activeColor: Colors.red,
inactiveColor: Colors.grey,
onChanged: (double value) {
setState(() {
changeToSecond(value.toInt());
value=value;
});
},
);
}
Widget buttonBackWard10Seconds(){
return IconButton( icon: Icon(CupertinoIcons.gobackward_10),
iconSize: 40,
color: Colors.black,
onPressed: (){
_position = _position - Duration(seconds:10);
if (_position < Duration(seconds:0)) {
_audioPlayer.seek(Duration(seconds: 0));
}
else {
_audioPlayer.seek(_position);
}});
}
Widget buttonForward10Seconds(){
return IconButton( icon:Icon( CupertinoIcons.goforward_10),
iconSize: 40,
color: Colors.black,
onPressed: (){
_position = _position + Duration(seconds:10);
if (_duration >_position) {
_audioPlayer.seek(_position);
}
else if (_duration <_position) {
_audioPlayer.seek(_duration);
}
}
);
}
}
import 'package:flutter/material.dart';
import 'package:gtd_official_sharped_focused/Reusable%20Widget/Player_Audio/widgets/audio_player_widget.dart';
import 'package:gtd_official_sharped_focused/Services/extract_file_Name_url/extract_file_name_url.dart';
Widget modalBottomPlayAudio (context,String urlToPlay){
showModalBottomSheet(
context: context,
//background color for modal bottom screen
backgroundColor: Colors.white,
//elevates modal bottom screen
elevation: 10,
// gives rounded corner to modal bottom screen
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
builder: (BuildContext context) {
// UDE : SizedBox instead of Container for whitespaces
return SizedBox(
height: 350,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
/*Padding(
padding: const EdgeInsets.all(28.0),
),*/
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left:18.0),
child: Text(getFileNameFromURL(urlToPlay),
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),),
),
],
),
SizedBox(height: 60,),
AudioPlayerWidget(url:urlToPlay),
],
),
),
);
},
);
}
you could change
setState(()=>{
...
})
to
if(mounted)(
setState(()=>{
...
})
)
Which ensures setState is called only when the widget is mounted on the screen.

Torch restarts after clicking camera button in flutter

I am trying to build an app with the camera plugin (camera: ^0.8.1+3) in flutter, In this app in am trying to click a picture while the torch is on, but the problem is that it works properly in some of the Oneplus devices but in any other device the torch restarts when I try to click a picture.I am using flutter 2.
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
class CameraExampleHome extends StatefulWidget {
#override
_CameraExampleHomeState createState() {
return _CameraExampleHomeState();
}
}
/// Returns a suitable camera icon for [direction].
IconData getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return Icons.camera_rear;
case CameraLensDirection.front:
return Icons.camera_front;
case CameraLensDirection.external:
return Icons.camera;
default:
throw ArgumentError('Unknown lens direction');
}
}
void logError(String code, String? message) {
if (message != null) {
print('Error: $code\nError Message: $message');
} else {
print('Error: $code');
}
}
class _CameraExampleHomeState extends State<CameraExampleHome>
with WidgetsBindingObserver, TickerProviderStateMixin {
CameraController? controller;
XFile? imageFile;
XFile? videoFile;
VideoPlayerController? videoController;
VoidCallback? videoPlayerListener;
bool enableAudio = true;
double _minAvailableExposureOffset = 0.0;
double _maxAvailableExposureOffset = 0.0;
double _currentExposureOffset = 0.0;
late AnimationController _flashModeControlRowAnimationController;
late Animation<double> _flashModeControlRowAnimation;
late AnimationController _exposureModeControlRowAnimationController;
late Animation<double> _exposureModeControlRowAnimation;
late AnimationController _focusModeControlRowAnimationController;
late Animation<double> _focusModeControlRowAnimation;
double _minAvailableZoom = 1.0;
double _maxAvailableZoom = 1.0;
double _currentScale = 1.0;
double _baseScale = 1.0;
// Counting pointers (number of user fingers on screen)
int _pointers = 0;
#override
void initState() {
super.initState();
WidgetsBinding.instance?.addObserver(this);
_flashModeControlRowAnimationController = AnimationController(
duration: const Duration(milliseconds: 10),
vsync: this,
);
_flashModeControlRowAnimation = CurvedAnimation(
parent: _flashModeControlRowAnimationController,
curve: Curves.easeInCubic,
);
_exposureModeControlRowAnimationController = AnimationController(
duration: const Duration(milliseconds: 10),
vsync: this,
);
_exposureModeControlRowAnimation = CurvedAnimation(
parent: _exposureModeControlRowAnimationController,
curve: Curves.easeInCubic,
);
_focusModeControlRowAnimationController = AnimationController(
duration: const Duration(milliseconds: 10),
vsync: this,
);
_focusModeControlRowAnimation = CurvedAnimation(
parent: _focusModeControlRowAnimationController,
curve: Curves.easeInCubic,
);
}
#override
void dispose() {
WidgetsBinding.instance?.removeObserver(this);
_flashModeControlRowAnimationController.dispose();
_exposureModeControlRowAnimationController.dispose();
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
final CameraController? cameraController = controller;
// App state changed before we got the chance to initialize.
if (cameraController == null || !cameraController.value.isInitialized) {
return;
}
if (state == AppLifecycleState.inactive) {
cameraController.dispose();
} else if (state == AppLifecycleState.resumed) {
onNewCameraSelected(cameraController.description);
}
}
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('Camera example'),
),
body: Column(
children: <Widget>[
Expanded(
child: Container(
child: Padding(
padding: const EdgeInsets.all(1.0),
child: Center(
child: _cameraPreviewWidget(),
),
),
decoration: BoxDecoration(
color: Colors.black,
border: Border.all(
color:
controller != null && controller!.value.isRecordingVideo
? Colors.redAccent
: Colors.grey,
width: 3.0,
),
),
),
),
_captureControlRowWidget(),
_modeControlRowWidget(),
Padding(
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_cameraTogglesRowWidget(),
_thumbnailWidget(),
],
),
),
],
),
);
}
/// Display the preview from the camera (or a message if the preview is not available).
Widget _cameraPreviewWidget() {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
return const Text(
'Tap a camera',
style: TextStyle(
color: Colors.white,
fontSize: 24.0,
fontWeight: FontWeight.w900,
),
);
} else {
return Listener(
onPointerDown: (_) => _pointers++,
onPointerUp: (_) => _pointers--,
child: CameraPreview(
controller!,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onScaleStart: _handleScaleStart,
onScaleUpdate: _handleScaleUpdate,
onTapDown: (details) => onViewFinderTap(details, constraints),
);
}),
),
);
}
}
void _handleScaleStart(ScaleStartDetails details) {
_baseScale = _currentScale;
}
Future<void> _handleScaleUpdate(ScaleUpdateDetails details) async {
// When there are not exactly two fingers on screen don't scale
if (controller == null || _pointers != 2) {
return;
}
_currentScale = (_baseScale * details.scale)
.clamp(_minAvailableZoom, _maxAvailableZoom);
await controller!.setZoomLevel(_currentScale);
}
/// Display the thumbnail of the captured image or video.
Widget _thumbnailWidget() {
final VideoPlayerController? localVideoController = videoController;
return Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
localVideoController == null && imageFile == null
? Container()
: SizedBox(
child: (localVideoController == null)
? Container(child: Image.file(File(imageFile!.path)))
: Container(
child: Center(
child: AspectRatio(
aspectRatio:
localVideoController.value.size != null
? localVideoController
.value.aspectRatio
: 1.0,
child: VideoPlayer(localVideoController)),
),
decoration: BoxDecoration(
border: Border.all(color: Colors.pink)),
),
width: 64.0,
height: 64.0,
),
],
),
),
);
}
/// Display a bar with buttons to change the flash and exposure modes
Widget _modeControlRowWidget() {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: Icon(Icons.flash_on),
color: Colors.blue,
onPressed: controller != null ? onFlashModeButtonPressed : null,
),
IconButton(
icon: Icon(Icons.exposure),
color: Colors.blue,
onPressed:
controller != null ? onExposureModeButtonPressed : null,
),
IconButton(
icon: Icon(Icons.filter_center_focus),
color: Colors.blue,
onPressed: controller != null ? onFocusModeButtonPressed : null,
),
IconButton(
icon: Icon(enableAudio ? Icons.volume_up : Icons.volume_mute),
color: Colors.blue,
onPressed: controller != null ? onAudioModeButtonPressed : null,
),
IconButton(
icon: Icon(controller?.value.isCaptureOrientationLocked ?? false
? Icons.screen_lock_rotation
: Icons.screen_rotation),
color: Colors.blue,
onPressed: controller != null
? onCaptureOrientationLockButtonPressed
: null,
),
],
),
_flashModeControlRowWidget(),
_exposureModeControlRowWidget(),
_focusModeControlRowWidget(),
],
);
}
Widget _flashModeControlRowWidget() {
return SizeTransition(
sizeFactor: _flashModeControlRowAnimation,
child: ClipRect(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
IconButton(
icon: Icon(Icons.flash_off),
color: controller?.value.flashMode == FlashMode.off
? Colors.orange
: Colors.blue,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.off)
: null,
),
IconButton(
icon: Icon(Icons.flash_auto),
color: controller?.value.flashMode == FlashMode.auto
? Colors.orange
: Colors.blue,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.auto)
: null,
),
IconButton(
icon: Icon(Icons.flash_on),
color: controller?.value.flashMode == FlashMode.always
? Colors.orange
: Colors.blue,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.always)
: null,
),
IconButton(
icon: Icon(Icons.highlight),
color: controller?.value.flashMode == FlashMode.torch
? Colors.orange
: Colors.blue,
onPressed: controller != null
? () => onSetFlashModeButtonPressed(FlashMode.torch)
: null,
),
],
),
),
);
}
Widget _exposureModeControlRowWidget() {
final ButtonStyle styleAuto = TextButton.styleFrom(
primary: controller?.value.exposureMode == ExposureMode.auto
? Colors.orange
: Colors.blue,
);
final ButtonStyle styleLocked = TextButton.styleFrom(
primary: controller?.value.exposureMode == ExposureMode.locked
? Colors.orange
: Colors.blue,
);
return SizeTransition(
sizeFactor: _exposureModeControlRowAnimation,
child: ClipRect(
child: Container(
color: Colors.grey.shade50,
child: Column(
children: [
Center(
child: Text("Exposure Mode"),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
TextButton(
child: Text('AUTO'),
style: styleAuto,
onPressed: controller != null
? () =>
onSetExposureModeButtonPressed(ExposureMode.auto)
: null,
onLongPress: () {
if (controller != null) {
controller!.setExposurePoint(null);
showInSnackBar('Resetting exposure point');
}
},
),
TextButton(
child: Text('LOCKED'),
style: styleLocked,
onPressed: controller != null
? () =>
onSetExposureModeButtonPressed(ExposureMode.locked)
: null,
),
],
),
Center(
child: Text("Exposure Offset"),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
Text(_minAvailableExposureOffset.toString()),
Slider(
value: _currentExposureOffset,
min: _minAvailableExposureOffset,
max: _maxAvailableExposureOffset,
label: _currentExposureOffset.toString(),
onChanged: _minAvailableExposureOffset ==
_maxAvailableExposureOffset
? null
: setExposureOffset,
),
Text(_maxAvailableExposureOffset.toString()),
],
),
],
),
),
),
);
}
Widget _focusModeControlRowWidget() {
final ButtonStyle styleAuto = TextButton.styleFrom(
primary: controller?.value.focusMode == FocusMode.auto
? Colors.orange
: Colors.blue,
);
final ButtonStyle styleLocked = TextButton.styleFrom(
primary: controller?.value.focusMode == FocusMode.locked
? Colors.orange
: Colors.blue,
);
return SizeTransition(
sizeFactor: _focusModeControlRowAnimation,
child: ClipRect(
child: Container(
color: Colors.grey.shade50,
child: Column(
children: [
Center(
child: Text("Focus Mode"),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
TextButton(
child: Text('AUTO'),
style: styleAuto,
onPressed: controller != null
? () => onSetFocusModeButtonPressed(FocusMode.auto)
: null,
onLongPress: () {
if (controller != null) controller!.setFocusPoint(null);
showInSnackBar('Resetting focus point');
},
),
TextButton(
child: Text('LOCKED'),
style: styleLocked,
onPressed: controller != null
? () => onSetFocusModeButtonPressed(FocusMode.locked)
: null,
),
],
),
],
),
),
),
);
}
/// Display the control bar with buttons to take pictures and record videos.
Widget _captureControlRowWidget() {
final CameraController? cameraController = controller;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: const Icon(Icons.camera_alt),
color: Colors.blue,
onPressed: cameraController != null &&
cameraController.value.isInitialized
// !cameraController.value.isRecordingVideo
? onTakePictureButtonPressed
: null,
),
IconButton(
icon: const Icon(Icons.videocam),
color: Colors.blue,
onPressed: cameraController != null &&
cameraController.value.isInitialized &&
!cameraController.value.isRecordingVideo
? onVideoRecordButtonPressed
: null,
),
IconButton(
icon: cameraController != null &&
cameraController.value.isRecordingPaused
? Icon(Icons.play_arrow)
: Icon(Icons.pause),
color: Colors.blue,
onPressed: cameraController != null &&
cameraController.value.isInitialized &&
cameraController.value.isRecordingVideo
? (cameraController.value.isRecordingPaused)
? onResumeButtonPressed
: onPauseButtonPressed
: null,
),
IconButton(
icon: const Icon(Icons.stop),
color: Colors.red,
onPressed: cameraController != null &&
cameraController.value.isInitialized &&
cameraController.value.isRecordingVideo
? onStopButtonPressed
: null,
)
],
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraTogglesRowWidget() {
final List<Widget> toggles = <Widget>[];
final onChanged = (CameraDescription? description) {
if (description == null) {
return;
}
onNewCameraSelected(description);
};
if (cameras.isEmpty) {
return const Text('No camera found');
} else {
for (CameraDescription cameraDescription in cameras) {
toggles.add(
SizedBox(
width: 90.0,
child: RadioListTile<CameraDescription>(
title: Icon(getCameraLensIcon(cameraDescription.lensDirection)),
groupValue: controller?.description,
value: cameraDescription,
onChanged:
controller != null && controller!.value.isRecordingVideo
? null
: onChanged,
),
),
);
}
}
return Row(children: toggles);
}
String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
void showInSnackBar(String message) {
// ignore: deprecated_member_use
_scaffoldKey.currentState?.showSnackBar(SnackBar(content: Text(message)));
}
void onViewFinderTap(TapDownDetails details, BoxConstraints constraints) {
if (controller == null) {
return;
}
final CameraController cameraController = controller!;
final offset = Offset(
details.localPosition.dx / constraints.maxWidth,
details.localPosition.dy / constraints.maxHeight,
);
cameraController.setExposurePoint(offset);
cameraController.setFocusPoint(offset);
}
void onNewCameraSelected(CameraDescription cameraDescription) async {
if (controller != null) {
await controller!.dispose();
}
final CameraController cameraController = CameraController(
cameraDescription,
ResolutionPreset.medium,
enableAudio: enableAudio,
imageFormatGroup: ImageFormatGroup.jpeg,
);
controller = cameraController;
// If the controller is updated then update the UI.
cameraController.addListener(() {
if (mounted) setState(() {});
if (cameraController.value.hasError) {
showInSnackBar(
'Camera error ${cameraController.value.errorDescription}');
}
});
try {
await cameraController.initialize();
await Future.wait([
cameraController
.getMinExposureOffset()
.then((value) => _minAvailableExposureOffset = value),
cameraController
.getMaxExposureOffset()
.then((value) => _maxAvailableExposureOffset = value),
cameraController
.getMaxZoomLevel()
.then((value) => _maxAvailableZoom = value),
cameraController
.getMinZoomLevel()
.then((value) => _minAvailableZoom = value),
]);
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
void onTakePictureButtonPressed() {
takePicture().then((XFile? file) {
if (mounted) {
setState(() {
imageFile = file;
videoController?.dispose();
videoController = null;
controller?.value.flashMode == FlashMode.torch;
});
if (file != null) showInSnackBar('Picture saved to ${file.path}');
}
});
}
void onFlashModeButtonPressed() {
if (_flashModeControlRowAnimationController.value == 1) {
_flashModeControlRowAnimationController.reverse();
} else {
_flashModeControlRowAnimationController.forward();
_exposureModeControlRowAnimationController.reverse();
_focusModeControlRowAnimationController.reverse();
}
}
void onExposureModeButtonPressed() {
if (_exposureModeControlRowAnimationController.value == 1) {
_exposureModeControlRowAnimationController.reverse();
} else {
_exposureModeControlRowAnimationController.forward();
_flashModeControlRowAnimationController.reverse();
_focusModeControlRowAnimationController.reverse();
}
}
void onFocusModeButtonPressed() {
if (_focusModeControlRowAnimationController.value == 1) {
_focusModeControlRowAnimationController.reverse();
} else {
_focusModeControlRowAnimationController.forward();
_flashModeControlRowAnimationController.reverse();
_exposureModeControlRowAnimationController.reverse();
}
}
void onAudioModeButtonPressed() {
enableAudio = !enableAudio;
if (controller != null) {
onNewCameraSelected(controller!.description);
}
}
void onCaptureOrientationLockButtonPressed() async {
if (controller != null) {
final CameraController cameraController = controller!;
if (cameraController.value.isCaptureOrientationLocked) {
await cameraController.unlockCaptureOrientation();
showInSnackBar('Capture orientation unlocked');
} else {
await cameraController.lockCaptureOrientation();
showInSnackBar(
'Capture orientation locked to ${cameraController.value.lockedCaptureOrientation.toString().split('.').last}');
}
}
}
void onSetFlashModeButtonPressed(FlashMode mode) {
setFlashMode(mode).then((_) {
if (mounted) setState(() {});
showInSnackBar('Flash mode set to ${mode.toString().split('.').last}');
});
}
void onSetExposureModeButtonPressed(ExposureMode mode) {
setExposureMode(mode).then((_) {
if (mounted) setState(() {});
showInSnackBar('Exposure mode set to ${mode.toString().split('.').last}');
});
}
void onSetFocusModeButtonPressed(FocusMode mode) {
setFocusMode(mode).then((_) {
if (mounted) setState(() {});
showInSnackBar('Focus mode set to ${mode.toString().split('.').last}');
});
}
void onVideoRecordButtonPressed() {
startVideoRecording().then((_) {
if (mounted) setState(() {});
});
}
void onStopButtonPressed() {
stopVideoRecording().then((file) {
if (mounted) setState(() {});
if (file != null) {
showInSnackBar('Video recorded to ${file.path}');
videoFile = file;
_startVideoPlayer();
}
});
}
void onPauseButtonPressed() {
pauseVideoRecording().then((_) {
if (mounted) setState(() {});
showInSnackBar('Video recording paused');
});
}
void onResumeButtonPressed() {
resumeVideoRecording().then((_) {
if (mounted) setState(() {});
showInSnackBar('Video recording resumed');
});
}
Future<void> startVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
showInSnackBar('Error: select a camera first.');
return;
}
if (cameraController.value.isRecordingVideo) {
return;
}
try {
await cameraController.startVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return;
}
}
Future<XFile?> stopVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isRecordingVideo) {
return null;
}
try {
return cameraController.stopVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
Future<void> pauseVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isRecordingVideo) {
return null;
}
try {
await cameraController.pauseVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> resumeVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isRecordingVideo) {
return null;
}
try {
await cameraController.resumeVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> setFlashMode(FlashMode mode) async {
if (controller == null) {
return;
}
try {
await controller!.setFlashMode(mode);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> setExposureMode(ExposureMode mode) async {
if (controller == null) {
return;
}
try {
await controller!.setExposureMode(mode);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> setExposureOffset(double offset) async {
if (controller == null) {
return;
}
setState(() {
_currentExposureOffset = offset;
});
try {
offset = await controller!.setExposureOffset(offset);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> setFocusMode(FocusMode mode) async {
if (controller == null) {
return;
}
try {
await controller!.setFocusMode(mode);
} on CameraException catch (e) {
_showCameraException(e);
rethrow;
}
}
Future<void> _startVideoPlayer() async {
if (videoFile == null) {
return;
}
final VideoPlayerController vController =
VideoPlayerController.file(File(videoFile!.path));
videoPlayerListener = () {
if (videoController != null && videoController!.value.size != null) {
// Refreshing the state to update video player with the correct ratio.
if (mounted) setState(() {});
videoController!.removeListener(videoPlayerListener!);
}
};
vController.addListener(videoPlayerListener!);
await vController.setLooping(true);
await vController.initialize();
await videoController?.dispose();
if (mounted) {
setState(() {
imageFile = null;
videoController = vController;
});
}
await vController.play();
}
Future<XFile?> takePicture() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
showInSnackBar('Error: select a camera first.');
return null;
}
if (cameraController.value.isTakingPicture) {
return null;
}
try {
XFile file = await cameraController.takePicture();
return file;
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
void _showCameraException(CameraException e) {
logError(e.code, e.description);
showInSnackBar('Error: ${e.code}\n${e.description}');
}
}
class CameraApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: CameraExampleHome(),
);
}
}
List<CameraDescription> cameras = [];
Future<void> main() async {
try {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
} on CameraException catch (e) {
logError(e.code, e.description);
}
runApp(CameraApp());
}

Slider widget does not work on iOS and Web

I have an audio player in my app. I used Slider.adaptive to make the seek bar. Although It works well on Android, it gives me this error on iOS and the Web:
════════ Exception caught by widgets library
═══════════════════════════════════ Assertion failed:
../…/cupertino/slider.dart:332 value != null && value >= 0.0 && value
<= 1.0 is not true
The relevant error-causing widget was Slider
Here is how my code looks like:
class PlayBackButtons extends StatefulWidget {
#override
_PlayBackButtonsState createState() => _PlayBackButtonsState();
}
class _PlayBackButtonsState extends State<PlayBackButtons> {
bool _isPlaying = false;
AudioPlayer _audioPlayer;
Duration _duration = new Duration();
Duration _position = new Duration();
int result = 0;
int tutsLenght;
int index;
#override
void initState() {
super.initState();
_audioPlayer = AudioPlayer();
Future.delayed(Duration.zero, () {
Provider.of<Tutorials>(context, listen: false).resetIndex();
});
}
#override
void dispose() {
_cleanup();
super.dispose();
}
double progress() => max() > (_position?.inMilliseconds ?? 0).toDouble()
? (_position?.inMilliseconds ?? 0).toDouble()
: 0.0;
double max() => (_duration.inMilliseconds ?? 0.0).toDouble();
void _cleanup() {
if (result == 1) {
_audioPlayer.stop();
_audioPlayer.dispose();
Provider.of<Tutorials>(context).resetIndex();
}
}
void _play(String url) async {
result = await _audioPlayer.play(url);
setState(() => _isPlaying = true);
if (result == 1) {
_audioPlayer.onDurationChanged.listen((Duration dd) {
setState(() {
_duration = dd;
});
});
_audioPlayer.onAudioPositionChanged.listen((Duration dd) {
setState(() {
_position = dd;
});
});
} else {
print('audio player crashed');
}
}
void _pause() async {
await _audioPlayer.pause();
setState(() => _isPlaying = false);
}
void _next() async {
await _audioPlayer.stop();
setState(() => _isPlaying = false);
if (Provider.of<Tutorials>(context).index < tutsLenght) {
} else {
Navigator.pop(context);
}
}
void _previous() {
if (Provider.of<Tutorials>(context).index != 0) {
_audioPlayer.stop();
setState(() => _isPlaying = false);
Provider.of<Tutorials>(context).decrementIndex();
}
}
#override
Widget build(BuildContext context) {
index = Provider.of<Tutorials>(context).index;
final tuts = Provider.of<Tutorials>(context, listen: false).tutsOfASection;
tutsLenght = tuts.length;
final url = tuts[index].audio;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Slider.adaptive(
min: 0.0,
value: progress(),//_position.inSeconds.toDouble(),
max: max(),//_duration.inSeconds.toDouble(),
onChanged: (double value) {
setState(() => _audioPlayer.seek(Duration(seconds: value.toInt())));
},
),
Row(
children: [
IconButton(
icon: Icon(Icons.skip_previous),
onPressed: () => _previous(),
),
IconButton(
icon: _isPlaying ? Icon(Icons.pause) : Icon(Icons.play_arrow),
onPressed: () {
if (_isPlaying) {
_pause();
} else {
_play(url);
}
},
),
IconButton(
icon: Icon(Icons.skip_next),
onPressed: () => _next(),
),
],
mainAxisAlignment: MainAxisAlignment.center,
),
],
);
}
}