LateInitializationError: Field 'dialogflow' has not been initialized - flutter

My code works fine last week, then when the credentials expire, i recreate another credentials and replace the credentials, now the code doesnt work anymore and show the error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Field 'dialogflow' has not been initialized.
import 'package:dialogflow_grpc/dialogflow_grpc.dart';
import 'package:dialogflow_grpc/generated/google/cloud/dialogflow/v2beta1/session.pb.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Chat extends StatefulWidget {
Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
final List<ChatMessage> _messages = <ChatMessage>[];
final TextEditingController _textController = TextEditingController();
late DialogflowGrpcV2Beta1 dialogflow;
#override
void initState() {
super.initState();
initPlugin();
}
Future<void> initPlugin()async{
final serviceAccount = ServiceAccount.fromString(
'${(await rootBundle.loadString('assets/credentials2.json'))}');
// Create a DialogflowGrpc Instance
dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
}
void handleSubmitted(text) async {
print(text);
_textController.clear();
ChatMessage message = ChatMessage(
text: text,
name: "You",
type: true,
);
setState(() {
_messages.insert(0, message);
});
DetectIntentResponse data = await dialogflow.detectIntent(text, 'en-US');
String fulfillmentText = data.queryResult.fulfillmentText;
if(fulfillmentText.isNotEmpty) {
ChatMessage botMessage = ChatMessage(
text: fulfillmentText,
name: "Bot",
type: false,
);
setState(() {
_messages.insert(0, botMessage);
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Chatbot Page'),
),
body: Column(children: <Widget>[
Flexible(
child: ListView.builder(
padding: EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
Divider(height: 1.0),
Container(
decoration: BoxDecoration(color: Theme.of(context).cardColor),
child: IconTheme(
data: IconThemeData(color: Theme.of(context).accentColor),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: <Widget>[
Flexible(
child: TextField(
controller: _textController,
onSubmitted: handleSubmitted,
decoration: InputDecoration.collapsed(hintText: "Send a message to begin"),
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 4.0),
child: IconButton(
icon: Icon(Icons.send),
onPressed: () => handleSubmitted(_textController.text),
),
),
],
),
),
)
),
]),
);
}
}
class ChatMessage extends StatelessWidget {
ChatMessage({required this.text, required this.name, required this.type});
final String text;
final String name;
final bool type;
List<Widget> otherMessage(context) {
return <Widget>[
new Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: new Text('B')),
),
new Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
];
}
List<Widget> myMessage(context) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(this.name, style: Theme.of(context).textTheme.subtitle1),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
Container(
margin: const EdgeInsets.only(left: 16.0),
child: CircleAvatar(
child: Text(
this.name[0],
style: TextStyle(fontWeight: FontWeight.bold),
)),
),
];
}
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: this.type ? myMessage(context) : otherMessage(context),
),
);
}
}

initPlugin is a future method, It will take some frame to initialize the dialogflow. You can make it nullable instead of using late,
DialogflowGrpcV2Beta1? dialogflow;
Now the place where you will use, you can do a null check.
Also a better way of doing this using FutureBuilder.
Future<DialogflowGrpcV2Beta?> initPlugin()async{
final serviceAccount = ServiceAccount.fromString(
'${(await rootBundle.loadString('assets/credentials2.json'))}');
// Create a DialogflowGrpc Instance
return DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
}
late final Future<DialogflowGrpcV2Beta> dialogflowFuture = initPlugin();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future:dialogflowFuture,
builder: (context, snapshot) {
if(snapshot.hasError) return Text("Got Error");
if (snapshot.hasData){
final dialogflow = snapshot.data;
return Column(children: <Widget>[...
}
return CircularProgressIndicator(); //last
More about using FutureBuilder

You can make nullable instead of using late.
DialogflowGrpcV2Beta1? dialogflow;
Try it, This one will work for you.

Related

My search bar is not filtering any data from listview. Can anyone tell me what's wrong with my onItemChanged() function and how to solve the issue?

The app only shows listview but doesn't filter any data.
If I type anything in searchbar the list view remains same
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => new _HomeState();
}
class _HomeState extends State<Home> {
Future<List> getData() async {
final response =
await http.get(Uri.parse("http://192.168.0.166/api/conn2.php"));
return json.decode(response.body);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("MY APP"),
),
body: Center(child: ListSearch()));
}
}
class ListSearch extends StatefulWidget {
ListSearchState createState() => ListSearchState();
}
class ListSearchState extends State<ListSearch> {
TextEditingController _textController = TextEditingController();
List newList = [];
onItemChanged(String value) {
setState(() {
newList = MyStatelessWidget(
list: [],
)
.list
.where((string) => string.toLowerCase().contains(value.toLowerCase()))
.toList(); //copying api data into newList
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Search here....",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: Icon(Icons.search),
suffixIcon: IconButton(
onPressed: _textController.clear,
icon: Icon(Icons.clear),
),
),
onChanged: onItemChanged, //onItemChanged() called here
),
),
Expanded(
child: new FutureBuilder<List>(
future: _HomeState().getData(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? new MyStatelessWidget(
list: snapshot.data ?? [],
)
: new Center(
child: CircularProgressIndicator(),
);
},
),
)
],
),
);
}
}
The database contains 'Articles','Features', 'Features2','Description' table
class _ArticleDescription extends StatelessWidget {
const _ArticleDescription({
Key? key,
required this.articles,
required this.features,
required this.features2,
//required this.description,
}) : super(key: key);
final String articles;
final String features;
final String features2;
// final String description;
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
articles,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const Padding(padding: EdgeInsets.only(bottom: 2.0)),
Text(
features,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
features2,
style: const TextStyle(
fontSize: 12.0,
color: Colors.black87,
),
),
/*Text(
description,
style: const TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),*/
],
),
),
],
);
}
}
Custom list view
class CustomListItemTwo extends StatelessWidget {
const CustomListItemTwo({
Key? key,
required this.thumbnail,
required this.articles,
required this.features,
required this.features2,
// required this.description,
}) : super(key: key);
final Widget thumbnail;
final String articles;
final String features;
final String features2;
//final String description;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: SizedBox(
height: 80,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 0.8,
child: thumbnail,
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 0.0, 2.0,0.0),
child: _ArticleDescription(
articles: articles,
features: features,
features2: features2,
// description: description,
),
),
)
],
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
final List list;
//final List<String> list;
const MyStatelessWidget({ required this.list});
//const MyStatelessWidget({Key? key, required this.list}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null ? 0 : list.length,
itemBuilder: (context, i) {
return Container(
padding: const EdgeInsets.all(10.0),
child: new GestureDetector(
onTap: ()=>Navigator.of(context).push(
new MaterialPageRoute(
builder: (BuildContext context)=> new Detail(list:list , index: i,)
)
),
child:Column(
children:<Widget> [
CustomListItemTwo(
thumbnail: Container(
decoration: const BoxDecoration(color: Colors.blue),
),
articles: (list[i]['Articles']),
features: (list[i]['Features']),
features2: (list[i]['Features2']),
//description: (list[i]['Description']),
),
],
),
),
);
}
);
}
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null ? 0 : list.length,
....
To
#override
Widget build(BuildContext context) {
var activeList = searchlist ;
//create isSearchBar bool var. and change
//true if search is Active
//false if search is inActive
isSearchBar
? activeList = searchlist
: activeList = list;
return ListView.builder(
itemCount: activeList == null ? 0 : activeList.length,
....
articles: (activeList[i]['Articles']),
....

Passing stateless widget from one screen to another screen in Flutter

I am trying to create a form builder, In one screen I want have small container with icon and text with gesture detector, when I tap on the container it should contruct a new DatePicker Widget. I know how to do it in the same screen, but onTap I want construct the Datepicker in another screen.
This is Form Component Class.
class FormComponents extends StatefulWidget {
#override
_FormComponentsState createState() => _FormComponentsState();
}
class _FormComponentsState extends State<FormComponents> {
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
int _count = 0;
final formData = FormWidgetData(widget: DatePicker());
#override
Widget build(BuildContext context) {
List<Widget> datePicker = List.generate(_count, (index) => DatePicker());
return Scaffold(
appBar: AppBar(
title: Text('Form Components'),
),
body: Container(
margin: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
FormBuilder(
key: _fbKey,
initialValue: {
'date': DateTime.now(),
'accept_terms': false,
},
autovalidate: true,
child: Column(
children: <Widget>[
Builder(
builder: (BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_count = _count + 1;
});
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Date Picker'),
duration: Duration(seconds: 2),
),
);
},
child: Container(
margin: EdgeInsets.all(16.0),
padding: EdgeInsets.all(8.0),
height: 100.0,
width: 120.0,
color: Colors.black,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Icon(
Icons.date_range,
color: Colors.white,
),
Text(
'Date Picker',
style: TextStyle(
color: Colors.white, fontSize: 18.0),
),
],
),
),
);
},
),
Container(
height: 200.0,
margin: EdgeInsets.all(8.0),
child: Expanded(
child: ListView(
children: datePicker,
),
),
),
],
),
),
],
),
),
);
}
}
This is my Date Picker Class
class DatePicker extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: FormBuilderDateTimePicker(
attribute: 'date',
inputType: InputType.date,
format: DateFormat('yyyy-MM-dd'),
decoration: InputDecoration(labelText: 'AppointmentTime'),
),
);
}
}
This is my Form Builder Class, How to do I Construct the above Date Picker class here.
class MyFormBuilder extends StatefulWidget {
final FormWidgetData data;
MyFormBuilder({this.data});
#override
_MyFormBuilderState createState() => _MyFormBuilderState();
}
class _MyFormBuilderState extends State<MyFormBuilder> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Builder'),
),
body: Container(
height: 300.0,
margin: EdgeInsets.all(8.0),
child: Expanded(
child: ListView(
children: <Widget>[],
),
),
),
);
}
}

Navigate Flat Button to Another Screen from Bottom Navigation Bar Item current Index using Provider

I created a provider using the provider package that tells if an item on the BottomNavigationBar is pressed, so that the page displayed matches the item from the BottomNavigationBar on the body properties of the Scaffold. I've made a screen with TextFormField and FlatButton on the first BottomNavigationBar item. what I want to do is, I want to add all the data that has been entered in TextFromField to the third screen item from the BottomNavigationBar that I have created, and then display the third item page from the BottomNavigationBar that was added to the data through FlatButton on first screen.
I have been searching for solutions to this problem for days, but I also haven't found the answer.
My provider for BottomNavigationBar
import 'package:flutter/material.dart';
class Index with ChangeNotifier {
int _currentindex = 0;
get currentindex => _currentindex;
set currentindex(int index){
_currentindex = index;
notifyListeners();
}
}
My Scaffold
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/View/bignote_screen.dart';
import 'package:kakeiboo/View/daily_screen.dart';
import 'package:provider/provider.dart';
import 'package:kakeiboo/controller/notifier.dart';
import 'package:kakeiboo/constant.dart';
class BottomNavigate extends StatefulWidget {
#override
_BottomNavigateState createState() => _BottomNavigateState();
}
class _BottomNavigateState extends State<BottomNavigate> {
var currentTab = [
BigNotePage(),
DailyExpensesPage(),
BalancePage(),
];
#override
Widget build(BuildContext context) {
var provider = Provider.of<Index>(context);
return Scaffold(
resizeToAvoidBottomInset: false,
body: currentTab[provider.currentindex],
bottomNavigationBar: BottomNavigationBar(
onTap: (index) {
provider.currentindex = index;
},
currentIndex: provider.currentindex,
backgroundColor: Color(0xff2196f3),
showUnselectedLabels: false,
selectedItemColor: Color(0xffffffff),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text(
'Big Note',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.receipt),
title: Text(
'Daily',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: Text(
'Balance',
style: kBottomNavigateStyle,
),
),
],
),
);
}
}
My First Screen
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/constant.dart';
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
bool _validate = false;
final _formKey = GlobalKey<FormState>();
final _incomeController = TextEditingController();
final _expensesController = TextEditingController();
final _savingsController = TextEditingController();
#override
void dispose() {
_incomeController.dispose();
_expensesController.dispose();
_savingsController.dispose();
super.dispose();
}
void cek() {
String income = _incomeController.text;
String expenses = _expensesController.text;
String savings = _savingsController.text;
if (int.parse(income) >= int.parse(expenses) + int.parse(savings)) {
_formKey.currentState.save();
Navigator.push(context, MaterialPageRoute(builder: (context)=>BalancePage()));
} else {
setState(() {
_validate = true;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
controler: _incomeController,
label: 'Income',
),
TxtField(
controler: _expensesController,
label: 'Expenses',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
TxtField(
controler: _savingsController,
label: 'Savings',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14.0),
onPressed: cek,
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.controler, this.error});
final String label;
final TextEditingController controler;
final String error;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
controller: controler,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
errorText: error,
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
My Third Screen
import 'package:flutter/material.dart';
import 'package:kakeiboo/constant.dart';
class BalancePage extends StatefulWidget {
#override
_BalancePageState createState() => _BalancePageState();
}
class _BalancePageState extends State<BalancePage> {
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Balance'),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Savings',
style: TextStyle(fontSize: 24.0),
),
Row(
textBaseline: TextBaseline.alphabetic,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text('IDR'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'5.000.000',
style: TextStyle(
fontSize: 56.0, color: Colors.green),
),
),
],
),
],
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Budget',
style: TextStyle(fontSize: 24.0),
),
Row(
textBaseline: TextBaseline.alphabetic,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text('IDR'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'5.000.000',
style: TextStyle(
fontSize: 56.0, color: Colors.red),
),
),
],
),
],
),
),
],
),
),
)
],
),
);
}
}
My First Screen Look
My Third Screen Look
Because you're already using Provider I would suggest using a PageController instead of your class Index(), this is because it will do exactly the same but PageController has some other advantages (as controlling a PageView, and it's already there to avoid more boilerplate when changing page)
//Your Savings model
class MySavings{
int savings = 0;
int income = 0;
int expenses = 0;
}
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/View/bignote_screen.dart';
import 'package:kakeiboo/View/daily_screen.dart';
import 'package:provider/provider.dart';
import 'package:kakeiboo/controller/notifier.dart';
import 'package:kakeiboo/constant.dart';
//import your Savings model
class BottomNavigate extends StatefulWidget {
#override
_BottomNavigateState createState() => _BottomNavigateState();
}
class _BottomNavigateState extends State<BottomNavigate> {
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose(){
super.dispose();
_pageController?.dispose();
}
#override
Widget build(BuildContext context) {
var provider = Provider.of<Index>(context);
return MultiProvider(
providers: [
ChangeNotifierProvider<PageController>.value(value: _pageController), //now the PageController can be seen as any other Provider
Provider<MySavings>(create: (_) => MySavings())
],
child: Scaffold(
resizeToAvoidBottomInset: false,
body: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(), //So the user doesn't scroll and move only when you pressed the buttons
children: <Widget>[
BigNotePage(),
DailyExpensesPage(),
BalancePage(),
],
),
bottomNavigationBar: MyBottomBar()
)
);
}
}
class MyBottomBar extends StatlessWidget{
#override
Widget build(BuildContext context){
final PageController pageController = Provider.of<PageController>(context, listen: false);
final int index = context.select<PageController, int>((pageController) => pageController.hasClients ? pageController.page.round() : pageController.initialPage);// the index the pageController currently is (if there is no client attached it uses the initialPAge that defaults to index 0)
return BottomNavigationBar(
onTap: (index) {
pageController.jumpToPage(index);
//In case you want it animated uncomment the next line and comment jumpToPage()
//pageController.animateToPage(index, duration: const Duration(milliseconds: 300), curve: Curves.ease);
},
currentIndex: index,
backgroundColor: Color(0xff2196f3),
showUnselectedLabels: false,
selectedItemColor: Color(0xffffffff),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text(
'Big Note',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.receipt),
title: Text(
'Daily',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: Text(
'Balance',
style: kBottomNavigateStyle,
),
),
],
),
);
}
}
Now in SCREEN 1
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/constant.dart';
//import your Savings model
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
bool _validate = false;
final _formKey = GlobalKey<FormState>();
final _incomeController = TextEditingController();
final _expensesController = TextEditingController();
final _savingsController = TextEditingController();
#override
void dispose() {
_incomeController.dispose();
_expensesController.dispose();
_savingsController.dispose();
super.dispose();
}
void cek() {
String income = _incomeController.text;
String expenses = _expensesController.text;
String savings = _savingsController.text;
if (int.parse(income) >= int.parse(expenses) + int.parse(savings)) {
final PageController pageController = Provider.of<PageController>(context, listen: false);
final MySavings mySavings = Provider.of<MySavings>(context, listen: false);
mySavings..income = int.parse(income)..expenses = int.parse(expenses)..savings= int.parse(savings);
_formKey.currentState.save();
pageController.jumpToPage(2); //Index 2 is BalancePage
//In case you want it animated uncomment the next line and comment jumpToPage()
//pageController.animateToPage(2, duration: const Duration(milliseconds: 300), curve: Curves.ease);
} else {
setState(() {
_validate = true;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
controler: _incomeController,
label: 'Income',
),
TxtField(
controler: _expensesController,
label: 'Expenses',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
TxtField(
controler: _savingsController,
label: 'Savings',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14.0),
onPressed: cek,
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.controler, this.error});
final String label;
final TextEditingController controler;
final String error;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
controller: controler,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
errorText: error,
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
And finally in SCREEEN 3 you just call
final MySavings mysavings = Provider.of<MySavings>(context, listen: false);
and use its values (savings, expenses and income) to display in each Text, do some math if you want or change its value (If you want to update as soon as you change them then make MySavings a ChangeNotifier).
If you dont't want to use PageView and stick with the Index class just check the logic and change all the PageController with your index provider and it should work the same
You could save the TextFormField value to a provider property, this way it will be available on all screens

How to change price on button pressed in flutter

SCENARIO
I have a dummy image, under image there is price and under price there three widget
Two widget are buttons (+) and (-) and one widget is Text('1') which is a QTY.
QUESTION
When i click on the button it increment and decrement the number but how do i change the price based on QTY (if QTY is 2 then price must be double)
class Quantities extends StatefulWidget {
final productprice;
final productimage;
Quantities({this.productprice, this.productimage});
#override
_QuantitiesState createState() => _QuantitiesState(productprice,productimage);
}
class _QuantitiesState extends State<Quantities> {
int counter = 1;
final productprice;
final productimage;
_QuantitiesState(this.productprice, this.productimage);
void increment() {
setState(() {
counter++;
});
}
void decrement() {
setState(() {
counter--;
});
}
#override
Widget build(BuildContext context) {
return PlatformScaffold(
appBar: PlatformAppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Quantities'),
),
body: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ListView(
children: <Widget>[
new Container(
height: 200.0,
child: GridTile(
child: Container(
color: Colors.white,
child: Image.asset(productimage),),),),
Center(
child: Text(
productprice,),),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: PlatformButton(
onPressed: () {
decrement();
if (counter < 1) {
counter = 1;
}
},
child: Text(
'-',
),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),
),
Text(
'$counter',
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: PlatformButton(
onPressed: () {
increment();
},
child: Text(
'+',
style: TextStyle(color: Colors.white, fontSize: 30.0),
),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),
this is the full code example:
import 'package:flutter/material.dart';
import 'package:project_app/proyects/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Product price',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Quantities(productimage: "",productprice: "20$",),
);
}
}
class Quantities extends StatefulWidget {
final productprice;
final productimage;
Quantities({this.productprice, this.productimage});
#override
_QuantitiesState createState() =>
_QuantitiesState(productprice, productimage);
}
class _QuantitiesState extends State<Quantities> {
int counter = 1;
final productprice;
double finalprice;
final productimage;
final productp =productprice.replaceAll(new RegExp(r'\$'), '');
_QuantitiesState(this.productprice, this.productimage);
void increment() {
setState(() {
counter++;
finalprice=double.parse(productp)*counter;
});
}
void decrement() {
setState(() {
counter--;
finalprice=double.parse(productp)*counter;
});
}
#override
void initState() {
super.initState();
finalprice= double.parse(productp);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Quantities'),
),
body: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ListView(
children: <Widget>[
Center(
child: Text(
finalprice.toString(),
),
),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: FlatButton(
onPressed: () {
if (counter > 1) {
decrement();
}
},
child: Text(
'-',
),
),
),
Text(
'$counter',
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: FlatButton(
onPressed: () {
increment();
},
child: Text(
'+',
style:
TextStyle(color: Colors.white, fontSize: 30.0),
),
),
),
]),
),
],
),
));
}
}
In this case you need to multiply the value of product price in
setstate(){
productprice=productprice*counter;
}
or
productprice*=counter;

How to update my ListView in Flutter and Solve problem with StateFull Widget?

My goal is to reach the updating of Listview. I have questions about my code. But I have to tell foreword about my problem. I used setState(), and I wasn't understanding, why this function didn't work and I realized that use Stateless widget.
I used this code
class _ListItem extends StatelessWidget {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
Lately, I changed class _ListItem to Stateful Widget
I used this code
class ListItem extends StatefulWidget {
#override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
But in outside it gives empty listview.
At this moment I used this fragment of code.
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
//some code
}
);
},
)
All code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:ui';
import 'package:samuraigym/my_icons_icons.dart' as custicon;
import 'package:samuraigym/program_training_handler.dart';
class MeasurementsScreen extends StatefulWidget {
#override
_MeasurementsScreenState createState() => _MeasurementsScreenState();
}
class _MeasurementsScreenState extends State<MeasurementsScreen> {
List<_ListItem> listItems;
String lastSelectedValue;
var name = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var nameItem = ["Рост", "Вес","Грудь","Плечи","Бицепс"];
var indication = ["Введите ваш рост", "Введите ваш вес"];
var indicationItem = ["Введите ваш рост", "Введите ваш вес"];
TextEditingController customcintroller;
void navigationPageProgrammTrainingHandler() {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => ProgrammTrainingHandler()),
);
}
#override
void initState() {
super.initState();
initListItems();
}
Future<String> createAlertDialog(BuildContext context, int indexAl) async{
customcintroller = TextEditingController();
if(indexAl < 2){
String returnVal = await showDialog(context: context, builder: (context){
return AlertDialog(
title: Text(name[indexAl]),
content: TextField(
textDirection: TextDirection.ltr,
controller: customcintroller,
style: TextStyle(
color: Colors.lightGreen[400],
fontSize: 18.5),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 4.0),
labelText: indication[indexAl],
alignLabelWithHint: false,
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.done,
),
actions: <Widget>[
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ОК'),
onPressed: () {
setState(() {
indicationItem[indexAl] = customcintroller.text.toString();
Navigator.of(context).pop();
});
},
),
],
);
});
} else if (indexAl > 1){
navigationPageProgrammTrainingHandler();
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xff2b2b2b),
appBar: AppBar(
title: Text(
'Замеры',
style: new TextStyle(
color: Colors.white,
),),
leading: IconButton(
icon:Icon(Icons.arrow_back),
color: Colors.white ,
onPressed:() => Navigator.of(context).pop(),
),
),
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index].widget,
onTap: () {
createAlertDialog(context, index).then((onValue){
indicationItem[index] = onValue.toString();
});
}
);
},
),
);
}
void initListItems() {
listItems = [
new _ListItem(
bgName: 'assets/images/soso_growth.jpg',
name: nameItem[0],
detail: "Нажми, чтобы добавить свой рост"),
new _ListItem(
bgName: 'assets/images/soso_weight.jpg',
name: nameItem[1],
detail: "Нажми, чтобы добавить свой вес"),
new _ListItem(
bgName: 'assets/images/soso_chest.jpg',
name: nameItem[2],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_shoulder.jpg',
name: nameItem[3],
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_biceps.jpg',
name: nameItem[4],
detail: "PRO-версия")
];
}
}
class ListItem extends StatefulWidget {
#override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
Help me, please. I can't solve the problem some days))
If you want to send data in the stateful widget you have to do this in the stateful class itself, not in the state
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
#override
_ListItem createState() => _ListItem();
}
to access it in the state class do it like this :
//somecode
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
//some code
to change the state in the stateful widget call the setState method when you tap on the widget for example , add gesture detector or InkWell to add on tap functionality
and call set state in it.
make a List of ListItem to use it in list view builder ,
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
ListView.builder(
itemCount:items.length,
itemBuilder: (context,index)=>items[index];
);
Complete Example
class ListItem extends StatefulWidget {
String bgName;
String name;
String detail;
ListItem({Key key, this.bgName, this.name, this.detail}) : super(key: key);
#override
_ListItem createState() => _ListItem();
}
class _ListItem extends State<ListItem> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
print(widget.bgName);
//call setState here;
setState(() {
widget.bgName = 'this item is tapped';
});
},
child: Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(widget.bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
widget.name,
style:
new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
widget.detail,
style: new TextStyle(
fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
),
);
}
}
List<ListItem> items = [ ListItem(bgName: ' the bgName' ,name :'the
name',detail:'details'),
//add another Items here
];
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return
listItems[index]
;
},
)
I hope that can help.
what solved the problem for me is to wrap your widget (the one that your builder return) in a container with a unique key .
In my case i was returning a stateless widget in the builder so here is the code that worked for me.
this is the return statement from my listView Builer
return new Container(child: CouponWidget(coupons[position],true),
key:UniqueKey()
);