Updating Value From API in a constructor flutter - flutter

I want to update the value of a constructor coming from page-1 to page-2. And I am using that value in an APIs response and wanted to update the response value with the new value.
Here is the code for better understanding.
Page-1 Code:
Future<void> forgotpass() async {
if (emailController.text.isNotEmpty) {
var response = await http
.post(Uri.parse('http://123.123.123/forgotPassword'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8",
},
body: jsonEncode({
"email": emailController.text,
}))
.then((response) {
print(response.statusCode);
print(response.body);
final parsedJson = json.decode(response.body);
var token = parsedJson['data']['forgotPasswordToken'];
var otp = parsedJson['data']['otp'];
print('OTP: $otp');
print("Token: $token");
if (response.body.contains('"statusCode":200')) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtpVerifyPage(
text: token,
)));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Invalid Email')));
}
return response;
});
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please Enter your Email Addrees')));
}
The token is been sent to a New Page-2.
Future<void> otpVerify() async {
if (otp.text.isNotEmpty) {
int newOtp = int.parse(otp.text);
var response = await http
.post(Uri.parse('http://123.123.123/verifyOtp'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8"
},
body: jsonEncode({
"forgotPasswordToken": widget.text, //wanted to update value here from when hitting resendCode() function.
"otp": newOtp,
}))
.then((response) {
print(response.statusCode);
print(response.body);
if (response.body.contains('"statusCode":200')) {
final parsedJson = json.decode(response.body);
var resetToken = parsedJson['data']['resetPasswordToken'];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SetNewPassPage(
text: resetToken,
)));
} else if (response.statusCode == 202) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Server issue. Please Try Again Later')));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Invalid OTP')));
}
return response;
});
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Please Enter your OTP')));
}
I am also using the resend OTP function as :
Future<void> resendCode() async {
// ignore: unused_local_variable
var response = await http
.post(Uri.parse('http://123.123.123/resendCode'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8"
},
body: jsonEncode({
"forgotPasswordToken": widget.text, //Getting new Token but can't update it in otpVerify() function.
}))
.then((response) {
print(response.statusCode);
print(response.body);
final parsedJson = json.decode(response.body);
var token = parsedJson['data']['forgotPasswordToken'];
var otp = parsedJson['data']['otp'];
print('OTP: $otp');
print("Token: $token");
if (response.body.contains('"statusCode":200')) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('OTP Send to your Email ID')));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Try again later')));
}
return response;
});
}
Now I wanted to update the "forgotPasswordToken" in the body of otpVerify().
Its updating in resendCode() function but not in otpVerify(). So if anyone knows how to solve this issue please help.
Here is the UI snapshot for better understanding: Page-1 & Page-2

What you can simply do is put this in resendCode function this will refresh your page with new values.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtpVerifyPage(text: token)));
Full code for better understanding:
Future<void> resendCode() async {
// ignore: unused_local_variable
var response = await http
.post(Uri.parse('http://123.123.123/resendCode'),
headers: <String, String>{
"content-type": "application/json; charset=utf-8"
},
body: jsonEncode({
"forgotPasswordToken": widget.text,
}))
.then((response) {
print(response.statusCode);
print(response.body);
final parsedJson = json.decode(response.body);
var token = parsedJson['data']['forgotPasswordToken'];
var otp = parsedJson['data']['otp'];
print('OTP: $otp');
print("Token: $token");
if (response.body.contains('"statusCode":200')) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OtpVerifyPage(text: token))); // Added here to refresh the page with new value of token.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('OTP Send to your Email ID')));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Try again later')));
}
return response;
});

Related

How to send a user to a specific page via firebase notification when the app is terminated in flutter?

Main Screen
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String? payload) async {
try {
if (payload != null && payload.isNotEmpty) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewScreen(info: payload.toString())));
} else {}
} catch (e) {}
return;
});
void sendPushMessage(String token, String body, String title) async {
try {
await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization':
'key=thekey'
},
body: jsonEncode(<String, dynamic>{
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'status': 'done',
'body': body,
'title': title
},
"notification": <String, dynamic>{
"title": title,
"body": body,
"android_channel_id": "androidchannelid"
},
"to": token,
}),
);
} catch (e) {
if (kDebugMode) {
print('error push notifications');
}
}
}
When the notification is received it should be send to the new screen and not the main screen.
This code works when the app is in background or foreground but it is not working when the app is terminated.
What should i do?
Use to getInitialMessage to check if there is a message when a application is opened.
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
// TODO navigate to a specific page
}
See Handling Interaction for details.

how can get paylod data when I using FCM in flutter?

how can get paylod data when I using FCM in flutter?
I tried used this methods, but I still could not got the data...
where has issues?
void getInitialMessage() async {
RemoteMessage? message =
await FirebaseMessaging.instance.getInitialMessage();
print(message?.data["type"]);
if (message != null) {
if (message.data["type"] == "noti") {
print("AAAAA");
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
PostDetailScreen(postid: message.data["postid"]),
),
);
} else if (message.data["type"] == "active") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PostDetailScreen(postid: '456'),
),
);
}
}
}
When I go to postman to test, I will send this format
Future<void> sendPushMessage(String token, String body, String title,
String postid, String images) async {
try {
await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization':
'key=AAAAm2nkpqg:APA91bH9l8kYkJqGyGnVJhUe4dmG5KeYVrErEB_vl7vhZDGBAgFGOYsyHguDna-SBeP8juVoTtLQ61aI61QZ-46JFwaR-8KPai7CT6n4-jRZFBIMOHEl1Ph',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{'body': body, 'title': title},
'priority': 'high',
'timeToLive': 24 * 60 * 60,
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done',
'type': 'noti',
'postid': 'Mi6Y3sE9E0uz4uAvQjwC'
},
"to": token,
},
),
);
} catch (e) {
print("error push notification");
}
}
I can receive the Notification, but I have setting "type": "noti". So when I click the notification message, it shoule be print AAAAA and Navigator to PostDetailScreen. But It's always open app then go to homepage....
Send out FCM message with this structure, here I use NodeJS Firebase Cloud Function, but the important thing is to add the second, options part:
await admin.messaging().sendToDevice(tokens, {
data: {
click_action: 'FLUTTER_NOTIFICATION_CLICK',
type: 'noti',
postid: 'ulEdnFiEZxyyc33UNvJs'
},
notification: {
title: 'title',
body: 'body'
},
}, {
contentAvailable: true,
priority: 'high',
timeToLive: 24 * 60 * 60, // in seconds
});
After this, in getInitialMessage you should have:
message.data['type'] // 'noti'
message.data['postid'] // 'ulEdnFiEZxyyc33UNvJs'

Flutter Page showing blank screen

I want to display data from api to the text and it is showing blank screen and I think I did anything required, I followed this tutrial https://docs.flutter.dev/cookbook/networking/fetch-data and still it does not work for me. I tried everything,
May you please help me.
My api call below
Future<CarDetails?> signInData() async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('token');
try {
Response response = await _dio.post('$_baseUrl/api/gateway',
data: {
"ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
"PlatformId": "ios",
"ClientUserId": "AhmedOmar",
"VinNumber": VINumber
},
options: Options(headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $token",
}));
print("data");
print(response.data.toString());
print(response.statusCode);
if (response.statusCode == 200) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const ResultsPage(),
),
);
}
else if (response.statusCode == 500) {
// call your refresh token api here and save it in shared preference
print(response.statusCode);
await getToken();
signInData();
}
return CarDetails.fromJson(jsonDecode(response.data.toString()));
} catch (e) {
print(e);
}
My other page where I wanna show the results
class ResultsPage extends StatefulWidget {
const ResultsPage({Key? key}) : super(key: key);
#override
_ResultsPageState createState() => _ResultsPageState();
}
class _ResultsPageState extends State<ResultsPage> {
//List<CarDetails> objectList = [];
late Future<CarDetails?>? objectList;
_APIState? api;
#override
void initState() {
super.initState();
objectList = api?.signInData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
//centerTitle: true,
),
body: Center(
child: FutureBuilder<CarDetails?>(
future: objectList,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data?.make??"error");
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
));
}
}
My model class
class CarDetails {
String? make;
String? type;
String? model;
int? year;
String? body;
String? driveType;
String? fueType;
CarDetails(
{this.make,
this.type,
this.model,
this.year,
this.body,
this.driveType,
this.fueType});
CarDetails.fromJson(Map<String, dynamic> json) {
make = json['make'];
type = json['type'];
model = json['model'];
year = json['year'];
body = json['body'];
driveType = json['drive_type'];
fueType = json['fue_type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['make'] = this.make;
data['type'] = this.type;
data['model'] = this.model;
data['year'] = this.year;
data['body'] = this.body;
data['drive_type'] = this.driveType;
data['fue_type'] = this.fueType;
return data;
}
}
The problem is you are replacing the widget in your navigator stack when you get success.
Future<CarDetails?> signInData() async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('token');
try {
Response response = await _dio.post('$_baseUrl/api/gateway',
data: {
"ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
"PlatformId": "ios",
"ClientUserId": "AhmedOmar",
"VinNumber": VINumber
},
options: Options(headers: {
"Content-Type": "application/json",
"Authorization": "Bearer $token",
}));
print("data");
print(response.data.toString());
print(response.statusCode);
if (response.statusCode == 200) {
//Get rid of this
//Navigator.of(context).pushReplacement(
// MaterialPageRoute(
// builder: (context) => const ResultsPage(),
// ),
//);
// Return your future here
return CarDetails.fromJson(jsonDecode(response.data.toString()));
}
else if (response.statusCode == 500) {
// call your refresh token api here and save it in shared preference
print(response.statusCode);
await getToken();
signInData();
}
} catch (e) {
print(e);
}

How to receive FCM push notification data in flutter web and redirect user to received link in notification?

I am trying to redirect user to specific page in flutter web on click of notification, till now I am receiving notification, the last open page is displayed in browser on click of notification, but I want user to redirect to specific page like specific post using unique post id, but I found no other ways, This thing happens in Android build, but doesn't happen on web build.
just take a look at ServiceWorker.js
in serviceworker.js even console.log() in not executing on receiving notification.
messaging.setBackgroundMessageHandler(function (payload) {
console.log(payload);
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
const title = payload.notification.title;
const options = {
body: payload.notification.body
};
return registration.showNotification(title, options);
});
return promiseChain;
});
self.addEventListener('notificationclick', function (event) {
console.log('notification received: ', event)
});
now the logic for sending FCM Push Notification:
#required String message,
#required String fcmToken,
#required String title,
String type,
String typeId,
}) async {
await http
.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
"click_action": 'FLUTTER_NOTIFICATION_CLICK',
'body': message,
'title': '$title',
'sound': 'default'
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done',
'type': type ?? "",
'typeId': typeId ?? "",
},
'to': fcmToken.toString().trim(),
},
),
)
.then((value) {
print("Notification Sent");
});
final Completer<Map<String, dynamic>> completer =
Completer<Map<String, dynamic>>();
// firebaseMessaging.configure(
// onMessage: (Map<String, dynamic> message) async {
// completer.complete(message);
// },
// );
return completer.future;
}
Now the way I am handling Notification Receive:
print("in setup interacted message");
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
NotificationSettings notifSettings =
await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true,
);
if (notifSettings.authorizationStatus == AuthorizationStatus.authorized) {
// Get any messages which caused the application to open from
// a terminated state.
try {
RemoteMessage initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "post",
// navigate to a post screen
if (initialMessage != null && initialMessage.data['type'] == 'post') {
await Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => IndividualPostPage(
postObjectId: initialMessage.data['typeId'],
),
),
);
print(initialMessage.data);
initialMessage = null;
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp
.listen((RemoteMessage message) async {
print("here");
if (message != null && message.data['type'] == 'post') {
if (message.data['type'] == 'post') {
await Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => IndividualPostPage(
postObjectId: message.data['typeId'],
),
),
);
}
print(message.data);
message = null;
}
});
} catch (e) {
print("Error $e");
}
}
}
messaging.setBackgroundMessageHandler(function (payload) {
console.log(payload);
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
const title = payload.notification.title;
var click_action =payload.data.ui_route;//ui route is ur route
const options = {
body: payload.notification.body ,
data: {
click_action,
}
};
return registration.showNotification(title, options);
});
return promiseChain;
});
// Notification click event listener
self.addEventListener('notificationclick', e => {
data=e.notification.data.obj;
// Close the notification popout
e.notification.close();
// Get all the Window clients
e.waitUntil(clients.matchAll({ type: 'window' }).then(clientsArr => {
// If a Window tab matching the targeted URL already exists, focus that;
const hadWindowToFocus = clientsArr.some(windowClient => windowClient.url === e.notification.data.click_action ? (windowClient.focus(), true) : false);
// Otherwise, open a new tab to the applicable URL and focus it.
if (!hadWindowToFocus) clients.openWindow(e.notification.data.click_action).then(windowClient => windowClient ? windowClient.focus() : null);
}));
});

How to set flutter POST method using DIO?

This is my code below, i'm stuck please help. How to set flutter POST method using DIO?
Map<String, dynamic> toJson() {
return {
'id': id,
"name": name,
"telNumber": telNumber,
"email": email,
"age": age
};
}
String postToJson(Post data){
final dyn = data.toJson();
return json.encode(dyn);
}
Future<http.Response> createPost(Post post) async {
final response = await http.post(
"$baseUrl/users",
headers: {
"content-type": "application"
},
body: postToJson(post));
return response;
}
This method works in http
BaseOptions options = new BaseOptions(
baseUrl: $baseUrl,
connectTimeout: 10000,
receiveTimeout: 10000,);
final dioClient = Dio(options);
try{
final response = await dioClient.post("/users", data: FormData.fromMap(
postToJson(post))
),);
return response;
} catch (e) {
throw (e);
}
Put this code inside the function
you can create a new function and call this from anywhere:
Future<Null> SendPost() async {
Response response;
BaseOptions options = new BaseOptions(
baseUrl: "https://your.url",
connectTimeout: 6000,
receiveTimeout: 3000,
);
Dio dio = new Dio(options);
FormData formData = new FormData.fromMap({
"post_data1": value,
"post_data2": value,
});
try {
response=await dio.post("/page.php", data: formData);
return response;
} catch (e) {
print('Error: $e');
}
}