Flutter: Getx translation fall without restarting the app - flutter

I'm using GetX package with my projects, this time some thing wrong happened in the translation, I have two languages (En - Ar), so when I press on the button that switch the language, it translate the most of the app and change the direction from ltr to rtl automatically, but still showing some words in the last language until I restart the app!!!
This is the example when I tried to switch from Ar to En, and before restarting the app.
And this image, is after restarting, every thing works good!!!
Here parts of my code, maybe help:
class LocaleController extends GetxController {
static LocaleController instance = LocaleController();
Locale? language;
AppServices appServices = Get.find();
changeLanguage(String langCode) {
Locale locale = Locale(langCode);
AppServices.sharedPreferences?.setString('lang', langCode);
Get.updateLocale(locale);
}
Locale? initialLang = AppServices.sharedPreferences?.getString('lang') == null
? Get.deviceLocale
: Locale(AppServices.sharedPreferences!.getString('lang')!);
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await initialServices();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
LocaleController controller = Get.put(LocaleController());
return GetMaterialApp(
initialBinding: Binding(),
debugShowCheckedModeBanner: false,
title: 'Super Market',
translations: Translation(),
locale: controller.initialLang,
initialRoute: AppRoutes.initial,
getPages: AppRoutes.routes,
);
}
}
So what is the problem with it?

Related

Flutter Web Url Route Doesn't Work on Real domain

I'm trying to use a url where I get a parameter and assign that parameter to a variable inside the web file.
for example my domain is example.com and in this website i need an id for user. I want to make example.com/?id=123 and getting that 123 id and giving a variable 123 value
In flutter web device It works but when i host this files it doesnt work on real domain. And flutter giving me a
Could not navigate to initial route.
The requested route name was: "/?id=sezen#gmail.com"
There was no corresponding route in the app, and therefore the initial route specified will be
ignored and "/" will be used instead.
Here is my code
void main() async {
WidgetsFlutterBinding.ensureInitialized();
setPathUrlStrategy();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
String myurl = Uri.base.toString(); //get complete url
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
void initState() {
super.initState();
getParams();
}
#override
Widget build(BuildContext context) {
getParams();
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'QR Numaratör',
home: MyHomePage(id: mail),
);
}
}
void getParams() {
var uri = Uri.dataFromString(window.location.href);
Map<String, String> params = uri.queryParameters;
var origin = params['id'];
mail = origin;
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.id}) : super(key: key);
String? id = Uri.base.queryParameters["id"];
#override
State<MyHomePage> createState() => _MyHomePageState();
}
In your MaterialApp widget, you need to specify onGenerateRoute parameter.
Something like this:
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'QR Numaratör',
home: MyHomePage(id: mail),
onGenerateRoute: (settings) {
switch (kIsWeb? Uri.parse(settings.name).path : settings.name) {
case'/':
Map args = settings.arguments as Map;
if(kIsWeb && args == null) {
args=Uri.parse(settings.name).queryParameters;
}
return MaterialPageRoute(builder: (_) => MyHomePage(id: args[id]));
}
});

Flutter Web Url Route Error While Passing Query Param [duplicate]

I'm trying to use a url where I get a parameter and assign that parameter to a variable inside the web file.
for example my domain is example.com and in this website i need an id for user. I want to make example.com/?id=123 and getting that 123 id and giving a variable 123 value
In flutter web device It works but when i host this files it doesnt work on real domain. And flutter giving me a
Could not navigate to initial route.
The requested route name was: "/?id=sezen#gmail.com"
There was no corresponding route in the app, and therefore the initial route specified will be
ignored and "/" will be used instead.
Here is my code
void main() async {
WidgetsFlutterBinding.ensureInitialized();
setPathUrlStrategy();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
String myurl = Uri.base.toString(); //get complete url
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
void initState() {
super.initState();
getParams();
}
#override
Widget build(BuildContext context) {
getParams();
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'QR Numaratör',
home: MyHomePage(id: mail),
);
}
}
void getParams() {
var uri = Uri.dataFromString(window.location.href);
Map<String, String> params = uri.queryParameters;
var origin = params['id'];
mail = origin;
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.id}) : super(key: key);
String? id = Uri.base.queryParameters["id"];
#override
State<MyHomePage> createState() => _MyHomePageState();
}
In your MaterialApp widget, you need to specify onGenerateRoute parameter.
Something like this:
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'QR Numaratör',
home: MyHomePage(id: mail),
onGenerateRoute: (settings) {
switch (kIsWeb? Uri.parse(settings.name).path : settings.name) {
case'/':
Map args = settings.arguments as Map;
if(kIsWeb && args == null) {
args=Uri.parse(settings.name).queryParameters;
}
return MaterialPageRoute(builder: (_) => MyHomePage(id: args[id]));
}
});

Initializing camera for list of available cameras in Future

I am using this code that I got directly from pub.dev regarding initializing the camera and creating a list of available cameras
the list is created in a Future main() function but it is not being automatically called when I navigate to the CameraApp page. Has anyone run into this issue? How do I initialize the camera and create the list of available cameras when it navigates to the page with this code? Please help, thank you.
/// CameraApp is the Main Application.
class CameraApp extends StatelessWidget {
/// Default Constructor
const CameraApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: CameraExampleHome(),
);
}
}
List<CameraDescription> _cameras = <CameraDescription>[];
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
_cameras = await availableCameras();
} on CameraException catch (e) {
_logError(e.code, e.description);
}
runApp(const CameraApp());
}
And this is the code where I call the CameraApp function from inside a button:
ElevatedButton(
onPressed: ()
{Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CameraApp()));},
child: const Text('Camera'),
style: ElevatedButton.styleFrom(
minimumSize: const Size(160.0, 35.0)),
),
You can create a kind of singleton to manage camera operations.
class CameraManager {
// Declare your camera list here
List<CameraDescription> _cameras = <CameraDescription>[];
// Constructor
CameraManager._privateConstructor() {}
// initialise instance
static final CameraManager instance =
CameraManager._privateConstructor();
// Add a getter to access camera list
List<CameraDescription> get cameras => _cameras;
// Init method
init() async {
try {
_cameras = await availableCameras();
} on CameraException catch (e) {
_logError(e.code, e.description);
}
}
// other needed methods to manage camera
...
}
And then in you main function
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
await CameraManager.instance.init();
}
runApp(const CameraApp());
}
Then on other part of your application, you can import the singleton and access methods and properties with CameraManager.instance.*, for example CameraManager.instance.cameras access _cameras through the getter.
There are few things to consider here.. The implementation you did was right but you named the cameras as a private variable which will be accessed in a single dart file by adding an _ like _cameras. Removing that will make it globally available in all classes just by importing main.dart
Here is the full code
main.dart
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:trial/CameraExampleHome.dart';
List<CameraDescription> cameras = <CameraDescription>[];
void main() async {
try {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
print(cameras);
} on CameraException catch (e) {
print(e.toString());
}
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(home: CameraApp());
}
}
class CameraApp extends StatelessWidget {
/// Default Constructor
const CameraApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: CameraExampleHome(),
);
}
}
cameraExampleHome.dart
import 'package:flutter/material.dart';
import 'main.dart';
class CameraExampleHome extends StatefulWidget {
const CameraExampleHome({Key? key}) : super(key: key);
#override
State<CameraExampleHome> createState() => _CameraExampleHomeState();
}
class _CameraExampleHomeState extends State<CameraExampleHome> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Available Cameras $cameras"),
//output: Available Cameras [CameraDescription(0, CameraLensDirection.back, 90), CameraDescription(1, CameraLensDirection.front, 270), CameraDescription(2, CameraLensDirection.front, 270)]
),
);
}
}
You could create a library file for Global Variables.
Create a file called "globals.dart" in your lib folder.
Declare the following line at the top.
library your_project_name.globals;
Then set your variable in it
List<CameraDescription> cameras = <CameraDescription>[];
Usage in main
import 'globals.dart' as globals;
main() {
...
globals.cameras = await availableCameras();
...
}
Then simply use the variable anywhere in your project.
import 'globals.dart' as globals;
globals.cameras...
Declare list of CameraDescription global instance as below:
List<CameraDescription> cameras = <CameraDescription>[];
Now you can access the camera instance by importing main.dart , _ always make the instance variable private which will not be accessible outside the file

How to set ThemeMode in splash screen using value stored in sqflite FLUTTER

I have a Flutter Application where an sqflite database stored the user preference of ThemeMode (viz Dark, Light and System). I have created a splash screen using flutter_native_splash which supports dark mode too.
The Problem is this that I want the splash screen to follow the users stored value for theme mode. Currently, the code I am using is as follows:
class MyRoot extends StatefulWidget {
// const MyRoot({Key? key}) : super(key: key);
static ValueNotifier<ThemeMode> themeNotifier = ValueNotifier(ThemeMode.system);
#override
State<MyRoot> createState() => _MyRootState();
}
class _MyRootState extends State<MyRoot> {
DatabaseHelper? databaseHelper = DatabaseHelper.dhInstance;
ThemeMode? tmSaved;
#override
void initState() {
Future.delayed(Duration.zero, () async => await loadData());
super.initState();
}
#override
Widget build(BuildContext context) {
//to prevent auto rotation of the app
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
return ValueListenableBuilder<ThemeMode>(
valueListenable: MyRoot.themeNotifier,
builder: (_, ThemeMode currentMode, __) {
return Sizer(
builder: (context, orientation, deviceType) {
return MaterialApp(
title: 'My Application',
theme: themeLight, //dart file for theme
darkTheme: themeDark, //dart file for theme
themeMode: tmSaved ?? currentMode,
initialRoute: // my initial root
routes: {
// my routes
.
.
.
// my routes
},
);
},
);
},
);
}
Future<void> loadData() async {
if (databaseHelper != null) {
ThemeMode? themeMode= await databaseHelper?.selectStoredTheme(); // function retrieving sqflite stored value and returning ThemeMode value
if (themeMode != null) {
MyRoot.themeNotifier.value = themeMode;
return;
}
}
MyRoot.themeNotifier.value = ThemeMode.system;
}
}
Currently, this shows a light theme splash screen loading, then converts it into dark with a visible flicker.
ValueListenableBuilder<ThemeMode>(... is to enable real time theme change from settings page in my app which working as intended (taken from A Goodman's article: "Flutter: 2 Ways to Make a Dark/Light Mode Toggle".
main.dart has the below code:
void main() {
runApp(MyRoot());
}
Have you tried loading the setting from sqflite in main() before runApp? If you can manage to do so, you should be able to pass the setting as argument to MyRoot and then the widgets would be loaded from the start with the correct theme. I'm speaking in theory, I can't test what I'm suggesting right now.
Something like:
void main() async {
ThemeMode? themeMode= await databaseHelper?.selectStoredTheme(); // function retrieving sqflite stored value and returning ThemeMode value
runApp(MyRoot(themeMode));
}
[...]
class MyRoot extends StatefulWidget {
ThemeMode? themeMode;
const MyRoot(this.themeMode, {Key? key}) : super(key: key);
static ValueNotifier<ThemeMode> themeNotifier = ValueNotifier(ThemeMode.system);
#override
State<MyRoot> createState() => _MyRootState();
}
EDIT
Regarding the nullable value you mentioned in comments, you can change the main like this:
void main() async {
ThemeMode? themeMode= await databaseHelper?.selectStoredTheme(); // function retrieving sqflite stored value and returning ThemeMode value
themeMode ??= ThemeMode.system;
runApp(MyRoot(themeMode!));
}
which makes themeMode non-nullable, and so you can change MyRoot in this way:
class MyRoot extends StatefulWidget {
ThemeMode themeMode;
const MyRoot(required this.themeMode, {Key? key}) : super(key: key);
[...]
}
Regarding the functionality of ValueNotifier, I simply thought of widget.themeMode as the initial value of your tmSaved property in your state, not as a value to be reused in the state logic. Something like this:
class _MyRootState extends State<MyRoot> {
DatabaseHelper? databaseHelper = DatabaseHelper.dhInstance;
late ThemeMode tmSaved;
#override
void initState() {
tmSaved = widget.themeMode;
super.initState();
}
[...]
}
so that your widgets would already have the saved value at the first build.
PS the code in this edit, as well as in the original part, isn't meant to be working by simply pasting it. Some things might need adjustments, like adding final to themeMode in MyRoot.
Make your splashscreen. A main widget which get data from sqlflite
And make splashscreen widget go to the your home widget with remove it using navigation pop-up
for example :
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'ToDo',
color: // color of background
theme: // theme light ,
darkTheme: // darktheme
themeMode: // choose default theme light - dark - system
home: Splashscreen(),// here create an your own widget of splash screen contains futurebuilder to fecth data and return the mainWidget ( home screen for example)
);
}
}
class Splashscreen extends StatelessWidget {
Future<bool> getData()async{
// get info
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getData(),
builder: (context,snapshot){
// if you want test snapshot
//like this
if(snapshot.hasData) {
return Home();
} else {
return Container(color: /* background color as same as theme's color */);
}
}
);
}
}

Riverpod ProviderListener - 'StateNotifierProvider<Auth, bool>' can't be assigned to 'ProviderBase<Object, StateController<bool>>'

I'm trying to use a ProviderListener from Riverpod to listen to my authProvider and control the page displayed if a user is authorized or not. I'm getting the error:
error: The argument type 'StateNotifierProvider<Auth, bool>' can't be assigned to the parameter type 'ProviderBase<Object, StateController>'.
The error shows up on the: provider: authProvider, inside the ProviderListener
I'm wondering if it's due to the update on StateNotifierProvider?
I would like to know how to use the ProviderListener better even if there's a better way to handle the authorization flow (I'm VERY open to feedback and criticism and greatly appreciate any time a person can take to help). I cut out non-relevant code
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class Auth extends StateNotifier<bool> {
Auth() : super(false);
void setAuth(bool auth) {
state = auth;
}
}
final authProvider = StateNotifierProvider<Auth, bool>((ref) => Auth());
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatefulHookWidget {
// const MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final Future<FirebaseApp> _fbMyApp = Firebase.initializeApp();
Widget route = SplashScreen();
#override
Widget build(BuildContext context) {
return ProviderListener<StateController<bool>>(
provider: authProvider,
onChange: (context, auth) {
if (auth.state = true) {
route = HomeScreen();
} else {
route = SplashScreen();
}
},
child: MaterialApp(
home: route,
);
}
}
I managed to get it to sort of work by changing to:
return ProviderListener<StateNotifier<bool>>(
provider: authProvider.notifier,
it's giving me a non-breaking error of:
info: The member 'state' can only be used within instance members of subclasses of 'package:state_notifier/state_notifier.dart'. (invalid_use_of_protected_member)
and not working properly - the state isn't being updated when I'm using a context.read
context.read(authProvider.notifier).state = true;
So it's buggy but not fully broken. At least it's some progress. I would still love help and any feedback anyone wants to give!
Remove StateController from ProviderListener, leave only the type (bool in this case)
return ProviderListener<bool>(
provider: authProvider, //this will read the state of your provider (a bool state)
onChange: (context, auth) {
if (auth) { //remove setter auth = true, it doesn't make sense to set a value inside an if
route = HomeScreen();
} else {
route = SplashScreen();
}
},
child: MaterialApp(
home: route,
);
This way you're reading the state of your StateNotifier