Related
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);
});
I'm pretty new both to Flutter/Dart and Stack Overflow. I started with some trip ETA code and modified it to be an initiative turn tracker for a fantasy RPG tabletop game.
My intent is to keep the End Encounter button on the screen at all times, and have the timeline content scroll in a window above it.
I added a SingleChildScrollView into _TurnSectionState at line 178, but as soon as I add a Container into it I get the overflow. I tried for about 3 hours before asking for help here.
final data = _data(1);
return Scaffold(
appBar: TitleAppBar(widget._title),
body: Center(
child: SingleChildScrollView(
child: SizedBox(
width: 380.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: _MissionName(
timeSliceInfo: data,
),
),
const Divider(height: 1.0),
_TurnSection(processes: data.deliveryProcesses),
const Divider(height: 1.0),
const Padding(
padding: EdgeInsets.all(20.0),
child: _OnTimeBar(),
),
],
),
),
),
),
);
}
}
// Mission name
class _MissionName extends StatelessWidget {
const _MissionName({
Key? key,
required this.timeSliceInfo,
}) : super(key: key);
final _TimeSliceInfo timeSliceInfo;
#override
Widget build(BuildContext context) {
return Row(
children: [
Text(
missions[currentMission].getTitle(),
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
],
);
}
}
// Lists items in each turn
class _InnerTimeline extends StatefulWidget {
const _InnerTimeline({
required this.messages,
});
final List<ActivationLineItem> messages;
#override
State<_InnerTimeline> createState() => _InnerTimelinePageState();
}
class _InnerTimelinePageState extends State<_InnerTimeline> {
#override
initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
bool isEdgeIndex(int index) {
return index == 0 || index == widget.messages.length + 1;
}
// Interior connector lines
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: FixedTimeline.tileBuilder(
theme: TimelineTheme.of(context).copyWith(
nodePosition: 0,
connectorTheme: TimelineTheme.of(context).connectorTheme.copyWith(
thickness: 1.0,
),
indicatorTheme: TimelineTheme.of(context).indicatorTheme.copyWith(
size: 10.0,
position: 0.5,
),
),
builder: TimelineTileBuilder(
indicatorBuilder: (_, index) =>
!isEdgeIndex(index) ? Indicator.outlined(borderWidth: 1.0) : null,
startConnectorBuilder: (_, index) => Connector.solidLine(),
endConnectorBuilder: (_, index) => Connector.solidLine(),
contentsBuilder: (_, index) {
if (isEdgeIndex(index)) {
return null;
}
// Line item (init value + icon + text)
return Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Row(children: [
Text(widget.messages[index - 1].tick.toString()),
const SizedBox(width: 6),
Image(
image: AssetImage(widget.messages[index - 1].thumbnail),
width: 20,
height: 20),
const SizedBox(width: 6),
Expanded(
child: Text(widget.messages[index - 1].message,
overflow: TextOverflow.ellipsis, maxLines: 1))
]));
},
itemExtentBuilder: (_, index) => isEdgeIndex(index) ? 10.0 : 30.0,
nodeItemOverlapBuilder: (_, index) =>
isEdgeIndex(index) ? true : null,
itemCount: widget.messages.length + 2,
),
),
);
}
}
// Outer timeline (List of turns)
class _TurnSection extends StatefulWidget {
const _TurnSection({Key? key, required processes})
: _processes = processes,
super(key: key);
final List<TurnContents> _processes;
#override
_TurnSectionState createState() => _TurnSectionState();
}
class _TurnSectionState extends State<_TurnSection> {
bool isExpanded = false;
#override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: const TextStyle(
color: Color(0xff9b9b9b), // Nobel Gray
fontSize: 12.5,
),
child: SingleChildScrollView(
child: SizedBox(
height: 480,
child: Column(
children: [
FixedTimeline.tileBuilder(
theme: TimelineThemeData(
nodePosition: 0,
color: const Color(0xff989898), // Spanish Gray
indicatorTheme: const IndicatorThemeData(
position: 0,
size: 20.0, // Outer timeline circle size
),
connectorTheme: const ConnectorThemeData(
thickness: 2.5, // Outer timeline line thickness
),
),
builder: TimelineTileBuilder.connected(
connectionDirection: ConnectionDirection.before,
itemCount: widget._processes.length,
contentsBuilder: (_, index) {
if (widget._processes[index].isCompleted) return null;
return GestureDetector(
onTap: () {
int turnNum = widget._processes[index].getTurnNum();
if (turnNum == currentTurn) {
// Ask if ready for next turn
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Next Turn?'),
content: Text('Ready to start turn ?' +
(currentTurn + 1).toString()),
actions: <Widget>[
TextButton(
onPressed: () =>
Navigator.pop(context, 'Yes'),
child: const Text('Yes'),
),
TextButton(
onPressed: () => Navigator.pop(context, 'No'),
child: const Text('No'),
),
],
),
).then((value) {
if (value == 'Yes') {
currentTurn++; // Move to the next turn
setState(() {}); // Draw the screen
}
});
}
},
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget._processes[index]
.getName(), // Turn name font size
style:
DefaultTextStyle.of(context).style.copyWith(
fontSize: 18.0,
),
),
_InnerTimeline(
messages:
widget._processes[index].getMessages()),
],
),
),
);
},
indicatorBuilder: (_, index) {
if (index <= currentTurn) {
return const DotIndicator(
color: Color(0xff66c97f), // Emerald Green dot
child: Icon(
Icons.check,
color: Colors.white,
size: 12.0,
),
);
} else {
return const OutlinedDotIndicator(
borderWidth: 2.5,
);
}
},
connectorBuilder: (_, index, ___) => SolidLineConnector(
color: index <= currentTurn
? const Color(0xff66c97f) // Emerald Green connector
: null, // Green
),
),
),
],
),
),
),
);
}
}
class _OnTimeBar extends StatelessWidget {
const _OnTimeBar({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
MaterialButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('On Time!'),
),
);
},
elevation: 0,
shape: const StadiumBorder(),
color: const Color(0xff66c97f),
textColor: Colors.white,
child: const Text('End Encounter'),
),
const Spacer(),
const SizedBox(width: 12.0),
],
);
}
}
/*
List<TurnContents> buildTimeline() {
List<TurnContents> turns;
return turns;
}
*/
_TimeSliceInfo _data(int id) => _TimeSliceInfo(
id: id,
date: DateTime.now(),
deliveryProcesses: ImpulseBuilder().buildTimeline(),
);
class _TimeSliceInfo {
const _TimeSliceInfo({
required this.id,
required this.date,
required this.deliveryProcesses,
});
final int id;
final DateTime date;
final List<TurnContents> deliveryProcesses;```
}
[1]: https://i.stack.imgur.com/mGd5X.png
use Expanded and in SingleChildScrollView add physics:ScrollPhysics()
Expanded(
child: Container(
child: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
children: []
)
)
)
);
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),
),
],
),
);
}),
))
],
),
),
])),
),
);
}
},
);
}
}
Why I am not able to use setState Under GestureDetector Using onTap:
After I use setState I got an error like: The function 'setState' isn't defined.
Try importing the library that defines 'setState', And VS Code editor show me
Error like: correcting the name to the name of an existing function, or defining a function named 'setState'.dart(undefined_function).
I try to fix different ways please tell me where is my problem
Thank you
Some Flutter Import Link ::::::::::
class ParsingMap extends StatefulWidget {
const ParsingMap({Key? key}) : super(key: key);
#override
_ParsingMapState createState() => _ParsingMapState();
}
class _ParsingMapState extends State<ParsingMap> {
Future<ApiList>? data;
#override
void initState() {
super.initState();
Network network = Network("https://fakestoreapi.com/products");
data = network.loadPosts();
// print(data);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: Icon(Icons.arrow_left, color: Colors.black),
actions: [
Icon(Icons.search, color: Colors.black),
SizedBox(width: 10),
Icon(Icons.home_filled, color: Colors.black),
SizedBox(width: 8)
],
),
body: Center(
child: Container(
child: FutureBuilder(
future: data,
builder: (context, AsyncSnapshot<ApiList> snapshot) {
List<Api> allPosts;
if (snapshot.hasData) {
allPosts = snapshot.data!.apis!;
return createListView(allPosts, context);
}
return CircularProgressIndicator();
},
),
),
),
);
}
}
class Network {
final String url;
Network(this.url);
Future<ApiList> loadPosts() async {
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
// print(response.body);
return ApiList.fromJson(json.decode(response.body));
} else {
throw Exception("Faild To get posts");
}
}
}
Widget createListView(List<Api> data, BuildContext context) {
return ListView(
children: [
Container(
height: 300,
margin: EdgeInsets.symmetric(vertical: 16),
child: ListView.builder(
itemCount: data.length,
scrollDirection: Axis.horizontal,
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 16),
itemBuilder: (context, index) {
int selectedIndex = 0;
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${data[index].category}",
style: TextStyle(
fontWeight: FontWeight.bold,
color: selectedIndex == index
? Colors.black
: Colors.black38),
),
Container(
margin: EdgeInsets.only(
top: 5,
),
height: 2,
width: 30,
color: selectedIndex == index
? Colors.black
: Colors.transparent,
)
],
),
),
);
},
),
),
],
);
}
Put top-level createListView function in _ParsingMapState class.
class _ParsingMapState extends State<ParsingMap> {
// ...
Widget createListView(...) {}
}
EDIT :
Here is my result now :
As you can see i have make a lot of work and now it is good Advanced. Now i have the 5 Numbers selected (5-34-37-42-49) in red just at top of the 2 green buttons. For the moment the function getWidget return the 5 Numbers in red using gridview again but not sure it is what i need to use. Can you help me for resolve the problem with the size of the 5 circles, i need it centered and not use scroll.
Here is my complete code Under :
import 'package:flutter/material.dart';
import 'dart:math';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'package:flutter_app/menu_member.dart';
import 'package:flutter_app/globals.dart' as globals;
class Lotto extends StatefulWidget {
#override
_LottoState createState() => new _LottoState();
}
class _LottoState extends State<Lotto> {
#override
void initState() {
super.initState();
}
var i=1;
var nb_num=49;
var no_select=[];
var no_a_select=5;
List<Color> colorList = List<Color>.generate(49, (int index) => Colors.lightBlue);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(
title: new Text('GRILLE DE LOTTO'),
),
body:
Center(
child: Column(
children: <Widget>[
Container(
width:400,
height:30,
margin: const EdgeInsets.only(top: 10.0),
child : new Text("Selectionnez 5 numéros",textAlign: TextAlign.center,style: TextStyle(fontSize: 30.0),),
),
Container(
width:400,
height:300,
child: new GridView.count(
crossAxisCount: 9,
padding: const EdgeInsets.all(30.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: new List<Widget>.generate(49, (index) {
return new GestureDetector(
onTap: () {
setState(() {
if (colorList[index] == Colors.lightBlue) {
if (no_select.length<no_a_select) {
colorList[index] = Colors.redAccent;
no_select.add(index+1);
}
else {
showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text("INFORMATION"),
content: Text("Vous ne pouvez pas sélectionner plus de 5 numéros !!!"),
);
}
);
}
print(no_select);
}
else {
colorList[index] = Colors.lightBlue;
no_select.remove(index+1);
print(no_select);
}
});
},
child: Container(
child: ClipOval(
child: Container(
color: colorList[index],
height: 20.0,
width: 20.0,
child: Center(
child: new Text((index+1).toString(),
style: TextStyle(color: Colors.white, fontSize: 24),
textAlign: TextAlign.center),
),
),
),
),
);
}
),
),
),
Container(
width:400,
height:30,
margin: const EdgeInsets.only(top: 10),
child : new Text("Vos Numéros",textAlign: TextAlign.center,style: TextStyle(fontSize: 30.0),),
),
Container(
width:400,
height:80,
margin: const EdgeInsets.only(top: 10.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.lightBlueAccent,
width: 2,
),
borderRadius: BorderRadius.circular(12),
),
child:
getWidget()
),
Container(
width:300,
height:45,
margin: const EdgeInsets.only(top: 10.0),
child:
RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('TIRAGE ALEATOIRE'),
onPressed: () {
Select_numbers();
},
),
),
Container(
width:300,
height:45,
margin: const EdgeInsets.only(top: 10.0),
child:
RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Text('VALIDER VOTRE GRILLE'),
onPressed: () {
Valide_grille();
},
),
),
]
)
),
),
);
}
getWidget() {
if (no_select.length==0) {
return Text("Pas de numéros");
}
else {
return GridView.count(
crossAxisCount: 5,
padding: const EdgeInsets.all(10.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: new List<Widget>.generate(no_select.length, (index) {
return ClipOval(
child: Container(
color: Colors.red,
height: 20.0,
width: 20.0,
child: Center(
child: new Text((no_select[index].toString()),
style: TextStyle(color: Colors.white, fontSize: 24),
textAlign: TextAlign.center),
),
),
);
}
)
);
}
}
Select_numbers() {
setState(() {
var j = 1;
var num_sel;
var pos_sel;
no_select=[];
colorList=[];
colorList=List<Color>.generate(49, (int index) => Colors.lightBlue);
var rng = new Random();
List tab=[];
tab = List.generate(49, (int index) => index + 1);
print (tab);
while (j <= no_a_select) {
pos_sel = rng.nextInt(tab.length-1);
num_sel=tab[pos_sel];
no_select.add(num_sel);
colorList[num_sel-1] = Colors.redAccent;
tab.remove(num_sel);
print(tab);
j++;
}
print(no_select);
});
}
Future Valide_grille() async{
// For CircularProgressIndicator.
bool visible = false ;
// Showing CircularProgressIndicator.
setState(() {
visible = true ;
});
// SERVER LOGIN API URL
var url = 'https://www.easytrafic.fr/game_app/valide_lotto.php';
// Store all data with Param Name.
var data = {'id_membre':globals.id_membre, 'result':no_select};
print (data);
var grille_encode=jsonEncode(data);
print(grille_encode);
// Starting Web API Call.
var response = await http.post(url, body: grille_encode,headers: {'content-type': 'application/json','accept': 'application/json','authorization': globals.token});
print(response.body);
// Getting Server response into variable.
var message = json.decode(response.body);
// If the Response Message is Matched.
if(message == 'OK')
{
print('VALIDATION DE LA GRILLE OK');
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
}else{
// Hiding the CircularProgressIndicator.
setState(() {
visible = false;
});
// Showing Alert Dialog with Response JSON Message.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(message),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
I think that you need a Flutter simple Alert Dialog instead of print command. So change your code :
print(
"Vous ne pouvez pas sélectionner plus de 5 numéros !!!");
to:
showDialog(
context: context,
builder: (BuildContext context){
return AlertDialog(
title: Text("Alert Dialog"),
content: Text("Vous ne pouvez pas sélectionner plus de 5 numéros !!!"),
);
}
);
Because print command sends its output to console.
I suggest you read this: https://dev.to/mightytechno/flutter-alert-dialog-to-custom-dialog-1ok4
Edit:
In order to have 49 circles between the buttons, you need move these lines of your code:
Expanded(
flex:2,
child:
RaisedButton(
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(9, 9, 9, 9),
child: Center(child: Text('TIRAGE ALEATOIRE')),
onPressed: () {
Select_numbers();
},
),
),
after these lines:
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(
title: new Text('GRILLE DE LOTTO'),
),
body:
Center(
child: Column(
children: <Widget>[
Also in order to make a RaisedButton's corners rounded, you can add this code:
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),),
after RaisedButton(
You can copy paste run full code below
You can use List to keep color of each number
code snippet
List<Color> colorList = List<Color>.generate(49, (int index) => Colors.lightBlue);
...
setState(() {
if (colorList[index] == Colors.lightBlue) {
if (no_select.length < no_a_select) {
colorList[index] = Colors.redAccent;
...
child: Container(
color: colorList[index],
working demo
full code
import 'package:flutter/material.dart';
class Lotto extends StatefulWidget {
#override
_LottoState createState() => new _LottoState();
}
class _LottoState extends State<Lotto> {
Color color;
void message() {
print('Clicked');
}
List<Color> colorList = List<Color>.generate(49, (int index) => Colors.lightBlue);
#override
void initState() {
super.initState();
color = Colors.lightBlue;
print(colorList[0].toString());
}
var i = 1;
var nb_num = 49;
var no_select = [];
var no_a_select = 5;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: <Widget>[
Expanded(
flex: 3,
child: new GridView.count(
crossAxisCount: 7,
children: new List<Widget>.generate(49, (index) {
return new GestureDetector(
onTap: () {
setState(() {
if (colorList[index] == Colors.lightBlue) {
if (no_select.length < no_a_select) {
colorList[index] = Colors.redAccent;
no_select.add(index + 1);
} else {
print(
"Vous ne pouvez pas sélectionner plus de 5 numéros !!!");
}
print(no_select);
} else {
colorList[index] = Colors.lightBlue;
no_select.remove(index + 1);
print(no_select);
}
});
},
child: Container(
child: ClipOval(
child: Container(
color: colorList[index],
height: 20.0,
width: 20.0,
child: Center(
child: new Text((index + 1).toString(),
style: TextStyle(color: Colors.white, fontSize: 24),
textAlign: TextAlign.center),
),
),
),
),
);
}),
),
),
Expanded(flex: 1, child: Text("abc")),
],
),
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Lotto(),
);
}
}
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>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}