I'm pretty new to flutter and I'm trying to make a login system using providers. It seems to be working when I test the login. But when I rebuild the app the provider returns a null value. Any help would be appreciated.
The screen to check for employee data. If it exist it should redirect to the home page. And if it doesn't, it should redirect to the login authenticate page
Landing Page
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Landing extends StatefulWidget {
#override
_LandingState createState() => _LandingState();
}
class _LandingState extends State<Landing> {
//AuthService auth = new AuthService();
#override
Widget build(BuildContext context) {
Future<Employee> getuserdata() => Employee_preferences().getEmployee();
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => AuthService(),
),
ChangeNotifierProvider(
create: (_) => Employee_Provider(),
)
],
child: MaterialApp(
title: 'ClockServe',
theme: ThemeData(primarySwatch: Colors.blue),
home: FutureBuilder(
future: getuserdata(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text('Error:${snapshot.error}');
} else if (snapshot.data.empId == null) {
return AuthenticatePage();
} else {
return HomePage(emp: snapshot.data);
}
}
}),
routes: {
'/navigatorPage': (context) => NavigatorPage(),
'/homePage': (context) => HomePage(),
'/authenticate': (context) => AuthenticatePage(),
'/attendancePage': (context) => AttendanceScanner()
},
),
);
}
}
The homepage. The page will hold employee information. Landing page is correctly redirecting to this page but for some reason the provider is returning null
HomePage
class HomePage extends StatefulWidget {
final Employee emp;
const HomePage({Key key, this.emp}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//to do: add back end
//use futurebuilder to return user object
//using futureprovider to get snapshot data of user object from database
#override
Widget build(BuildContext context) {
Employee emp = Provider.of<Employee_Provider>(context).emp;
print(emp.empEmail);
return Scaffold(
appBar: AppBar(
actions: <Widget>[
ElevatedButton.icon(
onPressed: () async {
Employee_preferences().removeEmployee();
Navigator.pushReplacementNamed(context, '/authenticate');
},
label: Text(
'Log Out',
style: TextStyle(color: Colors.white),
),
icon: Icon(
Icons.logout,
color: Colors.white,
),
)
],
title: Text('ClockServe'),
centerTitle: true,
),
//button to pop qr scanner camera
//after scanning a qr code it should parse the json array
//into a method, the method will take that as parameter.
//method should send http request check in the auth dart
floatingActionButton: FloatingActionButton.extended(
label: Text('Check In'),
icon: Icon(Icons.camera_alt),
onPressed: () => navigateToScanPage(context),
),
// floatingActionButton: FloatingActionButton(
// onPressed: () {},
// child: Icon(Icons.alarm_on),
// ),
body: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(emp.empFirstName ?? 'emp first name'),
],
),
),
),
);
}
}
Future navigateToScanPage(context) async {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AttendanceScanner()));
}
Code for login page just in case if it's relevant.
Login Page
class LoginPage extends StatefulWidget {
final Function toggleView;
LoginPage({this.toggleView});
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
String email = '';
String password = '';
String error = '';
bool loading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
ElevatedButton.icon(
onPressed: () {
widget.toggleView();
},
label: Text('Register'),
icon: Icon(Icons.person_add),
)
],
title: Text('Login'),
),
body: Container(
padding: EdgeInsets.all(30),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
WelcomeHeader(),
SizedBox(
height: 10,
),
TextFormField(
validator: (value) => value.isEmpty ? 'Enter email' : null,
onChanged: (val) {
setState(() => email = val);
},
decoration: decorationBox.copyWith(hintText: 'Email'),
),
SizedBox(
height: 20,
),
TextFormField(
validator: (value) => value.isEmpty ? 'Enter password' : null,
onChanged: (val) {
setState(() => password = val);
},
obscureText: true,
decoration: decorationBox.copyWith(hintText: 'Password'),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () async {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
AuthService auth = new AuthService();
final Future<Map<String, dynamic>> successMsg =
auth.empLogin(email, password);
successMsg.then((response) {
if (response['status']) {
Employee emp = response['employee'];
print(emp);
Provider.of<Employee_Provider>(context, listen: false)
.setEmp(emp);
Navigator.pushReplacementNamed(context, '/homePage');
}
});
}
},
child: Text('Log In'),
),
SizedBox(
height: 20.0,
),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 20.0),
)
],
),
),
),
),
);
}
}
class WelcomeHeader extends StatelessWidget {
const WelcomeHeader({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Text(
'Welcome To ClockServe',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 28.0,
),
),
Divider(
height: 20,
thickness: 2,
),
Text(
'Enter your credentials to login',
style: TextStyle(fontStyle: FontStyle.italic),
),
],
),
);
}
}
Related
I have a Stateful widget that i pass a list to (for example 2 items).
After I delete an item, the widget should rebuild itself.
Unfortunately, the deleted item is still displayed and the other one is not.
When I re-enter the widget, the correct item is loaded.
There is a similar problem List not updating on deleting item
but maybe someone can explain me what i did wrong and why provider is helping me here instead of setState?
My code is:
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:trip_planner/util/dialog_box.dart';
import 'package:trip_planner/util/previewUrl.dart';
class BookingPage extends StatefulWidget {
final List toDoList;
BookingPage({
super.key,
required this.toDoList,
});
#override
State<BookingPage> createState() => _BookingPageState();
}
class _BookingPageState extends State<BookingPage> {
//text controller
final _controller = TextEditingController();
final _database = FirebaseDatabase.instance.ref();
//Liste is an example what i have in my list
List toDoList2 = [
["https://www.booking.com/Share-Rnv2Kf", true],
["https://www.booking.com/Share-3hKQ0r", true],
];
void initState(){
super.initState();
}
void deleteTask(int index){
setState(() {
widget.toDoList.removeAt(index);
});
//DatabaseReference _testRef = _database.child("Hotel:");
//_testRef.set(widget.toDoList.toString());
}
//save new Item
void saveNewItem(){
setState(() {
widget.toDoList.add([_controller.text, false]);
//DatabaseReference _testRef = _database.child("Hotel:");
//_testRef.set(widget.toDoList.toString());
_controller.clear();
});
Navigator.of(context).pop();
}
void createNewItem(){
showDialog(
context: context,
builder: (context){
return DialogBox(
controller: _controller,
onSave: saveNewItem,
onCancel: () => Navigator.of(context).pop(),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Booking Seiten'),
elevation: 0,
),
floatingActionButton: FloatingActionButton(
onPressed: createNewItem,
child: Icon(Icons.add),
),
body: ListView.builder(
itemCount: widget.toDoList.length,
itemBuilder: (context, index){
return PreviewUrl(
url2: widget.toDoList[index][0],
deleteFunction: (context) => setState(() => deleteTask(index)),
);
},
),
);
}
}
i thought setState does the same thing as when i re-enter the widget, but it doesn't.
import 'package:any_link_preview/any_link_preview.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:url_launcher/url_launcher.dart';
class PreviewUrl extends StatelessWidget {
final String url2;
//Function(bool?)? onChanged;
Function(BuildContext)? deleteFunction;
PreviewUrl({
super.key,
required this.url2,
required this.deleteFunction,
//required this.onChanged,
});
Future openBrowserURL({
required String url,
bool inApp = false,
}) async {
if(await canLaunch(url)){
await launch(
url,
forceSafariVC: inApp, //iOS
forceWebView: inApp, //Android
enableJavaScript: true, //Android
);
}
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(1.0),
child: Slidable(
endActionPane: ActionPane(
motion: StretchMotion(),
children: [
SlidableAction(
onPressed: deleteFunction,
icon: Icons.delete,
backgroundColor: Colors.red.shade300,
borderRadius: BorderRadius.circular(12),
)
],
),
child: Container(
child: AnyLinkPreview.builder(
link: url2,
itemBuilder: (context, metadata, imageProvider) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (imageProvider != null)
GestureDetector(
onTap: () async {
final url = url2;
openBrowserURL(url: url, inApp: true);
},
child: Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.width *0.25,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
),
Container(
width: double.infinity,
color: Theme.of(context).primaryColor.withOpacity(0.6),
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (metadata.title != null)
Text(
metadata.title!,
maxLines: 1,
style:
const TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(height: 5),
if (metadata.desc != null)
Text(
metadata.desc!,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall,
),
Text(
metadata.url ?? url2,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
],
),
),
),
),
);
}
}
If you run the simplified version of your code in DartPad - it will work:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
List toDoList = [
["Button 1", true],
["Button 2", true],
];
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: BookingPage(toDoList: toDoList),
),
),
);
}
}
class BookingPage extends StatefulWidget {
final List toDoList;
const BookingPage({
super.key,
required this.toDoList,
});
#override
State<BookingPage> createState() => _BookingPageState();
}
class _BookingPageState extends State<BookingPage> {
//Liste is an example what i have in my list
List toDoList2 = [
["Button 1", true],
["Button 2", true],
];
#override
void initState() {
super.initState();
}
void deleteTask(int index) {
setState(() {
widget.toDoList.removeAt(index);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Booking Seiten'),
elevation: 0,
),
body: ListView.builder(
itemCount: widget.toDoList.length,
itemBuilder: (context, index) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.lightBlue,
padding: const EdgeInsets.all(12),
textStyle: const TextStyle(fontSize: 22),
),
child: Text(widget.toDoList[index][0]!),
onPressed: () => setState(() => deleteTask(index)),
);
},
),
);
}
}
Which tells me that the problem is your PreviewUrl. My guess is - it is a statful widget, and when the tree rebuilds - it will link the old State object to the first item.
Using Keys might help, something like:
return PreviewUrl(
key: ObjectKey(widget.toDoList[index]),
url2: widget.toDoList[index][0],
deleteFunction: (context) => setState(() => deleteTask(index)),
);
I am trying to toggle between Login Screen and HomeScreen based on the user status. The logic seems to be working as long as I don't put HomeScreen.
I replaced HomeScreen with a different screen to check and the app works as it should. It displays different screens on hot restart based on the user's login status. But as soon as I try to put HomeScreen I get null operator used on null value error.
Here is the toggle logic.
class Testing extends StatefulWidget {
const Testing({super.key});
#override
State<Testing> createState() => _TestingState();
}
class _TestingState extends State<Testing> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: TodoServiceHelper().checkifLoggedIn(),
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
print(snapshot.hasError);
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.data!.isNotEmpty) {
print(snapshot.data);
return RegisterPage();
// returning HomePage gives null check operator used on null value error
} else
return Login();
}),
);
}
}
Here is the HomeScreen
class HomePage extends StatefulWidget {
String? username;
HomePage({this.username});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final GlobalKey<FormState> formKey = GlobalKey();
TextEditingController termController = TextEditingController();
void clearText() {
termController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
User loginUser =
User(username: widget.username.toString(), isLoggedIn: false);
TodoServiceHelper().updateUserName(loginUser);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Login()));
},
icon: Icon(Icons.logout),
color: Colors.white,
)
],
title: FutureBuilder(
future: TodoServiceHelper().getTheUser(widget.username!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Text(
'Welcome ${snapshot.data!.username}',
style: TextStyle(color: Colors.white),
);
}),
),
body: SingleChildScrollView(
child: Column(children: [
Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: termController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(),
labelText: 'search todos',
),
),
TextButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShowingSerachedTitle(
userNamee: widget.username!,
searchTerm: termController.text,
)),
);
print(termController.text);
clearText();
setState(() {});
},
child: Text(
'Search',
)),
Divider(
thickness: 3,
),
],
),
),
),
],
),
Container(
child: Stack(children: [
Positioned(
bottom: 0,
child: Text(
' done Todos',
style: TextStyle(fontSize: 12),
),
),
IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CheckingStuff(userNamee: widget.username!)),
);
setState(() {});
},
icon: Icon(Icons.filter),
),
]),
),
Divider(
thickness: 3,
),
Container(
child: TodoListWidget(name: widget.username!),
height: 1000,
width: 380,
)
]),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color.fromARGB(255, 255, 132, 0),
onPressed: () async {
await showDialog(
barrierDismissible: false,
context: context,
builder: ((context) {
return AddNewTodoDialogue(name: widget.username!);
}),
);
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
The function used to return user with loginStatus true
Future<List<User>> checkifLoggedIn() async {
final Database db = await initializeDB();
final List<Map<String, Object?>> result = await db.query(
'users',
where: 'isLoggedIn = ?',
whereArgs: ['1'],
);
List<User> filtered = [];
for (var item in result) {
filtered.add(User.fromMap(item));
}
return filtered;
}
the problem is here
you used ! sign on a nullable String , and this string is nullable,
try to use this operation (??) so make it
widget.username??"" by this line you will check if the user name is null it will be replaced by an empty string.
I just started learning flutter I needed to pass data between pages so I found it easy to do with static variables but now I'm trying to make a setting page. I made a class named Settings like this :
class Settings {
static bool darkMode = false;
static bool addTable = true;
static saveSetting() {
GetStorage().write("darkMode", Settings.darkMode);
GetStorage().write("addTable", Settings.addTable);
}
static setSetting() {
GetStorage.init();
Settings.darkMode = (GetStorage().read("darkMode") ?? false);
Settings.addTable = (GetStorage().read("addTable") ?? true);
}
}
And a Switch in that page like this :
Switch(
value: Settings.addTable,
onChanged: (_) {
setState(() {
Settings.addTable = !Settings.addTable;
Settings.saveSetting();
});
}),
but after reloading the app the values are not saved in GetStorage, strings are saved perfectly except this one.
And the whole code is here :
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'widgets/menu_button.dart';
void main() async {
await GetStorage.init();
DataManagament dataManagament = DataManagament();
dataManagament.startingApp();
runApp(const MyApp());
}
class DataManagament {
static String reserveString = "";
static List<String> reserveList = [];
static String tableString = "";
static List<String> tableList = [];
void saveReserveList() {
GetStorage().write("reserveList", reserveList.toString());
}
void saveTableList() {
GetStorage().write("tableList", tableList.toString());
}
void startingApp() {
Settings.setSetting;
//reserve
reserveString = (GetStorage().read("reserveList") ?? "");
reserveString == ""
? reserveList = []
: reserveList =
reserveString.substring(1, reserveString.length - 1).split(",");
//table
tableString = (GetStorage().read("tableList") ?? "");
tableString == ""
? tableList = []
: tableList =
tableString.substring(1, tableString.length - 1).split(",");
}
}
class Settings {
static bool darkMode = false;
static bool addTable = true;
static saveSetting() {
GetStorage().write("darkMode", Settings.darkMode);
GetStorage().write("addTable", Settings.addTable);
}
static setSetting() {
Settings.darkMode = (GetStorage().read("darkMode") ?? false);
Settings.addTable = (GetStorage().read("addTable") ?? true);
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: IntroPage(),
debugShowCheckedModeBanner: false,
);
}
}
//
//
//************************************************************
//
//
//
//
//************************************************************
// Reserve Page
//
class ReservePage extends StatefulWidget {
const ReservePage({Key? key}) : super(key: key);
#override
State<ReservePage> createState() => _ReservePageState();
}
class _ReservePageState extends State<ReservePage> {
final _nameController = TextEditingController();
final _minuteController = TextEditingController();
final _hourController = TextEditingController();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: SingleChildScrollView(
child: Column(
children: [
TextField(
controller: _nameController,
textDirection: TextDirection.rtl,
decoration: const InputDecoration(
hintTextDirection: TextDirection.rtl,
border: OutlineInputBorder(),
labelText: 'نام',
),
),
Row(
children: [
Expanded(
flex: 5,
child: TextField(
controller: _hourController,
maxLength: 2,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'hour',
),
),
),
const Expanded(
flex: 3,
child: Center(
child: Text(
":",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
Expanded(
flex: 5,
child: TextField(
controller: _minuteController,
maxLength: 2,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'minute',
),
),
),
],
),
const SizedBox(height: 20),
Center(
child: OutlinedButton(
onPressed: () {
if (_hourController.text != "" &&
_nameController.text != "") {
setState(() {
DataManagament.reserveList
.add(_nameController.text);
DataManagament.reserveList.add(
"${_hourController.text}:${_minuteController.text}");
_hourController.clear();
_nameController.clear();
_minuteController.clear();
DataManagament().saveReserveList();
});
}
},
child: const Text(
"save",
style: TextStyle(
color: Colors.black,
),
),
style: OutlinedButton.styleFrom(
minimumSize: Size(
size.width / 3,
(size.width / 3) * 0.4,
),
backgroundColor: Colors.green,
),
),
)
],
),
),
title: const Center(child: Text("")),
);
});
},
child: const FittedBox(
child: Icon(
Icons.add,
),
),
),
appBar: AppBar(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
title: const Text(
"",
),
centerTitle: true,
),
body: DataManagament.reserveList.isNotEmpty
? SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: DataManagament.reserveList.length ~/ 2,
itemBuilder: (BuildContext context, int index) {
return Card(
// name 0 , time ,1
child: ListTile(
//name
trailing: Text(
DataManagament.reserveList[index * 2],
),
//time
title: Text(
DataManagament.reserveList[(index * 2) + 1],
),
leading: TextButton(
onPressed: () {
setState(() {
DataManagament.reserveList.removeAt(index * 2);
DataManagament.reserveList.removeAt(index * 2);
DataManagament().saveReserveList();
});
},
child: const Text("delete"),
),
));
},
),
],
),
)
: const Center(
child: Text("..."),
),
);
}
}
//
//
//************************************************************
// Menu Page
//
class MenuPage extends StatelessWidget {
const MenuPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SettingsPage(),
));
},
icon: const Icon(Icons.settings),
),
],
backgroundColor: Colors.white,
foregroundColor: Colors.black,
centerTitle: true,
title: const Text(
"",
),
),
body: Column(
children: [
const Spacer(flex: 1),
Expanded(
child: Center(
child: MenuButton(
func: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TablePage(),
));
},
text: "tables"),
),
flex: 2),
Expanded(
child: Center(
child: MenuButton(
func: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ReservePage(),
));
},
text: "رزروها"),
),
flex: 2),
Expanded(
child: Center(
child: MenuButton(func: () {}, text: "test"),
),
flex: 2),
const Spacer(
flex: 4,
)
],
),
);
}
}
//
//
//************************************************************
// Tables Page
//
class TablePage extends StatefulWidget {
const TablePage({Key? key}) : super(key: key);
#override
State<TablePage> createState() => _TablePageState();
}
class _TablePageState extends State<TablePage> {
final _nameController = TextEditingController(); // ignore: unused_field
final _minuteController = TextEditingController(); // ignore: unused_field
final _hourController = TextEditingController(); // ignore: unused_field
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Settings.addTable
? GestureDetector(
onLongPress: () {
setState(() {
Settings.addTable = false;
});
},
child: FloatingActionButton(
onPressed: () {
setState(() {
});
},
child: const Icon(
Icons.add,
),
),
)
: null,
appBar: AppBar(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
title: const Text(
"tables",
),
centerTitle: true,
),
body: DataManagament.tableList.isNotEmpty
? SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: DataManagament.tableList.length,
itemBuilder: (BuildContext context, int index) {
return Card(
// name 0 , time ,1
child: ListTile(
//name
trailing: Row(
children: [
Text(index.toString()),
TextButton(
onPressed: () {
setState(() {
DataManagament.tableList[index] =
_nameController.text;
});
},
child: const Text(""),
),
],
),
//time
title: TextButton(
onPressed: () {},
child: const Text(""),
),
leading: TextButton(
onPressed: () {},
child: Text(
DataManagament.tableList[index].toString()),
),
),
);
},
),
],
),
)
: const Center(
child: Text("..."),
),
);
}
}
//
//
//************************************************************
// Intro Page
//
class IntroPage extends StatefulWidget {
const IntroPage({Key? key}) : super(key: key);
#override
State<IntroPage> createState() => _IntroPageState();
}
class _IntroPageState extends State<IntroPage> {
Timer? _timer;
void startTimer() {
_timer = Timer(const Duration(seconds: 3), () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const MenuPage(),
));
});
}
#override
void initState() {
super.initState();
startTimer();
}
#override
void dispose() {
_timer!.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: Center(
child: Image.asset("images/eightball.png"),
),
flex: 4),
const Expanded(
child: Center(
child: CircularProgressIndicator(),
),
),
],
),
);
}
}
//
//
//************************************************************
// Settings Page
//
class SettingsPage extends StatefulWidget {
const SettingsPage({Key? key}) : super(key: key);
#override
State<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
title: const Text("settings"),
),
body: ListView(children: [
Card(
child: ListTile(
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text(
"add table",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(width: 10),
Icon(Icons.add, size: 30),
],
),
leading: Switch(
value: Settings.addTable,
onChanged: (_) {
setState(() {
Settings.addTable = !Settings.addTable;
Settings.saveSetting();
});
}),
),
),
Card(
child: ListTile(
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Text(
"night mode",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(width: 20),
Icon(Icons.dark_mode),
],
),
leading: Switch(
value: Settings.darkMode,
onChanged: (_) {
setState(() {
Settings.darkMode = !Settings.darkMode;
Settings.saveSetting();
});
}),
),
),
]),
);
}
}
You need to call
final settings = new Settings();
settings.setSettings();
in a page where you want to access settings
I think you are just reading data from GetStorage inside setSettings instead of writing to storage, so when the app releods or restarts data inside static variables will not be available. as:
static setSetting() {
GetStorage.init();
Settings.darkMode = (GetStorage().read("darkMode") ?? false);
Settings.addTable = (GetStorage().read("addTable") ?? true);
//Here you are just updating your settings variable.
//Update you storage also to keep the selection in storage
}
Hope it works.
I did manage to get no error for the code but cannot validate the form and show the error message. I have 3 component dart code which is the password, input field, and button. There is also one body dart in the library. ..................
I did manage to get no error for the code but cannot validate the form and show the error message. I have 3 component dart code which is the password, input field, and button. There is also one body dart in the library. ..................
import 'package:flutter_auth/Screens/Login/components/background.dart';
import 'package:flutter_auth/Screens/Login/components/uploadpage.dart';
import 'package:flutter_auth/components/rounded_button.dart';
import 'package:flutter_auth/components/rounded_input_field.dart';
import 'package:flutter_auth/components/rounded_password_field.dart';
class Body extends StatelessWidget {
const Body({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Background(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"LOGIN",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: size.height * 0.03),
RoundedInputField(
hintText: "Username",
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.length == 0)
return "Please enter email";
else if (!value.contains("#"))
return "Please enter valid email";
else
return null;
},
onChanged: (value) {},
),
PasswordField(
onSaved: (value) {},
),
RoundedButton(
text: "LOGIN",
press: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
},
),
],
),
),
);
}
}
class SecondScreen extends StatelessWidget {
goBackToPreviousScreen(BuildContext context) {
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.upload_file,
color: Colors.white,
),
onPressed: () {
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => uploadpage()),
);
} // do something
},
)
],
),
body: Stack(fit: StackFit.expand, children: <Widget>[
Positioned(
bottom: 0,
width: MediaQuery.of(context).size.width,
child: Center(
child: RaisedButton(
color: Colors.purple[400],
textColor: Colors.white,
onPressed: () {
goBackToPreviousScreen(context);
},
child: Text('Logout')),
),
)
]));
}
Here's a basic example of how Forms work:
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
GlobalKey<FormState> formKey = new GlobalKey();
String formFieldValue;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Form(
key: formKey,
child: Column(
children: [
TextFormField(
validator: (input) {
if (input.isEmpty) {
return 'Please type something';
}
return null;
},
onSaved: (input) => formFieldValue = input,
),
RaisedButton(
onPressed: submitForm,
child: Text(
'Submit'
),
)
],
),
)
);
}
submitForm() {
final formState = formKey.currentState;
if (formState.validate()) {
formState.save();
// then do something
}
}
}
Here the validator does not get called automatically. You have to call it manually onPressed of a button or something.
Here you need to wrap your column in Form widget and give it a key. Onpressed you need to validate it by calling key.currentState.validate()
final _formreg = GlobalKey<FormState>();
Form(key:_formreg, child:Column(children:
[RoundedInputField() ]
));
RaisedButton(onPressed:()=> {
a=_formreg.currentState.validate();
} )
a is a boolean value
I'm trying to get the user input to change the title using a text form in show dialog but it seems the state is rebuilding whenever the keyboard shows/closes, my code is working before, but when I did flutter upgrade to v1.17 it's not working anymore. I've been stuck here for a couple of days now and I don't know what's wrong with my code or what error might be causing it, I can only see "getSelectedText on inactive InputConnection" and "mSecurityInputMethodService is null" in the debug console, please help.
Here's a sample of my code:
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
final TextEditingController titleController = new TextEditingController();
final GlobalKey<FormState> _keyDialogForm = new GlobalKey<FormState>();
#override
void initState() {
super.initState();
titleController.text = 'Hello';
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: Column(
children: <Widget>[
Text(titleController.text),
SizedBox(
height: 50,
),
FlatButton(
color: Colors.redAccent,
onPressed: () {
showTitleDialog();
},
child: Text(
'Show Dialog',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
))
],
),
));
}
Future showTitleDialog() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Form(
key: _keyDialogForm,
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
icon: Icon(Icons.ac_unit),
),
maxLength: 8,
textAlign: TextAlign.center,
onSaved: (val) {
titleController.text = val;
},
autovalidate: true,
validator: (value) {
if (value.isEmpty) {
return 'Enter Title Name';
}
return null;
},
)
],
),
),
actions: <Widget>[
FlatButton(
onPressed: () {
if (_keyDialogForm.currentState.validate()) {
_keyDialogForm.currentState.save();
Navigator.pop(context);
}
},
child: Text('Save'),
color: Colors.blue,
),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Cancel')),
],
);
});
}
}
You can copy paste run full code below
You can call setState in onSaved
code snippet
onSaved: (val) {
titleController.text = val;
setState(() {});
},
working demo
full code
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
final TextEditingController titleController = new TextEditingController();
final GlobalKey<FormState> _keyDialogForm = new GlobalKey<FormState>();
#override
void initState() {
super.initState();
titleController.text = 'Hello';
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: Column(
children: <Widget>[
Text(titleController.text),
SizedBox(
height: 50,
),
FlatButton(
color: Colors.redAccent,
onPressed: () {
showTitleDialog();
},
child: Text(
'Show Dialog',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
))
],
),
));
}
Future showTitleDialog() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Form(
key: _keyDialogForm,
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
icon: Icon(Icons.ac_unit),
),
maxLength: 8,
textAlign: TextAlign.center,
onSaved: (val) {
titleController.text = val;
setState(() {});
},
autovalidate: true,
validator: (value) {
if (value.isEmpty) {
return 'Enter Title Name';
}
return null;
},
)
],
),
),
actions: <Widget>[
FlatButton(
onPressed: () {
if (_keyDialogForm.currentState.validate()) {
_keyDialogForm.currentState.save();
Navigator.pop(context);
}
},
child: Text('Save'),
color: Colors.blue,
),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Cancel')),
],
);
});
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Test(),
);
}
}