NavigatorPush is not working on my Flutter App - flutter

I try to build simple login with laravel but then got stuck. After login success I can't redirect to another page with Navigator.push. I think I've followed the tutorial right.
this is login.dart
class LoginScreen extends StatefulWidget {
static const routeName = '/login-screen';
const LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController txtUsername = new TextEditingController();
TextEditingController txtPassword = new TextEditingController();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; //provide total height and width
return Scaffold(
body: Background(
child1: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Positioned(
top: 0,
left: 0,
child: Image.asset('assets/images/wedding.png', width: 250),
),
SizedBox(height: size.height * 0.01),
roundedInputField(
hintText: 'Email',
controller: txtUsername,
onChanged: (value) {},
),
PasswordField(
hintText: 'Password',
controller: txtPassword,
onChanged: (value) {},
),
Button(
text: 'LOGIN',
press: () {
this.doLogin();
},
)
],
),
),
),
);
}
void showToast(msg) => Fluttertoast.showToast(msg: msg);
Future doLogin() async {
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
if(txtUsername.text.isEmpty || txtPassword.text.isEmpty) {
showToast('email/password kosong');
}else {
showDialog(
context: context,
builder: (context) {
return Center(
child: CircularProgressIndicator(),
);
});
final response = await http.post(
Uri.parse('http://10.0.2.2/flutter/api/login'),
body: {'email': txtUsername.text, 'password': txtPassword.text},
headers: {'Accept': 'application/json'}
);
final responseData = json.decode(response.body);
if (response.statusCode == 200) {
showToast('berhasil login');
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => const NavbarScreen(),
));
// Navigator.of(context).push(
// MaterialPageRoute(builder: (_){
// return NavbarScreen();
// },
// ),
// );
//print(responseData);
} else {
showToast('gagal login');
}
Navigator.of(context).pop(); //end loading
}
}
}
This is the login logic in login.dart
if (response.statusCode == 200) {
showToast('berhasil login');
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => const NavbarScreen(),
));
//print(responseData);
} else {
showToast('gagal login');
}
This is main.dart
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Breeze',
theme: ThemeData(
primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.white,
),
//home: DashboardScreen(),
initialRoute: '/',
routes: {
'/': (ctx) => LoginScreen(),
LoginScreen.routeName: (ctx) => LoginScreen(),
NavbarScreen.routeName: (ctx) => NavbarScreen(),
CheckinScreen.routeName: (ctx) => CheckinScreen(),
CheckoutScreen.routeName: (ctx) => CheckoutScreen(),
},
);
}
}

#Damara Jati P Kindly make the following changes Step 1-3
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class LoginScreen extends StatefulWidget {
static const routeName = '/login-screen';
const LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController txtUsername = new TextEditingController();
TextEditingController txtPassword = new TextEditingController();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; //provide total height and width
return Scaffold(
body: Background(
child1: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Positioned(
top: 0,
left: 0,
child: Image.asset('assets/images/wedding.png', width: 250),
),
SizedBox(height: size.height * 0.01),
roundedInputField(
hintText: 'Email',
controller: txtUsername,
onChanged: (value) {},
),
PasswordField(
hintText: 'Password',
controller: txtPassword,
onChanged: (value) {},
),
Button(
text: 'LOGIN',
press: () {
// Steps 1
this.doLogin(context);
},
)
],
),
),
),
);
}
void showToast(msg) => Fluttertoast.showToast(msg: msg);
// Steps 2
Future doLogin(BuildContext context) async {
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
if (txtUsername.text.isEmpty || txtPassword.text.isEmpty) {
showToast('email/password kosong');
} else {
showDialog(
context: context,
builder: (context) {
return Center(
child: CircularProgressIndicator(),
);
});
final response = await http.post(
Uri.parse('http://10.0.2.2/flutter/api/login'),
body: {'email': txtUsername.text, 'password': txtPassword.text},
headers: {'Accept': 'application/json'});
final responseData = json.decode(response.body);
if (response.statusCode == 200) {
showToast('berhasil login');
// Steps 3
Navigator.push(
context, MaterialPageRoute(builder: (context) => NavbarScreen()));
} else {
showToast('gagal login');
}
}
}
}

try using named route navigator. I show how to route with or without parameters. The generator class contains all the routing definitions in one place
class MyApp extends StatelessWidget{
return MaterialApp(
...
onGenerateRoute: RouteGenerator.handleRoute,
...
}
Navigator.pushNamed(context, RouteGenerator.homePage);
Navigator.pushNamed(
context,
RouteGenerator.page2Page,
arguments: myView)
.then((completion) {
});
class RouteGenerator {
static const String homePage = "/home";
static const String page1Page = "/page1";
static const String page2Page = "/page2";
RouteGenerator._();
static Route<dynamic> handleRoute(RouteSettings routeSettings) {
Widget childWidget;
switch (routeSettings.name) {
case homePage:
{
childWidget = HomePageWidget(title: 'Home');
}
break;
case page1Page:
{
childWidget = Page1Widget();
}
break;
case page2Page:
{
final args = routeSettings.arguments as MyView;
childWidget = Page2Widget(args);
}
break;
default:
throw FormatException("Route Not Found");
}
return MaterialPageRoute(builder: (context) => childWidget);
}
}

Firstly, you are using two different routename for LoginScreen. While this will be the home use
static const routeName = '/';
Now for the method try passing context for safety doLogin(context)
showDialog, push and Fluttertoast.showToast are future methods, provide await before theses.
Future<void> showToast(msg) async => await Fluttertoast.showToast(msg: msg);
showDialog brings another context that is needed to be close to move further. Hopping you are just depending on barrierDismissible: true. else create button or logic to close the dialog.
Future<void> doLogin(BuildContext context) async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) {
return Center(
child: Column(
children: [
Center(
child: CircularProgressIndicator(),
),
ElevatedButton(
onPressed: Navigator.of(context).pop,
child: Text("Close the dialog"))
],
),
);
},
);
await showToast('berhasil login');
await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => TS(), // place your screen widget
));
}

Related

setState() not updating UI elements even though the state variable, a Future, is updated?

I have a HomePage screen which has a FutureBuilder List implemented with a Future function as the state variable. I am updating this Future in another dart file by using keys to access the future. The Future gets updated and I'm sure of this as I've seen the print statements, but when I call the setState method, the UI doesn't show the newly added entry.
Here's my HomePage.dart:
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
Future<List<Model>> getData() async {
return await DatabaseHelper.instance.getModels();
}
Future? userFuture;
#override
void initState() {
super.initState();
userFuture = getData();
print(userFuture);
}
#override
Widget build(BuildContext context) {
print('Building listview');
return Center(
child: FutureBuilder<List<Model>>(
future: userFuture as Future<List<Model>>,
builder: ((context, AsyncSnapshot<List<Model>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
if (snapshot.data!.isEmpty) {
return Text('No data present');
} else if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((context, index) {
return MyCard(
key: ValueKey(snapshot.data![index].id),
snapshot.data![index].id,
snapshot.data![index].title,
snapshot.data![index].purpose);
}),
);
}
return Text('data');
}
}),
),
);
}
}
Here's my other dart file. Under the AddEntryState I'm updating the Future state variable and then right after calling the setState method.
class RootPage extends StatefulWidget {
const RootPage({super.key});
#override
State<RootPage> createState() => RootPageState();
}
class RootPageState extends State<RootPage> {
static final GlobalKey<HomePageState> homepageKey =
GlobalKey<HomePageState>();
int currentPage = 0;
List<Widget>? pages;
#override
void initState() {
super.initState();
pages = [
HomePage(key: homepageKey),
StatsPage(),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App Title'),
),
body: pages?[currentPage],
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddEntry()));
},
child: Icon(Icons.add),
),
bottomNavigationBar: NavigationBar(
destinations: [
NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
NavigationDestination(icon: Icon(Icons.data_usage), label: 'Stats'),
],
onDestinationSelected: (int index) {
setState(() {
currentPage = index;
print(index);
});
},
selectedIndex: currentPage,
),
);
}
}
class AddEntry extends StatefulWidget {
const AddEntry({super.key});
#override
State<AddEntry> createState() => _AddEntryState();
}
class _AddEntryState extends State<AddEntry> {
final GlobalKey<FormState> _key = GlobalKey<FormState>();
Map<String, String?> formField = <String, String?>{};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Entry'),
),
body: Form(
key: _key,
child: Column(
children: [
Flexible(
child: MyTextField('Title', callback),
),
Flexible(
child: MyTextField('Purpose', callback),
),
Flexible(
child: MyTextField('Password', callback, obscure: true),
),
TextButton(
onPressed: () async {
if (_key.currentState!.validate()) {
_key.currentState?.save();
formField.forEach((label, value) => print('$label = $value'));
await DatabaseHelper.instance.insertModel(Model(
id: null,
title: formField['Title'],
purpose: formField['Purpose'],
lastAccess: DateTime.now().toString(),
dateAdded: DateTime.now().toString(),
password: formField['Password']));
print(await DatabaseHelper.instance.getModels());
// await DatabaseHelper.instance.deleteAllData();
// print(await DatabaseHelper.instance.getModels());
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Data Saved!'),
action: SnackBarAction(
label: 'Edit',
onPressed: () {
print('edit pressed!');
},
),
),
);
Navigator.pop(context);
print("HomePage userFuture: ");
print(RootPageState.homepageKey.currentState!.userFuture!
.then((result) => print(result)));
print("getData function: ");
print(RootPageState.homepageKey.currentState!
.getData()
.then((result) => print(result)));
print("New Future: ");
print(RootPageState.homepageKey.currentState!.userFuture!
.then((result) => print(result)));
setState(() {
RootPageState.homepageKey.currentState!.userFuture =
RootPageState.homepageKey.currentState!.getData();
});
//add logic to rebuild home screen after every addition of entry
}
},
child: Text('Submit'),
),
],
),
),
);
}
callback(varLabel, varValue) {
formField[varLabel] = varValue;
}
}

Flutter - drawer doesn't pop out when performing logout

I have an app that presents an AuthScreen and then works with subsequent screens based on the Auth provider class result.
In fact, in the main.dart file I present different pages based on the provider class Auth.
If the user performs the login (and he is Supplier), he will be directed to SupplierOverviewScreen, where he can see all his events.
If he clicks on an event, he will be directed to the EditEventScreen class, where he can modify the event.
Both SupplierOverviewScreen and EditEventScreen use the same drawer (SupplierDrawer), which allows to perform the logout operation.
When peforming a logout, Auth info will be deleted and so the main.dart file (consuming Auth provider class) will present againt the AuthScreen page.
If I'm on the SupplierOverviewScreen and I open the drawer to logout, everything works.
The problem is that if I'm on the EditEventScreen and I try to logout, The screen remains stuck and the drawer doesn't pop out.
I see that under the hood everything works, and the main.dart file returns the AuthScreen exactly as it does in SupplierOverviewScreen (where it works), but nothing changes on the screen.
If I return to previous screen, it doesn't direct me to SupplierOverview screen, but to AuthScreen.
I've found two possible hacks, but I'm not satisfied with them:
Remove drawer from EditEventScreen
Change the drawer such that after the logout it performs Navigator.pushReplacementNamed(context, "/"); It works, but since main.dart file consumes Auth provider class, I have that the home is called twice (one when Auth provider class notify listeners and one when drawer calls Navigator.pushReplacementNamed(context, "/")
Do you have any idea to suggest? Thanks a lot
This is the main.dart file:
Future<void> main() async {
await dotenv.load(fileName: Environment.fileName);
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
//Init state operations
}
void _configureAmplify() async {
// Amplify initial configurations
}
List<Event> _mockEvents() {
// mocked list of event objects
}
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => Auth()),
ChangeNotifierProxyProvider<Auth, Supplier>(
create: (ctx) => Supplier(userId: null, username: null),
update: (ctx, authData, previous) => Supplier(
userId: authData.getUserId, username: previous?.username),
),
ChangeNotifierProxyProvider<Auth, SupplierEvents>(
create: (ctx) => SupplierEvents(
userId: null,
events:
_mockEvents()),
update: (ctx, authData, previous) => SupplierEvents(
userId: authData.getUserId, events: previous?.events ?? []),
),
],
child: Consumer<Auth>(
builder: (context, authData, child) => MaterialApp(
title: 'Apperò',
theme: ThemeData(
colorScheme: Theme.of(context).colorScheme.copyWith(),
),
home: !authData.isAuth()
? FutureBuilder(
future: authData.tryAutoLogin(),
builder: (ctx, authResultSnapshot) {
print(authResultSnapshot.connectionState.name);
if (authResultSnapshot.connectionState ==
ConnectionState.waiting) {
return LoadingScreen();
} else
return AuthScreen();
})
: (authData.getUserType == UserType.supplier
? SupplierOverviewScreen()
: CustomerOverviewScreen()),
routes: {
SupplierOverviewScreen.ROUTE_NAME: (ctx) =>
SupplierOverviewScreen(),
CustomerOverviewScreen.ROUTE_NAME: (ctx) =>
CustomerOverviewScreen(),
EditEventScreen.ROUTE_NAME: (ctx) => EditEventScreen(),
}),
),
);
}
}
This is the SupplierOverviewScreen class:
class SupplierOverviewScreen extends StatefulWidget {
static const String ROUTE_NAME = '/supplier-overview-screen';
const SupplierOverviewScreen({Key? key}) : super(key: key);
#override
State<SupplierOverviewScreen> createState() => _SupplierOverviewScreenState();
}
class _SupplierOverviewScreenState extends State<SupplierOverviewScreen> {
late Future _obtainedInfo;
Future<void> _fetchInfo() async {
await Provider.of<Supplier>(context, listen: false).fetchSupplierByUserId();
await Provider.of<SupplierEvents>(context, listen: false)
.fetchEventsByUserId();
}
#override
void initState() {
_obtainedInfo = _fetchInfo();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Your page'), actions: []),
drawer: SupplierDrawer(),
body: FutureBuilder(
future: _obtainedInfo,
builder: (context, snapshot) => snapshot.connectionState ==
ConnectionState.waiting
? const Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => _fetchInfo(),
child: Column(
children: [
Consumer<Supplier>(
builder: (context, supplierData, _) => Padding(
padding: EdgeInsets.all(8),
child: Text('Hello ${supplierData.username}'),
),
),
const SizedBox(
height: 10,
),
Consumer<SupplierEvents>(
builder: (context, supplierEventsData, _) => Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: supplierEventsData.events.length,
itemBuilder: (context, index) => Column(children: [
SupplierEventsItem(
event: supplierEventsData.events[index],
),
const Divider(),
]),
),
),
),
const SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.all(8),
child: Text('Bottom element'),
),
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Text('Add Event', textAlign: TextAlign.center,),
onPressed: () {
Navigator.of(context)
.pushNamed(EditEventScreen.ROUTE_NAME);
},
));
}
}
This is the EditEventScreen class:
class EditEventScreen extends StatefulWidget {
static const String ROUTE_NAME = '/edit-event-screen';
const EditEventScreen({Key? key}) : super(key: key);
#override
State<EditEventScreen> createState() => _EditEventScreenState();
}
class _EditEventScreenState extends State<EditEventScreen> {
late Future _obtainedInfo;
Event? inputEvent;
var _isLoading = false;
var _form = GlobalKey<FormState>();
var _titleFocusNode = FocusNode();
var _descriptionFocusNode = FocusNode();
Map<String, dynamic?> _initialValuesMap = {
//....
};
Event event = Event(// ...);
#override
void didChangeDependencies() {
_obtainedInfo = _fetchInfo();
super.didChangeDependencies();
}
#override
void dispose() {
// ...
}
Future<void> _fetchInfo() async {
try {
var eventId = ModalRoute.of(context)!.settings.arguments as int?;
print('eventId: $eventId');
if (eventId != null) {
inputEvent = await Provider.of<SupplierEvents>(context, listen: false)
.findById(eventId);
_initFormFields();
}
} catch (error) {
print(error);
}
}
void _initFormFields() {
// init form fields logic
}
Future<void> _saveForm() async {
//Form saving logic
}
#override
Widget build(BuildContext context) {
print('Building EditEventScreen');
return Scaffold(
appBar: AppBar(title: Text('Manage event'), actions: [
IconButton(
onPressed: () {
_saveForm();
},
icon: Icon(Icons.check))
]),
drawer: SupplierDrawer(),
body: FutureBuilder(
future: _obtainedInfo,
builder: (context, snapshot) => snapshot.connectionState ==
ConnectionState.waiting
? const Center(
child: CircularProgressIndicator(),
)
: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _form,
child: SingleChildScrollView(
child: Column(
children: [
// TextFormFields ...
],
),
),
),
),
),
);
}
}
This is the drawer class:
class SupplierDrawer extends StatelessWidget {
Future<void> logout(BuildContext context) async {
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Logout'),
content: Container(
alignment: Alignment.center,
height: 300,
width: 300,
child: Column(
children: const [
Text('Logging out...'),
Center(
child: CircularProgressIndicator(),
)
],
),
),
);
},
);
await Provider.of<Auth>(context, listen: false).signOutCurrentUser(false);
Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
AppBar(
title: Text('Your options'),
automaticallyImplyLeading: false,
),
Divider(),
ListTile(
leading: Icon(Icons.logout),
title: Text('Logout'),
onTap: () async {
await logout(context);
},
),
],
),
);
}
}

Flutter build not behaving as expected

I'm trying to make a note app but there is a yellow square showing on the screen.
I've included the main.dart code and also allnotesscreens.dart. I think there is something wrong with allnotesscreens code, but I don't know what.
Maybe _loadViewMode() part.
Why this problem is happening?!!!
Main.dart:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'providers/label_provider.dart';
import 'providers/note_provider.dart';
import 'package:provider/provider.dart';
import 'constants/app_constants.dart';
import 'screens/all_labels_screen.dart';
import 'screens/all_notes_screen.dart';
import 'screens/drawer_screen.dart';
main() {
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: ColorsConstant.grayColor,
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => NoteProvider()),
ChangeNotifierProvider(create: (_) => LabelProvider()),
],
builder: (context, child) => MaterialApp(
title: 'Note-App',
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.dark,
theme: customThemeData(context),
initialRoute: '/',
routes: {
'/': (context) => const AllNotesScreen(),
DrawerScreen.routeName: (context) => const DrawerScreen(),
AllLabelsScreen.routeName: (context) => const AllLabelsScreen(),
},
),
);
}
}
allnotesscreens.dart:
class AllNotesScreen extends StatefulWidget {
const AllNotesScreen({Key? key}) : super(key: key);
#override
State<AllNotesScreen> createState() => _AllNotesScreenState();
}
class _AllNotesScreenState extends State<AllNotesScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
String _viewMode = ViewMode.staggeredGrid.name;
bool _isLoading = false;
final _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
setState(() {
_isLoading = true;
});
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
Future _loadViewMode() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('view-mode')) return;
setState(() {
_viewMode = prefs.getString('view-mode') ?? ViewMode.staggeredGrid.name;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text(
"all notes",
style: TextStyleConstants.titleAppBarStyle,
),
actions: [
if (context
.watch<NoteProvider>()
.items
.isNotEmpty)
IconButton(
onPressed: () {
showSearch(
context: context,
delegate: NoteSearch(isNoteByLabel: false),
);
},
icon: const Icon(Icons.search),
),
IconButton(
onPressed: () async {
final result = await changeViewMode(_viewMode);
setState(() {
_viewMode = result;
});
},
icon: _viewMode == ViewMode.staggeredGrid.name
? const Icon(Icons.view_stream)
: const Icon(Icons.grid_view),
),
const SizedBox(
width: 6,
)
],
),
drawer: const DrawerScreen(),
body: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => refreshOrGetData(context),
child: Consumer<NoteProvider>(
builder: (context, noteProvider, child) =>
noteProvider.items.isNotEmpty
? NoteListViewWidget(
notes: noteProvider.items,
viewMode: _viewMode,
scaffoldContext: _scaffoldKey.currentContext!,
)
: child!,
child: const NoNoteUIWidget(
title: "your notes after adding will appear here",
),
),
),
floatingActionButton: FloatingActionButton(
child: linearGradientIconAdd,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const EditNoteScreen(),
));
},
),
);
}
}
}
The first few lines of your _AllNotesScreenState class are why there's a yellow square; that's what you're telling it to build.
class _AllNotesScreenState extends State<AllNotesScreen> {
// this build function here is what is drawing to the screen
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
Maybe it's just how you've pasted it in, but it appears as though you have a build function defined within the didChangeDependencies function. If you took it out of there, it would then make it apparent that you have two build functions defined for the class.
I'm assuming it's the second one that you actually want building.
#override
void didChangeDependencies() {
super.didChangeDependencies();
Future _loadViewMode() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('view-mode')) return;
setState(() {
_viewMode = prefs.getString('view-mode') ?? ViewMode.staggeredGrid.name;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
...

Can't get data from api

While I am passing value from home page in API page after applying logic how I am not getting data in my result variable. What I am doing wrong?
Here is my home page where I passes the value -
import 'package:flutter/material.dart';
import 'sourceScreen.dart';
import 'models/API.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int value=0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("uTTerNews")),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =1;
API(value: value);
});
},
child:Text('India'),
color: Colors.blue,
),
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =0;
API(value: value);
});
},
child:Text('World'),
color: Colors.blue,
),
],
),
),
);
}
}
Here is my API page where I wanna use that value with some logic which is given below hope u will understand-
import 'model.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class API{
int value;
API({this.value});
Future<List<Source>> fetchNewsSource() async {
final world ='https://newsapi.org/v2/sources?apiKey=';
final india = 'https://newsapi.org/v2/sources?language=en&country=in&apiKey=';
String result;
void logic(){
if(value==1){
result = india;
}
else if(value==0){
result = world;
}
}
final response = await http.get(result);
if (response.statusCode == 200) {
List sources = json.decode(response.body)['sources'];
return sources.map((source) => new Source.formJson(source)).toList();
} else {
throw Exception('Fail to load data');
}
}
}
Here is home page -
import 'package:flutter/material.dart';
import 'sourceScreen.dart';
import 'models/API.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int value=0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("uTTerNews")),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =1;
API(value: value);
});
},
child:Text('India'),
color: Colors.blue,
),
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =0;
API(value: value);
});
},
child:Text('World'),
color: Colors.blue,
),
],
),
),
);
}
}
Source screen
import 'package:flutter/material.dart';
import 'models/model.dart';
import 'models/card.dart';
import 'article.dart';
import 'models/API.dart';
class SourceScreen extends StatefulWidget {
SourceScreen(Map<int, int> map);
#override
_SourceScreenState createState() => _SourceScreenState();
}
class _SourceScreenState extends State<SourceScreen> {
var list_source;
var refreshKey = GlobalKey<RefreshIndicatorState>();
#override
void initState() {
super.initState();
refreshListSource();
}
Future<Null> refreshListSource() async {
API api = new API();
refreshKey.currentState?.show(atTop: false);
setState(() {
list_source = api.fetchNewsSource();
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: AppBar(
elevation: 1.0,
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
title: Text('uTTerNews'),
),
body: Center(
child: RefreshIndicator(
child: FutureBuilder<List<Source>>(
future: list_source,
builder: (context, snapshot) {
if (snapshot.hasError) {
Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
List<Source> sources = snapshot.data;
return new ListView(
children: sources
.map((source) =>
GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) =>
articleScreen(source: source,)));
},
child: card(source),
))
.toList());
}
return CircularProgressIndicator();
},
),
onRefresh: refreshListSource),
),
),
);
}
}
Output:
Try this full code:
void main() => runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int value = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("uTTerNews")),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: () async {
value = 1;
List list = await API(value: value).fetchNewsSource();
Navigator.push(context, MaterialPageRoute(builder: (context) => SourceScreen(list)));
},
child: Text('India'),
color: Colors.blue,
),
FlatButton(
onPressed: () async {
value = 0;
List list = await API(value: value).fetchNewsSource();
Navigator.push(context, MaterialPageRoute(builder: (context) => SourceScreen(list)));
},
child: Text('World'),
color: Colors.blue,
),
],
),
),
);
}
}
class API {
int value;
API({#required this.value});
Future<List<dynamic>> fetchNewsSource() async {
final world = 'https://newsapi.org/v2/sources?apiKey=$apiKey';
final india = 'https://newsapi.org/v2/sources?language=en&country=in&apiKey=$apiKey';
String result;
if (value == 1)
result = india;
else if (value == 0) result = world;
final response = await http.get(result);
if (response.statusCode == 200) {
List sources = json.decode(response.body)['sources'];
return sources;
} else {
throw Exception('Fail to load data');
}
}
}
class SourceScreen extends StatefulWidget {
final List list;
SourceScreen(this.list);
#override
_SourceScreenState createState() => _SourceScreenState();
}
class _SourceScreenState extends State<SourceScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Channels")),
body: ListView(
children: widget.list.map((map) => ListTile(title: Text(map["name"]))).toList(),
),
);
}
}

How to update state of a ModalBottomSheet in Flutter?

This code is very simple: shows a modal bottom sheet and when the uses clicks the button, it increases the height of the sheet by 10.
But nothing happens. Actually, it only updates its size if the user "slides" the bottom sheet with it's finger (I belive that swipe causes a internal setState on the sheet).
My question is: how do I call the update state of a ModalBottomSheet?
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(
onPressed: () {
setState(() {
heightOfModalBottomSheet += 10;
});
}),
);
});
You can use Flutter's StatefulBuilder to wrap your ModalBottomSheet as follows:
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState /*You can rename this!*/) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(onPressed: () {
setState(() {
heightOfModalBottomSheet += 10;
});
}),
);
});
});
Please note that the new setState will override your main widget setState but sure you can just rename it so you would be able to set state of your parent widget and the modal's
//This sets modal state
setModalState(() {
heightOfModalBottomSheet += 10;
});
//This sets parent widget state
setState(() {
heightOfModalBottomSheet += 10;
});
You can maybe use the showBottomSheet from the ScaffoldState. read more here about this showBottomSheet.
This will show the bottomSheet and return a controller PersistentBottomSheetController. with this controller you can call controller.SetState((){}) which will re-render the bottomSheet.
Here is an example
PersistentBottomSheetController _controller; // <------ Instance variable
final _scaffoldKey = GlobalKey<ScaffoldState>(); // <---- Another instance variable
.
.
.
void _incrementBottomSheet(){
_controller.setState(
(){
heightOfModalBottomSheet += 10;
}
)
}
.
void _createBottomSheet() async{
_controller = await _scaffoldKey.currentState.showBottomSheet(
context: context,
builder: (context) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(
onPressed: () {
_incrementBottomSheet()
}),
);
});
}
Screenshot:
Create a class:
class MyBottomSheet extends StatefulWidget {
#override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
bool _flag = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
FlutterLogo(
size: 300,
style: FlutterLogoStyle.stacked,
textColor: _flag ? Colors.black : Colors.red,
),
RaisedButton(
onPressed: () => setState(() => _flag = !_flag),
child: Text('Change Color'),
)
],
);
}
}
Usage:
showModalBottomSheet(
context: context,
builder: (_) => MyBottomSheet(),
);
Please refer to the below working code. I created a new Stateful widget(ModalBottomSheet) for the showModalBottomSheet. On button press, we are rebuilding the ModalBottomSheet only which is much cleaner now. We can use AnimationController if need animation for changing the height.
import 'dart:async';
import 'package:flutter/material.dart';
class ModalBottomSheet extends StatefulWidget {
_ModalBottomSheetState createState() => _ModalBottomSheetState();
}
class _ModalBottomSheetState extends State<ModalBottomSheet>
with SingleTickerProviderStateMixin {
var heightOfModalBottomSheet = 100.0;
Widget build(BuildContext context) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(
child: Text("Press"),
onPressed: () {
heightOfModalBottomSheet += 100;
setState(() {});
}),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Future(() => showModalBottomSheet(
context: context,
builder: (context) {
return ModalBottomSheet();
}));
return new Scaffold(
appBar: new AppBar(
title: new Text("Modal example"),
),
);
}
}
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(title: 'Flutter Demo', home: new MyHomePage());
}
}
create a separate StatefulWidget for the showModalBottomSheet(), like
showModalBottomSheet(
context: context,
builder: (ctx) {
return MapBottomSheet();
});
Bottom Sheet Statefulwidget
class MapBottomSheet extends StatefulWidget {
#override
_MapBottomSheetState createState() => _MapBottomSheetState();
}
class _MapBottomSheetState extends State<MapBottomSheet> {
List<String> places = [];
void _setPlaces(String place) {
setState(() {
places.add(place);
});
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black12,
child: Column(
children: [
AppTextField(
hint: "Search",
onEditingComplete: () {},
onChanged: (String text) {},
onSubmitted: (String text) async {
// Await the http get response, then decode the json-formatted response.
var response = await http.get(Uri.parse(
'https://api.mapbox.com/geocoding/v5/mapbox.places/$text.json?access_token=pk.eyJ1IjoidjNyc2lvbjkiLCJhIjoiY2ttNnZldmk1MHM2ODJxanh1ZHZqa2I3ZCJ9.e8pZsg87rHx9FSM0pDDtlA&country=PK&fuzzyMatch=false&place=park'));
if (response.statusCode == 200) {
Map<String, dynamic> data = jsonDecode(response.body);
print(data.toString());
List<dynamic> features = data['features'];
features.forEach((dynamic feature) {
setState(() {
_setPlaces(feature['place_name']);
});
});
} else {
print('Request failed with status: ${response.statusCode}.');
}
},
),
Expanded(
child: Container(
height: 250.0,
width: double.infinity,
child: ListView.builder(
itemCount: places.length,
itemBuilder: (ctx, idx) {
return Container(
child: Text(places[idx]),
);
}),
),
),
],
),
);
}
}