How to navigate to another page if time is over and select automatically a feature from new page? - flutter

I have this design:
If time is over, I want to navigate to this page automatically
This is my code:
home_page_timer.dart
import 'package:braintrinig/animation/LongBreak.dart';
import 'package:braintrinig/animation/ShortBreak.dart';
import 'package:braintrinig/animation/StartPomodoro.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePageTimerUI extends StatelessWidget {
bool PomoRed = false;
bool ShortYellow = false;
bool LongBlue = false;
#override
Widget build(BuildContext context) {
return Container(
height: 600,
width: double.infinity,
child: DefaultTabController(
length: 3,
child: Scaffold(
bottomNavigationBar: BottomBar(),
appBar: AppBar(
elevation: 1.0,
backgroundColor: Colors.transparent,
bottom: PreferredSize(
preferredSize: Size.fromHeight(55),
child: Container(
color: Colors.transparent,
child: SafeArea(
child: Column(
children: <Widget>[
TabBar(
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
color: Color(0xff3B3B3B), width: 4.0),
insets: EdgeInsets.fromLTRB(
12.0, 12.0, 12.0, 11.0)),
indicatorWeight: 15,
indicatorSize: TabBarIndicatorSize.label,
labelColor: Color(0xff3B3B3B),
labelStyle: TextStyle(
fontSize: 12,
letterSpacing: 1.3,
fontWeight: FontWeight.w500),
unselectedLabelColor: Color(0xffD7D7D7),
tabs: [
Tab(
text: "POMODORO",
icon: Icon(Icons.work_history, size: 40),
),
Tab(
text: "SHORT BREAK",
icon: Icon(Icons.ramen_dining, size: 40),
),
Tab(
text: "LONG BREAK",
icon: Icon(Icons.battery_charging_full_rounded,
size: 40),
),
])
],
),
),
),
),
),
body: TabBarView(
children: <Widget>[
Center(
child: StartPomodoro(),
),
Center(
child: ShortBreak(),
),
Center(
child: LongBreak()
),
],
))));
}
}
class BottomBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FloatingActionButton.extended(
backgroundColor: Color(0xffF2F2F2),
onPressed: () {},
icon: Icon(Icons.settings,
color: Color(0xff3B3B3B),),
label: Text("Settings",
style: TextStyle(color: Color(0xff3B3B3B),
),)),
FloatingActionButton.extended(
backgroundColor: Color(0xffF2F2F2),
onPressed: () {},
icon: Icon(Icons.show_chart,
color: Color(0xff3B3B3B),),
label: Text("Performance",
style: TextStyle(color: Color(0xff3B3B3B),
),))
],
),
);
}
}
startpomodoro.dart
import 'dart:async';
import 'package:braintrinig/animation/home_page_timer_ui.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:core';
import 'dart:math' as math;
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'ShortBreak.dart';
class StartPomodoro extends StatefulWidget {
const StartPomodoro({Key? key}) : super(key: key);
#override
State<StartPomodoro> createState() => _StartPomodoroState ();
}
class _StartPomodoroState extends State<StartPomodoro>
with TickerProviderStateMixin {
List<bool> isSelected = [true, false];
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
double progress = 1.0;
bool LongBreak = true;
void notify() {
if (countText == '00:00:00') {
FlutterRingtonePlayer.playNotification();
}
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 0),
);
controller.addListener(() {
notify();
if (controller.isAnimating) {
setState(() {
progress = controller.value;
});
} else {
setState(() {
progress = 1.0;
LongBreak = true;
});
}
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return Scaffold(
backgroundColor: LongBreak? Color(0xffD94530) : Color(0xff6351c5),
body: GestureDetector(
onTap: () {
if (controller.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
height:300,
child: CupertinoTimerPicker(
initialTimerDuration: controller.duration!,
onTimerDurationChanged: (time) {
setState(() {
controller.duration = time;
});
},
),
),
);
}
},
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Color(0xffD94530),
height:
controller.value * MediaQuery.of(context).size.height * 0.742,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child:
Align(
alignment: FractionalOffset.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
countText,
style: TextStyle(
fontSize: 90.0,
color: Color(0xffF2F2F2),),
),
],
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
);
}),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
child: FloatingActionButton.extended(
backgroundColor: Color(0xffF2F2F2),
onPressed:() {
if (controller.isAnimating) {
controller.stop();
setState(() {
LongBreak = false;
});
} else {
controller.reverse(
from: controller.value == 0 ? 1.0 : controller.value);
setState(() {
LongBreak = false;
});
}
},
icon: Icon(
controller.isAnimating ?
Icons.pause : Icons.play_arrow,
color: Color(0xff3B3B3B),),
label: Text(
controller.isAnimating ? "PAUSE" : "PLAY",
style: TextStyle(color: Color(0xff3B3B3B)),)),
);
}),
SizedBox(width: 20,),
],
),
],
),
),
],
);
}),
),
);
}
}
class CustomTimerPainter extends CustomPainter {
CustomTimerPainter({
required this.animation,
required this.backgroundColor,
required this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
}
#override
bool shouldRepaint( CustomTimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}
shortbreak.dart
import 'dart:async';
import 'package:braintrinig/animation/StartPomodoro.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:core';
import 'dart:math' as math;
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
class ShortBreak extends StatefulWidget {
const ShortBreak({Key? key}) : super(key: key);
#override
State<ShortBreak> createState() => _ShortBreakState ();
}
class _ShortBreakState extends State<ShortBreak>
with TickerProviderStateMixin {
List<bool> isSelected = [true, false];
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
double progress = 1.0;
bool LongBreak = true;
void notify() {
if (countText == '00:00:00') {
FlutterRingtonePlayer.playNotification();
}
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 0),
);
controller.addListener(() {
notify();
if (controller.isAnimating) {
setState(() {
progress = controller.value;
});
} else {
setState(() {
progress = 1.0;
LongBreak = true;
});
}
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return Scaffold(
backgroundColor: LongBreak? Color(0xff6351c5) : Color(0xffD94530),
body: GestureDetector(
onTap: () {
if (controller.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
height:300,
child: CupertinoTimerPicker(
initialTimerDuration: controller.duration!,
onTimerDurationChanged: (time) {
setState(() {
controller.duration = time;
});
},
),
),
);
}
},
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Color(0xff6351c5),
height:
controller.value * MediaQuery.of(context).size.height * 0.742,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child:
Align(
alignment: FractionalOffset.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
countText,
style: TextStyle(
fontSize: 90.0,
color: Color(0xffF2F2F2),),
),
],
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
);
}),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 2.0, horizontal: 15.0),
child: FloatingActionButton.extended(
backgroundColor: Color(0xffF2F2F2),
onPressed:() {
if (controller.isAnimating) {
controller.stop();
setState(() {
LongBreak = false;
});
} else {
controller.reverse(
from: controller.value == 0 ? 1.0 : controller.value);
setState(() {
LongBreak = false;
});
}
},
icon: Icon(
controller.isAnimating ?
Icons.pause : Icons.play_arrow,
color: Color(0xff3B3B3B),),
label: Text(
controller.isAnimating ? "PAUSE" : "PLAY",
style: TextStyle(color: Color(0xff3B3B3B)),)),
);
}),
SizedBox(width: 20,),
],
),
],
),
),
],
);
}),
),
);
}
}
class CustomTimerPainter extends CustomPainter {
CustomTimerPainter({
required this.animation,
required this.backgroundColor,
required this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
}
#override
bool shouldRepaint( CustomTimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}
How to be able to navigate to shortbreak.dart without losing the design? I mean the appbar on top and bottom.
I tried this:
void notify() {
if (countText == '00:00:00') {
FlutterRingtonePlayer.playNotification();
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>
StartShortBreak()));
});
}
}
But, unfortunately, the appbars to the top and bottom don't show up.
How to solve this issue? Thank you in advance

you want to navigate between tab view , not between actual Navigator
first, change your homeui to stateful widget with SigleTickerMixin,
instead of using DefaultTabController, make one. :
late TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
and assign that tabcontroller to tabview and tabbar :
TabBar(
controller: _tabController,
TabBarView(
controller: _tabController,
use this
void notify() {
if (countText == '00:00:00') {
FlutterRingtonePlayer.playNotification();
//REMOVE THIS NAVIGATOR
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>
StartShortBreak()));
});
//Change to this :
_tabController.animateTo(1, duration: const Duration(milliseconds: 300));
}
}
why index is 1, because you put ShortBreak in number 2 on your tabview childreen

In home page. Dart create a tab controller and assign it to the tab bar view. Then create a method to change index
void chageIndex(int index)
{
_tabController.animateTo(index);
}
Then pass this method to promo screen
class StartPomodoro extends StatefulWidget {
final Function (index) changeIndex;
const StartPomodoro({Key? key, required this.changeIndex}) : super(key: key);
#override
State<StartPomodoro> createState() => _StartPomodoroState ();
}
You have to pass it like this
body: TabBarView(
children: <Widget>[
Center(
child: StartPomodoro(changeIndex : changeIndex),
),
Center(
child: ShortBreak(),
),
Center(
child: LongBreak()
),
],
Then in startpromodoro in place of navigator. Push you can use
widget.changeIndex(1);

Inside your condition put this when start the timer or whatever you want to do:
Future.delayed(const Duration(milliseconds: 500), () {
Navigator.pop(context);
});

Related

Audio composing dashboard with flutter

I m trying to create the following view on my app, other area are done but now comes to the core feature of the app, which allows people to record the audio and stack other audio on top of the one that has been recorded, before going on the hard parts of recording and margin or trim the audios, I am stuck on the view, plz anyone who can shade a light on this will be appreciated. spare the bottom navigation bar, that one has no issue, only the timeline board.
here the view that I just prototyped.
Here some code that I've tried to play with but failed.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Studio extends StatefulWidget {
const Studio({Key? key}) : super(key: key);
#override
_Studio createState() => _Studio();
}
class _Studio extends State<Studio> with SingleTickerProviderStateMixin {
late AnimationController _controller;
double _time = 0.0, _scale = 1.0;
int _minutes = 0;
int _seconds = 0;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 60));
_controller.addListener(() {
setState(() {
_time = _controller.value;
_minutes = (_time * 60).floor();
_seconds = ((_time * 60) % 1 * 60).floor();
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Timeline'),
),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 12,
itemBuilder: (context, index) {
return Container(
width: 50,
height: 50,
margin: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text('$index'),
),
);
},
),
),
Container(
padding: EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$_minutes'),
Text(':'),
Text('$_seconds'),
],
),
),
ElevatedButton(
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
} else {
_controller.forward();
}
},
child: Text(_controller.isAnimating ? 'Stop' : 'Start'),
),
],
),
);
}
void _onScaleStart(ScaleStartDetails details) {
print(details);
setState(() {
//_scale = details.focalPoint;
});
}
void _onScaleUpdate(ScaleUpdateDetails details) {
setState(() {
_scale = details.scale;
});
}
Widget _buildTimeline() {
return Container(
height: 40,
child: Row(
children: <Widget>[
_buildTimelineMinute(0),
_buildTimelineMinute(5),
_buildTimelineMinute(10),
],
),
);
}
Widget _buildTimelineHour(int hour) {
return Container(
width: 10,
color: Colors.green,
child: Center(
child: Text(
"$hour:00",
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
);
}
Widget _buildTimelineMinute(int minute) {
return Container(
width: 10,
color: Colors.green,
child: Center(
child: Text(
"$minute",
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
);
}
}
Thank you

flutter error: The method 'CustomTimerPainter' isn't defined for the class '_CountDownTimerState

This is what it shows in terminal
59:48: Error: The method 'CustomTimerPainter' isn't defined for the
class '_CountDownTimerState'.
'_CountDownTimerState' is from 'package:braintrinig/pages/Countdown_timer.dart'
('lib/pages/Countdown_timer.dart'). Try correcting the name to the
name of an existing method, or defining a method named
'CustomTimerPainter'.
painter: CustomTimerPainter(
How to solve this issue?
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
class CountDownTimer extends StatefulWidget {
#override
_CountDownTimerState createState() => _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer>
with TickerProviderStateMixin {
late AnimationController controller;
String get timerString {
Duration duration = controller.duration! * controller.value;
return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
);
}
#override
Widget build(BuildContext context) {
ThemeData themeData = Theme.of(context);
return Scaffold(
backgroundColor: Colors.white10,
body:
Container(
color: Colors.amber,
height: controller.value * MediaQuery.of(context).size.height,
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.amber,
height:
controller.value * MediaQuery.of(context).size.height,
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.center,
child: AspectRatio(
aspectRatio: 1.0,
child: Stack(
children: <Widget>[
Positioned.fill(
child: CustomPaint(
painter: CustomTimerPainter(
animation: controller,
backgroundColor: Colors.white,
color: themeData.indicatorColor,
)),
),
Align(
alignment: FractionalOffset.center,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[
Text(
"Count Down Timer",
style: TextStyle(
fontSize: 20.0,
color: Colors.white),
),
Text(
timerString,
style: TextStyle(
fontSize: 112.0,
color: Colors.white),
),
],
),
),
],
),
),
),
),
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return FloatingActionButton.extended(
onPressed: () {
if (controller.isAnimating)
controller.stop();
else {
controller.reverse(
from: controller.value == 0.0
? 1.0
: controller.value);
}
},
icon: Icon(controller.isAnimating
? Icons.pause
: Icons.play_arrow),
label: Text(
controller.isAnimating ? "Pause" : "Play"));
}),
],
),
),
],
);
}),
),
);
}
}
It checked that "CustomTimerPainter" is from circular_countdown_timer library.
After you add this library, the problem you mentioned will be resolved.
I pasted your code to my project and install "circular_countdown_timer", I didn't see any error right now.
circular_countdown_timer pub.dev
Add circular_countdown_timer in your pubspec.yaml => get => update.
dependencies:
circular_countdown_timer: ^0.2.2
Import this library into your dart file
import 'package:circular_countdown_timer/custom_timer_painter.dart';
The CustomeTimerPainter is a custom widget that someone has already written in your taken example,
You may please check those examples, or you can use the sample below.
class CustomTimerPainter extends CustomPainter {
CustomTimerPainter({
this.animation,
this.backgroundColor,
this.color,
}) : super(repaint: animation);
final Animation<double> animation;
final Color backgroundColor, color;
#override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = backgroundColor
..strokeWidth = 10.0
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
}
#override
bool shouldRepaint(CustomTimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}

How to play multiple videos with (player_video) package

I have created this video player for my application which can play video from assets. Since, It is made from (video_player) package I guess I can play only one video with it But I want 3-4 videos to be played. How can I do that? It is possible or not...Help me! Furthermore, I also want to make the video the option of 10 seconds backward and forward while pressing it's sides. Thanks for your help!
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(VideoPlay());
}
class VideoPlay extends StatefulWidget {
String? pathh;
#override
_VideoPlayState createState() => _VideoPlayState();
VideoPlay({
this.pathh = "assets/video.mp4", // Video from assets folder
});
}
class _VideoPlayState extends State<VideoPlay> {
late VideoPlayerController controller;
late Future<void> futureController;
#override
void initState() {
//url to load network
controller = VideoPlayerController.asset(widget.pathh!);
futureController = controller.initialize();
controller.setLooping(true);
controller.setVolume(25.0);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FutureBuilder(
future: futureController,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: VideoPlayer(controller));
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
),
),
Padding(
padding: const EdgeInsets.all(6.0),
child: RaisedButton(
color: Color(0xff9142db),
child: Icon(
controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
onPressed: () {
setState(() {
if (controller.value.isPlaying) {
controller.pause();
} else {
controller.play();
}
});
},
),
)
],
));
}
}
App Image Is Here
I like your idea and wanted to deal with it, this is the result.
I hope you can do better.
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
void main(List<String> args) {
runApp(Example());
}
class Example extends StatelessWidget {
const Example({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
color: Colors.white,
debugShowCheckedModeBanner: false,
home: VideoPlayersList(),
);
}
}
class VideoPlayersList extends StatelessWidget {
const VideoPlayersList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
List<String> paths = [
"assets/images/testvideo.mp4",
"assets/images/testvideo.mp4",
"assets/images/testvideo.mp4",
"assets/images/testvideo.mp4",
"assets/images/testvideo.mp4",
];
return Scaffold(
body: SingleChildScrollView(
child: Column(children: [
ListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemCount: paths.length,
itemBuilder: (BuildContext context, int index) {
return VideoPlay(
pathh: paths[index],
);
},
),
]),
),
);
}
}
class VideoPlay extends StatefulWidget {
String? pathh;
#override
_VideoPlayState createState() => _VideoPlayState();
VideoPlay({
Key? key,
this.pathh, // Video from assets folder
}) : super(key: key);
}
class _VideoPlayState extends State<VideoPlay> {
ValueNotifier<VideoPlayerValue?> currentPosition = ValueNotifier(null);
VideoPlayerController? controller;
late Future<void> futureController;
initVideo() {
controller = VideoPlayerController.asset(widget.pathh!);
futureController = controller!.initialize();
}
#override
void initState() {
initVideo();
controller!.addListener(() {
if (controller!.value.isInitialized) {
currentPosition.value = controller!.value;
}
});
super.initState();
}
#override
void dispose() {
controller!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: futureController,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator.adaptive();
} else {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: SizedBox(
height: controller!.value.size.height,
width: double.infinity,
child: AspectRatio(
aspectRatio: controller!.value.aspectRatio,
child: Stack(children: [
Positioned.fill(
child: Container(
foregroundDecoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black.withOpacity(.7),
Colors.transparent
],
stops: [
0,
.3
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter),
),
child: VideoPlayer(controller!))),
Positioned.fill(
child: Column(
children: [
Expanded(
flex: 8,
child: Row(
children: [
Expanded(
flex: 3,
child: GestureDetector(
onDoubleTap: () async {
Duration? position =
await controller!.position;
setState(() {
controller!.seekTo(Duration(
seconds: position!.inSeconds - 10));
});
},
child: const Icon(
Icons.fast_rewind_rounded,
color: Colors.black,
size: 40,
),
),
),
Expanded(
flex: 4,
child: IconButton(
icon: Icon(
controller!.value.isPlaying
? Icons.pause
: Icons.play_arrow,
color: Colors.black,
size: 40,
),
onPressed: () {
setState(() {
if (controller!.value.isPlaying) {
controller!.pause();
} else {
controller!.play();
}
});
},
)),
Expanded(
flex: 3,
child: GestureDetector(
onDoubleTap: () async {
Duration? position =
await controller!.position;
setState(() {
controller!.seekTo(Duration(
seconds: position!.inSeconds + 10));
});
},
child: const Icon(
Icons.fast_forward_rounded,
color: Colors.black,
size: 40,
),
),
),
],
),
),
Expanded(
flex: 2,
child: Align(
alignment: Alignment.bottomCenter,
child: ValueListenableBuilder(
valueListenable: currentPosition,
builder: (context,
VideoPlayerValue? videoPlayerValue, w) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 10),
child: Row(
children: [
Text(
videoPlayerValue!.position
.toString()
.substring(
videoPlayerValue.position
.toString()
.indexOf(':') +
1,
videoPlayerValue.position
.toString()
.indexOf('.')),
style: const TextStyle(
color: Colors.white,
fontSize: 22),
),
const Spacer(),
Text(
videoPlayerValue.duration
.toString()
.substring(
videoPlayerValue.duration
.toString()
.indexOf(':') +
1,
videoPlayerValue.duration
.toString()
.indexOf('.')),
style: const TextStyle(
color: Colors.white,
fontSize: 22),
),
],
),
);
}),
))
],
),
),
])),
),
);
}
},
);
}
}

Finish an animation before starting another - Flutter

I try to add a prestart to a countdown, both have different duration. So i maked two animation A and B,
when i press the start button the animation A start and when it's finished the animation B begin.
What happen to me now, is they starts at the same time, i tried Interval class and Tween class and it didn't works.
My code at this moment looks like this :
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Timer2 extends StatefulWidget {
#override
_Timer2State createState() => _Timer2State();
}
class _Timer2State extends State<Timer2> with TickerProviderStateMixin {
AnimationController animationController;
#override
void initState() {
super.initState();
animationController = AnimationController(vsync: this,duration: Duration(seconds: 10));
}
#override
Widget build(BuildContext context) {
return Scaffold(backgroundColor: Colors.black,
body: Padding(
padding: EdgeInsets.all(8.0),
child: AnimatedBuilder(
animation: animationController,
builder: (context, child){
return Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.red,
height:
animationController.value * MediaQuery.of(context).size.height,
),
),
Column(
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.center,
child: AspectRatio(
aspectRatio: 1.0,
child: Stack(
children: <Widget>[
Positioned.fill(
child: AnimatedBuilder(
animation: animationController,
builder: (BuildContext context, Widget child) {
return CustomPaint(
painter: TimerPainter(
animation: animationController,
backgroundColor: Colors.white,
color: Colors.pink),
);
},
),
),
],
),
),
),
),
Container(
margin: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
child: AnimatedBuilder(
animation: animationController,
builder: (_, Widget child) {
return Icon(
animationController.isAnimating
? Icons.pause
: Icons.play_arrow
);
}),
backgroundColor: Colors.pinkAccent,
onPressed: () {
if (animationController.isAnimating ) {
animationController.stop();
} else {
animationController.reverse(
from: animationController.value == 0.0
? 1.0
: animationController.value);
};
setState(() {
Icon(animationController.isAnimating
? Icons.play_arrow
: Icons.pause
);
});
},
)
],
),
)
],
),
],
);
},
),
),
);
}
}
class TimerPainter extends CustomPainter {
final Animation<double> animation;
final Color backgroundColor;
final Color color;
TimerPainter({this.animation, this.backgroundColor, this.color})
: super(repaint: animation);
#override
void paint(Canvas canvas, Size size) {
paint = Paint()
..color = backgroundColor
..strokeWidth = 5.0
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
paint.color = color;
double progress = (1.0 - animation.value) * 2 * 3.14;
canvas.drawArc(Offset.zero & size, 3.14 * 1.5, - progress, false, paint);
}
#override
bool shouldRepaint(TimerPainter old) {
return animation.value != old.animation.value ||
color != old.color ||
backgroundColor != old.backgroundColor;
}
}
Thank you

Size to up animation for widgets

In Flutter you suppose I have a simple Container and I would like to change the size of that to up, for example in this simple screenshot I want to change top container in section 1 to up to have a top container in section 2
and top container in section 1 should behave only 100.0 after size to up
container B in section 1 and section 2 are in the same axis without change position when container A will be resized to up
for example, this is what I want to have
I'm not sure with which one animation I can have this feature
this code work, but this is not what I want to have.
i want to have draggable bottom sheet with changing border radius when bottom sheet arrived to top of screen like with pastes sample video screen and fade0n/out widget inside appbar which that inside top of bottom sheet, which that visible when bottom sheet arrived top or hide when bottom sheet don't have maximum size
import 'package:flutter/material.dart';
void main()=>runApp(SizeUp());
class SizeUp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: SizeUpAnim(),
);
}
}
class SizeUpAnim extends StatefulWidget {
#override
State<StatefulWidget> createState() =>_SizeUpAnim();
}
class _SizeUpAnim extends State with SingleTickerProviderStateMixin {
AnimationController _controller;
// ignore: constant_identifier_names
static const _PANEL_HEADER_HEIGHT = 32.0;
bool get _isPanelVisible {
final AnimationStatus status = _controller.status;
return status == AnimationStatus.completed ||
status == AnimationStatus.forward;
}
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 100), value: 1.0, vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 8.0,
title: const Text("Step4"),
leading: IconButton(
onPressed: () {
_controller.fling(velocity: _isPanelVisible ? -1.0 : 1.0);
},
icon: AnimatedIcon(
icon: AnimatedIcons.close_menu,
progress: _controller.view,
),
),
),
body: Column(
children: <Widget>[
Expanded(
child: LayoutBuilder(
builder: _buildStack,
),
),
Text('aaa'),
],
),
);
}
Animation<RelativeRect> _getPanelAnimation(BoxConstraints constraints) {
final double height = constraints.biggest.height;
final double top = height - _PANEL_HEADER_HEIGHT;
const double bottom = -_PANEL_HEADER_HEIGHT;
return RelativeRectTween(
begin: RelativeRect.fromLTRB(0.0, top, 0.0, bottom),
end: const RelativeRect.fromLTRB(0.0, 0.0, 0.0, 0.0),
).animate( CurvedAnimation(parent: _controller, curve: Curves.linear));
}
Widget _buildStack(BuildContext context, BoxConstraints constraints) {
final Animation<RelativeRect> animation = _getPanelAnimation(constraints);
final ThemeData theme = Theme.of(context);
return Container(
color: theme.primaryColor,
child: Stack(
children: <Widget>[
const Center(
child: Text("base"),
),
PositionedTransition(
rect: animation,
child: Material(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0)),
elevation: 12.0,
child: Container(
height: _PANEL_HEADER_HEIGHT,
child: const Center(child: Text("panel")),
),
),
),
],
),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isLong = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First'),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('hey'),
RaisedButton(
onPressed: () {
setImages();
setState(() {
isLong = !isLong;
});
},
child: Text(isLong ? 'long' : 'short'),
),
RaisedButton(
onPressed: _onPressed,
child: Text('open'),
)
],
),
),
);
}
_onPressed() {
Navigator.of(context)
.push(TransparentRoute(builder: (context) => NewWidget(images)));
}
List<String> images = List.generate(
5,
(_) => 'http://placeimg.com/100/100/any',
);
void setImages() {
images = List.generate(
isLong ? 5 : 25,
(_) => 'http://placeimg.com/100/100/any',
);
}
}
class NewWidget extends StatefulWidget {
const NewWidget(this.images, {Key key}) : super(key: key);
final List<String> images;
#override
_NewWidgetState createState() => _NewWidgetState();
}
class _NewWidgetState extends State<NewWidget> {
bool isBig = false;
bool isStack = false;
bool isBounsing = true;
final double topOffset = 200;
final double miniHandleHeigh = 30;
double safeAreaPadding = 0;
double startBigAnimationOffset;
double startStickyOffset;
double backgroundHeight = 0;
double get savedAppBarHeigh => safeAreaPadding + kToolbarHeight;
final ScrollController controller = ScrollController();
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
void _afterLayout(_) {
var media = MediaQuery.of(context);
safeAreaPadding = media.padding.top;
startBigAnimationOffset = topOffset - savedAppBarHeigh;
startStickyOffset = startBigAnimationOffset + 20;
backgroundHeight = media.size.height - miniHandleHeigh - topOffset;
var canScroll = !_isImageSizeBiggerThenBottomSheetSize(
media.size.width,
media.size.height,
);
controller.addListener(
canScroll ? withoutScrolling : withScrolling,
);
}
void withoutScrolling() {
var offset = controller.offset;
if (offset < 0) {
goOut();
} else {
controller.animateTo(
0,
duration: Duration(milliseconds: 100),
curve: Curves.easeIn,
);
}
}
void withScrolling() {
var offset = controller.offset;
if (offset < 0) {
goOut();
} else if (offset < startBigAnimationOffset && isBig) {
setState(() {
isBig = false;
});
} else if (offset > startBigAnimationOffset && !isBig) {
setState(() {
isBig = true;
});
} else if (offset > startStickyOffset && !isStack) {
setState(() {
isStack = true;
});
} else if (offset < startStickyOffset && isStack) {
setState(() {
isStack = false;
});
}
if (offset < topOffset && !isBounsing) {
setState(() => isBounsing = true);
} else if (offset > topOffset && isBounsing) {
setState(() => isBounsing = false);
}
}
void goOut() {
controller.dispose();
Navigator.of(context).pop();
}
_isImageSizeBiggerThenBottomSheetSize(
double screenWidth,
double screenHeight,
) {
// padding: 10, 3 in row;
print(screenHeight);
var itemHeight = (screenWidth - 20) / 3;
print(itemHeight);
var gridMaxHeight = screenHeight - topOffset - miniHandleHeigh;
print(gridMaxHeight);
return (widget.images.length / 3).floor() * itemHeight > gridMaxHeight;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: isStack ? Colors.white : Colors.transparent,
body: Stack(
children: [
Positioned(
bottom: 0,
right: 0,
left: 0,
child: Container(
constraints: BoxConstraints(minHeight: backgroundHeight),
decoration: BoxDecoration(
color: Colors.white,
),
),
),
ListView(
physics:
isBounsing ? BouncingScrollPhysics() : ClampingScrollPhysics(),
controller: controller,
children: <Widget>[
Container(
alignment: Alignment.bottomCenter,
height: topOffset,
child: TweenAnimationBuilder(
tween: Tween(begin: 0.0, end: isBig ? 1.0 : 0.0),
duration: Duration(milliseconds: 500),
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(top: 15),
child: Container(
decoration: BoxDecoration(
color: Colors.black38,
borderRadius: BorderRadius.circular(2),
),
height: 5,
width: 60,
),
),
),
builder: (_, number, child) {
return Container(
height: savedAppBarHeigh * number + miniHandleHeigh,
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular((1 - number) * 20)),
color: Colors.white,
),
child: Opacity(opacity: 1 - number, child: child),
);
}),
),
Container(
padding: EdgeInsets.all(10),
constraints: BoxConstraints(
minHeight:
MediaQuery.of(context).size.height - savedAppBarHeigh),
decoration: BoxDecoration(
color: Colors.white,
),
child: getGrid(),
)
],
),
if (isStack)
_AppBar(
title: 'Gallery',
)
],
),
);
}
Widget getGrid() {
return GridView.count(
crossAxisSpacing: 10,
mainAxisSpacing: 10,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 3,
children: widget.images.map((url) {
return Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.blueAccent,
),
),
child: Image(
image: NetworkImage(url),
),
);
}).toList(),
);
}
}
class _AppBar extends StatelessWidget {
const _AppBar({Key key, this.title}) : super(key: key);
final Color backgroundColor = Colors.white;
final Color color = Colors.grey;
final String title;
#override
Widget build(BuildContext context) {
return Material(
elevation: 5,
child: Container(
height: kToolbarHeight + MediaQuery.of(context).padding.top,
color: backgroundColor,
child: OverflowBox(
alignment: Alignment.topCenter,
maxHeight: 200,
child: SafeArea(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: kToolbarHeight),
child: AppBar(
centerTitle: false,
backgroundColor: backgroundColor,
iconTheme: IconThemeData(
color: color, //change your color here
),
primary: false,
title: Text(
title,
style: TextStyle(color: color),
),
elevation: 0,
),
),
),
),
),
);
;
}
}
class TransparentRoute extends PageRoute<void> {
TransparentRoute({
#required this.builder,
RouteSettings settings,
}) : assert(builder != null),
super(settings: settings, fullscreenDialog: false);
final WidgetBuilder builder;
#override
bool get opaque => false;
#override
Color get barrierColor => null;
#override
String get barrierLabel => null;
#override
bool get maintainState => true;
#override
Duration get transitionDuration => Duration(milliseconds: 350);
#override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
final result = builder(context);
return Container(
color: Colors.black.withOpacity(0.5),
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: animation,
curve: Curves.easeIn,
)),
child: result,
),
);
}
}
I think you may try this library, sliding_sheet
when you detect the expand status by controller, then you animate/enlarge the container A.