I was making an app using flutter and i have used shared_preferences package, and in auth stage i am facing an issue where when i build app user is logged in and when i log out and restart the app after killing it ,it still goes on homepage ,
Here is my code
main.dart
bool checkingKey;
Future<bool> checkKey() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool checkingKey=prefs.containsKey("jwt");
print("$checkingKey");
return checkingKey;
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
Paint.enableDithering = true;
await checkKey().then((value){
checkingKey=value;
});
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
// bool check=checkKey().then((bool value) => true);
print("hello=$checkingKey");
return MaterialApp(
home: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
color: Color(0xffccffcc),
child:checkingKey==false?LoginPage():mainPage()
),
),
),
routes: <String,WidgetBuilder>{
'/home':(BuildContext context)=>mainPage(),
'/login':(BuildContext context)=>LoginPage(),
}
);
}
}
login_signup_Auth.dart
Future<void> attemptLogIn(String username, String password,BuildContext context) async {
///?final storage =parent_inherit.of(context);
///?var verify=storage.verify;
SharedPreferences prefs = await SharedPreferences.getInstance();
print("$username $password");
final http.Response res = await http.post(
"https://green-earth.herokuapp.com/signin",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
// 'authorization':'Bearer '+
},
body: jsonEncode(<String, String>{
"email": username,
"password": password
}),
);
if(res.statusCode == 200) {
prefs.setString('jwt',res.body);
var value=prefs.getString('jwt');
print("storage= ${value.isEmpty}");
Navigator.of(context).pushNamed('/home');
}
else{
return _showMyDialoglogin(context,res.statusCode);
}
}
void logoutOutOfApp(BuildContext context) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.clear();
Navigator.of(context).pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);
}
On the second build without changing anything , the checking key variable is returned 'true' which i don't know ,how can it be possible!!!!!!
I am not getting what i am doing wrong ,also if u see any other problem which can make program efficient or any other code which shall be used .please tell
ThankYou very much!!
Why you are complicating things ?
Your main.dart can simply looks like this
bool checkingKey;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Paint.enableDithering = true;
var prefs = await SharedPreferences.getInstance();
checkingKey = prefs.containsKey("jwt");
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
print("hello=$checkingKey");
return MaterialApp(
home: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
),
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
color: Color(0xffccffcc),
child: !checkingKey ? LoginPage() : mainPage(),
),
),
),
routes: <String,WidgetBuilder>{
'/home':(BuildContext context) => mainPage(),
'/login':(BuildContext context) => LoginPage(),
},
);
}
}
Related
Authentication class
class Authentication with ChangeNotifier{
String _authToken='';
String _userId= '';
String get authToken{
return _authToken;
}
String get userId{
return _userId;
}
bool get isTokenValid{
print(authToken);
return _authToken.isNotEmpty;
}
Future<void> signIn(Map<String,Object> payload) async {
final url = Uri.parse("http://10.0.2.2:9090/api/v1/auth/register");
try{
final response= await http.post(url,
headers: {'Content-Type': 'application/json'},
body: json.encode(
{
'firstName': payload['firstName'],
'email': payload['email'],
'password': payload['password'],
}
),);
final responseData = json.decode(response.body);
_authToken = responseData['token'];
_userId = responseData['userId'].toString();
}catch(exception){
rethrow;
}
notifyListeners();
}
Future<void> logIn(Map<String,Object> payload) async {
final url = Uri.parse("http://10.0.2.2:9090/api/v1/auth/authenticate");
try{
final response= await http.post(url,
headers: {'Content-Type': 'application/json'},
body: json.encode(
{
'email': payload['email'],
'password': payload['password'],
}
),);
final responseData = json.decode(response.body);
_authToken = responseData['token'];
_userId = responseData['userId'].toString();;
print("LogIn");
}catch(exception){
rethrow;
}
notifyListeners();
}
}
Main.dart
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Authentication()),
ChangeNotifierProxyProvider<Authentication,CreditData>(
create: (_) => CreditData('', [],''),
update: (ctx, authentication, prevCreditData) =>
CreditData(
authentication.authToken,prevCreditData == null ? [] : prevCreditData.data,
authentication.userId
),
),
],
child: Consumer<Authentication>(
builder: (ctx, auth, _) => MaterialApp(
title: "Money Management",
debugShowCheckedModeBanner: false,
home: auth.isTokenValid ? const Home():const AuthenticationScreen(),
routes: {
Home.routeName: (ctx) => const Home(),
Debit.routeName: (ctx) => const Debit()
},
),
)
);
}
}
When I use ChangeNotifierProxyProvider in-order to send the authToken and userId generated from Authentication class my springboot api is behaving infinte loop while the request was only once.
This is the way the server is repeating the request itself when I tried to debug threadpoolExecutor was in ifinite loop and I got no idea what to do (https://i.stack.imgur.com/vI4T3.png)
But when I use postman or ChangeNotifierProvider (not ChangeNotifierProxyProvider) i'm not getting this problem as you can see down
(https://i.stack.imgur.com/qRNj3.png)
Can someone please rectify the problem and mention why is it so happening?
The problem is that Hive is acting unexpectedly, and when the app closes or I restart it all, the data in the box is cleared.
main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(statusBarColor: Colors.transparent));
await Firebase.initializeApp();
await Hive.initFlutter();
Hive.registerAdapter(CredentialsModelAdapter());
Hive.registerAdapter(DoctorModelAdapter());
Hive.registerAdapter(DuserModelAdapter());
Hive.registerAdapter(DoctorAppointmentsAdapter());
Hive.registerAdapter(AppointmentStatusesAdapter());
Hive.registerAdapter(AccountTypeAdapter());
Hive.registerAdapter(UserAdapter());
await Hive.openBox<CredentialsModel>("cred");
await Hive.openBox<DuserModel>("doctor");
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
final _appRouter = app_router.AppRouter();
#override
Widget build(BuildContext context) {
return MaterialApp.router(
title: "x",
debugShowCheckedModeBanner: false,
routerDelegate: _appRouter.delegate(),
routeInformationParser: _appRouter.defaultRouteParser(),
);
}
}
Here is where I fetch the data from the api and store it in box:
#override
Future<Either<ApiFailures, dynamic>> signInWithEmailAndPassword(
{required String email, required String password}) async {
late Box<CredentialsModel> credentials;
var result;
try {
final response = await http.get(Uri.parse(
"xxxxxxxx"));
if (response.statusCode == 200) {
result = await json.decode(response.body);
if (result["AZSVR"] == "FAILED") {
return const Left(ApiFailures.authFailed());
} else {
var content = CredentialsModel.fromJson(result);
credentials = Hive.box("cred");
credentials.put('cred', content);
return right(result["api_token"]);
}
}
} on SocketException catch (e) {
return const Left(ApiFailures.noConnection());
} on HttpException {
return const Left(ApiFailures.notfound());
} catch (_) {
return const Left(ApiFailures.notfound());
}
return Right(result["api_token"]);
}
Where I call the box:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:vwelfare/application/provider/doctor.repository.provider.dart';
import 'package:vwelfare/domain/models/doctor/duser.dart';
import '../../domain/models/credentials/credentials.dart';
class MyWidget extends HookConsumerWidget {
const MyWidget({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
final Box<CredentialsModel> credBox = Hive.box("cred");
final Box<DuserModel> doctorBox = Hive.box("doctor");
final controller = useTextEditingController();
final uid = useState(0);
final cred = useState(const CredentialsModel());
return Scaffold(
body: ValueListenableBuilder(
valueListenable: credBox.listenable(),
builder: (context, Box<CredentialsModel> box, _) {
final cred = box.get("cred");
print(cred!.api_token);
final doctor = ref.watch(getDoctor(cred.api_token!));
return doctor.when(
data: (data) => data.fold(
(l) => ValueListenableBuilder(
valueListenable: doctorBox.listenable(),
builder: (context, Box<DuserModel> box, _) {
final model = box.get("doctor");
final doctor = model!.User;
if (doctor != null) {
return Center(
child: Text("${doctor.address}"),
);
} else {
return const Center(
child: Text("CONTACT US"),
);
}
}),
(r) => Center(child: Text("${r.User!.name}"))),
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) {
print(error);
return Center(
child: Text("$error hello"),
);
});
},
),
);
}
}
I don't know if I am doing something wrong but I followed the docs as they say:
1- registered the adapter
2- opened the box
3- called it in a widget
What am I doing wrong?
I try to change theme by try to use SharedPreferences to save the data. So when I reopen the app it doesn’t reset. But the problem is when I reopen the app it does reset every-time.
Please look though my code
and maybe point out what’s wrong or provide some code if you’ve already knows. Thanks
In theme:
bool? colorMode = true;
Future<bool> savebool(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("colorMode", true);
return colorMode!;
}
Future<bool> loadbool() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.getBool("colorMode")!;
return colorMode!;
}
InkWell(
child: Row(mainAxisSize: MainAxisSize.min, children: const [
SizedBox(
width: 30.0,
height: 60.0,
),
Text('- Dark Mode', style: TextStyle()),
]),
onTap: () => {
themeManager.themeMode == ThemeMode.dark,
setState(
() {
themeManager.toggleTheme(colorMode!);
colorMode = colorMode;
savebool(colorMode!);
},
),
},
),
In main (some):
ThemeManager themeManager = ThemeManager();
#override
void initState() {
themeManager.addListener(themeListener);
super.initState();
}
#override
void dispose() {
themeManager.removeListener(themeListener);
super.dispose();
}
themeListener() {
if (mounted) {
setState(() {});
}
}
MultiProvider(
providers: [
Provider(create: (_) => User),
ChangeNotifierProvider(create: (context) => themeManager)
],
child: MaterialApp(
title: 'My app',
themeMode: themeManager.themeMode,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
home: const LoginScreen(),
debugShowCheckedModeBanner: false,
),
);
}
}
I think you forgot to set colorMode in loadbool() function...
Future<bool> loadbool() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
///right here, i think it must be like this
colorMode = prefs.getBool("colorMode") ?? false;
return colorMode!;
}
Your codes aren't full enough. I can't see the way you use save/load function. Anyway, before you get value from shared preference, you have to check it if it is null. I often load shared preferences in my singleton, like "isLogin", "firstOpenApp", "token"... Example:
DataInstance().firstLogin = prefs.getBool(PreferenceConstant.PREF_KEY_FIRST_LOGIN) ?? true;
Flutter no longer shows any error message, I'm using android studio, but even if I start the program in console messages still won't appear. For example if mapping an object goes wrong, there will be no error shown in console, I'll have to find it my self
This is my main file:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
ErrorWidget.builder = (FlutterErrorDetails details) => Container(
color: Colors.white,
child: const Center(
child: Text('Error'),
),
);
await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp],
);
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
} catch (e) {}
setupLocator();
await SentryFlutter.init((SentryFlutterOptions options) {
options.reportPackages = false;
options.enableOutOfMemoryTracking = true;
options.enableAppLifecycleBreadcrumbs = false;
options.anrEnabled = true;
options.debug = true;
options.dsn ='';
options.tracesSampleRate = 1.0;
}, appRunner: () => runApp(MyApp(route: route,)));
}
class MyApp extends StatelessWidget {
final String route;
final bool isLoggedIn;
MyApp({
required this.route,
required this.isLoggedIn,
});
#override
Widget build(BuildContext context) {
return GlobalBlocProviders(
isLoggedIn: isLoggedIn,
child: BlocListener<NotificationsBloc, NotificationsState>(
listener: (context, state) {
final route = state.route;
if (route == null) return;
locator<NavigationService>().navigateTo(route);
},
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: TylerTheme,
builder: (BuildContext context, Widget? childWidget) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
alwaysUse24HourFormat: true,
),
child: childWidget!,
);
},
initialRoute: route,
navigatorObservers: [
StackedService.routeObserver,
SentryNavigatorObserver()
],
navigatorKey: StackedService.navigatorKey,
onGenerateRoute: StackedRouter().onGenerateRoute,
),
),
);
}
}
Would be perfect if you have any suggestions. Thank you!
You just have to print the error via print method.
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
} catch (e) {
print("Catch Exception is $e");
}
I want to get the bool of a shared pref to decide which Widget should get loaded, but the method cant be async or to bool cant get the value because it is not allowed to "await" the value. I have tried fixing it, but it mostly fails because "home" can't receive a future widget..., is there another way how I could do this?
void main() => runApp(MyApp());
setloginbool() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("savelogin", true);
}
Future<bool> getloginbool() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool savelogin = prefs.getBool("savelogin") ?? false;
return savelogin;
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'KHS Plan',
theme: (ThemeData(
textTheme: const TextTheme(
bodyText1: TextStyle(fontSize: 14)
)
)),
home: checkifpassword(),
);
}
}
Widget checkifpassword() {
bool s = await getloginbool();
if(s){
return const Login();
} else {
return const MyHomePage();
}
}
//This does not work as well
checkifpassword() async {
bool s = await getloginbool();
if(s){
return const Login();
} else {
return const MyHomePage();
}
}
You can use FutureBuilder on Home
Future<bool> checkifpassword() async {
//perfrom your async operation and return bool
return await Future.delayed(Duration(seconds: 2), () {
return true;
});
}
And home
home: FutureBuilder<bool>(
future: checkifpassword(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data!) {// for true
return Login();;
} else return MyHomePage();
}
/// check others state
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
)