Flutter - setData to firebase on successfull payment - firebase

1) list_profile:
class DetailPage extends StatefulWidget {
final DocumentSnapshot post;
DetailPage({this.post});
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
bool pressed = false;
String taskname,tasksector,taskpocket,tasklandmark;
int _myTaskType = 0;
String taskVal;
StateModel appState;
bool _loadingVisible = false;
#override
Widget build(BuildContext context) {
// final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
DateTime now = DateTime.now();
String formattedDate = DateFormat('EEE d MMM y').format(now);
// firebase location to be set
confirm() { // for driver
appState = StateWidget.of(context).state;
//final userId = appState?.firebaseUserAuth?.uid ?? '';
final w_fl = appState?.user?.w_fl ?? '';
final firstName = appState?.user?.firstName ?? '';
final number = appState?.user?.number ?? '';
DocumentReference ds = Firestore.instance
.collection("customer2")
.document("${widget.post.data["driverNumber"]}")
.collection("1")
.document(formattedDate);
Map<String, dynamic> data = {
//"Status": firstName + " $lastName",
"customerName":firstName,
"customerNumber":number,
"time":taskVal,
"status": "Waiting...",
"address":taskname,
"sector":tasksector,
"pocket":taskpocket,
"landmark":tasklandmark,
"payment":"X"
};
ds.setData(data).whenComplete(() {
print('Task created');
});
}
confirm2() { // to fetched only on customer side i.e yourBookings
appState = StateWidget.of(context).state;
//final userId = appState?.firebaseUserAuth?.uid ?? '';
final w_fl = appState?.user?.w_fl ?? '';
final firstName = appState?.user?.firstName ?? '';
final lastName = appState?.user?.lastName ?? '';
final number = appState?.user?.number ?? '';
DocumentReference ds = Firestore.instance
.collection("confirmed_c_rides2")
.document(number)
.collection('1')
.document(formattedDate);
Map<String, dynamic> data = {
//"Status": firstName + " $lastName",
"carImage": "${widget.post.data["carImage"]}",
"driverImage": "${widget.post.data["driverImage"]}",
"experience": "${widget.post.data["experience"]}",
"firstName": "${widget.post.data["driverName"]}",
"gender": "${widget.post.data["gender"]}",
"time": taskVal,
"driverNumber": "${widget.post.data["driverNumber"]}",
//"status": "Waiting..."
"payment":"Complete your payment to confirm"
};
ds.setData(data).whenComplete(() {
print('Task created');
});
}
return Scaffold()
2) check.dart
class CheckRazor extends StatefulWidget {
#override
_CheckRazorState createState() => _CheckRazorState();
}
class _CheckRazorState extends State<CheckRazor> {
Razorpay _razorpay = Razorpay();
var options;
Future payData() async {
try {
_razorpay.open(options);
} catch (e) {
print("errror occured here is ......................./:$e");
}
_razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess);
_razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError);
}
void _handlePaymentSuccess(PaymentSuccessResponse response) async {
print("payment has succedded");
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => SuccessPage(
response: response,
),
),
(Route<dynamic> route) => false,
);
_razorpay.clear();
// Do something when payment succeeds
}
void _handlePaymentError(PaymentFailureResponse response) {..............}
#override
void initState() {
// TODO: implement initState
super.initState();
options = {.......}
#override
Widget build(BuildContext context) {
return Scaffold(
RaisedButton(onPressed(){
confirm();
confirm2();}
);
}
What i want is to create data to firebase only on successful payment only.
In above codes...i have just connected two different codes that is data creation(to firebase) and payment .
1) confirm() & confirm2() are responsible for creating data to firebase.
2) _handlePaymentSuccess() is responsible for successful payment.
Please help!!!

Use shared_preferences,
Add in list.dart:
void saveName() {
savedNamePreferences(taskVal).then((_) {});}
Future<bool> savedNamePreferences(String name) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("name", name);
return prefs.commit();
}
Future<String> getNamePreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String name = prefs.getString("name");
return name;
}
And call getNamePreferences() in another class i.e check.dart

Related

Firebase query Stream with filters not updating when document is added: Flutter

I am working on the chat section of my flutter application. I have a chat_messages collection which contains all of the messages sent by users for all chats in the application. Below is the structure of a chat_messages document:
Here user is the sender of the message. I would like to display the number of unread messages (where the message.seen==false) for a specific user hence i used the query below to get a stram of all messages which where not seen by the user and i listen to that stream for any new messages sent:
unreadMessagesStream = queryChatMessagesRecord(queryBuilder: (query)
{
return query
.where('chat_users', arrayContains: currentUserReference)
.where('user', isNotEqualTo: currentUserReference)
.where('seen', isEqualTo: false);
});
unreadMessagesStream.listen((msgs) {
if (mounted)
setState(() {
unreadMessagesCount = msgs?.length ?? 0;
});
});
Unfortunately, this stream only produces a value once when the app is run, but later on when any new message is sent, new values are not received in the stream and the number of unread messages remain the same.
NB: If I remove the filters and query the whole collection is works perfectly fine.
I give you a snippet of my code to get it done faster: The code juste below is for each user. It's a subcollection of the chat. So a user could have a chatMembre for each chat.
import 'package:cloud_firestore/cloud_firestore.dart';
enum IsDoing { reading, notReading, writing, recording }
class ChatMembre {
final String id;
final DateTime lastReading;
final DateTime lastReceived;
final IsDoing isDoing;
final bool hasSubscribeToTopic;
ChatMembre(
{required this.id,
required this.lastReading,
required this.lastReceived,
required this.isDoing,
required this.hasSubscribeToTopic});
Map<String, dynamic> toMap() {
return {
'id': id,
'lastReading': lastReading == DateTime.now()
? FieldValue.serverTimestamp()
: DateTime.now(),
'lastReceived': lastReceived == DateTime.now()
? FieldValue.serverTimestamp()
: DateTime.now(),
'isDoing':
isDoing.toString().substring(isDoing.toString().indexOf(".") + 1),
'isSubscribeToTopic': hasSubscribeToTopic
};
}
factory ChatMembre.fromMap(Map<String, dynamic>? map) {
if (map == null || map.isEmpty) {
return ChatMembre(
id: '',
lastReading: DateTime.now(),
lastReceived: DateTime.now(),
hasSubscribeToTopic: false,
isDoing: IsDoing.notReading);
}
IsDoing isDoing;
switch (map["isDoing"]) {
case "reading":
isDoing = IsDoing.reading;
break;
case "writing":
isDoing = IsDoing.writing;
break;
case "recording":
isDoing = IsDoing.recording;
break;
default:
isDoing = IsDoing.notReading;
break;
}
return ChatMembre(
id: (map['id'] ?? '') as String,
lastReading:
((map['lastReading'] ?? Timestamp.now()) as Timestamp).toDate(),
lastReceived:
((map['lastReceived'] ?? Timestamp.now()) as Timestamp).toDate(),
isDoing: isDoing,
hasSubscribeToTopic: (map['isSubscribeToTopic'] ?? false) as bool);
}
#override
String toString() {
return 'ChatMembre{id: $id, lastReading: $lastReading, lastReceived: $lastReceived, isDoing: $isDoing, hasSubscribeToTopic: $hasSubscribeToTopic}';
}
}
And under it's to look for the state of the chat page.
import 'dart:convert';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constants/credentials.dart';
import 'package:customer/constants/firestore_path.dart';
import 'package:customer/domain/repositories/my_chat_repository.dart';
import 'package:customer/services/firestore_service.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
class ChatRoomLifeCycle extends StatefulWidget {
final Widget child;
final MyChatRepository chatRepo;
final String chatId;
final String? token;
final String? idTo;
final Timestamp? lastReceivedOfFriend;
const ChatRoomLifeCycle(
{Key? key,
required this.chatId,
required this.chatRepo,
required this.child,
this.token,
this.idTo,
this.lastReceivedOfFriend})
: super(key: key);
#override
_ChatRoomLifeCycleState createState() => _ChatRoomLifeCycleState();
}
class _ChatRoomLifeCycleState extends State<ChatRoomLifeCycle>
with WidgetsBindingObserver {
late GlobalKey<AnimatedListState> listKey;
bool hasSentFcm = false;
#override
void initState() {
super.initState();
sendPushMessage();
WidgetsBinding.instance!.addObserver(this);
widget.chatRepo.setIsReading();
}
#override
void dispose() {
widget.chatRepo.setIsNotReading(isFromDispose: true);
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.paused:
widget.chatRepo.setIsNotReading();
break;
case AppLifecycleState.resumed:
widget.chatRepo.setIsReading();
break;
case AppLifecycleState.inactive:
widget.chatRepo.setIsNotReading();
break;
case AppLifecycleState.detached:
widget.chatRepo.setIsNotReading();
break;
}
}
Future<void> sendPushMessage() async {
if (hasSentFcm || widget.idTo == null || widget.token == null) {
return;
}
FirestoreService.instance.updateData(
path: MyPath.myUserStatus(uid: widget.idTo!), data: {'isLogin': false});
try {
await http
.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: constructFCMPayload(widget.token!),
)
.catchError((onError) {});
hasSentFcm = true;
} catch (e) {
Fluttertoast.showToast(msg: e.toString());
}
}
// Crude counter to make messages unique
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String token) {
return jsonEncode(<String, dynamic>{
'data': <String, dynamic>{
'test': 'check online',
'chatId': widget.chatId,
'idTo': widget.idTo
},
'to': token,
});
}
}

Flutter Firebase Messaging Deactivate Visible Notification

How can I deactivate the visible notification in Firebase Messaging and handle the notification manually with the flutter_local_notifications package so the notification doesn't show twice? I'm not able to edit the server integration side since am I using a wordpress plugin (https://wordpress.org/plugins/fcm-push-notification-from-wp/) to send a notification request for me.
The payload looks like this: https://ps.w.org/fcm-push-notification-from-wp/assets/screenshot-6.png?rev=2446404
String selectedNotificationPayload = "";
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final BehaviorSubject<String> selectNotificationSubject =
BehaviorSubject<String>();
FirebaseMessaging messaging;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('share_icon');
final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
onDidReceiveLocalNotification:
(int id, String title, String body, String payload) async {});
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
NotificationAppLaunchDetails notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
selectedNotificationPayload = notificationAppLaunchDetails.payload;
}
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String payload) async {
if (payload != null) {
selectedNotificationPayload = payload;
selectNotificationSubject.add(payload);
}
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(Start());
}
class Start extends StatefulWidget {
#override
_StartState createState() => _StartState();
}
class _StartState extends State<Start>{
void initializeFlutterFire() async {
try {
await Firebase.initializeApp();
print("Firebase - initialzed successfully");
} catch (e) {
print("Firebase - initialzed FAILED");
}
messaging = FirebaseMessaging.instance;
}
void _configureSelectNotificationSubject() async {
selectNotificationSubject.stream.listen((String _url) async {
try {
await Future.delayed(Duration(milliseconds: 500), () async {
await Navigator.of(context).push(new Route(_url, ""));
});
} catch (e) {
print("Fehler beim öffnen der Website");
}
});
}
#override
initState() {
super.initState();
initializeFlutterFire();
}
...
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
Map<String, dynamic> data = message.data;
String _title = data['title'];
String _description = data['message'];
sendNotification(_title, _description);
}

Flutter : Dynamic Link not launching the app

I am using firebase dynamic links to open the email verification link in my app, but unfortunetly the link doesn't launch the app when tapped.
What I've done so far
When a new user is created, a link is sent by email to be verified :
if(firebaseUser != null && !firebaseUser.emailVerified){
await createUserInDatabaseIfNew(firebaseUser);
var actionCodeSettings = auth.ActionCodeSettings(
url: 'https://muslimcoloc.page.link/?email=${firebaseUser.email}',
dynamicLinkDomain: "muslimcoloc.page.link",
androidInstallApp: true,
androidMinimumVersion: "12",
androidPackageName: "com.app.muslim_coloc",
iOSBundleId: "com.muslim_coloc.ios",
handleCodeInApp: true,
);
await firebaseUser.sendEmailVerification(actionCodeSettings);
}
I got the dynamicLinkDomain in the firebase console :
Then, I handle the reception of the link in my main.dart file, with the firebase dynamic links package :
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
MyApp({Key key, }) : super(key: key);
#override
Widget build(BuildContext context) {
return AppView();
}
}
class AppView extends StatefulWidget {
const AppView({
Key key,
}) : super(key: key);
#override
_AppViewState createState() => _AppViewState();
}
class _AppViewState extends State<AppView> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
this.initDynamicLinks();
}
}
void initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
FirebaseAuth auth = FirebaseAuth.instance;
//Get actionCode from the dynamicLink
var actionCode = deepLink.queryParameters['oobCode'];
try {
await auth.checkActionCode(actionCode);
await auth.applyActionCode(actionCode);
// If successful, reload the user:
auth.currentUser.reload();
} on FirebaseAuthException catch (e) {
if (e.code == 'invalid-action-code') {
print('The code is invalid.');
}
}
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(...)
}
When I tap the link of the email, the app doesn't start nor does the browser. Here's what happens :
It tries to launch something on the browser, but then comes back to gmail.
However if I click on the link in a desktop browser, it works fine, the email is validated.
I'm having a hard time understanding what it going on. Is there something wrong about how I did things ?
You should write a function to handle your dynamic links, as per the documentation, and this is working for me in an app being used currently:
void handleDynamicLinks() async {
///To bring INTO FOREGROUND FROM DYNAMIC LINK.
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLinkData) async {
await _handleDeepLink(dynamicLinkData);
},
onError: (OnLinkErrorException e) async {
print('DynamicLink Failed: ${e.message}');
return e.message;
},
);
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
_handleDeepLink(data);
}
// bool _deeplink = true;
_handleDeepLink(PendingDynamicLinkData data) async {
final Uri? deeplink = data.link;
if (deeplink != null) {
print('Handling Deep Link | deepLink: $deeplink');
}
}
and in initState:
#override
void initState() {
handleDynamicLinks();
super.initState();
}
write this logic in your home page. Not in void(main..etc)
But in your first widget after that, and it should work.
Also, be sure to double check your package name, i.e com.example.yourAwesomeApp123, it's what lets the whole system know what app is to be opened when the dynamic link is pressed.

Unhandled Exception: NoSuchMethodError: The method 'addAdvogado' was called on null. On Flutter

I researched other similar questions with this error but I couldn't fix it. I don't know what I'm doing wrong.
My application is not saving to the database when I try to send the information to the form.
What should I do to correct?
I receive the message:
Unhandled Exception: NoSuchMethodError: The method 'addAdvogado' was
called on null. E/flutter ( 7418): Receiver: null E/flutter ( 7418):
Tried calling: addAdvogado(Instance of 'Advogado')
lawyer.dart
class Advogado {
final String id;
final String nome;
final String email;
final String telefone;
final String endereco;
final String numeroOAB;
const Advogado(
{this.id,
#required this.nome,
#required this.email,
#required this.telefone,
#required this.endereco,
#required this.numeroOAB});
Advogado.fromMap(Map snapshot, String id)
: id = snapshot['id'] ?? '',
nome = snapshot['nome'] ?? '',
email = snapshot['email'] ?? '',
telefone = snapshot['telefone'] ?? '',
endereco = snapshot['endereco'] ?? '',
numeroOAB = snapshot['numeroOAB'] ?? '';
toJson() {
return {
"id": id,
"nome": nome,
"email": email,
"telefone": telefone,
"endereco": endereco,
"numeroOAB": numeroOAB,
};
}
}
form_lawyer.dart - Sample code
final _formAdvogado = GlobalKey<FormState>();
final Map<String, String> _dadosForm = {};
Container(
margin: EdgeInsets.all(10.0),
child: RaisedButton(
onPressed: () async {
if (_formAdvogado.currentState.validate()) {
_formAdvogado.currentState.save();
await advogadoProvider.addAdvogado(
Advogado(
nome: 'nome',
email: 'email',
telefone: 'telefone',
endereco: 'endereco',
numeroOAB: 'numeroOAB',
),
);
Navigator.pop(context);
}
},
child: Text("Enviar"),
color: Colors.cyan,
textColor: Colors.white,
),
api_lawyer_firebase.dart
class ApiFirebase {
// final FirebaseFirestore _bd = FirebaseFirestore.instance;
final Future<FirebaseApp> _initialize = Firebase.initializeApp();
FirebaseFirestore _bd = FirebaseFirestore.instance;
final String path;
CollectionReference ref;
ApiFirebase(this.path) {
ref = _bd.collection(path);
}
Future<QuerySnapshot> getColecaoDados() {
return ref.get();
}
Stream<QuerySnapshot> streamColecaoDados() {
return ref.snapshots();
}
Future<DocumentSnapshot> getDocumentoById(String id) {
return ref.doc(id).get();
}
Future<void> removerDocumento(String id) {
return ref.doc(id).delete();
}
Future<DocumentReference> addDocumento(Map dados) {
return ref.add(dados);
}
Future<void> atualizarDocumento(Map dados, String id) {
return ref.doc(id).update(dados);
}
}
CRUD - database_laywer.dart
class DBAdvogado with ChangeNotifier {
ApiFirebase _apiFirebase = locator<ApiFirebase>();
List<Advogado> advogados;
Future<List<Advogado>> buscarAdvogados() async {
var result = await _apiFirebase.getColecaoDados();
advogados =
result.docs.map((doc) => Advogado.fromMap(doc.data(), doc.id)).toList();
return advogados;
}
Stream<QuerySnapshot> buscarAdvogadoAsStream() {
return _apiFirebase.streamColecaoDados();
}
Future<Advogado> getAdvogadoById(String id) async {
var doc = await _apiFirebase.getDocumentoById(id);
return Advogado.fromMap(doc.data(), doc.id);
}
Future removerAdvogado(Advogado dados, String id) async {
await _apiFirebase.atualizarDocumento(dados.toJson(), id);
return;
}
Future addAdvogado(Advogado dados) async {
await _apiFirebase.addDocumento(dados.toJson());
return;
}
}
In general, when there is an error with "something" was called on null it means that the subject on which you are calling "something" is currently null.
You use addAdvogado method in one place on only one variable - in form_lawyer.dart on advogadoProvider. So the question is: how and where do you set advogadoProvider?

Unable to update data in firebase database while using phone authentication in Flutter

I am trying to add user registering form data to firebase database. But have tough time doing it effectivily. I am new to the flutter. I successfully register the user via phone number but unable to add corresponding details. I tried using getter and setter but it obviously is not working. I don't know what is idealic method of doing that. I tried googling it but didn't got any help. I am just stuck. I will really appreciate it.
Here is my code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:home_crisp/models/user.dart';
import 'package:home_crisp/services/auth.dart';
import 'package:provider/provider.dart';
class ChefRegisterScreen extends StatefulWidget {
ChefRegisterScreen();
#override
_ChefRegisterScreenState createState() => _ChefRegisterScreenState();
}
class _ChefRegisterScreenState extends State<ChefRegisterScreen> {
final AuthService _auth = AuthService();
bool loading = false;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String chefName = "", phoneNo = "";
String smsCode, verificationID;
String phnCode = "+92";
DateTime dateOfBirth;
bool codeSent = false;
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
final deviceSize = MediaQuery.of(context).size;
return loading
? Loading()
: Material(
type: MaterialType.card,
color: Color(0xffD4EBD3),
child: Stack(
children: <Widget>[
// --> Here is the code of getting "chefname, phone and dateOfBirth" and setting them using setState() method
//
// >>>>>>>>> Textfeild for getting OTP code
//
codeSent
? // Here is the code for textfeild which get OTP code
: Container(),
// ------------------------------------------------------ F I N I S H B U T T O N
FlatButton(
onPressed: () async {
if (user != null) {
print(
"TheRe IS uSer already logging in so signing out logging in new user");
AuthService().signOut();
}
if (codeSent) {
AuthService().signInWithOTP(smsCode, verificationID);
} else {
verifyPhone(phoneNo);
}
// ----> Here I tried to several methods to sent register form data to the seperate class named
// ----> "user.dart" from where I tried to extract that info in "auth" signinWithPhoneNumber method.
// ----> I first tried to send the info via constructor
ChefData(chefName: chefName,
chefPhNo: phoneNo,
chefDateOfBirth: dateOfBirth);
});
// ----> Then I tried "setter" but in vain
// ChefData().setChefName(chefName);
// ChefData().setChefPhNo(phoneNo);
// ChefData().setChefDateOfBirth(dateOfBirth);
child: ClipRRect(
child: Text(
"FINISH",
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat',
fontSize: 20,
),
),
),
),
],
),
),
)
],
),
),
],
),
);
}
//
// >>>>>>>>> S I G N I N W I T H P H O M E N U M B E R P R O C E S S
//
Future<void> verifyPhone(phoneNo) async {
final PhoneVerificationCompleted verificationComplete =
(AuthCredential authResult) {
print('1. Auto retrieving verification code');
}
};
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verID) {
verificationID = verID;
print("\n2. Auto retrieval time out");
};
final PhoneCodeSent smsCodeSent =
(String verID, [int forceCodeResend]) async {
verificationID = verID;
setState(() {
this.codeSent = true;
});
print("\n 3. Code Sent to " + phoneNo);
};
final PhoneVerificationFailed verificationFailed =
(AuthException authException) {
print('${AuthException(smsCode, "message")}');
if (authException.message.contains('not authorized'))
print('App not authroized');
else if (authException.message.contains('Network'))
print('Please check your internet connection and try again');
else
print('Something has gone wrong, please try later ' +
authException.message);
};
await FirebaseAuth.instance
.verifyPhoneNumber(
phoneNumber: phoneNo,
timeout: Duration(seconds: 50),
verificationCompleted: verificationComplete,
verificationFailed: verificationFailed,
codeSent: smsCodeSent,
codeAutoRetrievalTimeout: autoRetrieve,
)
.then((value) {})
.catchError((error) {
print(error.toString());
});
}
}
Here is the "auth.dart" class
import 'package:firebase_auth/firebase_auth.dart';
import 'package:home_crisp/models/user.dart';
import 'package:home_crisp/services/database.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on FirebaseUser
User _userFormFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
// auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFormFirebaseUser);
}
// ------------------------------------------------------ S I G N I N W I T H P H O M E N U M B E R
signInWithPhoneNumber(AuthCredential authCreds) async {
try {
AuthResult result = await _auth.signInWithCredential(authCreds);
FirebaseUser user = result.user;
if (user != null) {
print('AUTHENTICATONI SUCCESSFULL. Id: ' + user.uid);
// ---->> Now here I tried create a new document for the chef with the uid by extracting the chef data // // ---->> from "user.dart" class
// ---->> I used getter method. I know there is going to be some better way to get that data
await DatabaseService(uid: user.uid).updateChefData(
ChefData().getChefName(),
ChefData().getChefPhNo(),
ChefData().getChefDateOfBirth());
return _userFormFirebaseUser(user);
} else {
print('Invalid code/invalid authentication');
}
} catch (e) {
print(e.toString());
return null;
}
}
signInWithOTP(smsCode, verId) {
AuthCredential authCreds = PhoneAuthProvider.getCredential(
verificationId: verId, smsCode: smsCode);
signInWithPhoneNumber(authCreds);
}
}
Here is "user.dart" file containing "ChefData" class acting as intermediary between "auth.dart" and "chefRegisterScreen.dart"
class User {
final String uid;
User({this.uid});
}
class ChefData {
String chefId;
String chefName;
String chefPhNo;
DateTime chefDateOfBirth;
ChefData({this.chefId, this.chefName, this.chefPhNo, this.chefDateOfBirth});
// void setChefId(String _chefId) {
// this.chefId = _chefId;
// }
// void setChefName(String _chefName) {
// this.chefName = _chefName;
// }
// void setChefPhNo(String _chefPhNo) {
// this.chefPhNo = chefPhNo;
// }
// DateTime setChefDateOfBirth(DateTime _chefDateOfBirth) {
// this.chefDateOfBirth = _chefDateOfBirth;
// }
String getChefId() {
return chefId;
}
String getChefName() {
return chefName;
}
String getChefPhNo() {
return chefPhNo;
}
DateTime getChefDateOfBirth() {
return chefDateOfBirth;
}
}
I had a similar problem and I used shared preferences to store the user details during registration then uploaded the details after phone authentication was successful.
Shared preferences is a flutter plugin that allows you to store simple data in key-value pair form.Here is a more detailed article about shared preferences and how to use it.
In your case, I suggest you create a class for shared preferences.
class SharedPreference{
static Future<String> storeChefData(ChefData chefData) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String storeUser = userToJson(chefData);
await prefs.setString('user', storeUser);
return storeUser;
}
static Future<ChefData> getChefData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getString('user') != null) {
ChefData chefData = userFromJson(prefs.getString('user'));
return chefData;
} else {
return null;
}
}
}
The storeChefData() function is for storing users details during registration. While the getChefData() function is for retrieving the users details in order to upload to the database after authentication.
In your user.dart file you will be required to add functions that convert the chefData to jsonData for storage and from jsonData to ChefData for retrieval as shown in the above functions.
ChefData userFromJson(String str) {
final jsonData = json.decode(str);
return ChefData.fromJson(jsonData);
}
String userToJson(ChefData data) {
final dyn = data.toJson();
return json.encode(dyn);
}
class ChefData{
final String chefName;
final String chefPhNo;
final DateTime chefDateOfBirth;
ChefData({this.chefName,this.chefPhNo,this.chefDateOfBirth});
factory ChefData.fromJson(Map<String, dynamic> json) => ChefData(
chefName: json["chefName"],
chefPhNo: json["chefPhNo"]
chefDateOfBirth: json["chefDateOfBirth"]
);
Map<String, dynamic> toJson() => {
"chefName": chefName,
"chefPhNo": chefPhNo
"chefDateOfBirth": chefDateOfBirth
};
}
In your ChefRegistrationScreen you will add:
await SharedPreference.storeChefData(ChefData(chefName: chefName,chefPhNo: phoneNo,chefDateOfBirth: dateOfBirth));
at the point where you would like to insert the chefData.
Then in your auth.dart file you will add:
ChefData getChefData = await SharedPreference.getChefData();
await DatabaseService(uid: user.uid).updateUserData(getChefData);
in order to update your database.

Resources