Black Screen agora remote view flutter - flutter

I am trying to implement the flutter Agora SDK Livestream with agora and I'm getting a black screen on remote view, local view works fine.
Please what am I doing wrongly?
What I tried:
double-check if all permissions are enabled
recreate a new application In agora.io
switch devices
check internet connectivity
This is the code for the implementation:
void initEngine() async {
_engine = await RtcEngine.create(agoraKey);
addListeners();
_engine.enableVideo();
_engine.startPreview();
_engine.enableAudio();
_engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
print(widget.isBroadcaster);
if (("${widget.userData.uid}${widget.userData.name}" == widget.channeId)) {
_engine.setClientRole(ClientRole.Broadcaster);
print('broadcaster');
} else {
_engine.setClientRole(ClientRole.Audience);
print('audience');
}
_joinChannel();
}
_renderVideo(
user,
isScreenSharing,
) {
return AspectRatio(
aspectRatio: 16 / 9,
child: "${user.uid}${user.name}" == widget.channeId
? isScreenSharing
? kIsWeb
? const RtcLocalView.SurfaceView.screenShare()
: const RtcLocalView.TextureView.screenShare()
: const RtcLocalView.SurfaceView(
zOrderMediaOverlay: true,
zOrderOnTop: true,
)
: isScreenSharing
? kIsWeb
? const RtcLocalView.SurfaceView.screenShare()
: const RtcLocalView.TextureView.screenShare()
: isRendered
? RtcRemoteView.TextureView(
uid: _remoteUids[0],
channelId: widget.channeId,
)
: Center(
child: Text(
'No Video',
style: GoogleFonts.balooPaaji2(
fontSize: 15,
),
),
),
);
}
void addListeners() {
_engine.setEventHandler(RtcEngineEventHandler(
joinChannelSuccess: (channel, uid, elapsed) async {
debugPrint('joinChannelSuccess $channel $uid $elapsed');
print(
'joinChannelSuccess ======================================================> $uid');
},
leaveChannel: (stats) {
debugPrint('leaveChannel $stats');
setState(() {
_remoteUids.clear();
});
},
userJoined: (uid, elapsed) {
debugPrint('userJoined $uid $elapsed');
setState(() {
print('userJoined=====================>:$_remoteUids');
_remoteUids.add(uid);
setState(() {
isRendered = true;
});
print('=======>====>$_remoteUids');
});
},
userOffline: (uid, reason) {
debugPrint('userOffline=====================> $uid $reason');
setState(() {
_remoteUids.remove(uid);
});
},
userMuteAudio: (uid, muted) {
debugPrint('userMuteAudio $uid $muted');
},
userMuteVideo: (uid, muted) {
debugPrint('userMuteVideo $uid $muted');
},
userEnableVideo: (uid, enabled) {
debugPrint('userEnableVideo $uid $enabled');
},
error: (error) {
debugPrint('error $error');
},
));
print('=====.$_remoteUids========');
}
void _joinChannel() async {
//leave the current channel
if (defaultTargetPlatform == TargetPlatform.iOS) {
await [Permission.microphone, Permission.camera].request();
await _engine.joinChannel(
tempToken, 'testing_channel', widget.channeId, 0);
debugPrint('joinChannelWithUserAccount ${widget.channeId} ');
} else {
await [Permission.microphone, Permission.camera].request();
await _engine.joinChannel(
tempToken, 'testing_channel', widget.channeId, 0);
debugPrint('joinChannelWithUserAccount ${widget.channeId} ');
}
}
}

Make sure the Uid in Rtc remote view is the same with the user went live and the user joined to live
RtcRemoteView.SurfaceView(
uid: ,
channelId:,
)

Related

The following _TypeError was thrown building RegisterScreen() : type 'String' is not a subtype of type 'int' of 'index'

String? _selectedCity;
List cities = ['Select City'];
#override
void initState() {
super.initState();
_secureText = true;
_getCities();
}
Future _getCities() async {
var url = "baseurl/api/v1/cities";
try {
var response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
var data = json.decode(response.body);
setState(() {
cities = data;
});
}
print(cities);
} catch (e) {
// ignore: avoid_print
print("Error: $e");
}
}
DropdownButton(
hint
: const Text("Select City"), value
: _selectedCity, items
: cities
.map((category) {
return DropdownMenuItem(value
: category['name'], child
: Text(category['name']), );
})
.toList(),
onChanged
: (value) { setState(() { _selectedCity = value as String ? ; }); })
there is problem in my Dropdown Button
Value from dropdown were seen before but after update of 2023/1/25, i am facing error "type 'String' is not a subtype of type 'int' of 'index'"
Replace this code in your own code. must be correct.
DropdownButton(
hint: const Text("Select City"),
value: _selectedCity,
items: cities
.map((category) {
return DropdownMenuItem(
value: category['name'],
child: Text(category['name'])
);
})
.toList(),
onChanged: (value) {
setState(() {
_selectedCity = value;
});
})

The client_secret Provided does not match any associated PaymentIntent on this account

I'm trying to use flutter_stripe for a stripe connect account, But I always get the
same error: The client_secret provided doesn't match the client_secret associated with the PaymentIntend.
I've completed all steps according to flutter_stripe but I still face this error.
Below is my code Please check this and help me.
inde.js
const functions = require("firebase-functions");
const stripe = require("stripe")("secret_key");
exports.stripePaymentIntentRequest = functions.https.onRequest(async (req, res) => {
try {
let customerId;
//Gets the customer who's email id matches the one sent by the client
const customerList = await stripe.customers.list({
email: req.body.email,
limit: 1
});
//Checks the if the customer exists, if not creates a new customer
if (customerList.data.length !== 0) {
customerId = customerList.data[0].id;
}
else {
const customer = await stripe.customers.create({
email: req.body.email
});
customerId = customer.data.id;
}
//Creates a temporary secret key linked with the customer
const ephemeralKey = await stripe.ephemeralKeys.create(
{ customer: customerId },
{ apiVersion: '2020-08-27' }
);
//Creates a new payment intent with amount passed in from the client
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt(req.body.amount),
currency: 'usd',
customer: customerId,
})
res.status(200).send({
clientSecret: paymentIntent.client_secret,
paymentIntent: paymentIntent,
ephemeralKey: ephemeralKey.secret,
customer: customerId,
success: true,
})
} catch (error) {
res.status(404).send({ success: false, error: error.message })
}
});
PaymentService.dart
Future<void> initPaymentSheet(
{required BuildContext context, required String email, required int amount}) async {
try {
// 1. create payment intent on the server
final response = await http.post(
Uri.parse(
'Firebase api link of Functions'),
body: {
'email': email,
'amount': amount.toString(),
});
Map<String, dynamic> paymentIntentBody = jsonDecode(response.body);
log(paymentIntentBody.toString());
//2. initialize the payment sheet
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentBody["clientSecret"],
merchantDisplayName: 'Flutter Stripe Store Demo',
customerId: paymentIntentBody['customer'],
customerEphemeralKeySecret: paymentIntentBody['ephemeralKey'],
style: ThemeMode.light,
testEnv: true,
merchantCountryCode: 'US',
),
);
await Stripe.instance.presentPaymentSheet();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment completed!')),
);
} catch (e) {
if (e is StripeException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error from Stripe: ${e.error.localizedMessage}'),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error the Stripe of : $e')),
);
}
}
}
The log error print on my console is :
> [log] {paymentIntent:
> pi_3LI2acCTAUDjRNFV1Ra3dahz_secret_Fcqw73pWrE4avKRyuDVzRBitG,
> ephemeralKey:
> ek_test_YWNjdF8xSlQ3amtDVEFVRGpSTkZWLDl1OE5Vdm1jTGY4T1RpaVhHOTB3NTRVSkQ5UGl4azA_00j32OYG9n,
> customer: cus_LHG2YpQP9Cgwuy, success: true}
The following code is from a previous Stripe evaluation stage. But it worked. Slim it down to your needs.
Remember to publish your secret key to the server, so the server can talk to Stripe.
code.dart
Future<bool> payWithPaymentSheet(
ProductModel productModel, PriceModel priceModel,
{String merchantCountryCode = 'DE'}) async {
if (kIsWeb) {
throw 'Implementation not availabe on Flutter-WEB!';
}
String uid = AuthService.instance.currentUser().uid;
String email = AuthService.instance.currentUser().email ?? '';
HttpsCallableResult response;
try {
response = await FirebaseFunctions
.httpsCallable('createPaymentIntent')
.call(<String, dynamic>{
'amount': priceModel.unitAmount,
'currency': priceModel.currency,
'receipt_email': email,
'metadata': {
'product_id': productModel.id,
'user_id': uid,
"valid_until": productModel.getUntilDateTime().toIso8601String(),
'product_name': productModel.name.tr,
},
'testEnv': kDebugMode,
});
} on FirebaseFunctionsException catch (error) {
log(error.code);
log(error.details);
log(error.message ?? '(no message)');
Get.snackbar(
error.code,
error.message ?? '(no message)',
icon: const Icon(Icons.error_outline),
);
return false;
}
Map<String, dynamic> paymentIntentBody = response.data;
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentBody["clientSecret"],
currencyCode: priceModel.currency,
applePay: false,
googlePay: false,
merchantCountryCode: merchantCountryCode,
merchantDisplayName: Strings.appName,
testEnv: kDebugMode,
customerId: paymentIntentBody['customer'],
customerEphemeralKeySecret: paymentIntentBody['ephemeralKey'],
));
try {
await Stripe.instance.presentPaymentSheet();
return true;
} on StripeException catch (e) {
log(e.error.code.name);
log(e.error.message ?? '(no message)');
log(e.error.localizedMessage ?? '(no message)');
Get.snackbar(e.error.code.name, e.error.message ?? '',
icon: const Icon(Icons.error_outline));
} catch (e) {
Get.snackbar('An unforseen error occured', e.toString(),
icon: const Icon(Icons.error_outline));
}
return false;
}
index.ts
// SETTING SECRET KEY ON SERVER:
// cd functions
// firebase functions:config:set stripe.secret_key="sk_live_51L...Noe"
// firebase deploy --only functions
let stripe = require("stripe")(functions.config().stripe.secret_key);
exports.createPaymentIntent = functions
.https.onCall((data, context) => {
// if (!context.auth) {
// return { "access": false };
// }
return new Promise(function (resolve, reject) {
stripe.paymentIntents.create({
amount: data.amount,
currency: data.currency,
receipt_email: decodeURIComponent(data.receipt_email),
metadata: data.metadata,
}, function (err, paymentIntent) {
if (err != null) {
functions.logger.error("Error paymentIntent: ", err);
reject(err);
}
else {
resolve({
clientSecret: paymentIntent.client_secret,
paymentIntentData: paymentIntent,
});
}
});
});
});

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 Export data getting from FaceBook to CSV file using Flutter

I have the below screen which contains user info and have a button Export CSV:
All I need when click Export CSV just export a file as the below format:
This is the CSV Controller file:
import 'package:csv/csv.dart';
import 'dart:io' as Io;
import 'package:path_provider/path_provider.dart';
import 'package:intl/intl.dart';
import 'package:simpleappauth/general.dart';
class CsvController {
static Future<Io.File> getCsvFromList(List<List<dynamic>> csvDataList) async {
try {
String csvDataString = const ListToCsvConverter().convert(csvDataList);
Io.File csvFile = await _saveFile(csvDataString);
return csvFile;
} catch (e) {
print(e.toString());
return null;
}
}
static Future<Io.File> getCsvFromString(String csvString) async {
try {
Io.File csvFile = await _saveFile(csvString);
return csvFile;
} catch (e) {
print(e.toString());
return null;
}
}
static Future<String> _getFilePath(String fileName) async {
Io.Directory appDocumentsDirectory = await getExternalStorageDirectory(); // 1
String appDocumentsPath = appDocumentsDirectory.path; // 2
String filePath = '$appDocumentsPath/$fileName.csv'; // 3
return filePath;
}
final DateFormat formatter = DateFormat('yyyy-MM-dd');
static Future<Io.File> _saveFile(String fileDataString, {index = 0}) async {
try {
Io.File file = Io.File(await _getFilePath(
"${DateTime.now().millisecondsSinceEpoch}" +
(index > 0 ? "($index)" : "")));
if (!file.existsSync()) {
// 1
file.writeAsStringSync(fileDataString); // 2
return file;
} else {
return _saveFile(fileDataString, index: index + 1);
}
} catch (e) {
print(e.toString());
return null;
}
}
}
and this is the below main.dart:
import 'package:flutter/material.dart';
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as JSON;
import 'dart:io';
import 'package:simpleappauth/csv_controller.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
bool _isLoggedIn = false;
Map userProfile;
final facebookLogin = FacebookLogin();
_loginWithFB() async {
final result = await facebookLogin.logIn(['email']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
final token = result.accessToken.token;
final graphResponse = await http.get(Uri.parse(
'https://graph.facebook.com/v10.0/me?fields=id,name,picture,email,name_format,birthday,hometown&access_token=${token}'));
final profile = JSON.jsonDecode(graphResponse.body);
print(profile);
setState(() {
userProfile = profile;
_isLoggedIn = true;
});
break;
case FacebookLoginStatus.cancelledByUser:
setState(() => _isLoggedIn = false);
break;
case FacebookLoginStatus.error:
setState(() => _isLoggedIn = false);
break;
}
}
_logout() {
facebookLogin.logOut();
setState(() {
_isLoggedIn = false;
});
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
body: Center(
child: _isLoggedIn
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.network(
userProfile["picture"]["data"]["url"],
height: 100.0,
width: 100.0,
),
Text(userProfile["id"]),
Text(userProfile["name"]),
Text(userProfile["email"]),
Text(userProfile["name_format"]),
Text(userProfile["birthday"] ?? 'Birthday: empty'),
Text(userProfile["hometown"] ?? 'Hometown: empty'),
OutlinedButton(
child: Text("Logout"),
onPressed: () {
_logout();
},
),
OutlinedButton(
child: Text("Export CSV"),
onPressed: () {
},
),
],
)
: Center(
child: OutlinedButton(
child: Text("Login with Facebook"),
onPressed: () {
_loginWithFB();
},
),
)),
),
);
}
}
So now I want to use the CSV controller file in the main class as to export the csv file which contains the user data.
Step 1: Just add these two functions in your Csvcontroller class
static List<List<dynamic>> getCsvListFromUserProfilesMap(
List<Map<String, dynamic>> userProfiles) {
List<List<dynamic>> csvDataRows = [];
List<dynamic> headerRow = ["id", "name", "email", "hometown"];
csvDataRows.add(headerRow);
userProfiles.forEach((userProfile) {
List<dynamic> dataRow = [
userProfile["id"],
userProfile["name"],
userProfile["email"],
userProfile["hometown"] ?? 'Hometown: empty'
];
csvDataRows.add(dataRow);
});
return csvDataRows;
}
static List<List<dynamic>> getCsvListFromUserProfileMap(
Map<String, dynamic> userProfile) {
List<List<dynamic>> csvDataRows = [];
List<dynamic> headerRow = ["id", "name", "email", "hometown"];
csvDataRows.add(headerRow);
List<dynamic> dataRow = [
userProfile["id"],
userProfile["name"],
userProfile["email"],
userProfile["hometown"] ?? 'Hometown: empty'
];
csvDataRows.add(dataRow);
return csvDataRows;
}
Step 2: Just add the following code to your export CSV button.
//don't forget to import the CsvController file in the main
For example or testing purpose,
//Initialize these variables in your code
var userProfile = [
{
"id": 123,
"name": "User 1",
"email": "user1#gmail.com",
"homeTown": "city1"
},
];
var userProfiles = [
{
"id": 123,
"name": "User 1",
"email": "user1#gmail.com",
"homeTown": "city1"
},
{
"id": 1234,
"name": "User 2",
"email": "user2#gmail.com",
"homeTown": "city2"
},
];
onPressed: () {
//if you just want to export only one profile
var userCsvData = CsvController.getCsvListFromUserProfileMap(userProfile);
var csvFile = await CsvController.getCsvFromList(userCsvData);
if(csvFile != null){
print("File created here :"+csvFile.path);
}else{
print("file not created");
}
//if you just want to export only multiple profiles
var userCsvData = CsvController.getCsvListFromUserProfilesMap(userProfiles);
var csvFile = await CsvController.getCsvFromList(userCsvData);
if(csvFile != null){
print("File created here :"+csvFile.path);
}else{
print("file not created");
}
},

Flutter await for try catch [duplicate]

This question already has answers here:
How to Async/await in List.forEach() in Dart
(7 answers)
Closed 2 years ago.
I'm using firebase cloud firestore
inside a Future function I have this
try {
categories.forEach((element) async {
await FirebaseFirestore.instance.collection('Categories').add({
'name': element[0],
'imageUrl': element[1],
});
print('done');
});
print('complete');
} catch (e) {
CoolAlert.show(
context: context,
type: CoolAlertType.error,
content: Text(e),
text: "Upload Failed",
onConfirmBtnTap: () {
Navigator.pop(context);
Navigator.pop(context);
});
}
'completed' printed before 'done'
how to make it the opposite?
how to await for the forEach function to end first then proceed
and even if I moved print('complete'); after the whole try catch block it doesn't work either
so is there a way to wait try catch block?
You can use Future.foreach OR Future.doWhile
Future.doWhile :
int index = 0;
try {
Future.doWhile(() {
if (index < categories.length) {
await FirebaseFirestore.instance.collection('Categories').add({
'name': categories[index][0],
'imageUrl': categories[index][1],
});
print('done');
index++;
return true;
} else {
print('complete');
return false;
}
});
} catch (e) {
CoolAlert.show(
context: context,
type: CoolAlertType.error,
content: Text(e),
text: "Upload Failed",
onConfirmBtnTap: () {
Navigator.pop(context);
Navigator.pop(context);
});
}
Future.foreach:
try {
Future.forEach(categories,(element) async {
await FirebaseFirestore.instance.collection('Categories').add({
'name': element[0],
'imageUrl': element[1],
});
print('done');
});
print('complete');
} catch (e) {
CoolAlert.show(
context: context,
type: CoolAlertType.error,
content: Text(e),
text: "Upload Failed",
onConfirmBtnTap: () {
Navigator.pop(context);
Navigator.pop(context);
});
}