Reload page after locale change - flutter

After changing locale in context.setLocale() language in inactive widgets change. But I cannot figure out, hoe to reload current widget in new locale. Any ideas how to get it working?
Body of widget:
Form(
child: CardSettings(
children: <CardSettingsSection>[
CardSettingsSection(
header: CardSettingsHeader(
label: 'settings.general'.tr(),
),
children: [
CardSettingsListPicker(
label: 'Language',
items: context.supportedLocales
.map((locale) =>
locale.toStringWithSeparator(separator: ' '))
.toList(),
initialItem:
context.locale.toStringWithSeparator(separator: ' '),
onChanged: (String newLocale) {
context.setLocale(newLocale.toLocale(separator: ' '));
_getOptions();
},
),
],
),
CardSettingsSection(
header: CardSettingsHeader(
label: 'Map',
),
children: [
CardSettingsListPicker(
label: 'default floor',
items: _floorList,
initialItem: _floor,
onChanged: (String value) {
var floor = tr('plan.floor.' + value);
_preferences.setString('mapDefaultFloor', floor);
},
),
],
),
],
),
);
And options are loaded via async function called in initState and later on in code...
void _getOptions() {
setState(() {
_floorList = Floor.values
.map((value) => tr('plan.floor.' + value.toString().split('.')[1]))
.toList();
_planTypeList = PlanType.values
.map((value) => tr('plan.type.' + value.toString().split('.')[1]))
.toList();
_floor = tr('plan.floor.' +
(_preferences.getString('mapDefaultFLoor') ?? 'ground'));
_planType = tr('plan.type.' +
(_preferences.getString('mapDefaultType') ?? 'newNumbers'));
});
}

stateful widgets automatically reload when you update their state. therefore, all you need to do is have your widget set as a StatefulWidget, and use the setState function to tell flutter that a change has been made to the state, and the widget needs to reload.
Taken from the flutter project template:
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
in the example showed above, the _counter is updated in the state, and in order for it to show the correct value on the app itself, the setState function is called.

Solution was to make _getOptions() async and add the locale change there with await keyword. This way it is ensured that locale is changed before loading new values...

Related

set State of Certain Checkbox in List, without influencing other tiles | Flutter

So I have a ListView with Checkboxes
bool checked = false;
ListView.builder(
itemCount: logs!.length,
itemBuilder: (context, index) {
Log log = logs[index];
return ExpansionTile(
title:
Checkbox(
value: checked,
onChanged: (curValue) {
checked = curValue;
setState(() {});
}),
)
],
)
},
);
The problem is that when I check one Box in the List, all values are changed, because the variable is global & therefore the same boolean is appended to all checkboxes.
When I pack the boolean inside the ListView, I cant click on the Checkbox at all -> because of the setState the value is always reseted & no change appears
So what can I do to make all Checkboxes clickable without influencing the click state of the other ones?
Since you have only 1 variable to check the state of the checkbox, all other checkbox widgets will also depend on this checked variable.
You have to define for every checkbox a own "checked" variable, you could add a checked variable to the Log class and then query and set it each time.
Checkbox(
value: logs[index].checked,
onChanged: (curValue) {
logs[index].checked = curValue;
setState(() {});
},
),
The issue is here using single variable for all items. You can use a List for selected item
List<Log> selectedLogs = [];
Checkbox(
value: selectedLogs.contains(log),
onChanged: (curValue) {
if(selectedLogs.contains(log)){
selectedLogs.remove(log);
}else {
selectedLogs.add(log);
}
setState(() {});
}),
)

How do i modify the data of an existing variable in flutter?

I want to make an editable TextWidget in flutter but I don't really know how to go around it, I did some research, but still can't find a good solution.
Here's my sample code below.
I have a variable called
int qty = 1;
and so I called the variable in TextWidget
Column(
children: [
Text(
"${qty}",
style: TextStyle(),
)
],
),
I want to have these features that make user tab on the value to change it if they want, upon tap, a pop-up dialog will show to give the user the ability to change the existing value to whatever the user wants.
Please if anyone knows how, please help.
You will need a statfull widget to call setState and make the UI update with the new value stored in your qty variable. (I'am assuming that you are not using any state managment).
I wrote a possible solution for what you need.
Let look into some considerations:
Text will show whatever is in the qty as long we call setState after (or do it inside) we change the value of qty.
You need some widget to detect your tap. If you want to the text be 'clicable' then it should be wraped inside that widget.
The onTap/onPress call back of that widget should show a new widget. For this you can use the already made showDialog() and pass it a Dialog Widget. in here you will put your ui for that.
In some point of that UI you need to introduce the new value. So you can use a simple TextField that will save the introduced value, where you can assign it to qty, without forgetting to call setState! Note that it deal with strings, so you neet to do an int.parse() ou double.parse accordingly to you qty var type.
And I think that's it.
The could be other ways of doing it. This is a good and simple approach for your need.
I wrote a piece of code to help or somelse how is trying to do it:
InkWell(
// can be gesture detector, button, etc
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
color:
Colors.white60, // change it accordingly to you
height: 80, // change it accordingly to you
width: 200, // change it accordingly to you
child: Column(
children: [
const Text('Change your value here'),
TextField(
decoration:
InputDecoration(hintText: qty.toString()),
onChanged: (insertValue) => setState(() {
qty = int.parse(insertValue);
}),
// you can use other callBack function (like onComplete,
// onSaved), wich is more eficient than calling setState eveytime,
// but you have to do the needed adtaptions. Like onSave
// needs a key to call the save function. is easy just google it.
),
],
)),
)),
child: Text(
"${qty}",
),
),
What you are probably looking is a DropdownButton.
You would have something like this:
int qty = 1;
List<int> listOfValues = [1,2,3,4];
and then in your column you would have
DropdownButton<int>(
// This are the list of items that will appear in your dropdown menu.
// items is all the options you want your users to be able to select from,
// and it take a list of `DropdownMenuItem`. So instead of creating a `DropdownMenuItem`
// for each of the items in `listOfValues`, we iterate through it and return
// a `DropdownMenuItem`
items: listOfValues
.map((item) => DropdownMenuItem<int>(
value: item,
child: Text('$item'),
))
.toList(),
value: qty,
onChanged: (value) {
if (value != null) {
setState(() {
qty = value;
});
}
},
),
For more information on DropDownButton, check the following links:
https://api.flutter.dev/flutter/material/DropdownButton-class.html
https://www.youtube.com/watch?v=K8Y7sWZ7Q3s
Note: In a scenario where you want to increase the quantity of an item, like in a shopping cart, maybe having a button increment qty by 1 would be better.

Flutter DropDownButton value not changing after selecting a new value

I have been trying to make an external UI that a user can use to make certain changes to a database(dynamodb) in the cloud. When I select a new value, I want it to show the change that the user wants to make, without actually changing the database. The changes are saved only when I press a button on the appbar. Also when I use setState to rebuild the button, the value doesn't change on the cloud and it also changes the value for all of the buttons in the column(works fine without a setState). The code that I have provided changes the database when I press the save icon, but the drop-down button value stays the same unless I refresh the page. I apologize if I haven't explained my issue clearly enough, this is my first time posting on Stackoverflow, and I'm still learning about how to work with flutter and aws amplify.
body: InteractiveViewer(
constrained: false,
child: DataTable(
columns: [
DataColumn(label: Text('Apt #')),
DataColumn(label: Text('Type')),
DataColumn(label: Text('Availability')),
DataColumn(label: Text('Price')),
DataColumn(label: Text('Area'))
],
rows: aprts.map<DataRow>((element) { //aprts is a list that contains apartment objects.
return DataRow(cells: [
DataCell(Text(element.aptNum.toString())),
DataCell(Text(element.type)),
DataCell(DropdownButton<String>( /// this is the part im having problems wi
value: element.availabily, // gets the value for the availability attribute for the element and stores it into value.
onChanged: (String newValue) {
availValue = newValue; //stores the newValue in a global variable that is used in a function that is used toactually make changes to the database.
tempAvail = element;
},
items: <String>['AVAILABLE', 'SOLD', 'RESERVED']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)), // end of problem.
DataCell(TextField(
controller: TextEditingController()
..text = element.price.toString(),
onChanged: (text) {
aptPrice = text;
tempPrice = element;
},
)),
DataCell(TextField(
controller: TextEditingController()..text = element.area,
onChanged: (text) {
aptArea = text;
tempArea = element;
},
)),
]);
}).toList()),
),
What the app looks like. After pressing the button
Use
onChanged: (String newValue) {
setState(() {
availValue = newValue;
tempAvail = element;
}
)
},
because for every change in the UI you must call setState((){})

Dropdown box not displaying selected value

When I select a value from my dropdown the hint text does not change:
String fontSizeValue;
new DropdownButton<String>(
items: new List<double>.generate(72, (i) => i + 2.0).map((double value) {
return new DropdownMenuItem<String>(
value: value.toString(),
child: new Text(value.toString()),
);
}).toList(),
onChanged: (String _) {
setState(() {
fontSize = double.parse(_);
fontSizeValue = _;
print(fontSizeValue);
});
},
value: fontSizeValue,
hint: Text('Select'),
)),
],
),
),
);
Any idea how I can get the selected value to show instead of "select"? Thanks
You did not post enough code, but I'll take a wild guess anyway, because there are a lot of questions with this problem:
Your variable String fontSizeValue; is defined locally, probably in the build function.
You have to define it in a wider scope, so it will retain it's value after another call to build that will happen when you call setState. Probably as a class member of your State class.

Flutter testing find.byValueKey() for item in drop down menu doesn't work

My test doesn't found the item in drop down menu with a value key.
It's works with getText() and the value.
I create a dynamic function to fill every items with a value, a child with Text(value) and a key with Key('sign_$value_item');
This is my full form in the app:
static const menuSigns = <String>[
'aries',
'taurus',
'gemini',
'cancer',
'leo',
'virgo',
'libra',
'scorpio',
'sagittarius',
'capricorn',
'aquarius',
'pisces'
];
final List<DropdownMenuItem<String>> _dropDownMenuSigns = menuSigns
.map<DropdownMenuItem<String>>((String value) => DropdownMenuItem<String>(
key: new ValueKey('sign_$value_item'), // i even try with new Key('sign_$value')
value: value,
child: new Text(value),
))
.toList();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Container(
margin: EdgeInsets.fromLTRB(_hPad, 16.0, _hPad, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Container(
padding: EdgeInsets.fromLTRB(0, 0, 0, 16.0),
width: CustomTheme.customFormSize.width(context),
child: DropdownButton(
key: Key('sign_list'),
isExpanded: true,
value: _sign,
style: CustomTheme.style.dropDownMenu(context),
hint: Text('Choose a sign'),
icon: Icon(Icons.arrow_drop_down_circle),
onChanged: ((newValue) {
setState(() {
_sign = newValue;
});
}),
items: _dropDownMenuSigns,
),
),
),
],
),
),
);
}
And strange things, the test works with the Key if the length of value is very long, for exemple more 10 characters.
This is my test:
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
class AstroSignValidation extends AndWithWorld<FlutterWorld> {
#override
Future<void> executeStep() async {
await FlutterDriverUtils.getText(world.driver, find.text('AstroDay'));
await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_list')); // open drop down menu is ok
await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_cancer_item')); // here test not passed
}
RegExp get pattern => RegExp(r"I expect the user enters sign");
}
Edit: This is my feature file :
Feature: Get Astro day
User should be able to get successfully his astro after cliking astro button.
Scenario: User get astro in successfully
Given I expect the "user" 1 sign
And I expect the user enters day
When user hits Show your astro button
Then user should land on result screen
I recreated your case. Instead of using key property on DropdownMenuItem, you need to use it inside it's child, ie, in Text widget. That way, since the flutter driver will look for text to be selected when dropdown menu is open, the key property will come into play when menu items are displayed and then easier to click on whatever option we pass in the test. It worked well. Updated working code below:
final List<DropdownMenuItem<String>> _dropDownMenuSigns = menuSigns
.map<DropdownMenuItem<String>>((String value) => DropdownMenuItem<String>(
// key: new ValueKey('sign_$value'),
value: value,
child: new Text(value, key: Key('sign_$value'),), // use key here on text
))
.toList();
driver test:
class AstroSignValidation extends GivenWithWorld<FlutterWorld> {
#override
Future<void> executeStep() async {
await FlutterDriverUtils.getText(world.driver, find.text('Choose a sign'));
await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_list')); // open drop down menu is ok
await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_virgo')); // selects sign properly
print('selected sign');
}
RegExp get pattern => RegExp(r"I expect the user enters sign");
}
And test passes :
Note: I directly used Given statement in feature file and accordingly extended GivenWithWorld class in my test. You'll need to use it per your needs.
Hope this answers your question.
I created custom step definition at
https://gist.github.com/PROGrand/03b7fa0b49642e691148dc010816cc83#file-click_dropdown-dart
Usage in feature file:
...
And I tap the "someMenuItemKey" within the "someDropdownKey" dropdown
...