Flutter - Which identifier do I use to call classes? - flutter

There is an identifier that is needed to be passed for this to work but I am not sure what identifier has to be called. Can someone help?
I am needing to make it so when I press the button, it goes through all those working functions, and then takes the user to the next page page_ApiBox().
I am getting an "Expected Identifier, but got ," Error on the Navigator.of(context)... line.
I see that an identifier needs to be called inside of page_ApiBox(apibox: ))); but I am not sure what identifier is supposed to be called. Null does not work.
floatingActionButton: FloatingActionButton(backgroundColor: Color(0xFF7E57C2),
onPressed: () {
final api_key_input = _apiKeyController.text;
print('User API: $api_key_input');
getApi();
//var post = json.decode(response.body); *UNCOMMENT LATER*
// INSERT HERE: Store API Key Value in Encrypted Box.
// MOCK API RESPONSE----------------- *DELETE LATER*
print('Verification Successful');
addApi(api_key_input);
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>page_ApiBox(apibox: ,)));
label: Text('Verify'); floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat;},
class page_ApiBox extends StatefulWidget {
const page_ApiBox({Key? key, required this.apibox,}) : super(key: key);
final apiBox apibox;
#override
State<page_ApiBox> createState() => _page_ApiBoxState();
}
class _page_ApiBoxState extends State<page_ApiBox> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: buildApiBox(context, widget.apibox)
);
}
}

Related

"RangeError (index): Index out of range: no indices are valid: 0" when trying to get a barcode

In Flutter I actually write a smartphone app for my company. There is also a barcode reader to legitimize customers to enter the store.
The problem is that whenever I want to convert a 13 number string into a barcode I get the error shown above.
For first time using the App the customer types his number into a TextField. The number (originally a String) will be stored in a private variable _number (also from type String) for further processing.
Even if I use my function
convert2barcode('1111111111116')
the barcode is shown correctly, but not for
convert2barcode(_number)
I have no idea why. If I write
print(_number)
I get the correct result (e.g. '1111111111116').
Hope you can help. Tell me if you need more code information.
Best regards.
EDIT
I wrote a more simple example to understand what I mean.
I've a TextField where a numeric String will be converted into a barcode at submitting.
import 'package:flutter/material.dart';
import 'barcode.dart';
void main() => runApp(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(
home: GUI(),
);
}
}
class GUI extends StatefulWidget {
GUI({Key? key}) : super(key: key);
#override
State<GUI> createState() => _GUI();
}
class _GUI extends State<GUI> {
bool _isVisible = false;
String numer = "";
void showWidget() {
setState(() {
_isVisible = !_isVisible;
});
}
#override
Widget build(BuildContext contet) {
return Scaffold(
body: Visibility(
child: Row(
children: /*[
Text(_numer.runtimeType.toString())
]*/
Barcode.convert2Barcode(numer),
),
visible: _isVisible,
replacement: Column(
children: [
TextField(
onSubmitted: (value) {
numer = value;
showWidget();
},
),
],
),
),
);
}
}
This is the code which caused the exception:
Barcode.convert2Barcode(numer),
If I run the code I'll get the error shown in the headline.
Only If I write
convert2barcode('1111111111116'),
the barcode will be shown correctly.
I have output the type of the variable with runtimeType for both ('1111111111116' and _numer). It's always the same (String). Even if I make something like this
_numer = '1111111111116';
print(_numer);
I will get the correct result.
I have really no idea what this exception cause.
When TextField's onSubmit is not called, the number is empty. That's the reason you get the error.
Replace
Barcode.convert2Barcode(numer),
with
if (number.isNotEmpty)
Barcode.convert2Barcode(numer),

Read nested widget/class properties value in flutter

I'm building a simple app with lots of nested widgets/classes from different specialised files
list of files:
main.dart -> the menu file used to start the activity
"Activity()"
group_widgets.dart -> the file that contains the custom widget
"CustomWidget()"
file_a.dart -> the file that uses the custom widgets
inside the "Activity()"
other.dart -> other files that needs to manage data changed in CustomWidget()
inside main.dart:
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Activity(),
));
},
inside group_widgets.dart:
class CustomWidget extends StatefulWidget {
const CustomWidget({Key? key}) : super(key: key);
#override
State<CustomWidget> createState() => _CustomWidgetState();
}
class _CustomWidgetState extends State<CustomWidget> {
var _boolean = false;
bool switchBoolean(bool state) => !state;
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => {
setState(() {
_boolean = switchBoolean(_boolean);
})
},
child: Container(
color: _boolean == true ? Colors.green : Colors.red,
),
);
}
}
inside file_a.dart
class Activity extends StatefulWidget {
const Activity({Key? key}) : super(key: key);
#override
State<Activity> createState() => _ActivityState();
}
class _ActivityState extends State<Activity> {
#override
Widget build(BuildContext context) {
bool boolean = true;
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CustomWidget(),
Text('Here where to show the variable from CustomWidget'
'and prove I can retrieve it')
],
),
),
);
}
}
inside other.dart
if ( booleanFromCustomWidget == true) {
Something ...
}
What is the best practice to achieve it?
I've read a lot here but nothing seems to well fit my needing.
Just comment if my request is not as clear as it seems to me))
Please correct me if I am wrong, but if you want to access data from parent widgets from inside their descendants (children or even nested children) you can either pass them down via parameter arguments:
Child(int age, String name);
And then accept it in the new file, where the Child widget lives, via its constructor:
class Child {
String name;
int age;
// Constructor
Child(String passedName, int passedAge) {
this.name = passedName;
this.age = passedAge;
}
}
Inside the parent.dart you then have to import the children.dart to use it.
Or use a popular package like the provider package: https://pub.dev/packages/provider
This allows you to store data containers, which you can access basically anywhere in your code. Feel free to google it & watch some tutorials to get started, as it is the preferred approach to avoid passing data to widget which really do not care about the passed parameters.
Note: You can transfer the idea to output the String data like in your example code above.
you can use a state manager like provider, or bloc
At the top level, you set up the data services

Storing certain value in Widget build / Flutter

I've a question:
In my Widget build(BuildContext context), I want to store a certain value,
final userName = book.owner
(book is the reference to the certain value from Firestore)
But it's done not in the right way to my lack of knowledge. I'd appreciate if someone could guide through that.
Thank you in advance!
Snippet of my code
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
DatabaseMethods databaseMethods = new DatabaseMethods();
var userName;
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
Book book;
_BookViewState(this.book);
String userName;
#override
void initState() {
userName = book.owner;
super.initState();
}
// final Book book;
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
List<String> users = [userName, Constants.myName];
Map<String, dynamic> chatRoomMap = {
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
//widget.book;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
...
FlatButton(
child: Text(
"Get contact with",
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
onPressed: () {
createChatroomAndStartConversation(
userName: userName);
...
}
Snippet of Value not in range: 1
getChatRoomId(String a, String b) {
if (a.substring(0, 1).codeUnitAt(0) > b.substring(0, 1).codeUnitAt(0)) {
return "$b\_$a";
} else {
return "$a\_$b";
}
}
It's not a good practice to store any data in build() method, because this method is invoked too many times to do the such kind of move. Consider using StatefulWidget to store any state you have in the widget, for the very beginning. When you use this widget, you can define this all in such way:
class YourWidget extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<YourWidget> {
String userName;
#override
void initState() {
userName = book.owner;
super.initState()
}
#override
Widget build(BuildContext context) {
return Container(child: Text(userName),);
}
}
Here, in initState() you can retrieve value from book and set it to userName. But for more complex and bigger applications, consider using StateManagement solutions and some kind of architectural patterns i.e. Riverpod, Provider, MobX, BLoC.. Because changing the state via setState() method will cause rebuilding whole child widget tree, which could freeze whole UI in complex app.
UPD to 'Snippet of my code':
According to your code, if you are using a 'book' from Widget, not its state - use widget.book, in such way you have access to widget members, because of this you don't need a constructor of state. So, due to these changes, your code might looks like:
class BookView extends StatefulWidget {
final Book book;
BookView({Key key, #required this.book}) : super(key: key);
// You DON'T need this here, because you are retrieving these methods
// inside your state via DatabaseMethods constructor
DatabaseMethods databaseMethods = DatabaseMethods();
#override
_BookViewState createState() => _BookViewState(book);
}
class _BookViewState extends State<BookView> {
String userName;
#override
void initState() {
// Using widget.book to retrieve Book object from state's widget
userName = widget.book.owner;
super.initState();
}
createChatroomAndStartConversation({var userName}) {
if (userName != Constants.myName) {
String roomId = getChatRoomId(userName, Constants.myName);
// Also, it's just a recommendation, try to omit local variables types
// because they are already known with List type (String). Also, this
// all is about chatRoomMap
var users = <String>[userName, Constants.myName];
final chatRoomMap = <String, dynamic>{
"Users": users,
"roomId": roomId,
};
DatabaseMethods().createChatRoom(roomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(roomId, userName)),
);
} else {
print("You cannot send msg to your self");
}
}
#override
Widget build(BuildContext context) {
// your widgets here
}
}
UPD 2:
Second trouble and issue with 'Snippet of Value not in range: 1'. I could to reproduce it with given value of 'a' as empty string. So, your function invocation is like getChatRoomId('', 'user123'), because of empty 'userName', substring function can't take values from range [0, 1), so exception is raised.

Flutter pass data to new screen with onTap

My application has a bottom navigation bar, with 2 pages in the menu.
On page 1, I can fill out a form and it calculates me values ​​that it displays to me by pushing in a 1.1 page.
On this page I have a button that allows me to redirect me to page 2 as if I clicked menu 2 of the navigation bar.
This works. My problem is how to send the data from my page 1.1 to this page 2.
The goal being that my page 2 is a form which is empty if I call it by the navigation bar but which is filled automatically if I pass by the page 1.1 in focus of the calculated values.
Here an exemple of the redirection that I do:
Here is my code :
my_app.dart :
final ThemeData _AppTheme = AppTheme().data;
final navBarGlobalKey = GlobalKey(); // => This is my key for redirect page
class MyApp extends StatefulWidget{
#override
State<StatefulWidget> createState() => MyAppState();
}
class MyAppState extends State<MyApp>{
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'App',
home: MyBottomNavigationBar(),
theme: _AppTheme,
navigatorKey: locator<NavigationService>().navigatorKey,
onGenerateRoute: Router.generateRoute,
initialRoute: HOME_ROUTE,
);
}
}
My bottom_navigation_bar.dart :
class MyBottomNavigationBar extends StatefulWidget
{
MyBottomNavigationBar({Key key}) : super(key: key);
#override
_MyBottomNavigationBarState createState() => _MyBottomNavigationBarState();
}
class _MyBottomNavigationBarState extends State<MyBottomNavigationBar>
{
int _pageIndex = 0;
final List<Widget> _pagesOption = [
page1.1(), // => Here I load direclty my page 1.1 with data for the exemple
page2(),
];
void onTappedBar(int index)
{
setState(() {
_pageIndex = index;
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child : Scaffold(
body : _pagesOption.elementAt(_pageIndex),
bottomNavigationBar: BottomNavigationBar(
key: navBarGlobalKey,
currentIndex: _pageIndex,
onTap: onTappedBar,
type: BottomNavigationBarType.fixed,
items : [
BottomNavigationBarItem(
icon : Icon(Icons.home),
title : Text('Home')
),
BottomNavigationBarItem(
icon : Icon(Icons.settings),
title : Text('Setting')
),
]
),
)
);
}
}
And here my widget submit button of page 1.1 :
Widget _getSubmitButton(){
return RaisedButton(
child: Text(
'Send'
),
onPressed: () {
final BottomNavigationBar navigationBar = navBarGlobalKey.currentWidget;
navigationBar.onTap(1); // => How to send data that I have in my page ???
},
);
}
For this, you can use Shared Preferences, the main idea is that:
Store the value of the calculated value in SharedPref from Page 1 when you're passing to Page 1.1
Let you checks for the value by default in Page 2's initState(), any changes in the Shared Preferences will be fetched in the Page 2 itself, using SharedPref get method.
WHY?
This is probably a cleaner way to achieve what you want, since in the BottomNavigationBar will not help you do this, but a Shared Preferences value will always give you that data which you can use it any time
Let's see how you can achieve this:
PAGE ONE
// Set the data of the form here
class _PageOneState extends State<PageOne>
{
void onSubmit() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
//make sure you store the calculated value, if that is String
// use setString() or if it is an int, setInt()
// and then pass it to the SharedPref
// key is a string name, which is used to access
// key and store, so choose the name wisely
await prefs.setInt("key", your_calculated_value);
}
}
PAGE TWO
class _PageTwoState extends State<PageTwo>
{
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
// This will be responsible for getting the result from SharedPref
int calculated_value;
#override
void initState(){
super.initState();
// get your list here
calculated_value = _prefs.then((SharedPreferences prefs){
// here if no data is then _values will have 0
// which you can use it to check and populate data
return (prefs.getInt("key") ?? 0);
});
}
}
This is the most reasonable way of doing the thing which you want. In this manner, whenever, PageTwo will trace any values, it will reflect, else, your choice for 0 check result. Let me know, if you have any doubts in that.
In your FirstActivity
onPressed: () {
navigatePush(SecondActivity(text: "Data"));
}
In your SecondActivity
class SecondActivity extends StatefulWidget {
String text;
SecondActivity({this.text});
}
You can pass the the values as arguments when you push to your new screen. This could get messy if you're building a larger project.
A cleaner implementation would be to use a Provider. Set up the data you want in a model mixed in with ChangeNotifier and use Provider.of<*name of your class*>(context) where ever you need to use it.

Data passed to Stateful Flutter Widget using Navigator.pushNamed() is null

Using Flutter, I am trying to pass data via the constructor to a new screen.
However, this is somewhat of a special case because the screen is a Stateful widget and I am using the Navigation Routes method of navigation.
The data also happens to be of type int, if that matters.
The named route navigation is set up like so:
void main() => runApp(Main());
class Main extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: PreLoadScreen.id,
//initialRoute: TemporaryScreen.id,
routes: {
TemporaryScreen.id: (context) => TemporaryScreen(),
InfoScreen.id: (context) => InfoScreen(),
PreLoadScreen.id: (context) => PreLoadScreen(),
StatsScreen.id: (context) => StatsScreen(),
RideScreen.id: (context) => RideScreen(),
AudioScreen.id: (context) => AudioScreen(),
},
);
}
}
The screen that I'm passing the data to has the following constructor code:
class StatsScreen extends StatefulWidget {
static const String id = 'stats_screen';
int tableID; // current shift table ID being passed in from super
// Constructor required for having data passed in
StatsScreen({Key key, #required this.tableID}) : super(key: key);
#override
_StatsScreenState createState() {
print('statsscreen DEBUG: $tableID'); // <-- this shows the data passed was NULL! :(
return _StatsScreenState();
}
}
The screen that I'm passing the data FROM contains the following code:
void _checkShiftStatus() async {
bool userClockedIn = await ShiftManager().isUserClockedIn();
int tableName = await ShiftManager().getActiveRideTableName();
print('preload DEBUG: tablename: $tableName'); // <-- this verifies the data is NOT null here.
if (userClockedIn) {
Navigator.pushNamed(context, StatsScreen.id,
arguments: {'tableID': tableName}); // <--- something is wrong here, presumably
} else {
shouldDisplayStartShift = !userClockedIn;
showProgressSpinner = false;
}
}
I've tried changing the suspect line to:
Navigator.pushNamed(context, StatsScreen.id,
arguments: tableName);
and...
Navigator.pushNamed(context, StatsScreen.id,
arguments: {tableName});
But get the same result in the target screen (data passed is null). It's sort of like baseball... the batter is the initial screen... and the catcher is the screen we're navigating to. The ball is the data. Except in my case, the batter seems to be Sammy Sosa and the ball is out of the park someplace... which is great for the Cubs but not for me.
I've also tried googling, docs, stackoverflow (even this specific answer... but I can't seem to extract the pertinent meaning from it), and Bacardi... and I'm getting very annoyed. Please someone point out my syntax error and what line it's on. Thank you!
You have to access data using ModalRoute.
class Delete2 extends StatefulWidget {
Delete2({Key key}) : super(key: key);
#override
_Delete2State createState() => _Delete2State();
}
class _Delete2State extends State<Delete2> {
#override
Widget build(BuildContext context) {
final int args = ModalRoute.of(context).settings.arguments;
return Container(
child: Text(args.toString()),
);
}
}
(Full Documentation)