The State of Selected value keeps being reverted back to it's original value - flutter

I want the value of selected to be of the changed one, but everytime I navigate to a different page then come back it keeps returning selected = true
. I tried putting the late bool selected; then initializing in the initState() but it still doesn't work.
bool selected = true;
#override
Widget build(BuildContext context) {
var why = DateTime.parse(
"${DateTime.now().toString().substring(0, 10)} ${widget.time}");
return Container(
padding: EdgeInsets.all(10),
height: 100,
decoration: BoxDecoration(
color: Color(0xFFF9F9FB),
borderRadius: BorderRadius.circular(30),
),
child: Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 15,
),
Center(
child: Text(
"${widget.time}",
style: TextStyle(fontWeight: FontWeight.bold),
),
)
],
),
SizedBox(
width: 50,
),
Container(
height: 100,
width: 1,
color: Colors.grey.withOpacity(0.5),
),
SizedBox(
width: 10,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("${widget.module}"),
Row(
children: [
Icon(
Icons.location_on,
color: Colors.grey,
size: 20,
),
SizedBox(
width: 3,
),
Text(
"${widget.loc}",
style: TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
],
),
Row(
children: [
Icon(
Icons.person,
color: Colors.grey,
),
SizedBox(
width: 1,
),
Text(
"${widget.lecturer}",
style: TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
],
)
],
),
),
IconButton(
icon: Icon(selected
? Icons.notifications_none
: Icons.notifications_active),
onPressed: () async {
// print(why);
print(widget.time);
print(widget.module);
print(widget.id);
setState(() {
selected = !selected;
});
if (selected == false) {
displayNotification("${widget.module}", why, widget.id);
} else if (selected == true) {
localNotification.cancel(widget.id);
}
},
),
],
),
);
}
Future<void> displayNotification(
String lesson, DateTime lessonTime, int id) async {
FlutterLocalNotificationsPlugin().zonedSchedule(
id,
lesson,
"${lesson} ",
tz.TZDateTime.from(lessonTime, tz.local),
NotificationDetails(
android: AndroidNotificationDetails(
"channel id", "channel name", "channel Description"),
),
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
androidAllowWhileIdle: true);
}
}
void initializeSetting() async {
var initializeAndroid = AndroidInitializationSettings("#mipmap/ic_launcher");
var initializeSetting = InitializationSettings(android: initializeAndroid);
await localNotification.initialize(initializeSetting);
}

A quick fix :-
Just place your selected variable outside any class like this.
import ...//all the import statements
bool selected = true;
//Rest other code

Related

I have a Error Closure call with mismatched arguments: function '_GameDetailsPageState.build.<anonymous closure>

I am currently creating comments in the app that the user will be able to do and after doing the function I get this error and I don't know how to fix it.
error
https://i.stack.imgur.com/rbLph.png
https://i.stack.imgur.com/Xa4vg.png
https://i.stack.imgur.com/9SPQR.png
https://i.stack.imgur.com/5Wxag.png
I searched for similar errors but those solutions did not help me
CustomTextField
class CustomTextField extends StatelessWidget {
String? hint;
final TextEditingController commentController;
final Function(String)? onSubmit;
CustomTextField(
{this.hint, required this.onSubmit, required this.commentController});
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: commentController,
onSubmitted: onSubmit,
decoration: InputDecoration(
hintText: "$hint",
hintStyle: TextStyle(fontSize: 12),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: BorderSide(
color: Colors.deepPurple.shade200, width: 0)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: BorderSide(width: 2.0))),
)
],
),
);
}
}
Comments List
import 'package:intl/intl.dart';
import '../../../../../assets/paidwork_icons.dart';
import '../../../../../common/utils/paidwork_colors.dart';
class CommentsList extends StatefulWidget {
final List<Comment> comments;
CommentsList(this.comments);
#override
State<CommentsList> createState() => _CommentsListState();
}
class _CommentsListState extends State<CommentsList> {
int likes = 0;
int dislikes = 0;
void giveLike() {
setState(() {
if (likes == 0) {
likes++;
} else {
likes--;
}
});
}
void giveDisLike() {
setState(() {
if (dislikes == 0) {
dislikes++;
} else {
dislikes--;
}
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 300,
child: widget.comments.isEmpty
? Column(
children: <Widget>[
Text(
'No comments added yet!',
style: Theme.of(context).textTheme.headline6,
),
SizedBox(
height: 20,
),
Container(
height: 200,
child: Image.asset(
'assets/images/waiting.png',
fit: BoxFit.cover,
),
),
],
)
: ListView.builder(
itemBuilder: (ctx, index) {
return Card(
child: Row(
children: <Widget>[
Container(
width: 400,
height: 235,
decoration: BoxDecoration(
color: PaidworkColors.lightWhite,
borderRadius: BorderRadius.circular(10)),
child: Column(
children: [
SizedBox(
height: 8,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 50,
child: Image(image: AssetImage('')),
),
SizedBox(
width: 10,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
child: Row(
children: [
Text(
'Maciej',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontFamily: 'Poppins',
fontSize: 15),
),
SizedBox(
width: 10,
),
Text(
DateFormat('yyyy/MM/dd').format(
widget.comments[index].date),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey,
),
),
],
),
),
Container(
child: Row(
children: [
Icon(
PaidworkIcons
.paidwork_icon_chart_alt,
size: 30,
),
SizedBox(
width: 10,
),
],
),
),
Container(
width: 320,
child: Text(
widget.comments[index].description,
style: TextStyle(
color: Colors.black,
fontFamily: 'Poppins',
fontSize: 14),
),
),
Container(
width: 320,
child: Row(
children: [
Container(
child: Row(
children: [
Text(
likes.toString(),
style: TextStyle(
color: PaidworkColors
.lightUnactive),
),
GestureDetector(
onTap: () => giveLike(),
child: Icon(
PaidworkIcons
.paidwork_icon_heroicons_hand_like,
color: PaidworkColors
.lightUnactive,
),
)
],
),
),
SizedBox(
width: 20,
),
Container(
child: Row(
children: [
Text(
'${dislikes}',
style: TextStyle(
color: PaidworkColors
.lightUnactive),
),
GestureDetector(
onTap: () {
giveDisLike();
},
child: Icon(
PaidworkIcons
.paidwork_icon_heroicons_hand_dislike,
color: PaidworkColors
.lightUnactive,
),
)
],
),
),
],
)),
],
),
],
),
),
],
),
)
],
),
);
},
itemCount: widget.comments.length,
),
);
}
}
Functions
void _startAddNewTransaction(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (_) {
return AddingCommentForm(
commentController: commentController,
userCommentAvatar: 'assets/images/account_game_avatar.png',
userCommentUsername: 'Maciej',
userCommentDate: '21.12.2222',
addYourReview: () {},
cancelReview: () {},
addTx: _addNewTransaction);
},
);
}
final List<Comment> _userComments = [];
void _addNewTransaction(String txDescription, String txDifficulty) {
final newTx = Comment(
description: txDescription,
difficulty: txDifficulty,
date: DateTime.now(),
id: DateTime.now().toString(),
);
setState(() {
_userComments.add(newTx);
});
}
bool openAddReviewForm = false;
void addReview() {
setState(() {
openAddReviewForm = !openAddReviewForm;
});
}
final TextEditingController commentController = TextEditingController();
void submitData() {
final enteredDescription = commentController.text;
if (enteredDescription.isEmpty) {
return;
}
widget.addTx(
enteredDescription,
);
Navigator.of(context).pop();
}

Flutter: pass data from one screen to another based on a list that I fetch from API

I am building a Job Find app on flutter and I am facing some State Management problems. I have a screen where I show all of my job listings (job_list_screen.dart) and if the user press on a job the app loads this specific job with all the details(job_details_screen.dart).
enter image description here
enter image description here
As you can see, I have an apply button(the blue button) on both screens. When I press apply on the job_details_screen I send a put request on my database and it works fine. But, when I go back to my job_list_screen the button doesn't change even thought I wrapped it with a Consumer.
enter image description here
enter image description here
Here is all the code I wrote with the providers, the **screens **and the **widgets **I use.
The jobs provider:
First of all, this is how I fetch jobs from the API and I insert all my data in a List model:
`
/*
|--------------------------------------------------------------------------
| Fetch Jobs from database
|--------------------------------------------------------------------------
|
| 1. set the url for this function
| 2. GET the response from the server only if you are authenticated
| 3. Decode the
response.body: {
'listings': {
'data': (*Inside here, there are all the job list*)
}
}
| 4. For every job inside the data response
| add a new Job item in the List<Job>
| with the named variables from the current data.reposnse.job
*/
Future<List<Job>?> fetchJobs() async {
final key = await storage.read(key: 'auth');
final baseUrl = AppUrl.baseUrl;
try {
// 1.
var url = Uri.parse('$baseUrl/listings');
// 2.
var response = await http.get(
url,
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $key',
},
);
// print(key);
if (response.statusCode == 200 || response.statusCode == 201) {
// 3.
var jsonResponse = jsonDecode(response.body)['listings']['data'];
_jobs = [];
// 4.
for (var j in jsonResponse) {
Job job = Job(
id: j['id'],
title: j['title'],
employmentType: j['employmentType'],
major: j['major'],
city: j['city'],
companyName: j['companyName'],
experience: j['experience'],
date: j['date'],
views: j['views'],
description: j['description'],
benefits: j['benefits'],
requirements: j['requirements'],
hasApplied: j['hasApplied'],
hasViewed: j['hasViewed'],
);
_jobs.add(job);
notifyListeners();
}
notifyListeners();
return _jobs;
} else {
throw Exception('Problem loading jobs');
}
} catch (e) {
print(e);
}
}
`
This is the function that I call when the user presses the apply button:
`
/*
|--------------------------------------------------------------------------
| Apply for a job
|--------------------------------------------------------------------------
*/
Future<void> applyJob(String id) async {
final key = await storage.read(key: 'auth');
final baseUrl = AppUrl.baseUrl;
try {
var url = Uri.parse('$baseUrl/listings/$id/apply');
var response = await http.put(
url,
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $key',
},
);
if (response.statusCode == 200 || response.statusCode == 201) {
print(jsonDecode(response.body));
_hasApplied = jsonDecode(response.body)['hasApplied'];
notifyListeners();
} else {
print(jsonDecode(response.body));
notifyListeners();
}
} catch (e) {
print(e);
}
notifyListeners();
}
`
The job_card widget:
`
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:final_try/screens/job_details_screen.dart';
import '../models/job.dart';
import '../providers/jobs.dart';
import '../styles/colors.dart';
class JobCardBig extends StatefulWidget {
static const routeName = '/job-card-big';
#override
State<JobCardBig> createState() => _JobCardBigState();
}
class _JobCardBigState extends State<JobCardBig> {
#override
Widget build(BuildContext context) {
final job = Provider.of<Job>(context, listen: true);
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(bottom: 10),
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: lightgrey, width: 1),
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
BoxShadow(
color: lightgrey.withOpacity(.5),
spreadRadius: 1,
blurRadius: 2,
offset: Offset(0, 1), // changes position of shadow
),
],
color: white,
),
child: Column(children: [
Container(
child: Row(
children: [
Container(
height: 50,
width: 50,
alignment: Alignment.center,
decoration:
BoxDecoration(shape: BoxShape.circle, color: lightgrey),
),
SizedBox(
width: 10,
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
height: 70,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
job.title.toString(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
job.companyName.toString(),
style: TextStyle(
fontSize: 14,
color: lightgrey,
),
),
],
),
),
),
Container(
height: 70,
width: 50,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.remove_red_eye,
size: 14,
color: darkgrey,
),
SizedBox(
width: 5,
),
Text(
job.views == null
? job.views = '0'
: job.views.toString(),
style: TextStyle(
fontSize: 14,
color: darkgrey,
),
),
],
),
],
),
),
],
),
),
],
)),
SizedBox(
height: 5,
),
Divider(
thickness: 1,
),
SizedBox(
height: 5,
),
Container(
height: 80,
alignment: Alignment.bottomLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'Είδος Απασχόλησης:',
),
SizedBox(
width: 5,
),
Text(
Provider.of<Jobs>(context, listen: false)
.jobTypeFormat(job.employmentType.toString()),
style: TextStyle(color: lightgrey),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Προϋπηρεσία:'),
SizedBox(
width: 5,
),
Flexible(
child: job.experience == null
? Text(
'Δεν απαιτείται',
style: TextStyle(color: lightgrey),
)
: job.experience! > 1
? Text(
'${job.experience.toString()} χρόνια',
style: TextStyle(color: lightgrey),
)
: Text(
'${job.experience.toString()} χρόνο',
style: TextStyle(color: lightgrey),
),
),
],
),
Row(
children: [
Text('Τοποθεσία:'),
SizedBox(
width: 5,
),
Text(
job.city.toString(),
style: TextStyle(color: lightgrey),
),
],
),
Row(
children: [
Text('Δημοσιεύθηκε:'),
SizedBox(
width: 5,
),
Text(
Provider.of<Jobs>(context, listen: false)
.dateFormat(job.date),
// job.date.toString(),
style: TextStyle(color: lightgrey),
),
],
),
],
),
),
Container(
margin: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
border: Border.all(color: darkgrey, width: 1),
borderRadius: BorderRadius.circular(5.0),
color: darkgrey,
),
child: Text(
'Περισσότερα',
style: TextStyle(color: white),
),
),
onTap: () {
Navigator.of(context)
.pushNamed(JobDetailsScreen.routeName, arguments: job.id)
.then((_) {
// Provider.of<Jobs>(context, listen: false).fetchJobs();
});
},
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
color: job.hasApplied == 1
? Color.fromARGB(255, 196, 76, 68)
: buttonColor,
),
child: Consumer<Job>(
builder: (context, job, child) {
return Text(
job.hasApplied == 1 ? 'Δεν ενδιαφέρομαι' : 'Αίτηση',
style: TextStyle(
color: white,
),
);
},
),
),
],
),
),
]),
);
}
}
`
The job_list_screen:
Here I load all my job_card widgets with ListView.builder
`
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import '../styles/colors.dart';
import '../providers/jobs.dart';
import '../widgets/header_screen.dart';
import '../widgets/job_card_big.dart';
class JobListScreen extends StatefulWidget {
static const routeName = '/job-list-screen';
const JobListScreen({super.key});
#override
State<JobListScreen> createState() => _JobListScreenState();
}
class _JobListScreenState extends State<JobListScreen> {
final controller = ScrollController();
bool _firstLoading = true;
var _isLoading = false;
int page = 1;
final _formKey = GlobalKey<FormState>();
String? _searchText;
bool _isFiltered = false;
#override
void initState() {
controller.addListener(() {
if (controller.position.maxScrollExtent == controller.offset) {
fetch();
}
});
super.initState();
}
Future fetch() async {
if (!_isFiltered) {
setState(() {
_isLoading = true;
page++;
Provider.of<Jobs>(context, listen: false)
.fetchMore(page)
.then((_) => _isLoading = false);
});
}
}
#override
void didChangeDependencies() {
if (_firstLoading) {
Provider.of<Jobs>(context, listen: true).fetchJobs().then((_) {
setState(() {
_firstLoading = false;
});
});
}
super.didChangeDependencies();
}
void searchJob() {
if(_searchText == null || _searchText == ''){
setState(() {
_isFiltered = false;
});
}
else setState(() {
Provider.of<Jobs>(context, listen: false).filterJobs(_searchText!);
_isFiltered = true;
});
}
#override
Widget build(BuildContext context) {
final jobsData = Provider.of<Jobs>(context, listen: true);
var jobsList = jobsData.jobs;
var filteredList = jobsData.filteredJobs;
// var jobsListFiltered = jobsData.filteredJobs;
return Scaffold(
body: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.only(
top: 20,
right: 20,
left: 20,
),
child: Column(
children: [
HeaderScreen(title: 'Αγγελίες'),
Container(
child: Form(
key: _formKey,
child: Row(
children: [
Expanded(
child: Container(
child: TextFormField(
decoration: InputDecoration(
hintText: 'Enter some text',
),
onSaved: (value) {
_searchText = value;
},
),
),
),
Container(
margin: EdgeInsets.only(top: 10, bottom: 5),
height: 40,
width: 40,
child: ElevatedButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all<Color>(white),
backgroundColor: MaterialStateProperty.all<Color>(
primaryColor),
),
child: Container(
child: Icon(Icons.search),
),
onPressed: () {
_formKey.currentState?.save();
searchJob();
},
),
),
],
),
),
),
SizedBox(
height: 10,
),
Divider(
thickness: 1,
),
SizedBox(
height: 10,
),
Expanded(
child: !_isFiltered
? Container(
child: !_firstLoading
? ListView.builder(
controller: controller,
itemCount: jobsList.length,
itemBuilder: (ctx, i) =>
ChangeNotifierProvider.value(
value: jobsList[i],
child: Column(
children: [
JobCardBig(),
],
),
),
)
: Center(
child: CircularProgressIndicator(),
),
)
: Container(
child: !_firstLoading
? ListView.builder(
controller: controller,
itemCount: filteredList.length,
itemBuilder: (ctx, i) =>
ChangeNotifierProvider.value(
value: filteredList[i],
child: Column(
children: [
JobCardBig(),
],
),
),
)
: Center(
child: CircularProgressIndicator(),
),
),
),
],
),
),
Positioned(
child: _isLoading
? Container(
width: double.infinity,
height: MediaQuery.of(context).size.height,
color: Color.fromARGB(52, 0, 0, 0),
child: Center(
child: CircularProgressIndicator(),
),
)
: Container(),
),
],
),
);
}
}
`
I tried to load my fetchJobs() function when the user exits the job_details_screen but even though it works, it is not the right solution. The reason why I say that this is not the right way, is because of this possible scenario:
If the user scrolls down a lot, and the app load 60 jobs, then if he presses on job 60, and he exit the job_details_screen, the app will load the first 15 jobs and the user will have to scroll down again. And that's not the user experience I want to provide.
I am searching for a solution that will update only the apply button and it will not need to recreate the whole list. Plus, with this solution the user will go back to the same scroll point he was when he entered the job_details_screen.
I hope I explained my problem properly. This is the first time I upload a question here and I would also like to mention that this is my first project on flutter so don't judge my code too harshly.
Thanks in advance!!

The state of my checkboxes keep returning to their original value in flutter

I have a profile page with some widgets which after saving and redrawing, they keep their new states, but my checkboxes do not, and I have not modified them at all. The new value is being saved on the database, but on the UI it's not preserved. If I turn the email checkbox to true, the 'true' boolean is saved, but it's not displayed on the frontend after pressing the submit button.
class _ProfilePageState extends State<ProfilePage> {
final _formKey = GlobalKey<FormState>();
bool? emailIsChecked = false;
bool? smsisChecked = false;
bool isTextFieldEnabled = false;
bool isIgnored = true;
bool isVisible = false;
bool editIsVisible = true;
bool emailIsEnabled = false;
bool smsIsEnabled = false;
bool nameEdit = false;
late TextEditingController countryController;
late TextEditingController languageController;
#override
void initState() {
super.initState();
countryController = TextEditingController(text: globals.signedInUser!.country);
languageController = TextEditingController(text: globals.signedInUser!.language);
selectedCountry = globals.signedInUser!.country;
selectedLanguage = globals.signedInUser!.language;
globals.signedInUser!.notifications.forEach(
(element) {
if ((element['type']) == 'Email') {
emailIsChecked = element['status'];
}
if ((element['type']) == 'SMS') {
smsisChecked = element['status'];
}
},
);
cleanInputStates();
}
#override
void dispose() {
countryController.dispose();
languageController.dispose();
super.dispose();
}
checkEditVisibility() {
if (editIsVisible == true) {
return true;
}
if (editIsVisible == false) {
return false;
}
}
checkEditAvailability() {
if (editIsVisible == false) {
return true;
}
if (editIsVisible == true) {
return false;
}
}
cleanInputStates() {
isTextFieldEnabled = false;
isIgnored = true;
editIsVisible = true;
isVisible = false;
smsIsEnabled = false;
emailIsEnabled = false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: _formKey,
child: Row(
children: [
Flexible(
flex: 5,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Visibility(
visible: editIsVisible,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green)),
icon: const Icon(Icons.edit),
label: Text('Edit'),
onPressed: () {
setState(() {
isTextFieldEnabled = true;
isIgnored = false;
isVisible = true;
editIsVisible = false;
smsIsEnabled = true;
emailIsEnabled = true;
});
}),
),
SizedBox(
width: 250,
)
],
),
SizedBox(
height: 30,
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 20,
),
... // TextFieldInputs
Row(
children: [
Container(
child: Text(
"Country: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
),
SizedBox(
width: 100,
),
Container(
width: 300,
child: IgnorePointer(
ignoring: isIgnored,
child: DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
isExpanded: true,
hint: const Text(
'Select Your Country',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
items: countryItems
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
validator: (valueCountry) {
if (valueCountry == null) {
return 'Please select country.';
}
return null;
},
value: selectedCountry,
onChanged: (String? valueCountry) {
selectedCountry = valueCountry;
setState(() {
valueCountry;
});
},
),
),
),
// ),
],
),
SizedBox(
height: 20,
),
Row(
children: [
Container(
child: Text(
"Language: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
),
SizedBox(
width: 80,
),
Container(
width: 300,
child: IgnorePointer(
ignoring: isIgnored,
child: DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
isExpanded: true,
hint: const Text(
'Select Your Language',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
items: languageItems
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
value: selectedLanguage,
validator: (valueLanguage) {
if (valueLanguage == null) {
return 'Please select language.';
}
return null;
},
onChanged: (String? valueLanguage) {
selectedLanguage = valueLanguage;
setState(() {
valueLanguage;
});
},
),
),
),
// ),
],
),
Row()
],
),
SizedBox(
width: 120,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
child: Row(
children: [
Text(
"Receive notifications by: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
],
),
),
],
),
SizedBox(
height: 10,
),
Row(
children: [
Container(
width: 300,
child: CheckboxListTile(
enabled: emailIsEnabled,
title: Text("E-mail"),
value: emailIsChecked,
onChanged: (bool? newEmailValue) {
setState(() {
emailIsChecked = newEmailValue;
});
},
activeColor: Colors.green,
),
),
],
),
Row(
children: [
Container(
width: 300,
child: CheckboxListTile(
enabled: smsIsEnabled,
title: Text("SMS"),
value: smsisChecked,
onChanged: (bool? newSmsValue) {
setState(() {
smsisChecked = newSmsValue;
});
},
activeColor: Colors.green,
),
),
],
),
SizedBox(
height: 100,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Visibility(
visible: isVisible,
child: Row(
children: <Widget>[
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.red)),
onPressed: () {
setState(() {
cleanInputStates();
_formKey.currentState!.reset();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()));
});
print("Cleaning states");
},
child: Text("Dismiss"),
),
SizedBox(
width: 100,
),
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.green)),
onPressed: () {
if (_formKey.currentState!.validate()) {
final userInfo = {
"_id": globals.signedInUser!.userId,
"firstName": firstnameTextController.text,
"lastName": lastnameTextController.text,
"email": emailTextController.text,
"phoneNumber": phoneNumberTextController.text,
"country": selectedCountry.toString(),
"language": selectedLanguage.toString(),
"notifications": [
{"type": "Email", "status": emailIsChecked},
{"type": "SMS", "status": smsisChecked}
]
};
globals.socketController.updateUser(userInfo);
Fluttertoast.showToast(
msg: "Applying changes.", // message
toastLength: Toast.LENGTH_LONG, // length
gravity: ToastGravity.BOTTOM_RIGHT, // location
timeInSecForIosWeb: 2,
webBgColor: "#4caf50",
);
}
print("DATA IS BEING SAVED");
setState(() {
if (_formKey.currentState!.validate()) {
globals.signedInUser!.email =
emailTextController.text;
globals.signedInUser!.phoneNumber =
phoneNumberTextController.text;
globals.signedInUser!.firstName =
firstnameTextController.text;
globals.signedInUser!.lastName =
lastnameTextController.text;
globals.signedInUser!.country =
selectedCountry as String;
globals.signedInUser!.language =
selectedLanguage as String;
cleanInputStates();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()));
} else {
print("ingresando else");
}
});
},
child: Text("Save"),
),
],
),
)
],
)
],
),
],
),
),
),
],
), //Column ends here
),
),
],
),
),
);
}
}
Update: After some testings and workarounds, I found that the second issue was due to not assigning a new value prior to returning to the initState. To do that, I added the following code segment into the setState() of the submit button, which is the fetch of the notification parameters within the initState() but assigning the new checkbox values into the array. Additionally, I removed the cleanInputStates(); on the initState as #Paulo mentioned and everything else kept the same.
globals.signedInUser!.notifications.forEach(
(element) {
if ((element['type']) == 'Email') {
element['status'] = emailIsChecked;
}
if ((element['type']) == 'SMS') {
element['status'] = smsisChecked;
}
},
);

create a fixed sized widget on flutter

I'm currently trying to create a row that consist of maximum 3 column widget with each of them have the property of profile picture, nickname, and status. I wanted each of them to have fixed size so that even when the nickname is long it will still take the same amount of space.
Currently I just make the column to be spaced-evenly and some of the widget still take more space than the other 2. How can I fixed this ? maybe make the nickname turned into dotted (...) when it's too long.
here's my current code:
solverWidgets.add(
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BuildRoundedRectProfile(
height: 40,
width: 40,
name: solverTicket[solver]['nickname'],
profileLink: solverTicket[solver]['profile_picture_link'] ?? '',
),
SizedBox(height: 3),
Text(
solverTicket[solver]['nickname'],
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 13,
),
),
if (solversStatus[solver] != null && (povStatus == 'pic' || povStatus == 'pic-client'))
GestureDetector(
onTap: () {
if (solversStatus[solver] == 'Done') {
setState(() {
needToLoadSolverWidgets = true;
isNotExpandedSolverWidgets[solver] = !isNotExpandedSolverWidgets[solver];
});
if (isExpandedSolverWidgetsContent[solver]) {
Future.delayed(Duration(milliseconds: 300), () {
setState(() {
needToLoadSolverWidgets = true;
isExpandedSolverWidgetsContent[solver] = false;
});
});
} else {
setState(() {
needToLoadSolverWidgets = true;
isExpandedSolverWidgetsContent[solver] = true;
});
}
}
},
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
height: isNotExpandedSolverWidgets[solver] ? 20 : 55,
padding: EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5),
decoration: BoxDecoration(
color: defaultProfileColor.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: solversStatus[solver] != 'Done' ?
Text(
solversStatus[solver],
style: primaryColor600Style.copyWith(
fontSize: fontSize9,
),
).tr() : isNotExpandedSolverWidgets[solver] ?
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
solversStatus[solver],
style: primaryColor600Style.copyWith(
fontSize: fontSize10,
),
).tr(),
Icon(
Icons.arrow_drop_down,
size: fontSize15,
),
],
) : ClipRRect(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
children: [
Text(
solversStatus[solver],
style: primaryColor600Style
.copyWith(
fontSize: fontSize9,
),
).tr(),
Icon(
Icons.arrow_drop_down,
size: fontSize18,
),
],
),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (BuildContext
context) =>
ReusableConfirmationDialog(
titleText: 'changeWorkStatus'.tr(),
contentText: 'rejectWorkStatus'.tr(),
confirmButtonText: 'yes'.tr(),
onConfirm: () async {
await Database.changeWorkStatus(
ticketId: widget.ticketId,
ticketData: ticketData,
targetId: solver as String,
oldWorkStatus: 'done',
workStatus: 'todo');
Navigator.pop(context);
setState(() {
isNotExpandedSolverWidgets[solver] = true;
needToLoadTicket = true;
});
}));
},
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: warningColor,
borderRadius:
BorderRadius.circular(5),
),
child: Text(
'disagree',
style: primaryColor600Style
.copyWith(
fontSize: fontSize9,
color: Colors.white,
),
).tr(),
),
)
]),
),
),
),
if(solversStatus[solver] != null && (povStatus != 'pic' && povStatus != 'pic-client'))
Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: formBackgroundColor,
borderRadius: BorderRadius.all(
Radius.circular(10))),
child: Text(
solversStatus[solver],
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 9,
),
),
),
],
),
);
use Text overflow
Text(
'You have pushed the button this many times:dfjhejh dskfjkawejfkjadshfkljhaskdfhekjnkjvnkjasdklfjjekjlkj',
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
or You can use https://pub.dev/packages/marquee package, it will scroll your text infinitly. make sure to wrap this marquee widget in a sizedbox with height and width defined.

flutter Problem same quantity show on products

when I am increasing my quantity of one product then all product's quantity is increasing, so how to solve it.
This is my product page:
import 'dart:convert';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hospital/Authentication/LoginLogoutScreenPage/login.dart';
import 'package:hospital/CartPage/Cart_Api/cart_api.dart';
import 'package:hospital/CartPage/pages/cartPage.dart';
import 'package:hospital/Drawer/dropdown_menu.dart';
import 'package:hospital/ProductDetailsPage/product_detailPage.dart';
import 'package:hospital/ProductDetailsPage/related_product_page.dart';
import 'package:hospital/SecondSection/Medicine/medicine_page.dart';
import 'package:hospital/constant.dart';
import 'package:hospital/customApiVariable.dart';
import 'package:http/http.dart' as http;
import 'package:line_icons/line_icons.dart';
import 'package:provider/provider.dart';
class DetailPage extends StatefulWidget {
final plistId;
const DetailPage({Key key, this.plistId}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
final GlobalKey<FormState> _formKey = GlobalKey();
int quantity = 1;
var response;
var detailPageApi;
#override
void initState() {
super.initState();
fetchData(widget.plistId);
}
fetchData(var consultWithDoctor) async {
var api = Uri.parse(
'$ecommerceBaseUrl/productListApi.php?a2rTokenKey=$a2rTokenKey&plistId=${widget.plistId}');
response = await http.get(
api,
);
print("detailPageApi " + api.toString());
print("detailPageBody " + response.body);
detailPageApi = jsonDecode(response.body);
print("detailPagelist " + detailPageApi.toString());
setState(() {});
}
Future _submit() async {
var errorMessage = 'Authentication Failed';
if (successfully_add_cart_status.toString() == 'false') {
errorMessage = 'Please try again later';
print(errorMessage);
_showerrorDialog(errorMessage);
} else {
errorMessage = 'Product Succesfully Added to Cart';
print(errorMessage);
_showerrorDialog(errorMessage);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kGreen,
title: Text(
"Details",
style: TextStyle(fontStyle: FontStyle.italic),
),
actions: [
IconButton(
icon: Icon(Icons.shopping_cart),
// onPressed: () => print("open cart"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
},
),
DropDownMenu(),
],
),
body: Container(
child: response != null
? ListView.builder(
itemCount: detailPageApi.length.clamp(0, 1),
scrollDirection: Axis.vertical,
physics: ScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
var details = detailPageApi[index];
if (details['num'] == 0) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
);
}
return Column(
children: <Widget>[
Hero(
tag: "1",
child: SizedBox(
height: 300.0,
width: 300.0,
child: Carousel(
boxFit: BoxFit.cover,
autoplay: false,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds: 800),
dotSize: 6.0,
dotIncreasedColor: Colors.black,
dotBgColor: Colors.transparent,
// dotPosition: DotPosition.topRight,
dotVerticalPadding: 10.0,
showIndicator: true,
indicatorBgPadding: 7.0,
images: [
NetworkImage(details['pImgImg']),
],
),
),
),
SizedBox(
height: 50,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Name :",
style: TextStyle(
fontSize: 18,
height: 1.5,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Flexible(
child: Text(
// widget.details,
details['productName'],
style: TextStyle(
fontSize: 17,
height: 1.5,
fontWeight: FontWeight.w500),
),
),
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Details :",
style: TextStyle(
fontSize: 18,
height: 1.5,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Flexible(
child: Text(
// widget.details,
details['productDescription'],
style: TextStyle(
fontSize: 17,
height: 1.5,
fontWeight: FontWeight.w500),
),
),
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
children: <Widget>[
Text(
"Price :",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
Text(
// "Rs " + widget.pPromotionPrice,
"Rs 55.0",
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Text(
// "Rs " + widget.pPrice,
"Rs 100",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
// color: warning,
decoration: TextDecoration.lineThrough),
)
],
)
],
),
),
SizedBox(
height: 25,
),
Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (quantity > 1) {
setState(() {
quantity = --quantity;
});
}
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
LineIcons.minus,
size: 15,
),
),
),
SizedBox(
width: 15,
),
Text(
quantity.toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(
width: 15,
),
InkWell(
onTap: () {
setState(() {
quantity = ++quantity;
});
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
LineIcons.plus,
size: 15,
),
),
),
],
)
],
),
),
SizedBox(
height: 50,
),
InkWell(
onTap: () async {
if (var_uid.toString() != null.toString()) {
_submit();
var qty = quantity.toString();
var plistId = widget.plistId;
print('pplistid' + plistId);
var uid = var_uid.toString();
var sid = var_sid.toString();
print('uuid' + uid);
print('ssid' + sid);
var response =
await add_to_cart_fn(qty, plistId, uid, sid);
print("rsp: " + response['msg']);
} else {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => LoginPage()));
}
},
// },
child: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Container(
height: 45,
width: double.infinity,
decoration: BoxDecoration(
color: kGreen,
borderRadius: BorderRadius.circular(30)),
child: Center(
child: Text(
"ADD TO CART",
style: TextStyle(
color: kWhite,
fontSize: 20,
),
),
),
),
),
),
SizedBox(height: 20.0),
RelatedProductPage(plistId: widget.plistId)
],
);
})
: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
),
),
);
}
void _showerrorDialog(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.grey[350],
textColor: Colors.black,
fontSize: 16.0);
}
}
You are using the same quantity variable against each item. Changing the value on one of those will cause all items to update. What you need to do is to keep a Map of quantity selected against product id. That way whenever you increase or decrease the quantity, you update the quantity against that specific product id and the rest will remain unchanged.
EDIT: Here is how this will work
//Create a new map to save the product id and product selected quantity
var productQuantity = new Map<int, int>()
//When setting the values of the product, set the quantity from the map
Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(width: 20,),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (quantity > 1) {
setState(() {
//Changed here
productQuantity['$productId'] -= 1;
});
}
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(shape: BoxShape.circle),
child: Icon(
LineIcons.minus,
size: 15,
),
),
),
SizedBox(width: 15,),
Text(
//Changed here
productQuantity['$productId'].toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(width: 15,),
InkWell(
onTap: () {
setState(() {
//Changed here
productQuantity['$productId'] += 1;
});
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
shape: BoxShape.circle),
),
child: Icon(
LineIcons.plus,
size: 15,
),
),
),
],
)
],
),
)
you set the common quantity in all products so change it and set it inside the class.
Please Check the example
import 'package:flutter/material.dart';
class QuantityUpdatePage extends StatefulWidget {
#override
_QuantityUpdatePageState createState() => _QuantityUpdatePageState();
}
class _QuantityUpdatePageState extends State<QuantityUpdatePage> {
List<Product> productArray = [];
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
productArray.clear();
productArray.add(Product(1, "Product 1", 1));
productArray.add(Product(2, "Product 2", 1));
productArray.add(Product(3, "Product 3", 1));
productArray.add(Product(4, "Product 4", 1));
productArray.add(Product(5, "Product 5", 1));
setState(() {});
});
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("QUANTITY UPDATE")),
body: ListView.builder(
shrinkWrap: true,
itemCount: productArray.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
SizedBox(
height: 20,
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(productArray[index].productName),
SizedBox(
width: 40,
),
Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (productArray[index].quantity > 1) {
setState(() {
productArray[index].quantity = --productArray[index].quantity;
});
}
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
Icons.minimize,
size: 15,
),
),
),
SizedBox(
width: 15,
),
Text(
productArray[index].quantity.toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(
width: 15,
),
InkWell(
onTap: () {
setState(() {
productArray[index].quantity = ++productArray[index].quantity;
});
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
Icons.add,
size: 15,
),
),
),
],
)
],
),
],
),
SizedBox(
height: 20,
),
],
),
);
}));
}
}
class Product {
String productName;
int quantity;
int id;
Product(this.id, this.productName, this.quantity);
}
#Deepak if you don't understand Maps use list instead, with a value being updated for each index. Initialize a list of int types with some large values like 1000000, and update the value for each index. use ListView builder to fetch the data from the API for each index.
List<int> quantity = List.empty(growable: true);
OR
List<int> quantity = List.filled(10000, []);
For updating quantity:-
quantity[index] += 1;
For Grid view thing, refer this example from CodeGrepper:-
GridView.count(
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline5,
),
);
}),
);