How to get radio button value to int and calculate in flutter - flutter

I just started to learn Flutter/Dart as my lecturer ask me to do some simple mobile app of e-ticket where the user need to choose from the radio button the movie that have value price for each radio button . Then the user need to input quantity value then click the submit button where the result of calculation need to be shown in another result page. Below is the picture of the assignment and some code that i have done. But i got stuck in the calculation part where i did not find any solution to this. hope anyone can help me with this.
main dart
main dart
import 'package:flutter/material.dart';
import 'result.dart';
import 'customer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
enum SingingCharacter { avengers, batman, kimetsu }
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final txtName= TextEditingController();
final txtEmail = TextEditingController();
final txtQuantity = TextEditingController();
SingingCharacter? _character = SingingCharacter.avengers;
void _gotoResultScreen(){
Customer c= Customer(txtName.text, txtEmail.text, int.parse(txtQuantity.text));
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultPage(
title:"Result Screen",
content:"Congratulation! You've reached this page",
customer: c,)
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Name'),
TextField(
controller: txtName,
),
Text('Email'),
TextField(
controller: txtEmail,
),
Text('Choose a movie:'),
ListTile(
title: const Text('AVENGERS(RM20)'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.avengers,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
),
ListTile(
title: const Text('BATMAN(RM10)'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.batman,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
}
),
),
ListTile(
title: const Text('KIMETSU NO YAIBA(RM12)'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.kimetsu,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
}
),
),
Text('quantity'),
TextField(
controller: txtQuantity,
),
RaisedButton(
onPressed:_gotoResultScreen,
//do something
child: new Text('Calculate'),
),
],
),
),
);
}
}
result.dart
import 'package:flutter/material.dart';
import 'customer.dart';
class ResultPage extends StatefulWidget {
const ResultPage({Key? key, required this.title, required this.content, required this.customer}) : super(key: key);
final String title;
final String content;
final Customer customer;
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(widget.content,),
Text("Name:" + widget.customer.name),
Text("Email: " + widget.customer.email),
Text("Quantity:" + widget.customer.quantity.toString()),
],
),
),
);
}
}
customer.dart
class Customer {
final String name;
final String email;
final int quantity;
const Customer(this.name, this.email, this.quantity);
}

You can use Map<String, int> to store the movie name and its price. Then create the List<Map<String, int>> and use the .map() function on this list to covert the list into listTile.

You should pass necessary arguments to result page. You passed Customer, that is ok. But movie info is missing. For example:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultPage(
title:"Result Screen",
content:"Congratulation! You've reached this page",
customer: c,
movieName: ...,
price: ...,
)
),
);
And of course you should edit Result page accordingly.
After go to result page. Use price data and multiply quantity. This is gonna be final price.
However, this is not a good approach, Instead of using this kind of solutions, I recommend create a Movie class like Customer. Also quantity info should not be a field of Customer, it should be field of Movie class.

You can calculate the price like this.
Let's say your _character value is SingingCharacter.avengers
int price = getPriceFromCharacter(_character) * int.parse(txtQuantity.text);
getPriceFromCharacter(SingingCharacter? character) {
switch(character) {
case SingingCharacter.avengers: {
return 20;
}
case SingingCharacter.batman: {
return 10;
}
case SingingCharacter.kimetsu: {
return 12;
}
}
}
void _gotoResultScreen(){
int price = getPriceFromCharacter(_character) * int.parse(txtQuantity.text);
Customer c= Customer(txtName.text, txtEmail.text, int.parse(txtQuantity.text));
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultPage(
title:"Result Screen",
content:"Congratulation! You've reached this page",
customer: c,)
),
);
}

This is the answer to the solution above.
main.dart
import 'package:flutter/material.dart';
import 'calculate.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'eTicket'),
);
}
}
enum ticketName {Avengers,Batman,Kimetsu}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _name = new TextEditingController();
final TextEditingController _email = new TextEditingController();
final TextEditingController _quantity = new TextEditingController();
final formKey = GlobalKey<FormState>();
String name = "";
String email = "";
String quantity = "";
String movieName = "";
String ticketPrice = "";
ticketName? _movieName = ticketName.Avengers;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.symmetric (
horizontal: 20,),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Name',textAlign: TextAlign.left),
const Padding (
padding: EdgeInsets.symmetric(vertical: 5.0),
),
TextFormField(
validator: (value) {
if(value!.isEmpty ){
return 'Please Enter Your Name';
}
},
onSaved: (value){
name = value!;
},
controller: _name,
decoration: InputDecoration(
hintText: '',
filled: true,
fillColor: Colors.black.withOpacity (0.2),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular (10))),
),
const SizedBox(
height: 5,
),
const Padding (
padding: EdgeInsets.symmetric(vertical: 5.0),
),
const Text('Email',textAlign: TextAlign.left),
const Padding (
padding: EdgeInsets.symmetric(vertical: 5.0),
),
TextFormField(
validator: (value) {
if(value!.isEmpty || !value.contains('#') || !value.contains('.com'))
{
return 'Email is Invalid';
}
},
onSaved: (value){
email = value!;
},
controller: _email,
decoration: InputDecoration(
hintText: '',
filled: true,
fillColor: Colors.black.withOpacity (0.2),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular (10))),
),
const SizedBox(
height: 5,
),
const Padding (
padding: EdgeInsets.symmetric(vertical: 10.0),
),
//add radio button here
const Text("Choose a Movie: "),
const Padding (
padding: EdgeInsets.symmetric(vertical: 10.0),
),
Row(children: [
Radio(
value: ticketName.Avengers,
groupValue: _movieName,
onChanged: (ticketName?value){
setState(() {
_movieName = value;
movieName = 'Avengers (RM 20.00)';
ticketPrice = '20';
});
},
),
const SizedBox (width: 5.0,),
const Text("Avengers (RM 20.00)"),
],),
Row(children: [
//add radio button here
Radio(
value: ticketName.Batman,
groupValue: _movieName,
onChanged: (ticketName? value){
setState(() {
_movieName = value;
movieName = 'Batman (RM 10.00) ';
ticketPrice = '10';
});
},
),
const SizedBox (width: 5.0,),
const Text("Batman (RM 10.00)"),
],),
Row(children: [
//add radio button here
Radio(
value: ticketName.Kimetsu,
groupValue: _movieName,
onChanged: (ticketName? value){
setState(() {
_movieName = value;
movieName = 'Kimetsu No Yaiba (RM 12.00) ';
ticketPrice = '12';
});
},
),
const SizedBox (width: 5.0,),
const Text("Kimetsu No Yaiba (RM 12.00)"),
],),
const Padding (
padding: EdgeInsets.symmetric(vertical: 10.0),
),
const Text('Quantity',textAlign: TextAlign.left),
const Padding (
padding: EdgeInsets.symmetric(vertical: 5.0),
),
TextFormField(
validator: (value) {
if(value!.isEmpty || value.length < 0){
return 'Please Enter the Correct Quantity';
}
},
onSaved: (value){
var quantity = int.parse(value!);
},
controller: _quantity,
decoration: InputDecoration(
hintText: 'Quantity',
filled: true,
fillColor: Colors.black.withOpacity (0.2),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular (10))),
),
const SizedBox(
height: 5,
),
const Padding (
padding: EdgeInsets.symmetric(vertical: 10.0),
),
ElevatedButton(
onPressed: (){
final isValid = formKey.currentState?.validate();
if(isValid!=null) {
formKey.currentState!.save();
Navigator.push(
context, MaterialPageRoute(builder: (context) => calculatePrice(name: _name.text, movieName: movieName, ticketPrice: ticketPrice, email: _email.text, quantity: _quantity.text)));
}
},
child: const Text('Calculate'),
),
],
),
),
),
),
);
}
}
calculate.dart
import 'package:flutter/material.dart';
import 'main.dart';
class calculatePrice extends StatelessWidget {
late String name, email, movieName, ticketPrice, quantity;
calculatePrice({required this.name, required this.email, required this.quantity, required this.movieName, required this.ticketPrice});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("eTicket"),
),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric (
horizontal: 20,),
child: Column(
mainAxisAlignment: MainAxisAlignment.center ,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Name : $name'),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text('Email $email'),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text('Movie : $movieName'),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text('Quantity $quantity'),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text('Total Price : ${int.parse(quantity) * int.parse(ticketPrice) }'),
const Padding ( padding: EdgeInsets.symmetric(vertical: 10.0),),
ElevatedButton(
onPressed: (){
Navigator.push(
context, MaterialPageRoute(builder: (context) => const MyApp()));
},
child: const Text('Back'),
),
],
),
)
),
);
}
}

This is the answer based on the above code. Thank you for the suggestion and helps from the others.
main.dart
import 'package:flutter/material.dart';
import 'result.dart';
import 'customer.dart';
import 'movie.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'e-Ticket',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const MyHomePage(title: 'Movie e-Ticket'),
);
}
}
enum SingingCharacter { avengers, batman, kimetsu }
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final txtName = TextEditingController();
final txtEmail = TextEditingController();
final txtQuantity = TextEditingController();
SingingCharacter? _character = SingingCharacter.avengers;
getPriceFromCharacter(SingingCharacter? character, int quantity) {
switch (character) {
case SingingCharacter.avengers:
{
return 20 * quantity;
}
case SingingCharacter.batman:
{
return 10 * quantity;
}
case SingingCharacter.kimetsu:
{
return 12 * quantity;
}
}
}
getMovieName(SingingCharacter? character) {
switch (character) {
case SingingCharacter.avengers:
{
return "Avengers";
}
case SingingCharacter.batman:
{
return "Batman";
}
case SingingCharacter.kimetsu:
{
return "Kimetsu";
}
}
}
// this to go to result screen and show the result
void _gotoResultScreen() {
int price = getPriceFromCharacter(_character, int.parse(txtQuantity.text));
String movieName = getMovieName(_character);
Customer c = Customer(txtName.text, txtEmail.text);
Movie m = Movie(int.parse(txtQuantity.text), price, movieName);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultPage(
title: "Total Price",
content: "Here is your details",
customer: c,
movie: m,
)),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
const Text('Name', textAlign: TextAlign.left),
TextField(
controller: txtName,
decoration: InputDecoration(
hintText: '',
filled: true,
fillColor: Colors.green.withOpacity(0.2),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none
)
),
),
const Text('Email'),
TextField(
controller: txtEmail,
decoration: InputDecoration(
hintText: '',
filled: true,
fillColor: Colors.green.withOpacity(0.2),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none
),)
),
// This is for radio button in list tile
const Text('Choose a movie:'),
ListTile(
title: const Text('AVENGERS(RM20)'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.avengers,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
},
),
),
ListTile(
title: const Text('BATMAN(RM10)'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.batman,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
}),
),
ListTile(
title: const Text('KIMETSU NO YAIBA(RM12)'),
leading: Radio<SingingCharacter>(
value: SingingCharacter.kimetsu,
groupValue: _character,
onChanged: (SingingCharacter? value) {
setState(() {
_character = value;
});
}),
),
// Input Quantity of the movie
const Text('quantity'),
TextField(
controller: txtQuantity,
decoration: InputDecoration(
hintText: '',
filled: true,
fillColor: Colors.green.withOpacity(0.2),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(10)
)
),
),
// When user click calculate Button
ElevatedButton(
onPressed: _gotoResultScreen,
child: const Text('Calculate'),
),
],
),
),
);
}
}
movie.dart
class Movie {
final int quantity;
final int totalPrice;
final String movieName;
const Movie( this.quantity,this.totalPrice,this.movieName);
}
result.dart
import 'package:e_tickets/main.dart';
import 'package:flutter/material.dart';
import 'customer.dart';
import 'movie.dart';
class ResultPage extends StatefulWidget {
const ResultPage({Key? key, required this.title, required this.content, required this.customer, required this.movie}) : super(key: key);
final String title;
final String content;
final Customer customer;
final Movie movie;
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(widget.content,),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text("Name: " + widget.customer.name),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text("Email: " + widget.customer.email),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text("Quantity: " + widget.movie.quantity.toString()),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text("Movie Name: " + widget.movie.movieName),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
Text("Total Price: RM" + widget.movie.totalPrice.toString()),
const Padding ( padding: EdgeInsets.symmetric(vertical: 5.0),),
ElevatedButton(
onPressed: (){
Navigator.push(
context, MaterialPageRoute(builder: (context) => const MyApp()));
},
child: const Text('Back'),
),
],
),
),
);
}
}
customer.dart
class Customer {
final String name;
final String email;
const Customer(this.name, this.email);
}

Related

My Flutter ListView is always removing the last item from the list

I'm creating a Flutter Widget and when I try to remove an item from the list I'm using, it always removes the last one, I was thinking it could be a Key problem, but nothing suits it, do anyone know how I could solve this?
The code
create_game.dart
import 'package:flutter/material.dart';
import 'package:pontinho/components/custom_input.dart';
class CreateGame extends StatefulWidget {
const CreateGame({super.key});
#override
State<CreateGame> createState() => _CreateGameState();
}
class _CreateGameState extends State<CreateGame> {
List<String> names = [''];
void changeName(int nameIndex, String change) {
setState(() {
names[nameIndex] = change;
});
}
void removeName(int nameIndex) {
print(names);
print(nameIndex);
setState(() {
names.removeAt(nameIndex);
});
}
ListView createNamesInput() {
return ListView.builder(
itemCount: names.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
key: ObjectKey(index),
title: CustomInput(
key: ObjectKey(index),
labelText: "Nome",
onChanged: (String changed) => changeName(index, changed),
text: names[index],
onRemoved: () => removeName(index),
),
);
},
);
// return names
// .asMap()
// .entries
// .map((el) => CustomInput(
// key: ObjectKey('${el.key}'),
// labelText: "Nome",
// onChanged: changeName,
// index: el.key,
// text: names[el.key],
// onRemoved: removeName,
// ))
// .toList();
}
void addName() {
setState(() {
names.add('');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: GestureDetector(
onTap: (() => Navigator.pop(context)),
child: const Icon(
Icons.arrow_back,
color: Colors.black,
size: 40,
),
),
backgroundColor: Colors.white,
titleTextStyle: const TextStyle(
color: Colors.black,
fontSize: 20,
),
title: const Text("CRIE SEU JOGO"),
),
body: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16,
),
// child: createNamesInput(),
child: Column(
children: [
createNamesInput(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: addName,
child: Row(
children: const [
Icon(Icons.add),
Text('Adicionar Jogador'),
],
),
),
],
),
),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () => print('Iniciar!'),
child: const Text('Iniciar!'),
),
)
],
),
),
);
}
}
custom_input.dart
import 'package:flutter/material.dart';
typedef OneArgumentCallback = void Function(String changed);
class CustomInput extends StatefulWidget {
final OneArgumentCallback onChanged;
final VoidCallback onRemoved;
final String labelText;
final String text;
const CustomInput({
super.key,
required this.onChanged,
required this.labelText,
required this.text,
required this.onRemoved,
});
#override
State<CustomInput> createState() => _CustomInputState();
}
class _CustomInputState extends State<CustomInput> {
late final TextEditingController inputController;
#override
void initState() {
super.initState();
inputController = TextEditingController(text: widget.text);
}
void changeContent(String value) {
widget.onChanged(
value,
);
}
#override
Widget build(BuildContext context) {
return TextFormField(
key: widget.key,
controller: inputController,
textDirection: TextDirection.ltr,
decoration: InputDecoration(
border: const UnderlineInputBorder(),
labelText: widget.labelText,
suffixIcon: IconButton(
onPressed: () => widget.onRemoved(),
icon: const Icon(
Icons.close,
color: Colors.red,
),
),
),
autocorrect: false,
onChanged: (value) => changeContent(value),
);
}
}
Indeed it is a key issue, you have to create a combined key that must be unique for each item, I merged the index with names[index],
CustomInput(
key: ObjectKey('$index:${names[index]}'),
labelText: "Nome",
onChanged: (String changed) => changeName(index, changed),
text: names[index],
onRemoved: () => removeName(index),
),
note that if you try this code alone the textfield will lose focus because the key has changed, this will be solved by removing the setState inside the onChange
void changeName(int nameIndex, String change) {
names[nameIndex] = change;
}
here you don't need setState because the UI will be updated by default when you are typing in the textfield
I hope I made it clear
I was thinking it could be a Key problem
That's correct; You need to use names[index] as the value for your Key:
ListTile(
key: ObjectKey(names[index]),
title: CustomInput(

How to call setsate function from a different widget?

Well, I am coding a chatbot-like page in my app. But, I am stuck at calling setState function for page inside of chatBubble widget. Here is my page as MedicBot and chat question code as FirstQuestion. What I do want to do that whenever, user triggers radio tile's on tap condition. It should be trigger setState function in MedicBot, any suggestions?
import 'package:medicte/assets/back_button.dart';
import 'package:medicte/assets/first_question.dart';
class MedicBot extends StatefulWidget {
const MedicBot({Key? key}) : super(key: key);
#override
State<MedicBot> createState() => _MedicBotState();
}
class _MedicBotState extends State<MedicBot> {
late final List<Widget> _messages;
late final List<dynamic> botMessages;
FocusNode _focusNode = FocusNode();
setMainState() {
print('bum');
this.setState(() {});
}
#override
void initState() {
print('bumbeyarag');
botMessages = [
_buildChatBubbles(
widget: SizedBox.shrink(),
text:
'Do you have further medical information you can share? (e.g. lab results)',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: ['1-2 weeks', 'A Month', '1-3 Months', 'Other'],
setMainState: setMainState,
),
text: 'Where do you currently live?',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: [
'Online Consultation',
'Second Opinion',
'A treatment cost',
'Other'
],
setMainState: setMainState,
),
text: 'How soon do you want to get the treatment done?',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: ['Yes', 'No'],
setMainState: () {
setState(() {});
},
),
text: 'What service are you looking for?',
userControl: false),
_buildChatBubbles(
widget: FirstQuestion(
focus: _focusNode,
radioButtons: [],
setMainState: () {
setState(() {});
},
),
text: 'Have you already spoken a doctor?',
userControl: false),
_buildChatBubbles(
text: 'Which treatment are you interested in?',
userControl: false,
widget:
const Text('Enter a treatment name (e.g Hair Transplant, IVF)')),
_buildChatBubbles(
text: 'You are inquiring for',
userControl: false,
widget: FirstQuestion(
radioButtons: const ['Myself', 'For someone else'],
focus: _focusNode,
setMainState: () {
setState(() {});
},
)),
];
_messages = [
const SizedBox(
height: 1,
),
const SizedBox(
height: 10,
)
];
super.initState();
}
final TextEditingController _controller = TextEditingController();
bool value = false;
#override
Widget build(BuildContext context) {
if (botMessages.isNotEmpty) {
_messages.insert(1, botMessages.removeLast());
}
return Scaffold(
bottomSheet: Container(
color: Colors.white30,
child: Padding(
padding: const EdgeInsets.only(bottom: 30, right: 15, left: 15),
child: TextFormField(
focusNode: _focusNode,
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25),
),
hintText: 'Type your message',
suffixIcon: IconButton(
onPressed: () {
print(_controller.text);
print(_controller.value);
setState(() {
_messages.insert(
1,
_buildChatBubbles(
text: _controller.text,
userControl: true,
widget: const SizedBox.shrink()));
_controller.clear();
});
},
icon: const Icon(Icons.send),
),
),
),
),
),
appBar: AppBar(
leadingWidth: 101,
backgroundColor: Colors.blue.shade300,
leading: Row(
children: [
const BackWardButton(),
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: Container(
color: Colors.white,
child: Image.asset(
'lib/images/Lovepik_com-401792159-medical-robot.png',
height: 53,
width: 53),
),
),
],
),
title: const Text(
"MedicBot",
style: TextStyle(color: Colors.black54),
),
),
body: SafeArea(
minimum:
const EdgeInsets.only(top: 2, left: 10, right: 10, bottom: 90),
child: ListView.builder(
itemCount: _messages.length,
reverse: true,
itemBuilder: ((context, index) {
return _messages[index];
}),
)));
}
}
class _buildChatBubbles extends StatelessWidget {
bool userControl;
String text;
Widget widget;
_buildChatBubbles(
{required this.widget,
required this.text,
required this.userControl,
super.key});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 10),
child: Row(
mainAxisAlignment:
userControl ? MainAxisAlignment.end : MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
userControl
? const SizedBox.shrink()
: Container(
margin: const EdgeInsets.only(right: 10),
child: const CircleAvatar(
radius: 20,
backgroundImage: AssetImage(
'lib/images/Lovepik_com-401792159-medical-robot.png'),
),
),
Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.4,
maxWidth: MediaQuery.of(context).size.width * 0.6),
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: userControl ? Colors.green.shade300 : Colors.blue.shade300,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 7,
offset: const Offset(0, 3), // changes position of shadow
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
userControl ? 'You' : 'Medicte Bot',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 5),
Flexible(
child: Text(
text,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
),
),
),
widget
],
),
),
],
),
);
;
}
}
import 'package:flutter/material.dart';
import 'package:group_button/group_button.dart';
import 'package:medicte/pages/chat_ui.dart';
// ignore: must_be_immutable
class FirstQuestion extends StatefulWidget {
List<String> radioButtons;
FocusNode focus;
void Function() setMainState;
FirstQuestion(
{required this.setMainState,
required this.focus,
required this.radioButtons,
Key? key})
: super(key: key);
#override
State<FirstQuestion> createState() => _FirstQuestionState();
}
class _FirstQuestionState extends State<FirstQuestion> {
late GroupButtonController _radioController;
// ignore: prefer_typing_uninitialized_variables
late final _radioButtons;
#override
void initState() {
_radioButtons = widget.radioButtons;
_radioController = GroupButtonController(
selectedIndexes: [0, 1, 2, 3],
);
super.initState();
}
#override
Widget build(BuildContext context) {
return GroupButton(
controller: _radioController,
isRadio: true,
options: const GroupButtonOptions(groupingType: GroupingType.column),
buttons: _radioButtons,
buttonIndexedBuilder: (selected, index, context) {
return RadioTile(
title: _radioButtons[index],
selected: _radioController.selectedIndex,
index: index,
onTap: () {
print(_radioButtons[index].toString());
widget.setMainState();
_radioController.selectIndex(index);
/* Future.delayed(Duration(seconds: 1), () {
widget.setMainState();
}); */
},
);
},
onSelected: (val, i, selected) {
print('object');
});
}
}
class RadioTile extends StatelessWidget {
const RadioTile({
Key? key,
required this.selected,
required this.onTap,
required this.index,
required this.title,
}) : super(key: key);
final String title;
final int index;
final int? selected;
final VoidCallback onTap;
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
onTap: onTap,
leading: Radio<int>(
groupValue: selected,
value: index,
onChanged: (val) {
print(val);
onTap();
},
),
);
}
}
Try something like this. This is the code snippet of an application of mine. I used StatefulBuilder as the parent of the widgets I want to update and I sent the setState parameter to the widget where I trigger.
import 'package:flutter/material.dart';
class CryptoassetsPage extends StatefulWidget {
const CryptoassetsPage({Key? key}) : super(key: key);
#override
_CryptoassetsPageState createState() => _CryptoassetsPageState();
}
class _CryptoassetsPageState extends State<CryptoassetsPage> {
#override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).backgroundColor,
child: SingleChildScrollView(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
//My other class/widget
return OrderOptions(setState);
}),
),
);
}
}
class OrderOptions extends StatefulWidget {
const OrderOptions(this.setState, {Key? key}) : super(key: key);
final StateSetter setState;
#override
_OrderOptionsState createState() => _OrderOptionsState();
}
class _OrderOptionsState extends State<OrderOptions> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
StateSetter setState = widget.setState;
setState(() {});
},
);
}
}

The following _CastError was thrown while handling a gesture: Null check operator used on a null value

So i made an Create methode for my Sqlapi. I made a test project where the create method worked. So now i try to implement it in to the real application but now i get some strange error (Shown in the image). Any help would be amazing.
Error:
All the containers are the same.
My flutter code:
import 'package:flutter/material.dart';
import 'package:schepp/main.dart';
import '../Data_provider/api_service.dart';
import '../Model/KlantModel.dart';
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const appTitle = 'Inloggen';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: appTitle,
home: Registerenpage(
title: appTitle
),
);
}
}
class Registerenpage extends StatefulWidget {
const Registerenpage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_RegisterenpageState createState() => _RegisterenpageState();
}
class _RegisterenpageState extends State<Registerenpage> {
_RegisterenpageState();
final ApiService api = ApiService();
final _addFormKey = GlobalKey<FormState>();
final _mailaddres = TextEditingController();
final _wachtwoord = TextEditingController();
final _klantvoornaam = TextEditingController();
final _tussenvoegsel = TextEditingController();
final _klantachternaam = TextEditingController();
final _bedrijfsnaam = TextEditingController();
final _telefoonnummer = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SingleChildScrollView(
child: Column(
key: _addFormKey,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
Container(
margin: const EdgeInsets.only(left: 10.0, right: 10.0, top:80.0),
child: const Text("Registeren",style: TextStyle(color:Colors.white,fontSize:20),),
),
Container(),
Container(),
Container(),
Container(),
Container(
margin: const EdgeInsets.only(left: 50.0, right: 50.0),
child: Column(
children: <Widget>[
const Text('Mailaddres'),
TextFormField(
controller: _mailaddres,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
labelText: 'Mailaddress *', labelStyle: TextStyle(color:Colors.white),
),
style: const TextStyle(color: Colors.white, fontSize: 16.0,),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter mailaddres';
}
return null;
},
onChanged: (value) {},
),
],
),
),
Container(),
Container(),
Container(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
ElevatedButton(
child: const Text('Registeren', style: TextStyle(color:Colors.white,fontSize:16)),
onPressed: () {
if (_addFormKey.currentState!.validate()) {
_addFormKey.currentState!.save();
api.createCase(Cases(mailaddres: _mailaddres.text, wachtwoord: _wachtwoord.text,
klantvoornaam: _klantvoornaam.text, tussenvoegsel: _tussenvoegsel.text,
klantachternaam: _klantachternaam.text, bedrijfsnaam: _bedrijfsnaam.text,
telefoonnummer: _telefoonnummer.text));
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Loginpagina(title: widget.title),
),
);
}
},
style: ElevatedButton.styleFrom(
primary: Colors.deepOrange,
padding: const EdgeInsets.all(20),
),
)
],
),
),
]
),
),
);
}
}
This is my KlantModel:
import 'dart:convert';
List<Cases> welcomeFromJson(String str) => List<Cases>.from(json.decode(str).map((x) => Cases.fromJson(x)));
String welcomeToJson(List<Cases> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Cases {
Cases({
this.klantId,
this.mailaddres,
this.wachtwoord,
this.klantvoornaam,
this.tussenvoegsel,
this.klantachternaam,
this.bedrijfsnaam,
this.telefoonnummer,
});
int? klantId;
String? mailaddres;
String? wachtwoord;
String? klantvoornaam;
String? tussenvoegsel;
String? klantachternaam;
String? bedrijfsnaam;
String? telefoonnummer;
factory Cases.fromJson(Map<String, dynamic> json) => Cases(
klantId: json["KlantId"],
mailaddres: json["Mailaddres"],
wachtwoord: json["Wachtwoord"],
klantvoornaam: json["Klantvoornaam"],
tussenvoegsel: json["Tussenvoegsel"],
klantachternaam: json["Klantachternaam"],
bedrijfsnaam: json["Bedrijfsnaam"],
telefoonnummer: json["Telefoonnummer"],
);
Map<String, dynamic> toJson() => {
"KlantId": klantId,
"Mailaddres": mailaddres,
"Wachtwoord": wachtwoord,
"Klantvoornaam": klantvoornaam,
"Tussenvoegsel": tussenvoegsel,
"Klantachternaam": klantachternaam,
"Bedrijfsnaam": bedrijfsnaam,
"Telefoonnummer": telefoonnummer,
};
}
--------! UPDATE --------
I get this error when i press on the ElevatedButton in the last container. i'am trying to sent the information to another dart file which updates it to a rest api. if i'm correct it gets stuck at the if (_addFormKey.currentState!.validate())
You are not using Form widget. Wrap your Column with Form and use the _addFormKey on Form widget instead of Column.
child: Form(
key: _addFormKey,
child: Column(
And validator
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter mailaddres';
}
return null;
},
And
onPressed: () {
final isValidate = _addFormKey.currentState?.validate();
if (isValidate == null) {
print("got Null isValidate");
return;
}
if (isValidate) {
_addFormKey.currentState!.save();
More about Form

how to show a text field when a specific radio button is selected in flutter?

I want that when I choose home then a text field appears on the screen to input some information.
I wrapped the text field with Visibility but it didn't work.
Container(
margin: const EdgeInsets.only(top: 220,left:0),
child: RadioListTile(
title: const Text('home'),
value: place.home,
groupValue: selacted,
onChanged: (place? value) {
if(place.home==selacted) {
setState(() {
isVisible = true;
selacted= value;
});
}
}
),
),
Container(
margin: const EdgeInsets.only(top: 300,left:0),
child: Visibility(
visible:isVisible,
child:const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter a search term',
),
),
),
),
It seems you are comparing the previously selected value.
This should work:
setState(() {
_place = value;
_homeFieldVisible = value == Place.home;
});
Full code sample:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
enum Place { road, home, work }
class _HomePageState extends State<HomePage> {
Place? _place;
bool _homeFieldVisible = false;
void handleSelection(Place? value) {
setState(() {
_place = value;
_homeFieldVisible = value == Place.home;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
RadioListTile(
title: const Text('on the road'),
value: Place.road,
groupValue: _place,
onChanged: handleSelection,
),
RadioListTile(
title: const Text('at home'),
value: Place.home,
groupValue: _place,
onChanged: handleSelection,
),
if (_homeFieldVisible)
const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter a search term',
),
),
RadioListTile(
title: const Text('at work'),
value: Place.work,
groupValue: _place,
onChanged: handleSelection,
),
],
),
),
),
);
}
}
Your onChanged method should be changed to the following.
onChanged: (place? value) {
setState(() {
selacted = value;
if (place.home == selacted) {
isVisible = true;
}
});
}

Flutter Hive: values are not deleted

I am testing Hive NoSQL Database.
I have succeeded in creating a database, putting a value, and getting a value.
However, I failed to delete the value.
I've done a lot of searching, but I can't figure it out.
Also, when saving the value of TextFormField using Button, Get.Back(); was used using GetX, but it did not work.
The value is saved, but the screen is not popped.
So, I popped it using Navigation and it worked.
I don't know what was the cause.
I'd appreciate it if you could tell me what the problem is.
home_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hive_test1/component/todo_card.dart';
import 'package:hive_test1/db/database.dart';
import 'package:hive_test1/scr/form_screen.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.to(() => FormScreen());
},
child: Icon(Icons.add),
),
appBar: AppBar(
centerTitle: true,
title: const Text('Hive Test'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: ValueListenableBuilder(
valueListenable: Hive.box<Todos>('testTable').listenable(),
builder: (context, Box<Todos> box, child) {
return ListView.separated(
itemCount: box.length,
itemBuilder: (_, index) {
var item = box.get(index);
if (item == null) {
return Center(
child: Container(
child: Text('null'),
));
} else {
return TodoCard(
title: item.title,
note: item.note,
dateTime: item.dateTime,
id: item.id,
onPressed: () {
setState(() {
box.deleteAt(item.id); // This is not working.
});
});
}
},
separatorBuilder: (_, index) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Divider(),
);
},
);
}),
),
);
}
}
form_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:hive_test1/db/database.dart';
class FormScreen extends StatefulWidget {
const FormScreen({Key? key}) : super(key: key);
#override
_FormScreenState createState() => _FormScreenState();
}
class _FormScreenState extends State<FormScreen> {
GlobalKey<FormState> formKey = GlobalKey();
String? title;
String? note;
DateTime? dateTime;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Form Screen'),
),
body: Form(
key: formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
renderTextFormField(
label: 'Title',
hintText: 'Please enter a title',
onSaved: (val) {
setState(() {
title = val;
});
},
validator: (val) {
if (val.length < 1) {
return 'Please enter a title';
}
return null;
}),
renderTextFormField(
label: 'Note',
hintText: 'Please enter a value',
onSaved: (val) {
setState(() {
note = val;
});
},
validator: (val) {
if (val.length < 1) {
return 'Please enter a note';
}
return null;
}),
saveButton(),
],
),
),
),
);
}
renderTextFormField({
required String label,
required onSaved,
required validator,
required hintText,
}) {
return Column(
children: [
Row(
children: [
Text(
label,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(
height: 5,
),
TextFormField(
style: TextStyle(fontSize: 20),
autovalidateMode: AutovalidateMode.always,
onSaved: onSaved,
validator: validator,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
hintText: hintText,
border: const OutlineInputBorder(),
),
),
],
);
}
saveButton() {
return Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () async {
var box = Hive.box<Todos>('testTable');
if (formKey.currentState!.validate()) {
formKey.currentState?.save();
int id = 0;
if (box.isNotEmpty) {
final prevItem = box.getAt(box.length - 1);
id = prevItem!.id + 1;
}
box.put(
id,
Todos(
title: title!,
note: note!,
id: id,
dateTime: dateTime = DateTime.now(),
),
);
Get.snackbar(
'Saved!',
'Your form has been saved!',
);
print(title);
Navigator.of(context).pop(); // this is working
// Get.Back(); <- Not Working
} else if (formKey.currentState?.validate() == null) {
Get.snackbar(
"Required",
"All fields are required!",
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.white.withOpacity(0.5),
icon: Icon(
Icons.warning_amber_rounded,
color: Colors.red,
),
);
}
},
child: const Text(
'Save',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
),
],
);
}
}
database.dart
import 'package:hive/hive.dart';
part 'database.g.dart';
#HiveType(typeId: 1)
class Todos {
Todos(
{required this.title,
required this.note,
required this.id,
required this.dateTime});
#HiveField(0)
int id;
#HiveField(1)
String title;
#HiveField(2)
String note;
#HiveField(3)
DateTime dateTime;
}
There was no answer to my #1 question, so I tried to find the answer myself.
I haven't found an answer for the 2nd one yet.
Answer 1 should have declared VoidCallback instead of Function when declaring a Function.
Here's the code:
import 'package:flutter/material.dart';
class TodoCard extends StatefulWidget {
final String title;
final String note;
final int id;
final DateTime dateTime;
final VoidCallback onPressed;
// This is answer. VoidCallback instead of Function
renderIconButton() {
return IconButton(
onPressed: widget.onPressed, // This is answer.
icon: const Icon(
Icons.delete,
color: Colors.red,
size: 25,
),
);
}
return TodoCard(
title: item.title,
note: item.note,
dateTime: item.dateTime,
id: item.id,
onPressed: () => box.deleteAt(index),
);
You are not deleting with index I guess. If that so, to delete with id use .delete instead of .deleteAt method like:
onPressed: () async {
setState(() {
await box.delete(item.id);
});
}
SnackBars and dialogs are considered as routes in GetX. Therefore, you need to close that route using Get.back() if they are open in order to navigate away from the containing screen/page:
Get.back(); // to close the opened snackbar or dialog
Get.back(); // to close the current page and go back
You need to use Get.back() twice essentially. But there's a problem with this. Calling Get.back() twice immediately closes your snackbar and never shown. You could use Future.delayed to overcome this:
await Future.delayed(Duration(seconds: 3), ()=> Get.back()); // allows the snackbar to be displayed for 3 seconds before closing
Get.back(); // Go back