tcard is not resetting, getting null in tcardController.state Flutter - flutter

I am tcard pkg in my project. i want reset the card in every 5 seconds automatically the length of the list is changing but the UI is not resetting, getting null in tcardController.state
Is there any other pkg, so we can achieve same functionality of this tcard pkg.
Refer to below code:-
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:tcard/tcard.dart';
List<Color> colors = [
Colors.blue,
Colors.yellow,
Colors.red,
Colors.orange,
Colors.pink,
Colors.amber,
Colors.cyan,
Colors.purple,
Colors.brown,
Colors.teal,
];
class TCardPage extends StatefulWidget {
const TCardPage({Key? key}) : super(key: key);
#override
_TCardPageState createState() => _TCardPageState();
}
class _TCardPageState extends State<TCardPage> {
final TCardController _controller = TCardController();
int _index = 0;
Timer? timer;
bool changeColor = false;
#override
void initState() {
super.initState();
timer = Timer.periodic(
const Duration(seconds: 5), (Timer t) => sequenceApiCall());
print(_controller.state.toString());
// _controller.reset;
}
void sequenceApiCall() {
changeColor = !changeColor;
Future.delayed(const Duration(seconds: 10), () {
print('sequenceApiCall');
if (changeColor) {
print('changeColor');
colors.removeAt(0);
print('color count = ${colors.length}'); //9
} else {
colors.insert(0, Colors.black);
print('black');
print('color count = ${colors.length}'); //10
}
print(_controller.state.toString());
_controller.reset();
setState(() {});
});
}
#override
void dispose() {
super.dispose();
timer?.cancel();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
const SizedBox(height: 200),
TCard(
cards: cardsColor,
controller: _controller,
onForward: (index, info) {
_index = index;
print(info.direction);
setState(() {});
},
onBack: (index, info) {
_index = index;
setState(() {});
},
onEnd: () {
print('end');
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
OutlineButton(
onPressed: () {
_controller.back();
},
child: const Text('Back'),
),
OutlineButton(
onPressed: () {
_controller.forward();
},
child: const Text('Forward'),
),
OutlineButton(
onPressed: () {
_controller.reset();
},
child: const Text('Reset'),
),
],
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Text(_index.toString()),
),
);
}
List<Widget> cardsColor = List.generate(
colors.length,
(int index) {
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: colors[index],
),
child: Text(
'${index + 1}',
style: const TextStyle(fontSize: 100.0, color: Colors.white),
),
);
},
);
}
Thanks in advance.!!!

Related

Animation library is giving me this error about lifecycle state

Animation library is giving me this error about lifecycle state-- 'package:flutter/src/widgets/framework.dart': Failed assertion: line 4519 pos 12: '_lifecycleState != _ElementLifecycle.defunct': is not true. is was getting this error when i used animation controller.
After the error my flutter application crashed and i have to reload everytime.
// ignore_for_file: depend_on_referenced_packages, sized_box_for_whitespace, avoid_print
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:habbit_app/controllers/timer_tab_controller.dart';
import 'package:habbit_app/screens/timer/set_timer_component.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:habbit_app/widgets/text_widget/label_text.dart';
class TimerTab extends StatefulWidget {
const TimerTab({super.key});
#override
State<TimerTab> createState() => _TimerTabState();
}
class _TimerTabState extends State<TimerTab> with TickerProviderStateMixin {
AnimationController? animationController;
TimerTabController tabController =
Get.put(TimerTabController(), permanent: false);
late TabController _controller;
bool isPlaying = false;
// int get countText2 {
// int count = tabController.totalSeconds;
// return;
// }
String get countText {
Duration count =
animationController!.duration! * animationController!.value;
return animationController!.isDismissed
? '${animationController!.duration!.inHours}:${(animationController!.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(animationController!.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
#override
void dispose() {
animationController!.dispose();
super.dispose();
}
double progress = 1.0;
void notifiy() {
if (countText == "0:00:00") {
FlutterRingtonePlayer.playNotification();
}
}
#override
void initState() {
// ignore: todo
// TODO: implement initState
TimerTabController tabController =
Get.put(TimerTabController(), permanent: false);
super.initState();
_controller = TabController(length: 3, vsync: this);
_controller.addListener(() {
tabController.tabIndex.value = _controller.index;
// print(tabController.tabIndex.value);
});
super.initState();
animationController = AnimationController(
vsync: this, duration: Duration(seconds: tabController.totalSeconds));
animationController!.addListener(() {
notifiy();
if (animationController!.isAnimating) {
setState(() {
progress = animationController!.value;
});
} else {
setState(() {
progress = 1.0;
isPlaying = false;
});
}
});
}
#override
Widget build(BuildContext context) {
var color = Theme.of(context);
return Obx(
() => tabController.isFirst.value
? SetTimerComponent(
changeAnimation: () {
animationController!.duration =
Duration(seconds: tabController.totalSeconds);
tabController.changeFirst();
},
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// start timer screen
Container(
height: 350,
width: MediaQuery.of(context).size.width,
// color: color.cardColor,
child: Column(children: [
Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: 300,
height: 300,
child: CircularProgressIndicator(
color: color.primaryColor,
backgroundColor:
color.disabledColor.withOpacity(0.6),
value: progress,
strokeWidth: 10,
)),
GestureDetector(
onTap: () {
if (animationController!.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
height: 300,
child: CupertinoTimerPicker(
initialTimerDuration:
animationController!.duration!,
backgroundColor:
color.backgroundColor,
onTimerDurationChanged: (time) {
setState(() {
animationController!.duration =
time;
});
},
),
));
}
},
child: AnimatedBuilder(
animation: animationController!,
builder: ( context, child) => Text(
countText,
style: TextStyle(
fontSize: 60,
fontWeight: FontWeight.bold,
color: color.primaryColor),
),
),
),
],
),
]),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
print(tabController.totalSeconds);
if (animationController!.isAnimating) {
animationController!.stop();
setState(() {
isPlaying = false;
});
} else {
animationController!.reverse(
from: animationController!.value == 0
? 1.0
: animationController!.value);
setState(() {
isPlaying = true;
});
}
},
child: Container(
height: 35,
width: 90,
decoration: BoxDecoration(
borderRadius:
const BorderRadius.all(Radius.circular(30)),
color: color.primaryColor),
child: Center(
child: LabelText(
text: isPlaying == true ? "PAUSE" : "RESUME",
isBold: true,
isColor: true,
color: Colors.white,
)),
),
),
GestureDetector(
onTap: () {
animationController!.reset();
tabController.currentvalueHour.value = 0;
tabController.currentvalueMin.value = 0;
tabController.currentvalueSec.value = 0;
setState(() {
isPlaying = false;
});
tabController.changeFirst2();
},
child: Container(
height: 35,
width: 90,
decoration: BoxDecoration(
borderRadius:
const BorderRadius.all(Radius.circular(30)),
color: color.disabledColor.withOpacity(0.5)),
child: const Center(
child: LabelText(
text: "DELETE",
isColor: true,
color: Colors.white,
isBold: true,
)),
),
)
],
)
],
),
);
}
}

Can't convert setState to BloC

I am developing an audio player application using Flutter, I am using on_audio_query package to get audio files from device storage, and just_audio package for the audio player.
when I created the project, in the audio player I used setState to handle state management, and now, I want to convert to bloc pattern but when I tried to do that I faced a lot of issues and couldn't fix them.
I will attach the code of the audio player and also basic cubit code and if someone guided me or showed me how to convert I would appreciate it.
I'm sorry if the code is confusing but I don't know how to add it correctly.
audio player code
import 'package:just_audio/just_audio.dart';
import 'package:dorosi/shared/ui/my_icon.dart';
import 'package:dorosi/shared/ui/my_text.dart';
import 'package:flutter/material.dart';
import 'package:on_audio_query/on_audio_query.dart';
class AudioPlayerWithUrl extends StatefulWidget {
final SongModel songModel;
const AudioPlayerWithUrl({required this.songModel, Key? key})
: super(key: key);
#override
State<AudioPlayerWithUrl> createState() => _AudioPlayerWithUrlState();
}
class _AudioPlayerWithUrlState extends State<AudioPlayerWithUrl> {
final audioPlayer = AudioPlayer();
bool isPlaying = false;
Duration duration = const Duration();
Duration position = const Duration();
bool isPressed = false;
#override
void initState() {
super.initState();
setAudio();
playAudio();
}
Future setAudio() async {
audioPlayer.setLoopMode(LoopMode.off);
audioPlayer.setAudioSource(
AudioSource.uri(
Uri.parse(widget.songModel.uri!),
),
);
isPlaying = true;
audioPlayer.durationStream.listen((audioDuration) {
setState(() {
duration = audioDuration!;
});
});
audioPlayer.positionStream.listen((audioPosition) {
setState(() {
position = audioPosition;
});
});
}
#override
void dispose() {
audioPlayer.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const MyText(
writtenText: 'Now Playing',
textSize: 23,
textColor: Colors.black,
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: const MyIcon(
icon: Icons.arrow_back,
iconColor: Colors.black,
)),
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
IconButton(
onPressed: () {},
icon: const MyIcon(
icon: Icons.more_vert,
iconColor: Colors.black,
),
),
const SizedBox(width: 10)
],
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 15),
const CircleAvatar(
backgroundColor: Color(0xFFc61104),
radius: 100,
child: MyIcon(
icon: Icons.music_note,
iconSize: 100,
iconColor: Colors.white,
),
),
const SizedBox(
height: 15,
),
const SizedBox(height: 15),
MyText(
writtenText: widget.songModel.title,
textSize: 24,
textWeight: FontWeight.bold,
),
const SizedBox(height: 4),
MyText(
writtenText: widget.songModel.album!,
textSize: 20,
),
const SizedBox(height: 10),
Slider(
activeColor: Colors.orange,
inactiveColor: Colors.black87,
min: 0,
max: duration.inSeconds.toDouble(),
value: position.inSeconds.toDouble(),
onChanged: (value) async {
isPlaying = true;
final position = Duration(seconds: value.toInt());
await audioPlayer.seek(position);
await audioPlayer.play();
}),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText(
writtenText: formatTime(position),
textWeight: FontWeight.bold),
TextButton(
style: TextButton.styleFrom(primary: Colors.black),
onPressed: () {
setState(() {
showRemainingTime();
isPressed = !isPressed;
});
},
child: isPressed
? showRemainingTime()
: MyText(
writtenText: ' ${formatTime(duration)}',
textWeight: FontWeight.bold,
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: const Color(0xFFc61104),
radius: 23,
child: IconButton(
onPressed: () async {
if (position >= const Duration(seconds: 10)) {
seekTo(position.inSeconds - 10);
} else {
setState(() {
seekTo(const Duration(seconds: 0).inSeconds);
isPlaying = false;
});
pauseAudio();
}
},
icon: const MyIcon(
icon: Icons.settings_backup_restore,
iconSize: 30,
iconColor: Colors.white,
)),
),
const SizedBox(width: 40),
CircleAvatar(
backgroundColor: const Color(0xFFc61104),
radius: 35,
child: IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
iconSize: 50,
onPressed: () {
setState(() {
if (isPlaying) {
pauseAudio();
} else {
playAudio();
}
isPlaying = !isPlaying;
});
},
),
),
const SizedBox(width: 40),
CircleAvatar(
radius: 23,
backgroundColor: const Color(0xFFc61104),
child: IconButton(
onPressed: () async {
if (position < duration - const Duration(seconds: 10)) {
seekTo(position.inSeconds + 10);
} else {
setState(() {
seekTo(duration.inSeconds);
isPlaying = false;
});
pauseAudio();
}
},
icon: const MyIcon(
icon: Icons.forward_10,
iconSize: 30,
iconColor: Colors.white,
)),
),
],
),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(width: 40),
ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.orange),
onPressed: () {
setState(() {
if (audioPlayer.speed == 1) {
adjustAudioSpeed();
debugPrint('${audioPlayer.speed}');
} else if (audioPlayer.speed == 1.25) {
adjustAudioSpeed2();
} else if (audioPlayer.speed == 1.5) {
adjustAudioSpeed3();
} else if (audioPlayer.speed == 1.75) {
adjustAudioSpeed4();
} else if (audioPlayer.speed == 2) {
setAudioNormalSpeed();
}
});
},
child: MyText(
writtenText: '${audioPlayer.speed}',
textSize: 18,
textColor: Colors.black,
)),
const SizedBox(width: 40),
],
)
],
),
)),
);
}
Widget showRemainingTime() {
return MyText(
writtenText: '- ${formatTime(duration - position)}',
textWeight: FontWeight.bold,
);
}
seekTo(int seconds) {
audioPlayer.seek(Duration(seconds: seconds));
}
playAudio() {
audioPlayer.play();
}
pauseAudio() {
audioPlayer.pause();
}
setAudioNormalSpeed() {
audioPlayer.setSpeed(1);
}
adjustAudioSpeed() {
audioPlayer.setSpeed(1.25);
}
adjustAudioSpeed2() {
audioPlayer.setSpeed(1.5);
}
adjustAudioSpeed3() {
audioPlayer.setSpeed(1.75);
}
adjustAudioSpeed4() {
audioPlayer.setSpeed(2);
}
playNextAudio() {
audioPlayer.seekToNext();
}
playPreviousAudio() {
audioPlayer.seekToPrevious();
}
String formatTime(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
final hours = twoDigits(duration.inHours);
final minutes = twoDigits(duration.inMinutes.remainder(60));
final seconds = twoDigits(duration.inSeconds.remainder(60));
return [
if (duration.inHours > 0) hours,
minutes,
seconds,
].join(':');
}
}
player cubit code
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:meta/meta.dart';
part 'player_state.dart';
class PlayerCubit extends Cubit<PlayerState> {
static PlayerCubit get(context) => BlocProvider.of(context);
PlayerCubit() : super(PlayerInitialState());
}
player state code
part of 'player_cubit.dart';
#immutable
abstract class PlayerState {}
class PlayerInitialState extends PlayerState {}
class PlayerPlayingState extends PlayerState {}
class PlayerPauseState extends PlayerState {}

Cannot add new events after calling close

Flutter
i am using video_trimmer: ^0.5.2 plugin , which allows cutting and editing the video before uploading ,on pressed so everything work fine from the first time but if i reopen the editor again by clicking the bottom, video will be shown without the TrimmerEditor widget with this error Cannot add new events after calling close but if left the page and re-entered again, everything will work fine except if i click again and again with keeping in the same UI page !
i already know that happen because of the widget which is close again from the stack IF (true or false ) but i need a solution with same my code cuse i have big complicated project in the same code
class VideoTrimmer extends StatefulWidget {
const VideoTrimmer({Key key}) : super(key: key);
#override
_VideoTrimmerState createState() => _VideoTrimmerState();
}
class _VideoTrimmerState extends State<VideoTrimmer> {
Trimmer _trimmer = Trimmer(); // this object from the package its self
double _startValue = 0.0;
double _endValue = 0.0;
bool _isPlaying = false;
bool displayWidget = false;
_loadVideo() {
_trimmer.loadVideo(videoFile: file);
}
#override
void dispose() {
super.dispose();
_trimmer.dispose(); // i tried to remove this too , but same issue
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Stack(
children: [
TextButton(
onPressed: (){
final result = await FilePicker.platform.pickFiles(allowMultiple: false );
if (result == null) return;
final path = result.files.single.path;
setState(() => file = File(path));
_loadVideo();
setState(() => displayWidget = true);
},
child: Text("selectVideo")
),
displayWidget ?
Center(
child: Container(
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.black,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: VideoViewer(trimmer: _trimmer),
),
Center(
child: TrimEditor( // here is the issue happen
trimmer: _trimmer,
viewerHeight: 50.0,
viewerWidth: MediaQuery.of(context).size.width,
maxVideoLength: Duration(seconds: 60),
onChangeStart: (value) {
_startValue = value;
},
onChangeEnd: (value) {
_endValue = value;
},
onChangePlaybackState: (value) {
if(!mounted) {
setState(() =>
_isPlaying = value);
}
},
),
),
TextButton(
child: _isPlaying
? Icon(
Icons.pause,
size: 80.0,
color: Colors.white,
)
: Icon(
Icons.play_arrow,
size: 80.0,
color: Colors.white,
),
onPressed: () async {
bool playbackState = await _trimmer.videPlaybackControl(
startValue: _startValue,
endValue: _endValue,
);
if(!mounted) {
setState(() =>
_isPlaying = playbackState);
}
},
),
ElevatedButton(
child: Text("SAVE"),
onPressed: () {
uploadVideo();
setState(() => displayWidget = false);
},
),
],
),
),
),
],
),
);
}
}

How to save page state on revisit in flutter

I have 2 screens and I am trying to achieve understand how to achieve page state. For example, in the below screen, I have 4 options, and all of them take the user to the same screen the only difference is API getting called for each of them is different to build a list. I am trying to handle back arrow action, and that's where I am having issues.
Use Case -
When user is on screen 2 he is playing the song, now on back press song continues to play. Now when the user again chooses the same option from screen 1 I want to show the same list without reload and selection. If user selects any other option it should behave normal, which is working.
Solution -
I can hardcode loaded songs list and send back to screen 1 and then again get that back with the selection but this will take lot of resources.
AutomaticKeepAliveClientMixin i tried this tutorial but that didn't help or kept state active.
PageStorage is 3rd option i saw but i found majority of the time this is being used on app where we have a tab.
Screen 1 -
class Dashboard extends StatefulWidget {
int playingId;
Dashboard({this.playingId});
#override
_DashboardState createState() => _DashboardState(playingId);
}
class _DashboardState extends State<Dashboard> {
String appname;
int playingId = 0;
_DashboardState(this.playingId);
// print('${playingId}');
#override
void initState() {
appname="";
// playingId=0;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.darkBlue,
centerTitle: true,
title: Text("Tirthankar",
style: TextStyle(color: Colors.white),),
),
backgroundColor: AppColors.styleColor,
body: Column(
children: <Widget>[
// SizedBox(height: 5),
Padding(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomGridWidget(
child: Icon(
Icons.file_download,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/bhaktambar.png',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Bhakti",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Kids",playingId: playingId,),
),
);
},
),
CustomGridWidget(
child: Icon(
Icons.file_download,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/bhaktambar.png',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Kids",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Kids",playingId: playingId,),
),
);
},
),
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomGridWidget(
child: Icon(
Icons.favorite,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/kids.jpg',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
label: "Favorite",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Songs"),
),
);
},
),
Align(
alignment: Alignment.center,
child: CustomGridWidget(
child: Icon(
Icons.book,
size: 100,
color: AppColors.styleColor,
),
// image: 'assets/vidyasagar.jpg',
sizew: MediaQuery.of(context).size.width * .4,
sizeh: MediaQuery.of(context).size.width * .5,
borderWidth: 2,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => ListPage(appname: "Bhajan"),
),
);
},
),
),
],
),
),
]
),
);
}
Material boxTiles(IconData icon, String name){
return Material(
color: AppColors.mainColor,
elevation: 14.0,
shadowColor: AppColors.styleColor,
borderRadius: BorderRadius.circular(24.0),
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: (){print("tapped"); /* or any action you want */ },
child: Container(
width: 130.0,
height: 10.0,
color : Colors.transparent,
), // container
), //
//Text
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(name,
style:TextStyle(
color: AppColors.styleColor,
fontSize: 20.0,
)
),
),
//Icon
Material(
color: AppColors.styleColor,
borderRadius: BorderRadius.circular(50.0),
child: Padding(padding: const EdgeInsets.all(10.0),
child: Icon(icon, color: AppColors.lightBlue,size: 30,),
),
),
],
)
],
)
),
)
);
}
}
Screen 2 -
// import 'dart:js';
class ListPage extends StatefulWidget {
String appname;
int playingId;
ListPage({this.appname,this.playingId});
#override
_ListPageState createState() => _ListPageState(appname,playingId);
}
class _ListPageState extends State<ListPage>
with SingleTickerProviderStateMixin,AutomaticKeepAliveClientMixin<ListPage> {
String appname;
int playingId;
bool isPlaying = false;
_ListPageState(this.appname,playingId);
// List<MusicModel> _list1;
List<MusicData> _list;
var _value;
int _playId;
int _songId;
String _playURL;
bool _isRepeat;
bool _isShuffle;
bool _isFavorite;
String _startTime;
String _endTime;
AnimationController _controller;
Duration _duration = new Duration();
Duration _position = new Duration();
final _random = new Random();
AudioPlayer _audioPlayer = AudioPlayer();
#override
void initState() {
_playId = 0;
// _list1 = MusicModel.list;
this._fileUpdate();
// _list = _list1;
_controller =
AnimationController(vsync: this, duration: Duration(microseconds: 250));
_value = 0.0;
_startTime = "0.0";
_endTime = "0.0";
_isRepeat = false;
_isShuffle = false;
_isFavorite = false;
_audioPlayer.onAudioPositionChanged.listen((Duration duration) {
setState(() {
// _startTime = duration.toString().split(".")[0];
_startTime = duration.toString().split(".")[0];
_duration = duration;
// _position = duration.toString().split(".")[0];
});
});
_audioPlayer.onDurationChanged.listen((Duration duration) {
setState(() {
_endTime = duration.toString().split(".")[0];
_position = duration;
});
});
_audioPlayer.onPlayerCompletion.listen((event) {
setState(() {
isPlaying = false;
_position = _duration;
if (_isRepeat) {
_songId = _songId;
} else {
if (_isShuffle) {
var element = _list[_random.nextInt(_list.length)];
_songId = element.id;
} else {
_songId = _songId + 1;
}
}
_player(_songId);
});
});
super.initState();
}
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: AppColors.mainColor,
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Dashboard(playingId: _songId),
),
);
},
),
title: Text(
appname,
style: TextStyle(color: AppColors.styleColor),
),
),
backgroundColor: AppColors.mainColor,
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(24.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CustomButtonWidget(
child: Icon(
Icons.favorite,
color: AppColors.styleColor,
),
size: 50,
onTap: () {},
),
CustomButtonWidget(
image: 'assets/logo.jpg',
size: 100,
borderWidth: 5,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => DetailPage(),
),
);
},
),
CustomButtonWidget(
child: Icon(
Icons.menu,
color: AppColors.styleColor,
),
size: 50,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => HomePage(),
),
);
},
)
],
),
),
slider(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(
_isRepeat ? Icons.repeat_one : Icons.repeat,
color: _isRepeat ? Colors.brown : AppColors.styleColor,
),
onPressed: () {
if (_isRepeat) {
_isRepeat = false;
} else {
_isRepeat = true;
}
},
),
IconButton(
icon: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
color: AppColors.styleColor,
),
onPressed: () {
if (isPlaying) {
_audioPlayer.pause();
setState(() {
isPlaying = false;
});
} else {
if (!isPlaying){
_audioPlayer.resume();
setState(() {
isPlaying = true;
});
}
}
}),
IconButton(
icon: Icon(
Icons.stop,
color: AppColors.styleColor,
),
onPressed: () {
if (isPlaying){
_audioPlayer.stop();
setState(() {
isPlaying = false;
_duration = new Duration();
});
}
// isPlaying = false;
}),
IconButton(
icon: Icon(
Icons.shuffle,
color:
_isShuffle ? Colors.brown : AppColors.styleColor,
),
onPressed: () {
if (_isShuffle) {
_isShuffle = false;
} else {
_isShuffle = true;
}
}),
],
),
),
Expanded(
//This is added so we can see overlay else this will be over button
child: ListView.builder(
physics:
BouncingScrollPhysics(), //This line removes the dark flash when you are at the begining or end of list menu. Just uncomment for
// itemCount: _list.length,
itemCount: _list == null ? 0 : _list.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
_songId = index;
_player(index);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
//This below code will change the color of sected area or song being played.
decoration: BoxDecoration(
color: _list[index].id == _playId
? AppColors.activeColor
: AppColors.mainColor,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
//End of row color change
child: Padding(
padding: const EdgeInsets.all(
16), //This will all padding around all size
child: Row(
mainAxisAlignment: MainAxisAlignment
.spaceBetween, //This will allign button to left, else button will be infront of name
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_list[index].title,
style: TextStyle(
color: AppColors.styleColor,
fontSize: 16,
),
),
Text(
_list[index].album,
style: TextStyle(
color: AppColors.styleColor.withAlpha(90),
fontSize: 16,
),
),
],
),
IconButton(
icon: Icon(_isFavorite
? Icons.favorite
: Icons.favorite_border),
onPressed: () {
if (_isFavorite) {
_isFavorite = false;
} else {
_isFavorite = true;
}
})
//Diabled Play button and added fav button.
// CustomButtonWidget(
// //This is Play button functionality on list page.
// child: Icon(
// _list[index].id == _playId
// ? Icons.pause
// : Icons.play_arrow,
// color: _list[index].id == _playId
// ? Colors.white
// : AppColors.styleColor,
// ),
// size: 50,
// isActive: _list[index].id == _playId,
// onTap: () async {
// _songId = index;
// _player(index);
// },
// )
],
),
),
),
);
},
),
)
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 50,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
AppColors.mainColor.withAlpha(0),
AppColors.mainColor,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
),
)
],
),
// floatingActionButton: FloatingActionButton(
// child: Icon(Icons.music_note),
// onPressed: () async { // String filePath = await FilePicker.getFilePath();
// int status = await _audioPlayer.play("https://traffic.libsyn.com/voicebot/Jan_Konig_on_the_Jovo_Open_Source_Framework_for_Voice_App_Development_-_Voicebot_Podcast_Ep_56.mp3");
// if (status == 1){
// setState(() {
// isPlaying = true;
// });
// }
// },
// )
);
}
Widget slider() {
return Slider(
activeColor: AppColors.styleColor,
inactiveColor: Colors.lightBlue,
value: _duration.inSeconds.toDouble(),
min: 0.0,
max: _position.inSeconds.toDouble(),
divisions: 10,
onChangeStart: (double value) {
print('Start value is ' + value.toString());
},
onChangeEnd: (double value) {
print('Finish value is ' + value.toString());
},
onChanged: (double value) {
setState(() {
seekToSecond(value.toInt());
value = value;
});
});
}
Future<Void> _fileUpdate() async {
String url =
"azonaws.com/input.json";
String arrayObjsText = "";
try {
eos.Response response;
Dio dio = new Dio();
response = await dio.get(url,options: Options(
responseType: ResponseType.plain,
),);
arrayObjsText = response.data;
print(response.data.toString());
} catch (e) {
print(e);
}
var tagObjsJson = jsonDecode(arrayObjsText)['tags'] as List;
this.setState(() {
_list = tagObjsJson.map((tagJson) => MusicData.fromJson(tagJson)).toList();
});
// return _list;
// print(_list);
}
Future<void> _player(int index) async {
if (isPlaying) {
if (_playId == _list[index].id) {
int status = await _audioPlayer.pause();
if (status == 1) {
setState(() {
isPlaying = false;
});
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
_audioPlayer.stop();
int status = await _audioPlayer.play(_playURL);
if (status == 1) {
setState(() {
isPlaying = true;
});
}
}
} else {
_playId = _list[index].id;
_playURL = _list[index].songURL;
int status = await _audioPlayer.play(_playURL);
if (status == 1) {
setState(() {
isPlaying = true;
});
}
}
}
String _printDuration(Duration duration) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
}
void seekToSecond(int second) {
Duration newDuration = Duration(seconds: second);
_audioPlayer.seek(newDuration);
}
}
PageStorage is 3rd option i saw but i found majority of the time this is being used on app where we have a tab.
You still can use this approach with what you want, with or without Tab/ bottom navigation bar.
PageViewClass
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin{
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose() {
super.dispose();
_pageController?.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(), // so the user cannot scroll, only animating when they select an option
children: <Widget>[
Dashboard(playingId: 1, key: PageStorageKey<String>('MyPlayList'), pageController: _pageController), //or the name you want, but you need to give them a key to all the child so it can save the Scroll Position
ListPage(appname: "FirstButton",playingId: 1, key: PageStorageKey<String>('FirstButton'), pageController: _pageController),
ListPage(appname: "SecondButton",playingId: 1, key: PageStorageKey<String>('SecondButton'), pageController: _pageController),
ListPage(appname: "ThirdButton",playingId: 1, key: PageStorageKey<String>('ThirdButton'), pageController: _pageController),
ListPage(appname: "FourthButton",playingId: 1, key: PageStorageKey<String>('FourthButton'), pageController: _pageController)
],
),
)
);
}
}
Now you pass the PageController to all children (add a key and PageController attribute to Screen 1 and 2) and in DashBoard (Screen 1) you can change the onTap of the buttons from the MaterialRoute to this
onTap: () => widget.pageController.jumpToPage(x), //where x is the index of the children of the PageView you want to see (between 0 and 4 in this case)
In Screen 2 you wrap all your Scaffold with a WillPopScope so when the user tap back instead of closing the route it goes back to the Dashboard Widget at index 0
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
widget.pageController.jumpToPage(0); // Move back to dashboard (index 0)
return false;
}
child: Scaffold(...)
);
}
You can use other methods of PageController if you want some effects like animations (animateTo, nextPage, previousPage, etc.)

Trigger function on swipe

I am trying to implement a way of triggering a function on a swipe in Flutter. I am building a UI with a stacked card layout using Flutter_Swiper (https://pub.dev/packages/flutter_swiper)
I have tried using both GestureDetector and SwipeDetector (https://pub.dev/packages/swipedetector) but both of these result in Flutter_Swiper breaking.
Does anyone know of a way of using Flutter_Swiper to trigger a function?
You can copy paste run full code below
You can call function in onIndexChanged
code snippet
return Swiper(
onTap: (int index) {
...
customLayoutOption: customLayoutOption,
fade: _fade,
index: _currentIndex,
onIndexChanged: (int index) {
setState(() {
_currentIndex = index;
print(_currentIndex);
});
},
working demo
output
I/flutter ( 4664): 1
I/flutter ( 4664): 2
full code
import 'package:flutter/material.dart';
import 'package:flutter_page_indicator/flutter_page_indicator.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:flutter/cupertino.dart';
class FormWidget extends StatelessWidget {
final String label;
final Widget child;
FormWidget({this.label, this.child});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(5.0),
child: Row(
children: <Widget>[
Text(label, style: TextStyle(fontSize: 14.0)),
Expanded(
child: Align(alignment: Alignment.centerRight, child: child))
],
));
}
}
class FormSelect<T> extends StatefulWidget {
final String placeholder;
final ValueChanged<T> valueChanged;
final List<dynamic> values;
final dynamic value;
FormSelect({this.placeholder, this.valueChanged, this.value, this.values});
#override
State<StatefulWidget> createState() {
return _FormSelectState();
}
}
class _FormSelectState extends State<FormSelect> {
int _selectedIndex = 0;
#override
void initState() {
for (int i = 0, c = widget.values.length; i < c; ++i) {
if (widget.values[i] == widget.value) {
_selectedIndex = i;
break;
}
}
super.initState();
}
#override
Widget build(BuildContext context) {
String placeholder = widget.placeholder;
List<dynamic> values = widget.values;
return Container(
child: InkWell(
child: Text(_selectedIndex < 0
? placeholder
: values[_selectedIndex].toString()),
onTap: () {
_selectedIndex = 0;
showBottomSheet(
context: context,
builder: (BuildContext context) {
return SizedBox(
height: values.length * 30.0 + 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: values.length * 30.0 + 70.0,
child: CupertinoPicker(
itemExtent: 30.0,
children: values.map((dynamic value) {
return Text(value.toString());
}).toList(),
onSelectedItemChanged: (int index) {
_selectedIndex = index;
},
),
),
Center(
child: RaisedButton(
onPressed: () {
if (_selectedIndex >= 0) {
widget
.valueChanged(widget.values[_selectedIndex]);
}
setState(() {});
Navigator.of(context).pop();
},
child: Text("ok"),
),
)
],
),
);
});
},
),
);
}
}
class NumberPad extends StatelessWidget {
final num number;
final num step;
final num max;
final num min;
final ValueChanged<num> onChangeValue;
NumberPad({this.number, this.step, this.onChangeValue, this.max, this.min});
void onAdd() {
onChangeValue(number + step > max ? max : number + step);
}
void onSub() {
onChangeValue(number - step < min ? min : number - step);
}
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(icon: Icon(Icons.exposure_neg_1), onPressed: onSub),
Text(
number is int ? number.toString() : number.toStringAsFixed(1),
style: TextStyle(fontSize: 14.0),
),
IconButton(icon: Icon(Icons.exposure_plus_1), onPressed: onAdd)
],
);
}
}
const List<String> images = [
"https://picsum.photos/250?image=9",
"https://picsum.photos/250?image=10",
"https://picsum.photos/250?image=11",
];
class ExampleCustom extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ExampleCustomState();
}
}
class _ExampleCustomState extends State<ExampleCustom> {
//properties want to custom
int _itemCount;
bool _loop;
bool _autoplay;
int _autoplayDely;
double _padding;
bool _outer;
double _radius;
double _viewportFraction;
SwiperLayout _layout;
int _currentIndex;
double _scale;
Axis _scrollDirection;
Curve _curve;
double _fade;
bool _autoplayDisableOnInteraction;
CustomLayoutOption customLayoutOption;
Widget _buildItem(BuildContext context, int index) {
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(_radius)),
child: Image.network(
images[index % images.length],
fit: BoxFit.fill,
),
);
}
#override
void didUpdateWidget(ExampleCustom oldWidget) {
customLayoutOption = CustomLayoutOption(startIndex: -1, stateCount: 3)
.addRotate([-45.0 / 180, 0.0, 45.0 / 180]).addTranslate(
[Offset(-370.0, -40.0), Offset(0.0, 0.0), Offset(370.0, -40.0)]);
super.didUpdateWidget(oldWidget);
}
#override
void initState() {
customLayoutOption = CustomLayoutOption(startIndex: -1, stateCount: 3)
.addRotate([-25.0 / 180, 0.0, 25.0 / 180]).addTranslate(
[Offset(-350.0, 0.0), Offset(0.0, 0.0), Offset(350.0, 0.0)]);
_fade = 1.0;
_currentIndex = 0;
_curve = Curves.ease;
_scale = 0.8;
_controller = SwiperController();
_layout = SwiperLayout.TINDER;
_radius = 10.0;
_padding = 0.0;
_loop = true;
_itemCount = 3;
_autoplay = false;
_autoplayDely = 3000;
_viewportFraction = 0.8;
_outer = false;
_scrollDirection = Axis.horizontal;
_autoplayDisableOnInteraction = false;
super.initState();
}
// maintain the index
Widget buildSwiper() {
return Swiper(
onTap: (int index) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(" page"),
),
body: Container(),
);
}));
},
customLayoutOption: customLayoutOption,
fade: _fade,
index: _currentIndex,
onIndexChanged: (int index) {
setState(() {
_currentIndex = index;
print(_currentIndex);
});
},
curve: _curve,
scale: _scale,
itemWidth: 300.0,
controller: _controller,
layout: _layout,
outer: _outer,
itemHeight: 200.0,
viewportFraction: _viewportFraction,
autoplayDelay: _autoplayDely,
loop: _loop,
autoplay: _autoplay,
itemBuilder: _buildItem,
itemCount: _itemCount,
scrollDirection: _scrollDirection,
indicatorLayout: PageIndicatorLayout.COLOR,
autoplayDisableOnInteraction: _autoplayDisableOnInteraction,
pagination: SwiperPagination(
builder: const DotSwiperPaginationBuilder(
size: 20.0, activeSize: 20.0, space: 10.0)),
);
}
SwiperController _controller;
TextEditingController numberController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
Container(
color: Colors.black87,
child: SizedBox(
height: 300.0, width: double.infinity, child: buildSwiper()),
),
Expanded(
child: ListView(
children: <Widget>[
Text("Index:$_currentIndex"),
Row(
children: <Widget>[
RaisedButton(
onPressed: () {
_controller.previous(animation: true);
},
child: Text("Prev"),
),
RaisedButton(
onPressed: () {
_controller.next(animation: true);
},
child: Text("Next"),
),
Expanded(
child: TextField(
controller: numberController,
)),
RaisedButton(
onPressed: () {
var text = numberController.text;
setState(() {
_currentIndex = int.parse(text);
});
},
child: Text("Update"),
),
],
),
FormWidget(
label: "layout",
child: FormSelect(
placeholder: "Select layout",
value: _layout,
values: [
SwiperLayout.DEFAULT,
SwiperLayout.STACK,
SwiperLayout.TINDER,
SwiperLayout.CUSTOM
],
valueChanged: (value) {
_layout = value;
setState(() {});
})),
FormWidget(
label: "scrollDirection",
child: Switch(
value: _scrollDirection == Axis.horizontal,
onChanged: (bool value) => setState(() => _scrollDirection =
value ? Axis.horizontal : Axis.vertical)),
),
FormWidget(
label: "autoplayDisableOnInteractio",
child: Switch(
value: _autoplayDisableOnInteraction,
onChanged: (bool value) =>
setState(() => _autoplayDisableOnInteraction = value)),
),
//Pannel Begin
FormWidget(
label: "loop",
child: Switch(
value: _loop,
onChanged: (bool value) => setState(() => _loop = value)),
),
FormWidget(
label: "outer",
child: Switch(
value: _outer,
onChanged: (bool value) => setState(() => _outer = value)),
),
//Pannel Begin
FormWidget(
label: "autoplay",
child: Switch(
value: _autoplay,
onChanged: (bool value) => setState(() => _autoplay = value)),
),
FormWidget(
label: "padding",
child: NumberPad(
number: _padding,
step: 5.0,
min: 0.0,
max: 30.0,
onChangeValue: (num value) {
_padding = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "scale",
child: NumberPad(
number: _scale,
step: 0.1,
min: 0.0,
max: 1.0,
onChangeValue: (num value) {
_scale = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "fade",
child: NumberPad(
number: _fade,
step: 0.1,
min: 0.0,
max: 1.0,
onChangeValue: (num value) {
_fade = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "itemCount",
child: NumberPad(
number: _itemCount,
step: 1,
min: 0,
max: 100,
onChangeValue: (num value) {
_itemCount = value.toInt();
setState(() {});
},
),
),
FormWidget(
label: "radius",
child: NumberPad(
number: _radius,
step: 1.0,
min: 0.0,
max: 30.0,
onChangeValue: (num value) {
this._radius = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "viewportFraction",
child: NumberPad(
number: _viewportFraction,
step: 0.1,
max: 1.0,
min: 0.5,
onChangeValue: (num value) {
_viewportFraction = value.toDouble();
setState(() {});
},
),
),
FormWidget(
label: "curve",
child: FormSelect(
placeholder: "Select curve",
value: _layout,
values: [
Curves.easeInOut,
Curves.ease,
Curves.bounceInOut,
Curves.bounceOut,
Curves.bounceIn,
Curves.fastOutSlowIn
],
valueChanged: (value) {
_curve = value;
setState(() {});
})),
],
))
]);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: ExampleCustom()),
],
),
),
);
}
}