I'm coding await user?.reload();//here to reload `UserClass ' and during reloading, want to display indicator.
I learned Using FutureProvider-when() method from river_pod or 'FutureBuilder-snapshot` to implement this indicator.
Is these resolve is general or wonder there is more simple way to implement indicator display like this case ?
thanks for your helpful comment.
void currentUserNotNull(User? user, ref) async {
try {
var user = FirebaseAuth.instance.currentUser;
await user?.reload();//here
ref.read(authLoadingProvider.notifier).update((state) => false);
} on FirebaseAuthException catch (e) {
//
}
}
Iam using this method to loading, you can also use flutter spinners also
Try this
showLoaderDialog(BuildContext context){
AlertDialog alert=AlertDialog(
content: new Row(
children: [
CircularProgressIndicator(),
Container(margin: EdgeInsets.only(left: 7),child:Text("Loading..." )),
],),
);
showDialog(barrierDismissible: false,
context:context,
builder:(BuildContext context){
return alert;
},
);
}
I could solve this using flutter_easyloading package like
import 'package:flutter_easyloading/flutter_easyloading.dart';
void currentUserNotNull(User? user, ref) async {
try {
EasyLoading.show(maskType: EasyLoadingMaskType.black, status: "Loading...");
var user = FirebaseAuth.instance.currentUser;
await user?.reload();//here
EasyLoading.dismiss();
} on FirebaseAuthException catch (e) {
//
}
}
but still wonder I should do this or not...
Related
I'm really confusing that what is ref.watch(authUserFutureProvider);//here below detecting.
When final user = FirebaseAuth.instance.currentUser; // here set appropriately, ref.watch(authUserFutureProvider);//here detect the changes in the provider.
However, if I intentionally make user == null with FirebaseAuth.instance.signOut(); and execute authEmail(ref) with ref.refresh(authEmailFutureProvider);, ref.watch(authUserFutureProvider);//here do not detect any changes and nothing has been done in //do something when ref.watch() detected changes
I wonder why this happen and what kind of changes in FutureProvider should be detected.
Thanks for your helpful advises.
Future<bool> authEmail(ref) async {
try {
final user = FirebaseAuth.instance.currentUser; // here
await user?.sendEmailVerification();
return true;
}on FirebaseAuthException catch (e){
//do somthing
return false
}
//Declared Globally
final authEmailFutureProvider = FutureProvider<bool>((ref) async => authEmail(ref),);
class Test extends ConsumerWidget {
final authC = ref.watch(authUserFutureProvider);//here
authC.when(
//do something when ref.watch() detected changes
)
}
return Scaffold(
body: Padding(
//omit
Align(
child: SizedBox(
width: double.infinity,
child: TextButton(
onPressed: () {
ref.refresh(authEmailFutureProvider);
}
)
//omit
)
Solved!
I am getting date from FireBase via a futurebuilder.
It returns a Row whose children is a list of a widget i created called SmallDogCard (since my app is about dogs).
On a screen i want users to be able to press on the SmallDogCard to select it and change the border color, howerver. This causes the futurebuilder to load the data again... How should i approach this?
My code:
Futurebuilder:
FutureBuilder(
future: DogOwnerModel().getUserData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('error');
}
if (snapshot.connectionState ==
ConnectionState.done) {
List<SmallDogCard> dogCardList = [];
final userData =
snapshot.data as Map<String, dynamic>;
List<Map<String, dynamic>>? userDogs =
userData['user dog data'];
if (userDogs == null) {
return Text('no dogs yet');
} else {
for (Map<String, dynamic> dog
in userDogs) {
dogCardList.add(SmallDogCard(
dogName: dog['name'],
imageUrl: dog['profile image'],
isSelected: selectedDogs
.contains(dog['name'])
? true
: false,
selectCallback: selectDogCallback));
}
return Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: dogCardList);
}
}
return Text('Loading');
},
),
Onpress function callback passed to the SmallDogCard (which uses setstate and makes the futurbuilder get the data again).
selectDogCallback(String name, bool isSelected) {
if (isSelected == false) {
selectedDogs.add(name);
} else {
selectedDogs.remove(name);
}
setState(() {
selectedDogs;
});
}
How can i accomplish this without the futurebuilder being called again?
So i can setstate which changes the border color of the SmallDogCard which is returned from the FutureBuilder.
Thank you in advance!
Problem solved!
Initializing the future in initstate, so after initstate it wont be called again!
Like this:
#override
void initState() {
// TODO: implement initState
super.initState();
_future = setFuture();
}
setFuture() async {
return await DogOwnerModel().getUserData(email: email);
}
I have a flutter app and everything was fine until i want to release it.
I'm using firebase for auth.
I'm using:
firebase_core: ^0.7.0
firebase_auth: ^0.20.0
In debug mode or in release, my firebase auth login works fine. My problem is after that.
I have a decentralized 'listener' to firebaseAuth.authStateChanges. Here is where i control my app authentication. This is my buildSelf$ function in my auth repository(where i build the auth state listener):
ReplayConnectableStream<AuthState> buildSelf$() {
return Rx.concat([
Stream.value(AuthInit()),
firebaseAuth.authStateChanges().switchMap((firebaseUser) {
print('[AuthRepository][buildSelf][authStateChanges] firebaseUser');
print(firebaseUser);
if (firebaseUser == null) {
return Stream.value(Unauthenticated());
}
/* continue function */
return Authenticated(firebaseUser: firebaseUser);
})
]).publishReplay();
}
buildSelf$ is a method for my AuthRepository. And i initialize it on:
AuthRepository._() {
Firebase.initializeApp().then((app) {
_firebaseAuth = FirebaseAuth.instance;
state$ = buildSelf$();
state$.connect();
});
setPackageInfo();
}
static final AuthRepository instance = AuthRepository._();
All this code is inside my AuthRepository.
The problem is:
When i'm running my app in debug mode. Every thing works fine. I can login and my app (my navigator observer uses the auth repository state$) and i'm redirected to home page. [Here a printscreen from terminal in debug mode. success authStateChanges emit
But when i'm running im release mode, my login response shows in my terminal 'success' but my listener does not show state changes. Here a printscreen from terminal in release mode. authStateChanges emit only 1 time(when opening)
I'm realy lost about whats going on. I tried even to call this authStateChanges directly in my app.dart but still the same way(in release, only checking auth state once).
Solution:
After 3 days of headache, i finally found out my problem:
My app does not initialize firebase app on root (main). So i have to initialize it every time i need to use some firebase package.
I believe that every time one app was initialized, the others failed.
I move my firebase.initializeApp() to my main function and remove every other firebase initialize. Then, everything works fine.
This is my main:
void main() async {
/* ... main code ... */
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(App());
}
I did implement a project with the presented methods in release mode in my iPhone but wasn't able to reproduce the problem, the implementation I did to reproduce the project was:
class _TestFirebaseState extends State<TestFirebase> {
bool userLogado = false;
_loginLogout() {
if (FirebaseAuth.instance.currentUser == null) {
FirebaseAuth.instance.signInWithEmailAndPassword(
email: 'teste1#teste.com', password: '123456');
} else {
FirebaseAuth.instance.signOut();
}
}
#override
void initState() {
super.initState();
final stream = Rx.concat(
[
Stream.value('começou'),
FirebaseAuth.instance.authStateChanges().switchMap<String>(
(user) {
debugPrint('user: ' + user.toString());
if (user == null) {
return Stream.value('unauth');
} else {
return Stream.value('auth');
}
},
),
],
).publishReplay();
stream.listen((value) {
debugPrint('value: ' + value);
this.setState(() {
this.userLogado = value == 'auth';
});
});
stream.connect();
}
#override
Widget build(BuildContext context) {
String text = "sair";
if (!userLogado) {
text = "entrar";
}
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
child: Center(
child: RaisedButton(
onPressed: _loginLogout,
child: Text(text),
),
),
),
);
}
}
the only detail is that the main component that loads everything in the app has a future builder that awaits the firebase to init:
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
// Initialize FlutterFire:
future: Firebase.initializeApp(),
builder: (context, snapshot) {
// Check for errors
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text(
'ocorreu um problema inicializando o aplicativo...',
),
),
);
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
// return LoginPage();
// return VerifySignIn(homePage: Home());
return TestFirebase();
}
// Otherwise, show something whilst waiting for initialization to complete
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
),
debugShowCheckedModeBanner: false,
);
}
And another detail is that the firebase configuration is implemented following the flutter tutorial for the platform used.
So in order to evaluate if the app configuration is just fine, I would implement that button app inside the same project so you can evaluate it properly.
I have a problem with Streams. I'm getting null form the stream. My objective is to combine 2 futures so I'm using first future when user has not searched any parameters and other one when user searched because I have 2 endpoints one for searched list and one that has no filters. I'm not really sure if that's standard industry practice for app dev. If its not please tell me so and how should I set up back end
Widget Body(BuildContext context, TabController taby) {
Future<List<littleOffers>> searchdata = null;
Stream<List<littleOffers>> _dataSwitch() async* {
if (searchdata == null)
yield* Stream.fromFuture(fetchOffers());
else
yield* Stream.fromFuture(searchdata);
}
void resetSearchData() {
searchdata = null;
}
void setSearchData(Future<List<littleOffers>> data) {
searchdata = data;
}
return Column(
children: <Widget>[
Search_Sort(context),
Expanded(
child: StreamBuilder(
stream: _dataSwitch(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none || !snapshot.hasData) {
print('project snapshot data is: ${snapshot.data}');
print('project snapshot state is: ${snapshot.connectionState.toString()}');
return Container();
} else {
return TabBarView(controller: taby, children: [
getList(snapshot.data),
getList(snapshot.data),
getList(snapshot.data),
getList(snapshot.data),
]);
}
}),
),
],
);
}
That could work but I think you missed async and await on setSearchData
void setSearchData(Future<List<littleOffers>> newData) {
setState(()async{
searchdata = await newData;
});
}
and to remove data
void clearSearchData() {
setState((){
searchdata = null;
});
}
You can define only one List<littleOffers> (not future) ;
Widget Body(BuildContext context, TabController taby) {
List<littleOffers> searchdata = null;
Future<void> setSearchData(Future<List<littleOffers>> newData) async {
var _data = await newData;
setState((){
searchdata = _data;
});
}
return Column(
children: <Widget>[
Search_Sort(context),
Expanded(
child: searchData == null ? Center(child: CircularProcessIndicator()) : yourWidget;
),
],
);
}
Creating Stream from 2 futures so that one is alway actice and other one is on stand by when switch is needed.
Stream<List<littleOffers>> _dataOfferSwitch() async* {
if (searchOfferData == null)
yield* Stream.fromFuture(fetchOffers());
else
yield* Stream.fromFuture(searchOfferData);}
I need help regarding the images in my app. I would like to add 3 buttons for:
Download
Save as
Change phone wallpaper
I'm not using urls. I already have my images in an assets repository.
Do you have any idea how I can do that? Thank you.
You can copy paste run full code below
You can use package https://pub.dev/packages/wallpaper_manager
You can directly set wallpaper with image in assets
Example code's assets image path is "assets/tmp1.jpg"
code snippet
result = await WallpaperManager.setWallpaperFromAsset(
assetPath, WallpaperManager.HOME_SCREEN);
working demo
full code
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:wallpaper_manager/wallpaper_manager.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _wallpaperFile = 'Unknown';
String _wallpaperAsset = 'Unknown';
#override
void initState() {
super.initState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await WallpaperManager.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> setWallpaperFromFile() async {
setState(() {
_wallpaperFile = "Loading";
});
String result;
var file = await DefaultCacheManager().getSingleFile(
'https://images.unsplash.com/photo-1542435503-956c469947f6');
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await WallpaperManager.setWallpaperFromFile(
file.path, WallpaperManager.HOME_SCREEN);
} on PlatformException {
result = 'Failed to get wallpaper.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_wallpaperFile = result;
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> setWallpaperFromAsset() async {
setState(() {
_wallpaperAsset = "Loading";
});
String result;
String assetPath = "assets/tmp1.jpg";
// Platform messages may fail, so we use a try/catch PlatformException.
try {
result = await WallpaperManager.setWallpaperFromAsset(
assetPath, WallpaperManager.HOME_SCREEN);
} on PlatformException {
result = 'Failed to get wallpaper.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_wallpaperAsset = result;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Platform Version"),
onPressed: initPlatformState,
),
Center(
child: Text('Running on: $_platformVersion\n'),
),
RaisedButton(
child: Text("Set wallpaper from file"),
onPressed: setWallpaperFromFile,
),
Center(
child: Text('Wallpaper status: $_wallpaperFile\n'),
),
RaisedButton(
child: Text("Set wallpaper from asset"),
onPressed: setWallpaperFromAsset,
),
Center(
child: Text('Wallpaper status: $_wallpaperAsset\n'),
),
],
)),
);
}
}