英文:
Provider State is not Updating
问题
我理解你的请求,以下是你提供的代码的中文翻译:
我正在开发一个Flutter应用程序,可以播放音频。音频是从Firebase获取的,并且播放得很完美,但问题是,当开始播放音频并退出该屏幕后,再次访问该屏幕时,它不会更新其状态(进度条、播放/暂停按钮、已播放时间)。
通常情况下,当我实现了本地状态时,当音频加载完毕时,音乐的持续时间会得到更新,然后开始播放,滑块(进度条)和歌曲的当前位置也会得到更新。但是在我使用Provider后,它没有完全更新。
以下是小部件代码:
(代码已略)
以下是状态类代码:
(代码已略)
请注意,这是你提供的代码的直译中文翻译,不包含代码部分。如果你需要进一步的帮助或有其他问题,请随时提出。
英文:
I'm developing the flutter app which can play audio. Audio is fetching from firebase and playing perfectly but the problem is that when begin to play audio and exit from that screen, again, revisiting that screen, it won't update its state(seekbar, play/pause button, time passed).
usually what happens that when I have implemented local state when audio is been load then duration of the music is updated and I' started playing then it is updating slider(seekbar) and current position of the song. But after I have used Provider it is not updating completely.
below is the widget code
import 'dart:ui';
import 'package:app/model/PlayerState.dart';
import 'package:app/stories/get_stories.dart';
import 'package:audio_service/audio_service.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:app/globals.dart' as globals;
import 'package:just_audio/just_audio.dart';
import 'package:provider/provider.dart';
import '../widgets/error_alert.dart';
import 'package:audio_session/audio_session.dart';
class PlayingStory extends StatefulWidget {
final String story;
final String episode;
final String playLink;
final String poster;
const PlayingStory(
{Key? key,
required this.story,
required this.episode,
required this.playLink,
required this.poster})
: super(key: key);
@override
State<StatefulWidget> createState() => PlayingStoryState();
}
class PlayingStoryState extends State<PlayingStory> with WidgetsBindingObserver {
double _value = 0.0;
final audioPlayer = AudioPlayer();
late bool isPlaying;
late AppLifecycleState state;
late String episode = widget.episode;
// void _showChoices(BuildContext context) {
//
// // GetStories().updateStoryList(widget.story,context);
// var nextEpisode = GetStories().fetchNextEpisodes(widget.story);
//
// OverlayState overlayState = Overlay.of(context);
// OverlayEntry? choice;
//
// final Size size = MediaQuery.of(context).size;
// final height = size.height;
// final width = size.width;
//
// choice = OverlayEntry(builder: (context) {
// print("_-_-_-_-_-_-_-_-_-_-_ OVERLAY CALLED _-_-_-_-_-_-_-_-_-_-_");
// return Scaffold(
// backgroundColor: Colors.transparent,
// body: Center(
// child: Padding(
// padding: EdgeInsets.symmetric(horizontal: width * 0.035, vertical: height * 0.06),
// child: ColoredBox(
// color: const Color(0xff838080),
// child: BackdropFilter(
// filter: ImageFilter.blur(
// sigmaY: 8.0,
// sigmaX: 8.0,
// ),
// child: Center(
// child: ListView(
// children: [
//
// FutureBuilder<Map<dynamic, dynamic>>(
// future: nextEpisode,
// builder: (context, snapshot) {
// if (!snapshot.hasData) {
// return const Center(
// child: CircularProgressIndicator(),
// );
// }
//
// final nxteps = snapshot.data!;
//
// return ListView.builder(
// physics: const NeverScrollableScrollPhysics(),
// shrinkWrap: true,
// itemCount: nxteps.length,
// itemBuilder: (context, index) {
// return ListTile(
// onTap: () async {
// var eps = await GetStories().playNextEpisode(widget.story, nxteps.keys.toList()[index]);
// setState(() {
// print(eps);
// audioInit(eps["episode_audio"]);
// episode = eps["episode_id"];
// choice!.remove();
// });
// },
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(5),
// ),
// tileColor: Colors.red,
// title: Text(
// nxteps.values.toList()[index],
// style: const TextStyle(color: Colors.white),
// ),
// subtitle: Text(
// nxteps.keys.toList()[index],
// style: const TextStyle(color: Colors.white),
// ),
// leading: IconButton(
// onPressed: () {
// choice!.remove();
// },
// color: Colors.white,
// iconSize: height * 0.04,
// icon: const Icon(
// Icons.play_arrow_rounded,
// ),
// ),
// );
// },
// );
// },
// )
//
// ],
// ),
// ),
// ),
// ),
// ),
// ),
// );
// });
//
// overlayState.insert(choice);
// }
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
audioInit(widget.playLink);
isPlaying = false;
}
Future<void> audioInit(audio) async {
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
audioPlayer.positionStream.listen((position) {
if (mounted == true) {
// setState(() {
_value = position.inSeconds.toDouble();
Duration duration = Duration(seconds: _value.toInt());
Provider.of<PlayerStateModel>(context, listen: false).setCurrentPosition(duration);
// });
}
});
audioPlayer.durationStream.listen((event) {
Provider.of<PlayerStateModel>(context, listen: false).setDuration(event!);
});
audioPlayer.playerStateStream.listen((event) {
if(event.processingState == ProcessingState.completed) {
if(mounted) {
// setState(() {
isPlaying = false;
showAlert(context, "SOng is Completed!");
// _showChoices(context);
// });
}
if (kDebugMode) {
print("_-_-_-_-_-_ SONG COMPLETED _-_-_-_-_-_");
}
} else {
if (kDebugMode) {
print("_-_-_-_-_-_ SONG NOT COMPLETED _-_-_-_-_-_");
}
}
});
audioPlayer.playbackEventStream.listen((event) {
}, onError: (Object e, StackTrace stackTrace) {
if (kDebugMode) {
print('A stream error occurred: $e');
}
});
// Try to load audio from a source and catch any errors.
try {
// AAC example: https://dl.espressif.com/dl/audio/ff-16b-2c-44100hz.aac
await audioPlayer.setAudioSource(AudioSource.uri(
Uri.parse(audio),
tag: MediaItem(
// Specify a unique ID for each media item:
id: 'StoryFy',
// Metadata to display in the notification:
album: widget.story,
title: episode.split("=")[0],
artUri: Uri.parse(widget.poster),
),
));
final duration = audioPlayer.duration;
Provider.of<PlayerStateModel>(context, listen: false).setCurrentPosition(duration!);
// audioPlayer.play();
// setState(() {
// isPlaying = true;
// });
} catch (e) {
if (kDebugMode) {
print("Error loading audio source: $e");
}
}
}
// @override
// void dispose() {
// audioPlayer.dispose();
// WidgetsBinding.instance.removeObserver(this);
// super.dispose();
// }
// @override
// void didChangeAppLifecycleState(AppLifecycleState state) {
// super.didChangeAppLifecycleState(state);
// if (state == AppLifecycleState.resumed) {
// // Resume audio playback if necessary
// // if (isPlaying) {
// // audioPlayer.play();
// // }
// state = state;
// } else if (state == AppLifecycleState.paused) {
// // Pause audio playback if necessary
// // if (isPlaying) {
// // audioPlayer.pause();
// // }
// }
// }
String formatDuration(Duration duration) {
final hours = duration.inHours.remainder(60).toString().padLeft(2, '0');
final minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0');
final seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0');
return '$hours:$minutes:$seconds';
}
@override
Widget build(BuildContext context) {
final Size screenSize = MediaQuery.of(context).size;
final double width = screenSize.width;
final double height = screenSize.height;
final playerStateModel = Provider.of<PlayerStateModel>(context, listen: false);
return Scaffold(
appBar: AppBar(),
body: ChangeNotifierProvider(
create: (_) => PlayerStateModel(),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: width * 0.03),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Card(
elevation: 10,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
widget.poster,
height: height * 0.5,
width: width,
fit: BoxFit.fill,
),
),
),
),
SizedBox(
height: height * 0.05,
),
Center(
child: Text(
episode.split("=")[0],
style: TextStyle(
fontSize: height * 0.03,
),
),
),
SizedBox(
height: height * 0.01,
),
Center(
child: Text(
widget.story,
style: TextStyle(
fontSize: height * 0.02,
),
),
),
SizedBox(
height: height * 0.02,
),
Consumer<PlayerStateModel>(
builder: (context, playerState, child) {
_value = playerState.currentPosition.inSeconds.toDouble();
return Slider(
value: _value,
min: 0.0,
max: playerState.duration.inSeconds.toDouble(),
inactiveColor: globals.shadowColor,
onChanged: (newValue) {
final clampedValue = newValue.clamp(0.0, playerState.duration.inSeconds.toDouble());
audioPlayer.seek(Duration(seconds: clampedValue.toInt()));
setState(() {
_value = clampedValue;
});
},
);
},
),
// StreamBuilder<Duration?>(
// stream: audioPlayer.durationStream,
// builder: (context, snapshot) {
// final duration = snapshot.data ?? Duration.zero;
// return Slider(
// value: _value,
// min: 0.0,
// max: duration.inSeconds.toDouble(),
// inactiveColor: globals.shadowColor,
// onChanged: (newValue) {
// final clampedValue = newValue.clamp(0.0, duration.inSeconds.toDouble());
// audioPlayer.seek(Duration(seconds: clampedValue.toInt()));
// },
// );
// },
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// StreamBuilder<Duration>(
// stream: audioPlayer.positionStream,
// builder: (context, snapshot) {
// final position = snapshot.data ?? Duration.zero;
// return Text(formatDuration(position));
// },
// ),
Consumer<PlayerStateModel>(
builder: (context, playerState, child) {
return Text(formatDuration(playerState.currentPosition));
},
),
// StreamBuilder<Duration?>(
// stream: audioPlayer.durationStream,
// builder: (context, snapshot) {
// final duration = snapshot.data ?? Duration.zero;
// return Text(formatDuration(duration));
// },
// ),
Consumer<PlayerStateModel>(
builder: (context, playerState, child) {
return Text(formatDuration(playerState.duration));
},
),
],
),
SizedBox(
height: height * 0.02,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () {
showAlert(context, "data.values.toList()[index]");
audioPlayer.seekToPrevious();
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.skip_previous_rounded,
),
),
IconButton(
onPressed: () async {
final currentPosition = audioPlayer.position;
final duration = audioPlayer.duration;
if (currentPosition != null && duration != null) {
final newPosition = currentPosition - const Duration(seconds: 10);
final clampedPosition = newPosition.isNegative ? Duration.zero : newPosition;
audioPlayer.seek(clampedPosition);
}
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.replay_10_rounded,
),
),
IconButton(
onPressed: () {
if (mounted == true) {
playerStateModel.setIsPlaying(!playerStateModel.isPlaying);
(isPlaying) ? audioPlayer.pause() : audioPlayer.play();
setState(() {
isPlaying = !isPlaying;
});
}
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: isPlaying
? const Icon(
Icons.pause,
)
: const Icon(
Icons.play_arrow_rounded,
),
),
IconButton(
onPressed: () async {
final currentPosition = audioPlayer.position;
final duration = audioPlayer.duration;
if (currentPosition != null && duration != null) {
final newPosition = currentPosition + const Duration(seconds: 10);
final clampedPosition = newPosition.compareTo(duration) > 0 ? duration : newPosition;
audioPlayer.seek(clampedPosition);
}
// await audioPlayer.seek(Duration(
// seconds: audioPlayer.position.inSeconds + 10));
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.forward_10_rounded,
),
),
IconButton(
onPressed: () {
showAlert(context, "data.values.toList()[index]");
audioPlayer.seekToNext();
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.skip_next_rounded,
),
)
],
)
],
),
),
),
);
}
}
and below is the state class
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
class PlayerStateModel extends ChangeNotifier {
bool _isPlaying = true;
Duration _currentPosition = Duration.zero;
Duration _duration = Duration.zero;
bool get isPlaying => _isPlaying;
Duration get duration => _duration;
Duration get currentPosition => _currentPosition;
void setIsPlaying(bool value) {
_isPlaying = value;
notifyListeners();
}
void setCurrentPosition(Duration value) {
_currentPosition = value;
notifyListeners();
}
void setDuration(Duration value) {
_duration = value;
notifyListeners();
}
}
答案1
得分: 0
因为这是很多代码,可能会有其他错误,但初步查看:
为什么要插入两个ChangeNotifierProvider
?
您内部的Consumer
小部件将使用内部提供程序的PlayerStateModel
,但您的audioInit
从外部提供程序访问并修改PlayerStateModel
,而消费者将不会收到更新。
此外,顺便提一下,有时您仍然使用状态对象的本地isPlaying
,有时使用setState
,有时不使用,有时使用PlayerStateModel.isPlaying
。这是有意的吗?
英文:
Because this is a lot of code, there might be other errors, but on a first quick look:
why are you inserting two ChangeNotifierProvider
?
Your inner Consumer
widgets will use the PlayerStateModel
of the inner provider, but your modifications from your audioInit
access and modify the PlayerStateModel
of the outer provider instead for which the consumers will get no updates.
Also as a side note, you sometimes still use the local isPlaying
of the state object sometimes with setState
and sometimes not and sometimes you use the PlayerStateModel.isPlaying
instead. Is this intended?
答案2
得分: 0
UPDATE
所以,以下是更新后的代码,在当前屏幕下运行良好。但让我们考虑一种情况,你需要离开应用程序然后再次访问此屏幕,那么它将不会获取更新的值。我还想在音频通知上实现一个自动导航到PlayingStory
屏幕的点击事件。
英文:
UPDATE
So, below is the updated code that works well when we are in current screen. but let us consider a situation that you need to some how leaving the app and revisiting this screen then it will not get updated values. also I wan to implement such on tap event on audio notification that auto navigates PlayingStory
screen.
import 'dart:ui';
import 'package:app/model/PlayerState.dart';
import 'package:app/stories/get_stories.dart';
import 'package:audio_service/audio_service.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:app/globals.dart' as globals;
import 'package:just_audio/just_audio.dart';
import 'package:provider/provider.dart';
import '../widgets/error_alert.dart';
import 'package:audio_session/audio_session.dart';
class PlayingStory extends StatefulWidget {
final String story;
final String episode;
final String playLink;
final String poster;
const PlayingStory(
{Key? key,
required this.story,
required this.episode,
required this.playLink,
required this.poster})
: super(key: key);
@override
State<StatefulWidget> createState() => PlayingStoryState();
}
class PlayingStoryState extends State<PlayingStory> with WidgetsBindingObserver {
double _value = 0.0;
final audioPlayer = AudioPlayer();
late bool isPlaying;
bool _isCompleted = false;
late AppLifecycleState state;
late String episode = widget.episode;
void _showChoices(BuildContext context) {
// GetStories().updateStoryList(widget.story,context);
var nextEpisode = GetStories().fetchNextEpisodes(widget.story);
OverlayState overlayState = Overlay.of(context);
OverlayEntry? choice;
final Size size = MediaQuery.of(context).size;
final height = size.height;
final width = size.width;
choice = OverlayEntry(builder: (context) {
print("_-_-_-_-_-_-_-_-_-_-_ OVERLAY CALLED _-_-_-_-_-_-_-_-_-_-_");
return Scaffold(
backgroundColor: Colors.transparent,
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: width * 0.035, vertical: height * 0.06),
child: ColoredBox(
color: const Color(0xff838080),
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaY: 8.0,
sigmaX: 8.0,
),
child: Center(
child: ListView(
children: [
FutureBuilder<Map<dynamic, dynamic>>(
future: nextEpisode,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
final nxteps = snapshot.data!;
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: nxteps.length,
itemBuilder: (context, index) {
return ListTile(
onTap: () async {
var eps = await GetStories().playNextEpisode(widget.story, nxteps.keys.toList()[index]);
var lst = eps.values.toList();
setState(() {
// print("_-_-_-_-_ EPS _-_-_-_-_\n$eps");
// print("_-_-_-_-_ LST _-_-_-_-_\n$lst");
audioInit(lst[1]);
episode = lst[0];
choice!.remove();
});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
tileColor: Colors.red,
title: Text(
nxteps.values.toList()[index],
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
nxteps.keys.toList()[index],
style: const TextStyle(color: Colors.white),
),
leading: IconButton(
onPressed: () {
choice!.remove();
},
color: Colors.white,
iconSize: height * 0.04,
icon: const Icon(
Icons.play_arrow_rounded,
),
),
);
},
);
},
)
],
),
),
),
),
),
),
);
});
overlayState.insert(choice);
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
audioInit(widget.playLink);
isPlaying = false;
}
Future<void> audioInit(audio) async {
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
audioPlayer.positionStream.listen((position) {
if (mounted == true) {
// setState(() {
_value = position.inSeconds.toDouble();
Duration duration = Duration(seconds: _value.toInt());
Provider.of<PlayerStateModel>(context, listen: false).setCurrentPosition(duration);
// });
}
});
audioPlayer.durationStream.listen((event) {
Provider.of<PlayerStateModel>(context, listen: false).setDuration(event!);
});
audioPlayer.playerStateStream.listen((event) {
if (event.processingState == ProcessingState.completed && !_isCompleted) {
// setState(() {
Provider.of<PlayerStateModel>(context, listen: false).setIsPlaying(false);
_isCompleted = true;
// });
// Show overlay or perform actions on audio completion
_showChoices(context);
} else if (event.processingState == ProcessingState.ready) {
// Reset the completion state when the player is ready to play the next audio
_isCompleted = false;
} else {
if (kDebugMode) {
print("_-_-_-_-_-_ SONG NOT COMPLETED _-_-_-_-_-_");
}
}
});
audioPlayer.playbackEventStream.listen((event) {
}, onError: (Object e, StackTrace stackTrace) {
if (kDebugMode) {
print('A stream error occurred: $e');
}
});
// Try to load audio from a source and catch any errors.
try {
// AAC example: https://dl.espressif.com/dl/audio/ff-16b-2c-44100hz.aac
await audioPlayer.setAudioSource(AudioSource.uri(
Uri.parse(audio),
tag: MediaItem(
// Specify a unique ID for each media item:
id: 'StoryFy',
// Metadata to display in the notification:
album: widget.story,
title: episode.split("=")[0],
artUri: Uri.parse(widget.poster),
),
));
final duration = audioPlayer.duration;
Provider.of<PlayerStateModel>(context, listen: false).setCurrentPosition(duration!);
// audioPlayer.play();
// setState(() {
// isPlaying = true;
// });
} catch (e) {
if (kDebugMode) {
print("Error loading audio source: $e");
}
}
}
// @override
// void dispose() {
// audioPlayer.dispose();
// WidgetsBinding.instance.removeObserver(this);
// super.dispose();
// }
// @override
// void didChangeAppLifecycleState(AppLifecycleState state) {
// super.didChangeAppLifecycleState(state);
// if (state == AppLifecycleState.resumed) {
// // Resume audio playback if necessary
// // if (isPlaying) {
// // audioPlayer.play();
// // }
// state = state;
// } else if (state == AppLifecycleState.paused) {
// // Pause audio playback if necessary
// // if (isPlaying) {
// // audioPlayer.pause();
// // }
// }
// }
String formatDuration(Duration duration) {
final hours = duration.inHours.remainder(60).toString().padLeft(2, '0');
final minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0');
final seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0');
return '$hours:$minutes:$seconds';
}
@override
Widget build(BuildContext context) {
final Size screenSize = MediaQuery.of(context).size;
final double width = screenSize.width;
final double height = screenSize.height;
final playerStateModel = Provider.of<PlayerStateModel>(context, listen: false);
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: EdgeInsets.symmetric(horizontal: width * 0.03),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Card(
elevation: 10,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
widget.poster,
height: height * 0.5,
width: width,
fit: BoxFit.fill,
),
),
),
),
SizedBox(
height: height * 0.05,
),
Center(
child: Text(
episode.split("=")[0],
style: TextStyle(
fontSize: height * 0.03,
),
),
),
SizedBox(
height: height * 0.01,
),
Center(
child: Text(
widget.story,
style: TextStyle(
fontSize: height * 0.02,
),
),
),
SizedBox(
height: height * 0.02,
),
Consumer<PlayerStateModel>(
builder: (context, playerState, child) {
_value = playerState.currentPosition.inSeconds.toDouble();
return Slider(
value: _value,
min: 0.0,
max: playerState.duration.inSeconds.toDouble(),
inactiveColor: globals.shadowColor,
onChanged: (newValue) {
final clampedValue = newValue.clamp(0.0, playerState.duration.inSeconds.toDouble());
audioPlayer.seek(Duration(seconds: clampedValue.toInt()));
setState(() {
_value = clampedValue;
});
},
);
},
),
// StreamBuilder<Duration?>(
// stream: audioPlayer.durationStream,
// builder: (context, snapshot) {
// final duration = snapshot.data ?? Duration.zero;
// return Slider(
// value: _value,
// min: 0.0,
// max: duration.inSeconds.toDouble(),
// inactiveColor: globals.shadowColor,
// onChanged: (newValue) {
// final clampedValue = newValue.clamp(0.0, duration.inSeconds.toDouble());
// audioPlayer.seek(Duration(seconds: clampedValue.toInt()));
// },
// );
// },
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// StreamBuilder<Duration>(
// stream: audioPlayer.positionStream,
// builder: (context, snapshot) {
// final position = snapshot.data ?? Duration.zero;
// return Text(formatDuration(position));
// },
// ),
Consumer<PlayerStateModel>(
builder: (context, playerState, child) {
return Text(formatDuration(playerState.currentPosition));
},
),
// StreamBuilder<Duration?>(
// stream: audioPlayer.durationStream,
// builder: (context, snapshot) {
// final duration = snapshot.data ?? Duration.zero;
// return Text(formatDuration(duration));
// },
// ),
Consumer<PlayerStateModel>(
builder: (context, playerState, child) {
return Text(formatDuration(playerState.duration));
},
),
],
),
SizedBox(
height: height * 0.02,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () {
showAlert(context, "data.values.toList()[index]");
audioPlayer.seekToPrevious();
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.skip_previous_rounded,
),
),
IconButton(
onPressed: () async {
final currentPosition = audioPlayer.position;
final duration = audioPlayer.duration;
if (currentPosition != null && duration != null) {
final newPosition = currentPosition - const Duration(seconds: 10);
final clampedPosition = newPosition.isNegative ? Duration.zero : newPosition;
audioPlayer.seek(clampedPosition);
}
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.replay_10_rounded,
),
),
IconButton(
onPressed: () {
if (mounted == true) {
playerStateModel.setIsPlaying(!playerStateModel.isPlaying);
(isPlaying) ? audioPlayer.pause() : audioPlayer.play();
setState(() {
isPlaying = !isPlaying;
});
}
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: isPlaying
? const Icon(
Icons.pause,
)
: const Icon(
Icons.play_arrow_rounded,
),
),
IconButton(
onPressed: () async {
final currentPosition = audioPlayer.position;
final duration = audioPlayer.duration;
if (currentPosition != null && duration != null) {
final newPosition = currentPosition + const Duration(seconds: 10);
final clampedPosition = newPosition.compareTo(duration) > 0 ? duration : newPosition;
audioPlayer.seek(clampedPosition);
}
// await audioPlayer.seek(Duration(
// seconds: audioPlayer.position.inSeconds + 10));
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.forward_10_rounded,
),
),
IconButton(
onPressed: () {
showAlert(context, "data.values.toList()[index]");
audioPlayer.seekToNext();
},
iconSize: height * 0.05,
color: Colors.storyfytheme,
icon: const Icon(
Icons.skip_next_rounded,
),
)
],
)
],
),
),
);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论