How to enable SystemChrome - SystemUiOverlayStyle in Flutter - flutter

please I tried to set SystemChrome.setSystemUiOverlayStyle() based on a condition that is bool value stored in phone using shared_preferences. Even if dark mode is true or not, SystemChrome.setSystemUiOverlayStyle did not work or changed on the condition when app launched. Sorry my bad English grammar. Below is my code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:kjv_bible/screens/book_chapters.dart';
import 'package:kjv_bible/screens/home_page.dart';
import 'package:kjv_bible/utils/color_helper.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'providers/setting_provider.dart';
import 'package:provider/provider.dart';
import 'models/theme_preferences.dart';
void main() => runApp(Bible());
class Bible extends StatefulWidget {
#override
_BibleState createState() => _BibleState();
}
class _BibleState extends State<Bible> {
SharedPreferences _prefs;
bool _isDark;
#override
void initState() {
setTheme();
super.initState();
}
void setTheme() async {
_isDark = false;
if (_prefs == null) _prefs = await SharedPreferences.getInstance();
if (_prefs.containsKey('theme')) {
_isDark = _prefs.getBool('theme') == true ? true : false;
} else {
_isDark = false;
}
if (_isDark) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: color("#232D36"),
statusBarColor: color("#101D25"),
));
} else {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
systemNavigationBarColor: Colors.white,
statusBarColor: color("#22A2EE"),
));
}
}
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: SettingProvider()),
],
child: Consumer<SettingProvider>(builder: (ctx, status, _) {
return MaterialApp(
theme: status.darkTheme ? darkTheme : lightTheme,
title: "Bible",
debugShowCheckedModeBanner: false,
home: HomePage(),
routes: {
BookChapters.routeName: (ctx) => BookChapters(),
},
);
}),
);
}
}

Try this:
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await setTheme();
runApp(Bible());
}
Just a side note, try using Dart features in your code
if (_prefs == null) _prefs = await SharedPreferences.getInstance();
_prefs ??= await SharedPreferences.getInstance();
.
if (_prefs.containsKey('theme')) {
_isDark = _prefs.getBool('theme') == true ? true : false;
} else {
_isDark = false;
}
_isDark = _prefs.containKey('theme') ? _prefs.getBool('theme') : false;

Related

flutter does not show data from API

When I try to pull data from the jsonplaceholder API and put it on the screen, I don't have any problems, but when I try to change the data in this link (https://reqres.in/api/users?page=2 ) on the reqres.io site with the same codes, only by changing the API and model, the text no data appears on the screen. I'm getting it can you help me ?
My project with JsonPlaceHolder
main.dart
import 'package:flutter/material.dart';
import 'package:my_app/models/json_model.dart';
import 'service/api_service.dart';
void main() =\> runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Json Deneme'),
),
body: const Home(),
),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
#override
State\<Home\> createState() =\> \_HomeState();
}
class \_HomeState extends State\<Home\> {
List\<JsonModel\>? \_postItems;
bool \_isLoading = false;
String? \_errorMessage;
#override
void initState() {
super.initState();
loadData();
}
Future\<void\> loadData() async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
final postItems = await Api.fetchApi();
setState(() {
_postItems = postItems;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Error fetching data: $e';
});
}
}
#override
Widget build(BuildContext context) {
if (\_isLoading) {
return const Center(child: CircularProgressIndicator());
} else if (\_postItems == null || \_postItems!.isEmpty) {
return const Center(child: Text('No Data'));
} else {
return ListView.builder(
itemCount: \_postItems!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(\_postItems!\[index\].name),
);
},
);
}
}
}`
api_service.dart
`import 'dart:io';
import 'package:my_app/models/json_model.dart';
import 'package:dio/dio.dart';
class Api {
static Future<List<JsonModel>?> fetchApi() async {
final res = await Dio().get("https://jsonplaceholder.typicode.com/users");
if (res.statusCode == HttpStatus.ok) {
final data = res.data!;
if (data is List) {
return data.map((e) =\> JsonModel.fromMap(e)).toList();
}
}
return <JsonModel>[];
}
}
`
conclusion
conclusion
My project with reqres.in
main.dart
`import 'package:flutter/material.dart';
import 'package:my_app/models/json_model.dart';
import 'service/api_service.dart';
void main() =\> runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Json Deneme'),
),
body: const Home(),
),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<ReqresModel>? _postItems;
bool _isLoading = false;
String? _errorMessage;
#override
void initState() {
super.initState();
loadData();
}
Future<void> loadData() async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
final postItems = await Api.fetchApi();
setState(() {
_postItems = postItems;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Error fetching data: $e';
});
}
}
#override
Widget build(BuildContext context) {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
} else if (_postItems == null || _postItems!.isEmpty) {
return const Center(child: Text('No Data'));
} else {
return ListView.builder(
itemCount: _postItems!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(\_postItems!\[index\].data\[index\].firstName),
);
},
);
}
}
}`
api_servise.dart
`import 'dart:io';
import 'package:my_app/models/json_model.dart';
import 'package:dio/dio.dart';
class Api {
static Future<List<ReqresModel>?> fetchApi() async {
final res = await Dio().get("https://reqres.in/api/users?page=2");
if (res.statusCode == HttpStatus.ok) {
final data = res.data!;
if (data is List) {
return data.map((e) => ReqresModel.fromMap(e)).toList();
}
}
return <ReqresModel>[];
}
}`
conclusion
conclusion
**Thank you **
I sent the API using Postman, there was no problem, I don't think the problem was caused by the API, sorry for my bad English
Change your api_service.dart for reqres.in project with following code.
First api which returns List directly, but second api which return Json which has data as List
Edited
main.dart
import 'package:flutter/material.dart';
import 'package:my_app/models/json_model.dart';
import 'service/api_service.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Json Deneme'),
),
body: const Home(),
),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<ReqresModel>? _postItems;
bool _isLoading = false;
String? _errorMessage;
#override
void initState() {
super.initState();
loadData();
}
Future<void> loadData() async {
setState(() {
_isLoading = true;
_errorMessage = null;
});
try {
final postItems = await Api.fetchApi();
setState(() {
_postItems = postItems;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Error fetching data: $e';
});
}
}
#override
Widget build(BuildContext context) {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
} else if (_postItems == null || _postItems!.isEmpty) {
return const Center(child: Text('No Data'));
} else {
return ListView.builder(
itemCount: _postItems!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_postItems![index].firstName),//Updated here
);
},
);
}
}
}
api_service.dart
import 'dart:io';
import 'package:my_app/models/json_model.dart';
import 'package:dio/dio.dart';
class Api {
static Future<List<ReqresModel>?> fetchApi() async {
final res = await Dio().get("https://reqres.in/api/users?page=2");
if (res.statusCode == HttpStatus.ok) {
final data = res.data!['data'];//Updated here
if (data is List) {
return data.map((e) => ReqresModel.fromMap(e)).toList();
}
}
return <ReqresModel>[];
}
}
ReqresModel - should be updated
//Updated here
class ReqresModel {
int? id;
String? email;
String? firstName;
String? lastName;
String? avatar;
ReqresModel(
{this.id, this.email, this.firstName, this.lastName, this.avatar});
ReqresModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
email = json['email'];
firstName = json['first_name'];
lastName = json['last_name'];
avatar = json['avatar'];
}
}

How to get and use saved language/locale from shared preferences in Flutter?

I am using flutter localizations for changing language in my flutter app. I want to change my app's language in real time and have implemented logic for that. Now, I want that when user closes app and restarts it, he gets same language he chose before, i.e. language should not set back to default after user closes the app. For this purpose, I am using shared preferences to save the code of language that user selected, and now I can't retrieve it in the beginning of the app. Please help!
locale_provider.dart:
import 'package:flutter/material.dart';
import 'package:myapp/l10n/l10n.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LocaleProvider extends ChangeNotifier {
Locale? _locale = const Locale('en');
Locale? get locale => _locale;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
//setLocaleSettings(locale);
}
void clearLocale() {
_locale = null;
notifyListeners();
}
void changeLocaleSettings(Locale newLocale) async {
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("code", _locale?.countryCode??"en");
notifyListeners();
}
Future getLocaleFromSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString("code")??"en";
Locale newLocale = Locale(code);
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
}
}
In my language selection dropdown, I am changing language like this:
class LanguagePickerWidget extends StatelessWidget {
const LanguagePickerWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final provider = Provider.of<LocaleProvider>(context);
final locale1 = provider.locale ?? const Locale('en');
return DropdownButtonHideUnderline(
child: SizedBox(
width: 15,
child: Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.green.shade300,
),
child: DropdownButton(
borderRadius:BorderRadius.circular(12),
isExpanded: true,
itemHeight: null,
value: locale1,
icon: Container(
//width: 10.0
),
items: L10n.all.map(
(locale) {
final flag = L10n.getFlag(locale.languageCode);
return DropdownMenuItem(
child: Align(
alignment: Alignment.center,
child: Text(
flag,
style: const TextStyle(fontSize: 22.0),
),
),
value: locale,
onTap: () {
final provider = Provider.of<LocaleProvider>(context, listen: false);
provider.setLocale(locale);
provider.changeLocaleSettings(locale);
print(locale);
},
);
},
).toList(),
onChanged: (_) {},
),
),
),
);
}
}
In main.dart:
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) => ChangeNotifierProvider(
create: (context) => LocaleProvider(),
builder: (context, child) {
final provider = Provider.of<LocaleProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.lightGreen[100],
primarySwatch: Colors.green,
),
//locale: provider.locale,
supportedLocales: L10n.all,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: const HomePage(),
);
});
}
It works pretty well for changing the language in runtime..
And now I don't understand how to retrieve and set the previously selected language (from shared preferences)? Please help!
Create a default constructor for LocaleProvider class and put this code inside it
LocaleProvider(){
Fututre.delayed(Duration.zero, getLocaleFromSettings);
}
and at the end of your function getLocaleFromSettings(), call notifyListeners();
the reason to use FutureBuilder is that if you called notifyListeners while building frame is processing it will give you an error, so adding some delay to prevent rendering issues
tried this get locale whenever you intialize LocaleProvider class:-
import 'package:flutter/material.dart';
import 'package:myapp/l10n/l10n.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LocaleProvider extends ChangeNotifier {
Locale? locale;
LocaleProvider({this.locale});
Locale? get locale => _locale;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
//setLocaleSettings(locale);
}
void clearLocale() {
_locale = null;
notifyListeners();
}
void changeLocaleSettings(Locale newLocale) async {
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("code", _locale?.countryCode??"en");
notifyListeners();
}
Future getLocaleFromSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString("code")??"en";
Locale newLocale = Locale(code);
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
}
}
use this in main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences _sharedPreferences = await SharedPreferences.getInstance();
string savedLangugae = get from sharepreference;
runApp(MultiProvider(providers: [
ChangeNotifierProvider(create: (_) => LocaleProvider(locale:Locale(savedLanguage))),
], child: const MyApp()));
}
Hope it will work.

Flutter - Applying theme mode Dark/Light from a boolean variable in Shared preferences using Provider

I am using Provider to manage the Dark/Light theme across a Flutter mobile application and I need to store the theme setting in Shared Preferences as a boolean currently the theme setting is controlled via a Switch.
I couldn't figure out how to do it and couldn't make my way around Shared Prefs.
Below is my attempt at implementing said feature but couldn't make it work.
Q: How to implement Shared Prefs and store the theme data inside?
Switch button widget:
class ThemeToggle extends StatelessWidget {
setThemeModeSP(bool isDark) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('isDarkEnabled', isDark);
}
isPresentSP(String prefKey) async {
SharedPreferences sp = await SharedPreferences.getInstance();
if (sp.containsKey(prefKey)) {
return true;
} else {
return false;
}
}
removeThemeModeSP() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove('isDarkEnabled');
}
#override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Switch.adaptive(
value: themeProvider.isDarkMode,
onChanged: (value) {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value);
setThemeModeSP(value);
});
}
}
Theme provider class
class ThemeProvider extends ChangeNotifier {
ThemeMode themeMode = ThemeMode.light;
bool get isDarkMode => themeMode == ThemeMode.dark;
void toggleTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
UPDATE: I MANAGED TO STORE A DARK MODE BOOLEAN IN SHARED PREFERENCES BUT WHEN I RETRIEVE IT THE THEME DOES NOT CHANGE
I tested and found the the boolean value is stored and retrieved successfully the only problem that remains is that the theme goes back to default when app is restarted
Here are the changes I made:
Switch button widget:
class ThemeToggle extends StatelessWidget {
#override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Switch.adaptive(
value: themeProvider.isDarkMode,
onChanged: (value) {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value);
mSharedPrefs.setBool('myThemeMode', value);
});
}
}
Theme provider class
isPresentSP(String prefKey) async {
SharedPreferences sp = await SharedPreferences.getInstance();
if (sp.containsKey(prefKey)) {
return true;
} else {
return false;
}
}
Future<bool> fetchThemeSettingsFromSP() async {
SharedPreferences mSharedPrefs = await SharedPreferences.getInstance();
try {
if (isPresentSP('myThemeMode') == false) {
return false;
} else {
var spr = mSharedPrefs.getBool('myThemeMode');
if (spr != null) {
if (spr) {
return true;
} else if (!spr) {
return false;
}
} else if (spr == null) {
return false;
}
}
return false;
} catch (e) {
print('fetch theme from SP err: ' + e.toString());
return false;
}
}
themeModeSettings() {
fetchThemeSettingsFromSP().then((val) {
if (val == null) {
return false;
} else {
return val;
}
});
}
class ThemeProvider extends ChangeNotifier {
ThemeMode themeMode = ThemeMode.light;
bool get isDarkMode => themeModeSettings() ?? themeMode == ThemeMode.dark;
void toggleTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
in ThemeToggle class:
class ThemeToggle extends StatelessWidget {
#override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Switch.adaptive(
value: themeProvider.getThemeBoolSP().toString() == 'false' ? false : true,
onChanged: (value) async {
SharedPreferences mSharedPrefs = await SharedPreferences.getInstance();
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value);
mSharedPrefs.setBool('myThemeMode', value);
});
}
}
in ThemeProvider class:
class ThemeProvider extends ChangeNotifier {
getThemeBoolSP() async {
SharedPreferences mSharedPrefs = await SharedPreferences.getInstance();
return mSharedPrefs.getBool('myThemeMode');
}
ThemeMode themeMode = ThemeMode.light;
bool get isDarkMode => themeMode == ThemeMode.dark;
void toggleTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
in main.dart/MyApp class:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) => ChangeNotifierProvider(
create: (context) => ThemeProvider(),
builder: (context, _) {
final themeProvider = Provider.of<ThemeProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
themeMode: themeProvider.getThemeBoolSP().toString() == 'false' ? ThemeMode.light : ThemeMode.dark,
theme: UIThemes.lightTheme,
darkTheme: UIThemes.darkTheme,
home: Newsfeed(),
);
});
}

How to have the ability to use both Navigator.push and Navigator.pushNamed flutter

I have added some routes to my flutter app so that when a specific link is pressed a specific page will be opened
This is the source code of the main page
import 'dart:convert';
import 'package:admob_flutter/admob_flutter.dart';
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:catcher/catcher.dart';
import 'package:dynamic_theme/dynamic_theme.dart';
import 'package:firebase_admob/firebase_admob.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:videos/c.dart';
import 'package:flutter/foundation.dart';
import 'package:videos/post.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'database/database.dart';
import 'database/database/mobile.dart' as mobile;
import 'src/app_route.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
FirebaseAdMob.instance.initialize(appId: APP_ID);
Admob.initialize(APP_ID);
await AndroidAlarmManager.initialize();
CatcherOptions debugOptions =CatcherOptions(DialogReportMode(), [kIsWeb?ConsoleHandler(): EmailManualHandler(["ahmad.rajab#windowslive.com"])]);
CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
kIsWeb?ToastHandler():EmailManualHandler(["ahmad.rajab#windowslive.com"])
]);
Catcher(MyApp(), debugConfig: debugOptions, releaseConfig: releaseOptions);
}
class MyApp extends StatefulWidget{
#override
State<StatefulWidget> createState()=>MyAppState();
}
class MyAppState extends State<MyApp> {
static Future configureDatabase()async{
/*database = await openDatabase(DATABASE_NAME, version: DATABASE_VERSION,
onCreate: (Database db, int version) async {
await db.execute('create table $WATCHED_VIDEOS ($VIDEO_ID text,$REACHED_SECOND integer default 0,$NOTE text)');
await db.execute('create table $TABLE_FAVORITE_VIDEOS ($VIDEO_TITLE text,$VIDEO_ID text,$VIDEO_DESCRIPTION text,$VIDEO_THUMBURL text)');
await db.execute('create table $CHANNELS ($ID integer ,$NAME text,$LINK text, $PICTURE_LINK text,$VIEWED integer default 0,$GET_NOTIFICATIONS integer default 1,$LAST_VIDEO_TITLE text)');
},
onUpgrade: (db, oldVersion, newVersion)async {
var tableColumns= await db.query('PRAGMA table_info($WATCHED_VIDEOS)');
bool noteColumnExists=false;
for(int c=0;c<tableColumns.length;c++){
if(tableColumns[c]['name'].toString()==NOTE)noteColumnExists=true;
}
if(!noteColumnExists) await db.execute('alter table $WATCHED_VIDEOS add $NOTE text');
},);
*/
}
AppRouterDelegate _routerDelegate = AppRouterDelegate();
AppRouteInformationParser _routeInformationParser =
AppRouteInformationParser();
#override
void initState() {
super.initState();
initialiseNotification();
initialiseTimeZone();
showDailyReminderNotification();
configureDailyNewVideosFitch();
}
void configureDailyNewVideosFitch()async{
await AndroidAlarmManager.periodic(const Duration(days: 1),DAILY_NEW_VIDEOS_FETCH_ALARAM_ID , ()async{
Database d=RepositoryProvider.of<Database>(context);
List<Channel>subscribedChannels=await (d.select($ChannelsTable(d))..where((tbl) => tbl.getNotifications.equals(1))).get();
String channelsIds='';
for(int i=0;i<subscribedChannels.length;i++)channelsIds+=subscribedChannels[i].link+"/";
Map<String,String> map=Map();
map['channels']=channelsIds;
Post p=Post(context,'getVideosFromTime.php',map);
await p.fetchPost();
if(p.connectionSucceed){
dynamic resultJson=json.decode(p.result);
if(resultJson['result']=='success'){
for(int i=0;i<resultJson['data'].length;i++){
dynamic videoJson=resultJson['data'][i];
await flutterLocalNotificationsPlugin.show(videoJson['id'], videoJson['channelName'], videoJson['title'],
NotificationDetails(
android: AndroidNotificationDetails(
APP_NAME,
APP_NAME, NEW_VIDEO_AVAILABLE,
icon: '#mipmap/ic_launcher',
ticker: videoJson['title']
),
),
payload:'/watch?v='+videoJson['videoId']
);
}
}
}
},rescheduleOnReboot: true);
}
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
void showDailyReminderNotification()async{
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(APP_NAME,
APP_NAME, 'dailyReminder'+APP_NAME,
icon: '#mipmap/ic_launcher',
ticker: TIME_TO_LEARN);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.periodicallyShow(DAILY_REMINDER_NOTIFICATION_ID, TIME_TO_LEARN,
TIME_TO_LEARN_DESCRIPTION, RepeatInterval.daily, platformChannelSpecifics,
androidAllowWhileIdle: false);
}
void initialiseTimeZone()async{
tz.initializeTimeZones();
tz.setLocalLocation(tz.getLocation(await FlutterNativeTimezone.getLocalTimezone()));
}
void initialiseNotification()async{
flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('#mipmap/ic_launcher');
final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings(
/*onDidReceiveLocalNotification: onDidReceiveLocalNotification*/);
final MacOSInitializationSettings initializationSettingsMacOS =
MacOSInitializationSettings();
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: initializationSettingsMacOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: selectNotification);
await flutterLocalNotificationsPlugin.cancel(DAILY_REMINDER_NOTIFICATION_ID);
}
Future selectNotification(String payload) async {
if(payload!=null)Navigator.pushNamed(context, payload);
}
#override
Widget build(BuildContext context) {
return DynamicTheme(
defaultBrightness: Brightness.light,
data: (brightness) => ThemeData(
primarySwatch: PRIMARY_COLOR,
brightness: brightness
),
themedWidgetBuilder: (context, data) {
return RepositoryProvider<Database>(
create:(context)=>mobile.constructDb() ,
child: BlocProvider(
create: (context){
//final db = RepositoryProvider.of<Database>(context);
//return AppBloc(db);
},
child: MaterialApp.router(
//title: 'Books App',
theme: data,
routerDelegate: _routerDelegate,
routeInformationParser: _routeInformationParser,
)
)
);
}
);
}
}
MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
// ignore: deprecated_member_use
gender: MobileAdGender.unknown,
childDirected: true
);
class AdmobAdd extends StatelessWidget{
#override
Widget build(BuildContext context) {
return !PRO?AdmobBanner(
adUnitId: kReleaseMode?BANNER_AD_UNIT_ID:BannerAd.testAdUnitId,
adSize: AdmobBannerSize.BANNER,
):Container();
}
}
InterstitialAd myInterstitial = InterstitialAd(
adUnitId: InterstitialAd.testAdUnitId,
targetingInfo: targetingInfo,
);
this is the source code of the routes configuration file
import 'package:catcher/catcher.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:videos/home.dart';
import 'package:videos/video.dart';
class AppRouteInformationParser extends RouteInformationParser<AppRoutePath> {
#override
Future<AppRoutePath> parseRouteInformation(
RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.location);
// Handle '/'
if (uri.pathSegments.length == 0) {
return AppRoutePath.home();
}
// Handle '/watch?v=fsdfsdfsd
if (uri.pathSegments.length == 1) {
if (!uri.pathSegments[0].startsWith('/watch?')) return AppRoutePath.unknown();
if(uri.pathSegments[0].startsWith('/watch?v=')){
var videoId=uri.queryParameters['v'];
return AppRoutePath.video(videoId);
/*var remaining = uri.pathSegments[1];
var id = int.tryParse(remaining);
if (id == null) return AppRoutePath.unknown();
return AppRoutePath.details(id);*/
}
}
// Handle unknown routes
return AppRoutePath.unknown();
}
#override
RouteInformation restoreRouteInformation(AppRoutePath path) {
if (path.isUnknown) {
return RouteInformation(location: '/404');
}
if (path.isHomePage) {
return RouteInformation(location: '/');
}
if(path.isVideoPage){
return RouteInformation(location: '/watch?v=${path.id}');
}
if (path.isDetailsPage) {
return RouteInformation(location: '/book/${path.id}');
}
return null;
}
}
class AppRouterDelegate extends RouterDelegate<AppRoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoutePath> {
final GlobalKey<NavigatorState> navigatorKey;
//Book _selectedBook;
bool show404 = false;
String videoId;
/*List<Book> books = [
Book('Stranger in a Strange Land', 'Robert A. Heinlein'),
Book('Foundation', 'Isaac Asimov'),
Book('Fahrenheit 451', 'Ray Bradbury'),
];*/
AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();
AppRoutePath get currentConfiguration {
if (show404) {
return AppRoutePath.unknown();
}
if(videoId!=null) return AppRoutePath.video(videoId);
/*return _selectedBook == null
? AppRoutePath.home()
: AppRoutePath.details(books.indexOf(_selectedBook));*/
return AppRoutePath.home();
}
#override
Widget build(BuildContext context) {
return Navigator(
key: Catcher.navigatorKey,
pages: [
MaterialPage(
key: ValueKey('Home'),
child: MyHomePage()
),
if (show404)
MaterialPage(key: ValueKey('Unknown'), child: UnknownScreen())
else if(videoId!=null) VideoPageRoute(videoId: videoId)
/*else if (_selectedBook != null)
BookDetailsPage(book: _selectedBook)*/
],
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
// Update the list of pages by setting _selectedBook to null
//_selectedBook = null;
videoId=null;
show404 = false;
notifyListeners();
return true;
},
);
}
#override
Future<void> setNewRoutePath(AppRoutePath path) async {
if (path.isUnknown) {
//_selectedBook = null;
videoId=null;
show404 = true;
return;
}
/*if (path.isDetailsPage) {
if (path.id < 0 || path.id > books.length - 1) {
show404 = true;
return;
}
_selectedBook = books[path.id];
} else {
_selectedBook = null;
}*/
show404 = false;
}
void videoNotFound(){
videoId=null;
show404=true;
notifyListeners();
}
/*void _handleBookTapped(Book book) {
_selectedBook = book;
notifyListeners();
}*/
}
class AppRoutePath {
final String id;
final bool isUnknown;
AppRoutePath.home()
: id = null,
isUnknown = false;
AppRoutePath.details(this.id) : isUnknown = false;
AppRoutePath.video(this.id): isUnknown=false;
AppRoutePath.unknown()
: id = null,
isUnknown = true;
bool get isHomePage => id == null;
bool get isDetailsPage => id != null;
bool get isVideoPage => id!=null;
}
/*class BooksListScreen extends StatelessWidget {
final List<Book> books;
final ValueChanged<Book> onTapped;
BooksListScreen({
#required this.books,
#required this.onTapped,
});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView(
children: [
for (var book in books)
ListTile(
title: Text(book.title),
subtitle: Text(book.author),
onTap: () => onTapped(book),
)
],
),
);
}
}
*/
/*class BookDetailsScreen extends StatelessWidget {
final Book book;
BookDetailsScreen({
#required this.book,
});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (book != null) ...[
Text(book.title, style: Theme.of(context).textTheme.headline6),
Text(book.author, style: Theme.of(context).textTheme.subtitle1),
],
],
),
),
);
}
}
*/
class UnknownScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text('404!'),
),
);
}
}
The problem is that I have several screens that has no specific url and I do not want to provide them with routes, I want simply to use Navigator.push()
That is working fine, but when pressing the back button or when I use Navigator.pop() the app closes entirely instead of navigating back to the previous page
How can I use Navigator.pushNamed only for named routes and use Navigator.push for other pages without causing the problem to occur
Thanks in advance

ChangeNotifierProxyProvider flutter not getting update from ChangeNotifierProvider

I am trying to access userModel.uid from UserProvider inside the ItemProvider so it can load _savedItems.
However, when I call loadUserSavedItems(), _userId is null.
Here is my main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/user.dart';
import 'providers/item.dart';
import 'screens/home.dart';
void main() {
Provider.debugCheckInvalidValueType = null;
WidgetsFlutterBinding.ensureInitialized();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<UserProvider>(
create: (_) => UserProvider.initialize()),
ChangeNotifierProxyProvider<UserProvider, ItemProvider>(
create: (_) => ItemProvider(),
update: (_, userProvider, itemProvider) => itemProvider,
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.white,
primaryTextTheme: TextTheme(
headline6: TextStyle(color: Colors.black),
),
),
home: Home(),
),
),
);
}
UserProvider.dart
import 'models/user.dart';
import 'services/user.dart';
enum Status { Uninitialized, Authenticated, Authenticating, Unauthenticated }
class UserProvider extends ChangeNotifier {
FirebaseAuth _auth;
FirebaseUser _user;
Status _status = Status.Uninitialized;
Firestore _firestore = Firestore.instance;
UserServices _userServicse = UserServices();
UserModel _userModel;
// getter
UserModel get userModel => _userModel;
Status get status => _status;
FirebaseUser get user => _user;
UserProvider.initialize() : _auth = FirebaseAuth.instance {
_auth.onAuthStateChanged.listen(_onStateChanged);
notifyListeners();
}
Future<void> _onStateChanged(FirebaseUser firebaseUser) async {
if (firebaseUser == null) {
_status = Status.Unauthenticated;
} else {
_user = firebaseUser;
_status = Status.Authenticated;
_userModel = await _userServicse.getUserById(user.uid);
}
notifyListeners();
}
Future<bool> signIn() async {
bool retVal = false;
try {
_status = Status.Authenticating;
notifyListeners();
AuthResult _authResult = await _auth.signInWithEmailAndPassword(
email: email.text.trim(), password: password.text.trim());
if (_authResult.user != null) {
retVal = true;
}
} catch (e) {
_status = Status.Unauthenticated;
notifyListeners();
print(e.toString());
}
return retVal;
}
}
ItemProvider.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
import 'models/item.dart';
import 'providers/user.dart';
import 'services/item.dart';
class ItemProvider extends ChangeNotifier {
ItemProvider({UserProvider userProvider}) : _userProvider = userProvider;
UserProvider _userProvider;
final databaseReference = Firestore.instance;
ItemServices _itemServices = ItemServices();
List<Item> _items = [];
List<Item> _savedItems = [];
String _userId;
// getter
List<Item> get items => _items;
List<Item> get savedItems => _savedItems;
String get userId => _userId;
UserProvider get userProvider => _userProvider;
//get the items to load when the app is initiated
ItemProvider.initialize() {
loadAllActiveItems();
if (_userProvider.status == Status.Authenticated) {
loadUserSavedItems();
}
}
//get active items from DB
loadAllActiveItems() async {
_items = await _itemServices.getBatchOfActiveItems();
notifyListeners();
}
//get user saved items from DB
loadUserSavedItems() async {
_userId = userProvider.userModel.uid;
_savedItems = await _itemServices.getUserSavedItems(userId);
notifyListeners();
}
}
Can someone help me, I am not quite sure what I am missing, can't userModel object/properties in ItemProvider.dart when implemented as ChangeNotifierProxyProvider.
I finally found a way around, maybe not the best but it worked.
Inside ItemProvider created updates() to receive the userId from
void updates(String userId, Status status) {
this._userId = userId;
}
And then made the changes in main.dart to pass the userId from ChangeNotifierProxyProvider.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/user.dart';
import 'providers/item.dart';
import 'screens/home.dart';
void main() {
Provider.debugCheckInvalidValueType = null;
WidgetsFlutterBinding.ensureInitialized();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<UserProvider>(
create: (_) => UserProvider.initialize()),
ChangeNotifierProxyProvider<UserProvider, ItemProvider>(
create: (_) => ItemProvider(),
update: (_, userProvider, itemProvider) => itemProvider
..updates(
userProvider.user != null ? userProvider.user.uid : ''),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.white,
primaryTextTheme: TextTheme(
headline6: TextStyle(color: Colors.black),
),
),
home: Home(),
),
),
);
}
Happy to hear what others have done as well.