Flutter RangeError (index): Invalid value: Valid value range is empty: 0 - flutter

I am fetching data from my api previously i am suing hardcoded json data so its working perfectly in app but now when i am using the API data its showing this error
RangeError (index): Invalid value: Valid value range is empty: 0
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool showApp = false;
var _questions = new List<Questions>();
_getQuestions() {
API.getUsers().then((response) {
setState(() {
Iterable list = json.decode(response.body);
print(list);
print(list);
_questions = list.map((model) => Questions.fromJson(model)).toList();
print(_questions);
showApp = true;
});
});
}
initState() {
super.initState();
_getQuestions();
}
int index = 0;
bool shouldShow = false;
#override
Widget build(BuildContext context) {
int size = _questions.length;
void nextQuestion() {
if (index < size - 1)
setState(() {
index++;
});
print(index);
}
double percentage1Calculate() {
int wouldClick = 12;
int ratherClick = 13;
double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
return percentage1;
}
double percentage2Calculate() {
int wouldClick = 2;
int ratherClick = 3;
double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
return percentage2;
}
void percengtageTrigger(){
setState(() {
shouldShow = true;
});
Timer timer = Timer(Duration(milliseconds: 1350), () {
setState(() {
shouldShow = false;
});
});
}
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
double stackHeight = (MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top);
double stackWidth = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Color(0xff404040),
appBar: appBar,
body: Stack(
children: [
GestureDetector(
onTap: () {
percengtageTrigger();
},
child: Container(
height: stackHeight * 0.5,
width: stackWidth,
color: Colors.blue,
child: Column(
children: <Widget>[
shouldShow
? Container(
padding: const EdgeInsets.only(top: 10, right: 10),
height: stackHeight * 0.1,
color: Colors.blue,
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'${percentage1Calculate().toStringAsFixed(0)}%',
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
],
))
: Container(
height: stackHeight * 0.1,
color: Colors.blue,
width: double.infinity,
),
Container(
color: Colors.blue,
height: stackHeight * 0.4,
width: double.infinity,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(
_questions[index].would, //here its showing error
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
),
],
)),
],
),
),
),
GestureDetector(
onTap: () {
percengtageTrigger();
},
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
height: stackHeight * 0.5,
width: stackWidth,
color: Colors.red,
child: Column(
children: <Widget>[
shouldShow
? Container(
padding:
const EdgeInsets.only(top: 10, right: 10),
height: stackHeight * 0.1,
color: Colors.red,
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'${percentage2Calculate().toStringAsFixed(0)}%',
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
],
))
: Container(
height: stackHeight * 0.1,
color: Colors.red,
width: double.infinity,
),
Container(
color: Colors.red,
height: stackHeight * 0.4,
width: double.infinity,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 40),
child: Text(
_questions[index].rather,
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
),
],
)),
],
),
),
),
),
Align(
alignment: Alignment.center,
child: Container(
width: stackWidth,
height: stackHeight * 0.015,
color: Color(0xff404040),
),
),
Align(
alignment: Alignment.center,
child: Container(
width: stackWidth,
height: stackHeight * 0.15,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff404040),
),
child: Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
nextQuestion();
},
child: Text(
"SKIP",
style: TextStyle(
color: Colors.white,
fontFamily: 'FredokaOne',
fontSize: 27),
),
),
)),
),
],
));
}
}
Also comment in code where its showing error. I dont know how to solve it but i think the issue is causing because API data is not loaded before its calling the index data maybe ?
Try to use Futurebuild function but its just keep loading the function and showing the indicator not showing the Container when its loaded in termail its keep printing the value as infinite loop.
class _MyHomePageState extends State<MyHomePage> {
bool showApp = false;
var _questions = new List<Questions>();
Future<List> _getQuestions() async {
final response = await API.getUsers();
setState(() {
Iterable list = json.decode(response.body);
print(list);
print(list);
_questions = list.map((model) => Questions.fromJson(model)).toList();
print(_questions);
showApp = true;
});
return Future.value(_questions);
}
int index = 0;
bool shouldShow = false;
#override
Widget build(BuildContext context) {
int size = _questions?.length;
void nextQuestion() {
if (index < size - 1)
setState(() {
index++;
});
print(index);
}
double percentage1Calculate() {
int wouldClick = 12;
int ratherClick = 13;
double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
return percentage1;
}
double percentage2Calculate() {
int wouldClick = 2;
int ratherClick = 3;
double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
return percentage2;
}
void percengtageTrigger() {
setState(() {
shouldShow = true;
});
Timer timer = Timer(Duration(milliseconds: 1350), () {
setState(() {
shouldShow = false;
});
});
}
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
double stackHeight = (MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top);
double stackWidth = MediaQuery.of(context).size.width;
return FutureBuilder(
initialData: null, //initial default data if you have some
future: _getQuestions(),
builder: (BuildContext context,
AsyncSnapshot<List> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
print("Data found, You can continue");
return Center(child: Text('Datafound'));
} else if (snapshot.hasError) {
return Center(child: Text('HaSError'));
}
} else {
print("loading");
return CircularProgressIndicator();
}
});
}
}

It seems like the problem is what you are suspecting. The data is not available before the build method starts executing and thus we are encountering an out of range error. The solution to this problem would be to use a FutureBuilder in your build method.
Instead of getting the data in initState, wrap the code inside your build method in FutureBuilder and set the getUser() as the future parameter in the FutureBuilder. Take a look the code snippet below
#override
Widget build(BuildContext context) {
return FutureBuilder(
initialData:null //initial default data if you have some
future: API.getUsers(),
builder:(BuildContext context,AsyncSnapshot snapshot){
if(snapshot.ConnectionState==ConnectionState.none||snapshot.ConnectionState==ConnectionState.waiting){
print("data has not been fetched yet");
return CircularProgressIndicator();
}
else{
if(snapshot.hasData){
print("Data found, You can continue");
//decode your json here and initialize the variables you need
return Scaffold(
// your widgets
);
}else{
print("No data found");
return Text("No data found");
}
}
}
);
}
In your case, you'd do something like this
import 'package:flutter/material.dart';
class _MyHomePageState extends State<MyHomePage> {
bool showApp = false;
var _questions = new List<Questions>();
// Future<List> _getQuestions() async {
// final response = await API.getUsers();
// setState(() {
// Iterable list = json.decode(response.body);
// print(list);
// print(list);
// _questions = list.map((model) => Questions.fromJson(model)).toList();
// print(_questions);
// showApp = true;
// });
// return Future.value(_questions);
// }
int index = 0;
bool shouldShow = false;
#override
Widget build(BuildContext context) {
int size = _questions?.length;
void nextQuestion() {
if (index < size - 1)
setState(() {
index++;
});
print(index);
}
double percentage1Calculate() {
int wouldClick = 12;
int ratherClick = 13;
double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
return percentage1;
}
double percentage2Calculate() {
int wouldClick = 2;
int ratherClick = 3;
double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
return percentage2;
}
void percengtageTrigger() {
setState(() {
shouldShow = true;
});
Timer timer = Timer(Duration(milliseconds: 1350), () {
setState(() {
shouldShow = false;
});
});
}
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
double stackHeight = (MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top);
double stackWidth = MediaQuery.of(context).size.width;
return FutureBuilder(
initialData: null, //initial default data if you have some
future: API.getUsers(),
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
var response = snapshot.data;
print("Data found, You can continue");
Iterable list = json.decode(response.body);
print(list);
print(list);
_questions =
list.map((model) => Questions.fromJson(model)).toList();
print(_questions);
showApp = true;
return Center(child: Text('Datafound'));
} else if (snapshot.hasError) {
return Center(child: Text('HaSError'));
}
} else {
print("loading");
return CircularProgressIndicator();
}
});
}
}

Related

Need to keep old values when I comeback from the second screen

I’m making a pomodoro timer app. When I go to the SettingsScreen and come back to the home screen it reset the setNum value to 0 and the done value to 0.
I need to keep those previous values when I come back from the SettingsScreen.
In the settings screen, If I changed
Navigator.of(context).push(MaterialPageRoute()
To this
Navigator.of(context).pop(MaterialPageRoute()
In home screen, it will keep the previous values and it won’t change setNum to 0 but then I cannot change Times from that screen.
How to solve this?
Home Screen
import 'dart:async';
import 'dart:ffi';
import 'package:audioplayers/audio_cache.dart';
import 'package:flutter/material.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:pomodoroapp/model/menu_item.dart';
import 'package:pomodoroapp/model/pomodoro_status.dart';
import 'package:pomodoroapp/screens/report_screen.dart';
import 'package:pomodoroapp/screens/settings_screen.dart';
import 'package:pomodoroapp/utils/constants.dart';
import 'package:pomodoroapp/widget/custom_button.dart';
import 'package:pomodoroapp/widget/menu_items.dart';
import 'package:pomodoroapp/widget/progress_icons.dart';
class Home extends StatefulWidget {
//////////////////////// passed (changed) values //////////////////////
final pomodoroTimeChanged;
final shortBreakTimeChanged;
final longBreakTimeChanged;
Home(
{Key key,
this.pomodoroTimeChanged,
this.shortBreakTimeChanged,
this.longBreakTimeChanged})
: super(key: key);
#override
State<Home> createState() => _HomeState(
pomodoroTimeChanged, shortBreakTimeChanged, longBreakTimeChanged);
}
//////////////////////// main button labels ////////////////////////
const _btnTextStart = 'START';
const _btnTextResumePomodoro = 'RESUME';
const _btnTextResumeBreak = 'RESUME';
const _btnTextStartShortBreak = 'START';
const _btnTextStartLongBreak = 'START';
const _btnTextStartNewSet = 'START NEW SET';
const _btnTextPause = 'PAUSE';
const _btnTextReset = 'RESET';
#override
class _HomeState extends State<Home> {
//////////////////////// values //////////////////////
int pomodoroTime;
int shortBreakTime;
int longBreakTime;
//////////////////////// default times //////////////////////
int pomodoroTimeDefault = 5;
int shortBreakTimeDefault = 2;
int longBreakTimeDefault = 3;
int pomodoriPerSet = 4;
int pomodoroTimeChanged;
int shortBreakTimeChanged;
int longBreakTimeChanged;
_HomeState(this.pomodoroTimeChanged, this.shortBreakTimeChanged,
this.longBreakTimeChanged);
static AudioCache player = AudioCache();
int remainingTime = pomodoroTotalTime;
String mainBtnText = _btnTextStart;
PomodoroStatus pomodoroStatus = PomodoroStatus.pausedPomodoro;
Timer _timer;
int pomodoroNum = 0;
int setNum = 0;
//////////////////////// dispose, to avoid memory leak //////////////////////
#override
void dispose() {
_cancelTimer();
super.dispose();
}
/////////////////////// Update state function for changed value ///////////////////////
_updateStatepomodoroTime() {
setState(() {
remainingTime = pomodoroTime;
});
}
_updateStateShortBreakTime() {
setState(() {
remainingTime = shortBreakTime;
});
}
_updateStateLongBreakTime() {
setState(() {
remainingTime = longBreakTime;
});
}
#override
void initState() {
super.initState();
player.load('bell.mp3');
//////////////////// setting an initial value //////////////////////
if (pomodoroTimeChanged != null) {
pomodoroTime = pomodoroTimeChanged;
_updateStatepomodoroTime();
} else {
pomodoroTime = pomodoroTimeDefault;
}
if (shortBreakTimeChanged != null) {
shortBreakTime = shortBreakTimeChanged;
//_updateStateShortBreakTime();
_updateStatepomodoroTime();
} else {
shortBreakTime = shortBreakTimeDefault;
}
if (longBreakTimeChanged != null) {
longBreakTime = longBreakTimeChanged;
//_updateStateLongBreakTime();
_updateStatepomodoroTime();
} else {
longBreakTime = longBreakTimeDefault;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.grey[900],
appBar: PreferredSize(
preferredSize: Size.fromHeight(27.0),
child: AppBar(
backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(color: Colors.white, size: 10.0),
elevation: 0,
actions: [
PopupMenuButton<MenuItem>(
onSelected: (item) => onSelected(context, item),
itemBuilder: (context) =>
[...MenuItems.itemsFirst.map(buildItem).toList()],
)
],
),
),
body: Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://firebasestorage.googleapis.com/v0/b/flutterbricks-1926c.appspot.com/o/images%2Fwidgets%2F1634411682152%2FScreen%20Shot%202021-10-16%20at%203.14.09%20PM.png?alt=media&token=ec556af9-6dff-4020-a530-2b1eec58dafe'),
fit: BoxFit.cover,
),
),
child: Center(
child: Column(
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularPercentIndicator(
radius: 220.0,
lineWidth: 15.0,
percent: _getPomodoroPercentage(),
circularStrokeCap: CircularStrokeCap.round,
center: Text(
_secondsToFormatedString(remainingTime),
style:
const TextStyle(fontSize: 40, color: Colors.white),
),
progressColor: statusColor[pomodoroStatus],
),
const SizedBox(
height: 12,
),
ProgressIcons(
total: pomodoriPerSet,
done: pomodoroNum - (setNum * pomodoriPerSet),
),
const SizedBox(
height: 12,
),
Text(
'#$setNum',
style: const TextStyle(fontSize: 15, color: Colors.grey),
),
const SizedBox(
height: 5,
),
Text(
statusDescription[pomodoroStatus],
style: const TextStyle(color: Colors.white),
),
const SizedBox(
height: 12,
),
const SizedBox(
height: 12,
),
CustomButton(
onTap: _mainButtonPressed,
text: mainBtnText,
),
CustomButton(
onTap: _resetButtonPressed,
text: _btnTextReset,
)
],
),
)
],
),
),
),
);
}
_secondsToFormatedString(int seconds) {
int roundedMinutes = seconds ~/ 60;
int remainingSeconds = seconds - (roundedMinutes * 60);
String remainingSecondsFormated;
if (remainingSeconds < 10) {
remainingSecondsFormated = '0$remainingSeconds';
} else {
remainingSecondsFormated = remainingSeconds.toString();
}
return '$roundedMinutes:$remainingSecondsFormated';
}
_getPomodoroPercentage() {
int totalTime;
switch (pomodoroStatus) {
case PomodoroStatus.runingPomodoro:
totalTime = pomodoroTime;
break;
case PomodoroStatus.pausedPomodoro:
totalTime = pomodoroTime;
break;
case PomodoroStatus.runningShortBreak:
totalTime = shortBreakTime;
break;
case PomodoroStatus.pausedShortBreak:
totalTime = shortBreakTime;
break;
case PomodoroStatus.runningLongBreak:
totalTime = longBreakTime;
break;
case PomodoroStatus.pausedLongBreak:
totalTime = longBreakTime;
break;
case PomodoroStatus.setFinished:
totalTime = pomodoroTime;
break;
}
double percentage = (totalTime - remainingTime) / totalTime;
return percentage;
}
_mainButtonPressed() {
switch (pomodoroStatus) {
case PomodoroStatus.pausedPomodoro:
_startPomodoroCountdown();
break;
case PomodoroStatus.runingPomodoro:
_pausePomodoroCountdown();
break;
case PomodoroStatus.runningShortBreak:
_pauseShortBreakCountdown();
break;
case PomodoroStatus.pausedShortBreak:
_startShortBreak();
break;
case PomodoroStatus.runningLongBreak:
_pauseLongBreakCountdown();
break;
case PomodoroStatus.pausedLongBreak:
_startLongBreak();
break;
case PomodoroStatus.setFinished:
setNum++;
_startPomodoroCountdown();
break;
}
}
_startPomodoroCountdown() {
pomodoroStatus = PomodoroStatus.runingPomodoro;
_cancelTimer();
if (_timer != null) {
_timer.cancel();
}
_timer = Timer.periodic(
Duration(seconds: 1),
(timer) => {
if (remainingTime > 0)
{
setState(() {
remainingTime--;
mainBtnText = _btnTextPause;
})
}
else
{
_playSound(),
pomodoroNum++,
_cancelTimer(),
if (pomodoroNum % pomodoriPerSet == 0)
{
pomodoroStatus = PomodoroStatus.pausedLongBreak,
setState(() {
remainingTime = longBreakTime;
mainBtnText = _btnTextStartLongBreak;
}),
}
else
{
pomodoroStatus = PomodoroStatus.pausedShortBreak,
setState(() {
remainingTime = shortBreakTime;
mainBtnText = _btnTextStartShortBreak;
}),
}
}
});
}
_startShortBreak() {
pomodoroStatus = PomodoroStatus.runningShortBreak;
setState(() {
mainBtnText = _btnTextPause;
});
_cancelTimer();
_timer = Timer.periodic(
Duration(seconds: 1),
(timer) => {
if (remainingTime > 0)
{
setState(() {
remainingTime--;
}),
}
else
{
_playSound(),
remainingTime = pomodoroTime,
_cancelTimer(),
pomodoroStatus = PomodoroStatus.pausedPomodoro,
setState(() {
mainBtnText = _btnTextStart;
}),
}
});
}
_startLongBreak() {
pomodoroStatus = PomodoroStatus.runningLongBreak;
setState(() {
mainBtnText = _btnTextPause;
});
_cancelTimer();
_timer = Timer.periodic(
Duration(seconds: 1),
(timer) => {
if (remainingTime > 0)
{
setState(() {
remainingTime--;
}),
}
else
{
_playSound(),
remainingTime = pomodoroTime,
_cancelTimer(),
pomodoroStatus = PomodoroStatus.setFinished,
setState(() {
mainBtnText = _btnTextStartNewSet;
}),
}
});
}
_pausePomodoroCountdown() {
pomodoroStatus = PomodoroStatus.pausedPomodoro;
_cancelTimer();
setState(() {
mainBtnText = _btnTextResumePomodoro;
});
}
_resetButtonPressed() {
pomodoroNum = 0;
setNum = 0;
_cancelTimer();
_stopCountdown();
}
_stopCountdown() {
pomodoroStatus = PomodoroStatus.pausedPomodoro;
setState(() {
mainBtnText = _btnTextStart;
remainingTime = pomodoroTime;
});
}
_pauseShortBreakCountdown() {
pomodoroStatus = PomodoroStatus.pausedShortBreak;
_pauseBreakCountdown();
}
_pauseLongBreakCountdown() {
pomodoroStatus = PomodoroStatus.pausedLongBreak;
_pauseBreakCountdown();
}
_pauseBreakCountdown() {
_cancelTimer();
setState(() {
mainBtnText = _btnTextResumeBreak;
});
}
_cancelTimer() {
if (_timer != null) {
_timer.cancel();
}
}
_playSound() {
player.play('bell.mp3');
}
PopupMenuItem<MenuItem> buildItem(MenuItem item) => PopupMenuItem<MenuItem>(
value: item,
child: Row(children: [
Icon(
item.icon,
color: Colors.black,
size: 20,
),
const SizedBox(
width: 12,
),
Text(item.text)
]),
);
void onSelected(BuildContext context, MenuItem item) {
switch (item) {
case MenuItems.itemSettings:
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()),
);
break;
case MenuItems.itemReport:
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => ReportScreen()),
);
break;
}
}
}
class PopUpMenu extends StatelessWidget {
final List<PopupMenuEntry> menuList;
final Widget icon;
const PopUpMenu({Key key, this.menuList, this.icon}) : super(key: key);
#override
Widget build(BuildContext context) {
return PopupMenuButton(
itemBuilder: (context) => menuList,
icon: icon,
);
}
}
Settings Screen
import 'package:flutter/material.dart';
import 'package:numberpicker/numberpicker.dart';
import 'package:pomodoroapp/screens/home_screen.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({Key key}) : super(key: key);
#override
_SettingsScreen createState() => _SettingsScreen();
}
class _SettingsScreen extends State<SettingsScreen>
with TickerProviderStateMixin {
// Switch states
int _workSessionValue = 25;
int _shortBreakValue = 5;
int _longBreakValue = 15;
NumberPicker integerNumberPicker;
////////////////////// values to pass //////////////////////
int pomodoroTimeToChanged;
int shortBreakTimeToChanged;
int longBreakTimeToChanged;
// Work Session
_handleWorkValueChange(num value) {
if (value != null) {
setState(() {
_workSessionValue = value;
});
}
}
_handleWorkValueChangedExternally(num value) {
if (value != null) {
setState(() {
_workSessionValue = value;
});
integerNumberPicker.animateInt(value);
}
print('Updated pomodoro value: $_workSessionValue ');
pomodoroTimeToChanged = value * 60;
}
// Short break
_handleShortBreakValueChange(num value) {
if (value != null) {
setState(() {
_shortBreakValue = value;
});
}
}
_handleShortBreakValueChangedExternally(num value) {
if (value != null) {
setState(() {
_shortBreakValue = value;
});
integerNumberPicker.animateInt(value);
}
print('Updated short break value: $_shortBreakValue ');
shortBreakTimeToChanged = value * 60;
}
// Long Break
_handleLongBreakValueChange(num value) {
if (value != null) {
setState(() {
_longBreakValue = value;
});
}
}
_handleLongBreakChangedExternally(num value) {
if (value != null) {
setState(() {
_longBreakValue = value;
});
integerNumberPicker.animateInt(value);
}
print('Updated Long break value: $_longBreakValue ');
longBreakTimeToChanged = value * 60;
}
// Animation
AnimationController animationController;
String get timerString {
Duration duration =
animationController.duration * animationController.value;
return '${duration.inMinutes.toString().padLeft(2, '0')}\n${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
#override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this, duration: const Duration(seconds: 1500));
}
//number pick values
#override
Widget build(BuildContext context) {
integerNumberPicker = NumberPicker.integer(
initialValue: _workSessionValue,
minValue: 1,
maxValue: 50,
onChanged: _handleWorkValueChange,
);
integerNumberPicker = NumberPicker.integer(
initialValue: _shortBreakValue,
minValue: 1,
maxValue: 50,
onChanged: _handleShortBreakValueChange,
);
integerNumberPicker = NumberPicker.integer(
initialValue: _longBreakValue,
minValue: 1,
maxValue: 50,
onChanged: _handleLongBreakValueChange,
);
//UI
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.chevron_left),
onPressed: () => {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Home(
pomodoroTimeChanged: pomodoroTimeToChanged,
shortBreakTimeChanged: shortBreakTimeToChanged,
longBreakTimeChanged: longBreakTimeToChanged,
)))
},
),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text("Timer",
textAlign: TextAlign.left,
style: TextStyle(
color: Colors.black,
fontSize: 32,
fontWeight: FontWeight.w700)),
const Divider(
thickness: 2,
color: Colors.black26,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
const Text(
"Pomodoro",
style: TextStyle(
color: Colors.black,
fontSize: 22,
fontWeight: FontWeight.w400),
),
Row(
children: <Widget>[
Container(
width: 30,
height: 30,
child: RawMaterialButton(
shape: const CircleBorder(),
onPressed: _showWorkSessionDialog,
fillColor: Colors.amber,
elevation: 0,
child: Text(
"$_workSessionValue",
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w500),
),
),
),
const Padding(
padding: EdgeInsets.all(5),
child: Text(
"min",
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500),
),
)
],
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
const Text(
"Short Break",
style: TextStyle(
color: Colors.black,
fontSize: 22,
fontWeight: FontWeight.w400),
),
Row(
children: <Widget>[
Container(
width: 30,
height: 30,
child: RawMaterialButton(
shape: CircleBorder(),
onPressed: _showShortBreakDialog,
fillColor: Colors.amber,
elevation: 0,
child: Text(
"$_shortBreakValue",
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w500),
),
),
),
const Padding(
padding: EdgeInsets.all(5),
child: Text(
"min",
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500),
),
)
],
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
const Text(
"Long Break",
style: TextStyle(
color: Colors.black,
fontSize: 22,
fontWeight: FontWeight.w400),
),
Row(
children: <Widget>[
Container(
width: 30,
height: 30,
child: RawMaterialButton(
shape: CircleBorder(),
onPressed: _showLongBreakDialog,
fillColor: Colors.amber,
elevation: 0,
child: Text(
"$_longBreakValue",
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w500),
),
),
),
const Padding(
padding: EdgeInsets.all(5),
child: Text(
"min",
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w500),
),
)
],
)
],
),
)
],
)
],
),
),
);
}
//dialog boxes
_showWorkSessionDialog() {
showDialog<int>(
context: context,
builder: (BuildContext context) {
return NumberPickerDialog.integer(
minValue: 0,
maxValue: 50,
initialIntegerValue: _workSessionValue,
title: const Text("Select a minute"),
);
},
).then(_handleWorkValueChangedExternally);
}
_showShortBreakDialog() {
showDialog<int>(
context: context,
builder: (BuildContext context) {
return NumberPickerDialog.integer(
minValue: 0,
maxValue: 50,
initialIntegerValue: _shortBreakValue,
title: const Text("Select a minute"),
);
},
).then(_handleShortBreakValueChangedExternally);
}
_showLongBreakDialog() {
showDialog<int>(
context: context,
builder: (BuildContext context) {
return NumberPickerDialog.integer(
minValue: 0,
maxValue: 50,
initialIntegerValue: _longBreakValue,
title: const Text("Select a minute"),
);
},
).then(_handleLongBreakChangedExternally);
}
}

Video player play image and video looping flutter

can video player play image for 10sec then loop to next video ?
How can i loop image only for 10sec then loop into next new video in my video clip data or video player controller ?
I manage to add video to video player but don't know how to add image to the player.
video clip data
class VideoClip {
final String fileName;
final String thumbName;
final String title;
final String parent;
int runningTime;
VideoClip(this.title, this.fileName, this.thumbName, this.runningTime, this.parent);
String videoPath() {
return "$parent/$fileName";
}
String thumbPath() {
return "$parent/$thumbName";
}
static List<VideoClip> remoteClips = [
VideoClip("For Bigger Fun", "ForBiggerFun.mp4", "images/ForBiggerFun.jpg", 0, "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample"),
VideoClip("Elephant Dream", "ElephantsDream.mp4", "images/ForBiggerBlazes.jpg", 0, "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample"),
VideoClip("BigBuckBunny", "BigBuckBunny.mp4", "images/BigBuckBunny.jpg", 0, "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample"),
];
}
Video player controller
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_video_list_sample/clips.dart';
import 'package:video_player/video_player.dart';
import 'package:wakelock/wakelock.dart';
class PlayPage extends StatefulWidget {
PlayPage({Key key, #required this.clips}) : super(key: key);
final List<VideoClip> clips;
#override
_PlayPageState createState() => _PlayPageState();
}
class _PlayPageState extends State<PlayPage> {
VideoPlayerController _controller;
List<VideoClip> get _clips {
return widget.clips;
}
var _playingIndex = -1;
var _disposed = false;
var _isFullScreen = false;
var _isEndOfClip = false;
var _progress = 0.0;
var _showingDialog = false;
Timer _timerVisibleControl;
double _controlAlpha = 1.0;
var _playing = false;
bool get _isPlaying {
return _playing;
}
set _isPlaying(bool value) {
_playing = value;
_timerVisibleControl?.cancel();
if (value) {
_timerVisibleControl = Timer(Duration(seconds: 2), () {
if (_disposed) return;
setState(() {
_controlAlpha = 0.0;
});
});
} else {
_timerVisibleControl = Timer(Duration(milliseconds: 200), () {
if (_disposed) return;
setState(() {
_controlAlpha = 1.0;
});
});
}
}
void _onTapVideo() {
debugPrint("_onTapVideo $_controlAlpha");
setState(() {
_controlAlpha = _controlAlpha > 0 ? 0 : 1;
});
_timerVisibleControl?.cancel();
_timerVisibleControl = Timer(Duration(seconds: 2), () {
if (_isPlaying) {
setState(() {
_controlAlpha = 0.0;
});
}
});
}
#override
void initState() {
Wakelock.enable();
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
_initializeAndPlay(0);
super.initState();
}
#override
void dispose() {
_disposed = true;
_timerVisibleControl?.cancel();
Wakelock.disable();
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
_exitFullScreen();
_controller?.pause(); // mute instantly
_controller?.dispose();
_controller = null;
super.dispose();
}
void _toggleFullscreen() async {
if (_isFullScreen) {
_exitFullScreen();
} else {
_enterFullScreen();
}
}
void _enterFullScreen() async {
debugPrint("enterFullScreen");
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
await SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
if (_disposed) return;
setState(() {
_isFullScreen = true;
});
}
void _exitFullScreen() async {
debugPrint("exitFullScreen");
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
if (_disposed) return;
setState(() {
_isFullScreen = false;
});
}
void _initializeAndPlay(int index) async {
print("_initializeAndPlay ---------> $index");
final clip = _clips[index];
final controller = clip.parent.startsWith("http")
? VideoPlayerController.network(clip.videoPath())
: VideoPlayerController.asset(clip.videoPath());
final old = _controller;
_controller = controller;
if (old != null) {
old.removeListener(_onControllerUpdated);
old.pause();
debugPrint("---- old contoller paused.");
}
debugPrint("---- controller changed.");
setState(() {});
controller
..initialize().then((_) {
debugPrint("---- controller initialized");
old?.dispose();
_playingIndex = index;
_duration = null;
_position = null;
controller.addListener(_onControllerUpdated);
controller.play();
setState(() {});
});
}
var _updateProgressInterval = 0.0;
Duration _duration;
Duration _position;
void _onControllerUpdated() async {
if (_disposed) return;
// blocking too many updation
// important !!
final now = DateTime.now().millisecondsSinceEpoch;
if (_updateProgressInterval > now) {
return;
}
_updateProgressInterval = now + 500.0;
final controller = _controller;
if (controller == null) return;
if (!controller.value.isInitialized) return;
if (_duration == null) {
_duration = _controller.value.duration;
}
var duration = _duration;
if (duration == null) return;
var position = await controller.position;
_position = position;
final playing = controller.value.isPlaying;
final isEndOfClip = position.inMilliseconds > 0 && position.inSeconds + 1 >= duration.inSeconds;
if (playing) {
// handle progress indicator
if (_disposed) return;
setState(() {
_progress = position.inMilliseconds.ceilToDouble() / duration.inMilliseconds.ceilToDouble();
});
}
// handle clip end
if (_isPlaying != playing || _isEndOfClip != isEndOfClip) {
_isPlaying = playing;
_isEndOfClip = isEndOfClip;
debugPrint("updated -----> isPlaying=$playing / isEndOfClip=$isEndOfClip");
if (isEndOfClip && !playing) {
debugPrint("========================== End of Clip / Handle NEXT ========================== ");
final isComplete = _playingIndex == _clips.length - 1;
if (isComplete) {
print("played all!!");
if (!_showingDialog) {
_showingDialog = true;
_showPlayedAllDialog().then((value) {
_exitFullScreen();
_showingDialog = false;
});
}
} else {
_initializeAndPlay(_playingIndex + 1);
}
}
}
}
Future<bool> _showPlayedAllDialog() async {
return showDialog<bool>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
content: SingleChildScrollView(child: Text("Played all videos.")),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text("Close"),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _isFullScreen
? null
: AppBar(
title: Text("Play View"),
),
body: _isFullScreen
? Container(
child: Center(child: _playView(context)),
decoration: BoxDecoration(color: Colors.black),
)
: Column(children: <Widget>[
Container(
child: Center(child: _playView(context)),
decoration: BoxDecoration(color: Colors.black),
),
Expanded(
child: _listView(),
),
]),
);
}
void _onTapCard(int index) {
_initializeAndPlay(index);
}
Widget _playView(BuildContext context) {
final controller = _controller;
if (controller != null && controller.value.isInitialized) {
return AspectRatio(
//aspectRatio: controller.value.aspectRatio,
aspectRatio: 16.0 / 9.0,
child: Stack(
children: <Widget>[
GestureDetector(
child: VideoPlayer(controller),
onTap: _onTapVideo,
),
_controlAlpha > 0
? AnimatedOpacity(
opacity: _controlAlpha,
duration: Duration(milliseconds: 250),
child: _controlView(context),
)
: Container(),
],
),
);
} else {
return AspectRatio(
aspectRatio: 16.0 / 9.0,
child: Center(
child: Text(
"Preparing ...",
style: TextStyle(color: Colors.white70, fontWeight: FontWeight.bold, fontSize: 18.0),
)),
);
}
}
Widget _listView() {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
itemCount: _clips.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
borderRadius: BorderRadius.all(Radius.circular(6)),
splashColor: Colors.blue[100],
onTap: () {
_onTapCard(index);
},
child: _buildCard(index),
);
},
).build(context);
}
Widget _controlView(BuildContext context) {
return Column(
children: <Widget>[
_topUI(),
Expanded(
child: _centerUI(),
),
_bottomUI()
],
);
}
Widget _centerUI() {
return Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () async {
final index = _playingIndex - 1;
if (index > 0 && _clips.length > 0) {
_initializeAndPlay(index);
}
},
child: Icon(
Icons.fast_rewind,
size: 36.0,
color: Colors.white,
),
),
TextButton(
onPressed: () async {
if (_isPlaying) {
_controller?.pause();
_isPlaying = false;
} else {
final controller = _controller;
if (controller != null) {
final pos = _position?.inSeconds ?? 0;
final dur = _duration?.inSeconds ?? 0;
final isEnd = pos == dur;
if (isEnd) {
_initializeAndPlay(_playingIndex);
} else {
controller.play();
}
}
}
setState(() {});
},
child: Icon(
_isPlaying ? Icons.pause : Icons.play_arrow,
size: 56.0,
color: Colors.white,
),
),
TextButton(
onPressed: () async {
final index = _playingIndex + 1;
if (index < _clips.length - 1) {
_initializeAndPlay(index);
}
},
child: Icon(
Icons.fast_forward,
size: 36.0,
color: Colors.white,
),
),
],
));
}
String convertTwo(int value) {
return value < 10 ? "0$value" : "$value";
}
Widget _topUI() {
final noMute = (_controller?.value?.volume ?? 0) > 0;
final duration = _duration?.inSeconds ?? 0;
final head = _position?.inSeconds ?? 0;
final remained = max(0, duration - head);
final min = convertTwo(remained ~/ 60.0);
final sec = convertTwo(remained % 60);
return Row(
children: <Widget>[
InkWell(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Container(
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
BoxShadow(offset: const Offset(0.0, 0.0), blurRadius: 4.0, color: Color.fromARGB(50, 0, 0, 0)),
]),
child: Icon(
noMute ? Icons.volume_up : Icons.volume_off,
color: Colors.white,
)),
),
onTap: () {
if (noMute) {
_controller?.setVolume(0);
} else {
_controller?.setVolume(1.0);
}
setState(() {});
},
),
Expanded(
child: Container(),
),
Text(
"$min:$sec",
style: TextStyle(
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(0.0, 1.0),
blurRadius: 4.0,
color: Color.fromARGB(150, 0, 0, 0),
),
],
),
),
SizedBox(width: 10)
],
);
}
Widget _bottomUI() {
return Row(
children: <Widget>[
SizedBox(width: 20),
Expanded(
child: Slider(
value: max(0, min(_progress * 100, 100)),
min: 0,
max: 100,
onChanged: (value) {
setState(() {
_progress = value * 0.01;
});
},
onChangeStart: (value) {
debugPrint("-- onChangeStart $value");
_controller?.pause();
},
onChangeEnd: (value) {
debugPrint("-- onChangeEnd $value");
final duration = _controller?.value?.duration;
if (duration != null) {
var newValue = max(0, min(value, 99)) * 0.01;
var millis = (duration.inMilliseconds * newValue).toInt();
_controller?.seekTo(Duration(milliseconds: millis));
_controller?.play();
}
},
),
),
IconButton(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
color: Colors.yellow,
icon: Icon(
Icons.fullscreen,
color: Colors.white,
),
onPressed: _toggleFullscreen,
),
],
);
}
Widget _buildCard(int index) {
final clip = _clips[index];
final playing = index == _playingIndex;
String runtime;
if (clip.runningTime > 60) {
runtime = "${clip.runningTime ~/ 60}분 ${clip.runningTime % 60}초";
} else {
runtime = "${clip.runningTime % 60}초";
}
return Card(
child: Container(
padding: EdgeInsets.all(4),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(right: 8),
child: clip.parent.startsWith("http")
? Image.network(clip.thumbPath(), width: 70, height: 50, fit: BoxFit.fill)
: Image.asset(clip.thumbPath(), width: 70, height: 50, fit: BoxFit.fill),
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(clip.title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Padding(
child: Text("$runtime", style: TextStyle(color: Colors.grey[500])),
padding: EdgeInsets.only(top: 3),
)
]),
),
Padding(
padding: EdgeInsets.all(8.0),
child: playing
? Icon(Icons.play_arrow)
: Icon(
Icons.play_arrow,
color: Colors.grey.shade300,
),
),
],
),
),
);
}
}

Another exception was thrown: type 'Null' is not a subtype of type 'String'

getting this error showing in red screen I update my packages
_TypeError Another exception was thrown: type 'Null' is not a subtype of type 'String' I tried to update the sdk and I'm not understanding where the problem is in this code. I added CircularProgressIndicator with condition statements
The relevant error-causing widget was:
quizpage
quizpage:file:///C:/Users/flutt/Downloads/quiz/flutter-quizstar-master/lib/quizpage.dart:57:18
class getjson extends StatefulWidget {
String langname;
getjson(this.langname);
#override
State<getjson> createState() => _getjsonState();
}
class _getjsonState extends State<getjson> {
late String assettoload;
// a function
setasset() {
if (widget.langname == "Science") {
assettoload = "assets/Science.json";
} else if (widget.langname == "Maths") {
assettoload = "assets/Maths.json";
} else if (widget.langname == "History") {
assettoload = "assets/History.json";
}
}
#override
Widget build(BuildContext context) {
setasset();
// and now we return the FutureBuilder to load and decode JSON
return FutureBuilder(
future:
DefaultAssetBundle.of(context).loadString(assettoload, cache: false),
builder: (context, snapshot) {
if (snapshot.hasData) {
List mydata = json.decode(snapshot.data.toString());
if (mydata == null) {
return Scaffold(
body: Center(
child: Text(
"Loading",
),
),
);
} else {
return quizpage(mydata: mydata);
}}
return CircularProgressIndicator();
},
);
}
}
class quizpage extends StatefulWidget {
final List mydata;
quizpage({required this.mydata});
#override
_quizpageState createState() => _quizpageState(mydata);
}
class _quizpageState extends State<quizpage> {
final List mydata;
_quizpageState(this.mydata);
Color colortoshow = Colors.indigoAccent;
Color right = Colors.green;
Color wrong = Colors.red;
int marks = 0;
int i = 1;
bool disableAnswer = false;
int j = 1;
int timer = 30;
String showtimer = "30";
var random_array;
Map<String, Color> btncolor = {
"a": Colors.indigoAccent,
"b": Colors.indigoAccent,
"c": Colors.indigoAccent,
"d": Colors.indigoAccent,
};
bool canceltimer = false;
genrandomarray(){
var distinctIds = [];
var rand = new Random();
for (int i = 0;; ) {
distinctIds.add(rand.nextInt(10));
random_array = distinctIds.toSet().toList();
if(random_array.length < 10){
continue;
}else{
break;
}
}
print(random_array);
}
#override
void initState() {
starttimer();
genrandomarray();
super.initState();
}
#override
void setState(fn) {
if (mounted) {
super.setState(fn);
}
}
void starttimer() async {
const onesec = Duration(seconds: 1);
Timer.periodic(onesec, (Timer t) {
setState(() {
if (timer < 1) {
t.cancel();
nextquestion();
} else if (canceltimer == true) {
t.cancel();
} else {
timer = timer - 1;
}
showtimer = timer.toString();
});
});
}
void nextquestion() {
canceltimer = false;
timer = 30;
setState(() {
if (j < 10) {
i = random_array[j];
j++;
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(marks: marks),
));
}
btncolor["a"] = Colors.indigoAccent;
btncolor["b"] = Colors.indigoAccent;
btncolor["c"] = Colors.indigoAccent;
btncolor["d"] = Colors.indigoAccent;
disableAnswer = false;
});
starttimer();
}
void checkanswer(String k) {
// in the previous version this was
// mydata[2]["1"] == mydata[1]["1"][k]
// which i forgot to change
// so nake sure that this is now corrected
if (mydata[2][i.toString()] == mydata[1][i.toString()][k]) {
// just a print sattement to check the correct working
// debugPrint(mydata[2][i.toString()] + " is equal to " + mydata[1][i.toString()][k]);
marks = marks + 5;
// changing the color variable to be green
colortoshow = right;
} else {
// just a print sattement to check the correct working
// debugPrint(mydata[2]["1"] + " is equal to " + mydata[1]["1"][k]);
colortoshow = wrong;
}
setState(() {
btncolor[k] = colortoshow;
canceltimer = true;
disableAnswer = true;
});
// nextquestion();
// changed timer duration to 1 second
Timer(Duration(seconds: 2), nextquestion);
}
Widget choicebutton(String k) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
child: MaterialButton(
onPressed: () => checkanswer(k),
child: Text(
mydata[1][i.toString()][k],
style: TextStyle(
color: Colors.white,
fontFamily: "Alike",
fontSize: 16.0,
),
maxLines: 1,
),
color: btncolor[k],
splashColor: Colors.indigo[700],
highlightColor: Colors.indigo[700],
minWidth: 200.0,
height: 45.0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
),
);
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]);
return WillPopScope(
onWillPop: () async{
return await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Welcome",
),
content: Text("You Can't Go Back At This Stage."),
actions: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Ok',
),
)
],
));
},
child: Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 3,
child: Container(
padding: EdgeInsets.all(15.0),
alignment: Alignment.bottomLeft,
child: Text(
mydata[0][i.toString()] ,
style: TextStyle(
fontSize: 16.0,
fontFamily: "Quando",
),
),
),
),
Expanded(
flex: 6,
child: AbsorbPointer(
absorbing: disableAnswer,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
choicebutton('a'),
choicebutton('b'),
choicebutton('c'),
choicebutton('d'),
],
),
),
),
),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.topCenter,
child: Center(
child: Text(
showtimer,
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.w700,
fontFamily: 'Times New Roman',
),
),
),
),
),
],
),
),
);
}
}
In your code some place your are show some variable in Text widget that might be null so change them to these:
Text(
mydata[1][i.toString()][k] ?? "",//<--- add this
style: TextStyle(
color: Colors.white,
fontFamily: "Alike",
fontSize: 16.0,
),
maxLines: 1,
)
and
Expanded(
flex: 3,
child: Container(
padding: EdgeInsets.all(15.0),
alignment: Alignment.bottomLeft,
child: Text(
mydata[0][i.toString()] ?? "",//<--- add this
style: TextStyle(
fontSize: 16.0,
fontFamily: "Quando",
),
),
),
),
Can you check if your expression is evaluating to null in Text() Widget,
just put some constant strings in text widgets and try to run.
if expression is evaluating to null, use ?? operation to provide default string value to Text Widget.

AutoScroll Text with pinch and zoom in flutter

I'm new to flutter and I'm trying to implement a page where I want to show Text Widget with AutoScroll Also users can Zoom in and Zoom Out the text. I have implemented AutoScroll using the help of this link (AutoScroll Text). I have also added GestureDetector but It's not working as expected. Here is the complete source code which I have right now...
import 'dart:async';
import 'dart:ui';
import 'package:ffmpeg_demo/Utility/util.dart';
import 'package:flutter/material.dart';
class PDFViewer extends StatefulWidget {
final Function() onDismissTapped;
final String pdfText;
const PDFViewer(
{Key? key, required this.onDismissTapped, required this.pdfText})
: super(key: key);
#override
State<PDFViewer> createState() => _PDFViewerState();
}
class _PDFViewerState extends State<PDFViewer> {
double scrollSpeed = 1.0;
Function? onDismissTapped;
//https://stackoverflow.com/questions/57138772/how-to-autoscroll-text-in-flutter
final ScrollController _scrollController = ScrollController();
bool scroll = false;
int speedFactor = 100;
//For Scaling Text Area
//https://stackoverflow.com/questions/55440184/flutter-gesturedetector-how-to-pinch-in-out-or-zoom-in-out-text-using-two-finge
double _fontSize = 20;
final double _baseFontSize = 20;
double _fontScale = 1;
double _baseFontScale = 1;
double _scaleFactor = 1.0;
double _baseScaleFactor = 1.0;
bool _stopScrolling = false;
_scroll() {
double maxExtent = _scrollController.position.maxScrollExtent;
double distanceDifference = maxExtent - _scrollController.offset;
double durationDouble = distanceDifference / speedFactor;
int duration = durationDouble.toInt();
if (duration <= 0) {
duration = 1;
}
print(
"maxScrollExtent = $maxExtent and distanceDifference = $distanceDifference and durationDouble = $durationDouble");
_scrollController.animateTo(_scrollController.position.maxScrollExtent,
duration: Duration(seconds: duration), curve: Curves.linear);
}
_toggleScrolling() {
/* if (_stopScrolling) {
print("Stop scrolling flag value is $_stopScrolling");
return;
} */
setState(() {
scroll = !scroll;
});
if (scroll) {
_scroll();
} else {
_scrollController.animateTo(_scrollController.offset,
duration: const Duration(seconds: 1), curve: Curves.linear);
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
Future.delayed(const Duration(seconds: 1), () {
_toggleScrolling();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
color: Colors.transparent,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Container(
color: Colors.black.withOpacity(0.5),
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 50, 10, 100),
child: NotificationListener(
onNotification: (notif) {
if (notif is ScrollEndNotification && scroll) {
Timer(const Duration(seconds: 1), () {
_scroll();
});
}
return true;
},
child: SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.vertical,
padding: const EdgeInsets.all(20),
child: DefaultTextStyle(
style: const TextStyle(color: Colors.white),
child: GestureDetector(
onScaleStart: (ScaleStartDetails scaleStartDetails) {
setState(() {
//_stopScrolling = true;
_toggleScrolling();
});
//_baseScaleFactor = _scaleFactor;
_baseFontScale = _fontScale;
print("base scale factor = $_baseFontScale");
},
onScaleUpdate:
(ScaleUpdateDetails scaleUpdateDetails) {
// don't update the UI if the scale didn't change
/* if (scaleUpdateDetails.scale == 1.0) {
debugPrint("Scale is 1.0 returning");
setState(() {
_stopScrolling = false;
_toggleScrolling();
});
return;
} */
/* _scaleFactor =
_baseScaleFactor * scaleUpdateDetails.scale;
print("Final scale factor = $_scaleFactor");
if (_scaleFactor < 1.0) {
_scaleFactor = 1.0;
}
print("New Final scale factor = $_scaleFactor"); */
//setState(() {
_fontScale =
(_baseFontScale * scaleUpdateDetails.scale)
.clamp(0.5, 5.0);
_fontSize = _fontScale * _baseFontSize;
debugPrint("New Final font size = $_fontSize");
if (_fontSize < 20) {
_fontSize = 20;
}
//});
setState(() {
//_toggleScrolling();
_stopScrolling = false;
_toggleScrolling();
});
},
child: Text(
widget.pdfText,
/* textScaleFactor:
(_scaleFactor <= 0.1) ? 1.0 : _scaleFactor, */
style: TextStyle(
fontSize: (_fontSize < 20) ? 20 : _fontSize),
),
),
),
),
),
),
Positioned(
bottom: 0,
child: Container(
height: 100,
width: deviceWidth(context),
color: Colors.black.withAlpha(50),
child: Stack(
children: [
Positioned(
bottom: 0,
width: deviceWidth(context),
child: Center(
child: TextButton(
child: const Text(
"Dismiss",
style: TextStyle(color: Colors.white),
),
onPressed: () => widget.onDismissTapped(),
),
),
),
Positioned(
top: 0,
width: deviceWidth(context),
child: Container(
height: 50,
width: deviceWidth(context),
child: _buildSlider(context)),
),
],
),
),
),
],
),
),
),
),
);
}
Widget _buildSlider(BuildContext context) {
return Container(
width: deviceWidth(context),
child: SliderTheme(
data: SliderThemeData(
activeTrackColor: Colors.brown[700],
inactiveTrackColor: Colors.brown[300],
inactiveTickMarkColor: Colors.transparent,
activeTickMarkColor: Colors.transparent),
child: Slider(
divisions: 100,
min: 0,
max: 100,
value: speedFactor.toDouble(),
onChanged: (double value) {
setState(() {
//scrollSpeed = value;
_toggleScrolling();
});
speedFactor = value.toInt();
if (speedFactor == 0) {
speedFactor = 1;
}
Future.delayed(const Duration(seconds: 1), () {
setState(() {
//scrollSpeed = value;
_toggleScrolling();
});
});
}),
),
);
}
}

flutter:: RangeError (index): Invalid value: Not in inclusive range 0..14: 15

I made a function to delete saved recording files.
The delete function works fine.
However, if it is deleted, an error
'RangeError (index): Invalid value: Not in inclusive range 0..14: 15'
will occur and it will look like the picture above.
How can I solve this?
This is the delete function.
_delete() {
widget.file[widget.index].delete(recursive: true);
setState(() {
position = new Duration();
widget.file.removeAt(widget.index);
});
}
This is my listview code.
class _AudioViewerState extends State<AudioViewer> {
var audioPath;
var directory;
List file = [];
#override
void initState() {
super.initState();
getFiles();
}
void getFiles() async {
directory = (await getExternalStorageDirectory())!.path;
setState(() {
file = Directory("$directory").listSync();
});
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
elevation: 0,
title: Text(
"Audio List",
),
),
body: Container(
child: CustomPaint(
child: ListView.builder(
reverse: true,
itemCount: file.length,
itemBuilder: (BuildContext context, int index) {
return AudioViewerCustomTile(
text: file[index].path.split('/').last,
path: file[index].path.toString(),
height: height,
width: width,
file: file,
index: index,
);
},
),
),
),
);
}
}
This is the file with the delete function.
class DialogBuilder extends StatefulWidget {
final String path;
final int index;
final List file;
DialogBuilder({required this.path,required this.index,required this.file});
#override
_DialogBuilderState createState() => _DialogBuilderState();
}
class _DialogBuilderState extends State<DialogBuilder> {
late AudioPlayer audioPlayer;
bool _isplaying = false;
var _icon = Icons.play_arrow;
var _deleteicon = Icons.delete;
Color _color = Colors.deepOrangeAccent;
Duration position = Duration();
Duration duration = Duration(seconds: 1);
#override
Widget build(BuildContext context) {
return Container(
height: 200,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Container(
child: IconButton(
iconSize: 100,
onPressed: () {
if (!_isplaying) {
_play();
} else {
_stop();
}
},
icon: Icon(_icon),
color: _color,
),
),
Container(
child: IconButton(
iconSize: 50,
onPressed: () {
_delete();
},
icon: Icon(_deleteicon),
),
),
]
)
),
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation(Colors.deepOrangeAccent),
value: (position.inMilliseconds / duration.inMilliseconds) * 1.0,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
_getDuration(position),
style: TextStyle(color: Colors.black),
),
Text(
_getDuration(duration),
style: TextStyle(color: Colors.black),
)
],
),
)
],
),
);
}
String _getDuration(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";
}
_play() {
audioPlayer.resume();
setState(() {
_isplaying = true;
_icon = Icons.pause;
_color = Colors.blueGrey;
});
}
_stop() {
audioPlayer.release();
setState(() {
position = new Duration();
_isplaying = false;
_icon = Icons.play_arrow;
_color = Colors.deepOrangeAccent;
});
}
_delete() {
widget.file[widget.index].delete(recursive: true);
setState(() {
position = new Duration();
widget.file.removeAt(widget.index);
});
}
_stateListener(PlayerState state) {
print(" In _stateListener the state of AudioPlayer :- " +
state.toString() +
"\n");
if (state == PlayerState.COMPLETED) {
Navigator.pop(context);
_stop();
}
}
The List file = []; is an empty list, so when you try to do itemCount = file.length, it displays an error, try giving the List file; a value instead of a an empty list and im sure it will work