Commit 3103d00c authored by Inomjon's avatar Inomjon

update chiqarish

parent 7831c56e
This diff is collapsed.
import 'dart:async';
import 'dart:convert';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:universal_io/io.dart';
import 'package:uuid/uuid.dart';
import 'package:connectycube_sdk/connectycube_sdk.dart';
import '../utils/consts.dart';
import '../utils/platform_utils.dart';
import '../utils/pref_util.dart';
class PushNotificationsManager {
static const TAG = "PushNotificationsManager";
static final PushNotificationsManager _instance =
PushNotificationsManager._internal();
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
PushNotificationsManager._internal() {
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
}
BuildContext? applicationContext;
static PushNotificationsManager get instance => _instance;
Future<dynamic> Function(String? payload)? onNotificationClicked;
init() async {
log('[init]', TAG);
FirebaseMessaging firebaseMessaging = FirebaseMessaging.instance;
await firebaseMessaging.requestPermission(
alert: true, badge: true, sound: true);
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('ic_launcher_foreground');
final DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestSoundPermission: true,
requestBadgePermission: true,
requestAlertPermission: true,
onDidReceiveLocalNotification: onDidReceiveLocalNotification,
);
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: DarwinInitializationSettings());
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) {
log('[onDidReceiveNotificationResponse] payload: ${notificationResponse.payload}',
TAG);
var data = notificationResponse.payload;
if (data != null) {
if (onNotificationClicked != null) {
onNotificationClicked?.call(data);
} else {
String? dialogId = jsonDecode(data)['dialog_id'];
SharedPrefs.instance.saveSelectedDialogId(dialogId ?? '');
}
}
},
onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
);
String? token;
if (Platform.isAndroid || kIsWeb || Platform.isIOS || Platform.isMacOS) {
firebaseMessaging.getToken().then((token) {
log('[getToken] token: $token', TAG);
subscribe(token);
}).catchError((onError) {
log('[getToken] onError: $onError', TAG);
});
}
if (!isEmpty(token)) {
subscribe(token);
}
firebaseMessaging.onTokenRefresh.listen((newToken) {
subscribe(newToken);
});
FirebaseMessaging.onMessage.listen((remoteMessage) {
log('[onMessage] message: ${remoteMessage.data}', TAG);
showNotification(remoteMessage);
});
// TODO test after fix https://github.com/FirebaseExtended/flutterfire/issues/4898
FirebaseMessaging.onMessageOpenedApp.listen((remoteMessage) {
log('[onMessageOpenedApp] remoteMessage: $remoteMessage', TAG);
onNotificationClicked?.call(jsonEncode(remoteMessage.data));
});
}
subscribe(String? token) async {
log('[subscribe] token: $token', PushNotificationsManager.TAG);
SharedPrefs sharedPrefs = await SharedPrefs.instance.init();
if (sharedPrefs.getSubscriptionToken() == token) {
log('[subscribe] skip subscription for same token',
PushNotificationsManager.TAG);
return;
}
CreateSubscriptionParameters parameters = CreateSubscriptionParameters();
parameters.pushToken = token;
bool isProduction = kIsWeb ? true : bool.fromEnvironment('dart.vm.product');
parameters.environment =
isProduction ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;
if (Platform.isAndroid || kIsWeb || Platform.isIOS || Platform.isMacOS) {
parameters.channel = NotificationsChannels.GCM;
parameters.platform = CubePlatform.ANDROID;
}
var deviceInfoPlugin = DeviceInfoPlugin();
var deviceId;
if (kIsWeb) {
var webBrowserInfo = await deviceInfoPlugin.webBrowserInfo;
deviceId = base64Encode(utf8.encode(webBrowserInfo.userAgent ?? ''));
} else if (Platform.isAndroid) {
var androidInfo = await deviceInfoPlugin.androidInfo;
deviceId = androidInfo.id;
} else if (Platform.isIOS) {
var iosInfo = await deviceInfoPlugin.iosInfo;
deviceId = iosInfo.identifierForVendor;
} else if (Platform.isMacOS) {
var macOsInfo = await deviceInfoPlugin.macOsInfo;
deviceId = macOsInfo.computerName;
}
parameters.udid = deviceId ?? Uuid().v4;
var packageInfo = await PackageInfo.fromPlatform();
parameters.bundleIdentifier = packageInfo.packageName;
createSubscription(parameters.getRequestParameters())
.then((cubeSubscription) {
log('[subscribe] subscription SUCCESS', PushNotificationsManager.TAG);
sharedPrefs.saveSubscriptionToken(token!);
cubeSubscription.forEach((subscription) {
if (subscription.clientIdentificationSequence == token) {
sharedPrefs.saveSubscriptionId(subscription.id!);
}
});
}).catchError((error) {
log('[subscribe] subscription ERROR: $error',
PushNotificationsManager.TAG);
});
}
Future<void> unsubscribe() {
return SharedPrefs.instance.init().then((sharedPrefs) {
int subscriptionId = sharedPrefs.getSubscriptionId();
if (subscriptionId != 0) {
return deleteSubscription(subscriptionId).then((voidResult) {
FirebaseMessaging.instance.deleteToken();
sharedPrefs.saveSubscriptionId(0);
});
}
return Future.value();
}).catchError((onError) {
log('[unsubscribe] ERROR: $onError', PushNotificationsManager.TAG);
});
}
Future<dynamic> onDidReceiveLocalNotification(
int id, String? title, String? body, String? payload) {
log('[onDidReceiveLocalNotification] id: $id , title: $title, body: $body, payload: $payload',
PushNotificationsManager.TAG);
return Future.value();
}
Future<dynamic> onSelectNotification(String? payload) {
log('[onSelectNotification] payload: $payload',
PushNotificationsManager.TAG);
onNotificationClicked?.call(payload);
return Future.value();
}
}
showNotification(RemoteMessage message) {
log('[showNotification] message: ${message.data}',
PushNotificationsManager.TAG);
Map<String, dynamic> data = message.data;
NotificationDetails buildNotificationDetails(
int? badge,
String threadIdentifier,
) {
final DarwinNotificationDetails darwinNotificationDetails =
DarwinNotificationDetails(
badgeNumber: badge,
threadIdentifier: threadIdentifier,
);
final AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'messages_channel_id',
'Chat messages',
channelDescription: 'Chat messages will be received here',
importance: Importance.max,
priority: Priority.high,
showWhen: true,
color: Colors.green,
);
return NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: darwinNotificationDetails,
macOS: darwinNotificationDetails);
}
var badge = int.tryParse(data['badge'].toString());
var threadId = data['ios_thread_id'] ?? data['dialog_id'] ?? 'ios_thread_id';
FlutterLocalNotificationsPlugin().show(
6543,
"Chat sample",
data['message'].toString(),
buildNotificationDetails(badge, threadId),
payload: jsonEncode(data),
);
}
@pragma('vm:entry-point')
Future<void> onBackgroundMessage(RemoteMessage message) async {
log('[onBackgroundMessage] message: ${message.data}',
PushNotificationsManager.TAG);
showNotification(message);
if(!Platform.isIOS) {
updateBadgeCount(int.tryParse(message.data['badge'].toString()));
}
return Future.value();
}
Future<dynamic> onNotificationSelected(String? payload, BuildContext? context) {
log('[onSelectNotification] payload: $payload', PushNotificationsManager.TAG);
if (context == null) return Future.value();
log('[onSelectNotification] context != null', PushNotificationsManager.TAG);
if (payload != null) {
return SharedPrefs.instance.init().then((sharedPrefs) {
CubeUser? user = sharedPrefs.getUser();
Map<String, dynamic> payloadObject = jsonDecode(payload);
String? dialogId = payloadObject['dialog_id'];
log("[onSelectNotification] dialog_id: $dialogId",
PushNotificationsManager.TAG);
getDialogs({'id': dialogId}).then((dialogs) {
if (dialogs?.items != null && dialogs!.items.isNotEmpty) {
CubeDialog dialog = dialogs.items.first;
Navigator.pushNamed(context, 'chat_dialog',
arguments: {USER_ARG_NAME: user, DIALOG_ARG_NAME: dialog});
}
});
});
} else {
return Future.value();
}
}
@pragma('vm:entry-point')
void notificationTapBackground(NotificationResponse notificationResponse) {
log('[notificationTapBackground] payload: ${notificationResponse.payload}');
}
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';
import 'package:universal_io/io.dart';
import 'package:connectycube_sdk/connectycube_sdk.dart';
import 'utils/consts.dart';
import 'utils/pref_util.dart';
import 'utils/route_utils.dart';
const String PHONE_INPUT_ROUTE_NAME = 'PhoneInputScreen';
const String SMS_CODE_INPUT_ROUTE_NAME = 'SMSCodeInputScreen';
class VerifyPhoneNumber extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Navigator(
observers: [PhoneAuthRouteObserver(context)],
key: Navigation.verifyPhoneNavigation,
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder(
reverseTransitionDuration:
Duration(milliseconds: Platform.isIOS ? 1000 : 300),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween =
Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
settings: RouteSettings(name: PHONE_INPUT_ROUTE_NAME),
pageBuilder: (context, animation, secondaryAnimation) =>
PhoneInputScreen(
actions: [
SMSCodeRequestedAction((ctx1, action, flowKey, phoneNumber) {
Navigator.of(context).push(
MaterialPageRoute(
settings: RouteSettings(name: SMS_CODE_INPUT_ROUTE_NAME),
builder: (ctx2) => SMSCodeInputScreen(
flowKey: flowKey,
actions: [
AuthStateChangeAction<SignedIn>((ctx3, state) {
log('[AuthStateChangeAction] SignedIn');
state.user?.getIdToken().then((idToken) {
SharedPrefs.instance.saveLoginType(LoginType.phone);
Navigator.of(ctx3, rootNavigator: true)
.pushNamedAndRemoveUntil(
'login', (route) => false);
});
}),
AuthStateChangeAction<CredentialLinked>((ctx3, state) {
log('[AuthStateChangeAction] CredentialLinked');
state.user.getIdToken().then((idToken) {
SharedPrefs.instance.saveLoginType(LoginType.phone);
Navigator.of(ctx3, rootNavigator: true)
.pushNamedAndRemoveUntil(
'login', (route) => false);
});
}),
AuthStateChangeAction<Uninitialized>((ctx3, state) {
log('[AuthStateChangeAction] Uninitialized');
}),
AuthStateChangeAction<CredentialReceived>(
(ctx3, state) {
log('[AuthStateChangeAction] CredentialReceived');
}),
AuthStateChangeAction<AuthFailed>((ctx3, state) {
log('[AuthStateChangeAction] AuthFailed');
}),
AuthStateChangeAction<UserCreated>((ctx3, state) {
log('[AuthStateChangeAction] UserCreated');
state.credential.user?.getIdToken().then((idToken) {
SharedPrefs.instance.saveLoginType(LoginType.phone);
Navigator.of(ctx3, rootNavigator: true)
.pushNamedAndRemoveUntil(
'login', (route) => false);
});
}),
],
),
),
);
}),
],
),
);
},
);
}
}
class PhoneAuthRouteObserver extends RouteObserver {
final BuildContext context;
PhoneAuthRouteObserver(this.context);
@override
void didPop(Route route, Route? previousRoute) {
super.didPop(route, previousRoute);
if (route.settings.name == PHONE_INPUT_ROUTE_NAME) {
Navigator.of(context, rootNavigator: true).pop();
}
}
}
......@@ -7,13 +7,13 @@ import 'package:vmeeting/service/routes/routes_name.dart';
import 'package:vmeeting/src/extension/context_extensions.dart';
import '../app_models/app_users_model/app_users_model.dart';
import '../src/constants/colors_const.dart';
import '../src/managers/push_notifications_manager.dart';
import '../src/utils/app_utils.dart';
import '../src/utils/pref_util.dart';
import '../src/widgets/image_avatar.dart';
import '../src/widgets/textfiled_widgets/auth_text_fild.dart';
import 'managers/push_notifications_manager.dart';
import 'utils/api_utils.dart';
import 'utils/consts.dart';
import 'utils/pref_util.dart';
class SettingsScreen extends StatelessWidget {
final CubeUser currentUser;
......@@ -339,7 +339,7 @@ class _BodyLayoutState extends State<BodyLayout> {
CubeChatConnection.instance.destroy();
PushNotificationsManager.instance.unsubscribe();
FirebaseAuth.instance.currentUser?.unlink(PhoneAuthProvider.PROVIDER_ID);
SharedPrefs.instance.deleteUser();
SharedPrefs.deleteUserData();
Navigator.pop(context); // cancel current screen
_navigateToLoginScreen(context);
});
......@@ -394,7 +394,7 @@ class _BodyLayoutState extends State<BodyLayout> {
}
_navigateToLoginScreen(BuildContext context) {
SharedPrefs.instance.deleteUser();
SharedPrefs.deleteUserData();
Navigator.pushReplacementNamed(context, MainRoutes.sign_in_page);
}
......
import 'dart:async';
import 'dart:collection';
import 'package:connectycube_sdk/connectycube_chat.dart';
import 'package:connectycube_sdk/connectycube_sdk.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:universal_io/io.dart';
import '../managers/push_notifications_manager.dart';
import 'platform_utils.dart';
void showDialogError(exception, context) {
......@@ -16,11 +13,11 @@ void showDialogError(exception, context) {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Error"),
title: const Text("Error"),
content: Text("Something went wrong $exception"),
actions: <Widget>[
TextButton(
child: Text("OK"),
child: const Text("OK"),
onPressed: () => Navigator.of(context).pop(),
)
],
......@@ -33,11 +30,11 @@ void showDialogMsg(msg, context) {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Alert"),
title: const Text("Alert"),
content: Text(msg),
actions: <Widget>[
TextButton(
child: Text("OK"),
child: const Text("OK"),
onPressed: () => Navigator.of(context).pop(),
)
],
......@@ -68,7 +65,6 @@ Future<Map<int, CubeUser>> getUsersByIds(Set<int> ids) async {
Future<CubeFile> getUploadingImageFuture(FilePickerResult result) async {
// there possible to upload the file as an array of bytes, but here showed two ways just as an example
if(kIsWeb){
return uploadRawFile(result.files.single.bytes!, result.files.single.name, isPublic: true, onProgress: (progress) {
log("uploadImageFile progress= $progress");
......
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:connectycube_sdk/connectycube_chat.dart';
import 'consts.dart';
const String prefLoginType = "pref_login_type";
const String prefUserLogin = "pref_user_login";
const String prefUserEmail = "pref_user_email";
const String prefUserPhone = "pref_user_phone";
const String prefUserPsw = "pref_user_psw";
const String prefUserName = "pref_user_name";
const String prefUserId = "pref_user_id";
const String prefUserAvatar = "pref_user_avatar";
const String prefSubscriptionToken = "pref_subscription_token";
const String prefSubscriptionId = "pref_subscription_id";
const String prefSelectedDialogId = "pref_selected_dialog_id";
class SharedPrefs {
static final SharedPrefs _instance = SharedPrefs._internal();
late SharedPreferences prefs;
SharedPrefs._internal();
bool inited = false;
static SharedPrefs get instance => _instance;
Future<SharedPrefs> init() async {
Completer<SharedPrefs> completer = Completer();
if (inited) {
completer.complete(_instance);
} else {
prefs = await SharedPreferences.getInstance();
inited = true;
completer.complete(_instance);
}
return completer.future;
}
saveNewUser(CubeUser cubeUser, LoginType loginType) {
prefs.clear();
prefs.setString(prefLoginType, describeEnum(loginType));
if (cubeUser.login != null) prefs.setString(prefUserLogin, cubeUser.login!);
if (cubeUser.email != null) prefs.setString(prefUserEmail, cubeUser.email!);
if (cubeUser.phone != null) prefs.setString(prefUserPhone, cubeUser.phone!);
if (cubeUser.password != null)
prefs.setString(prefUserPsw, cubeUser.password!);
if (cubeUser.fullName != null)
prefs.setString(prefUserName, cubeUser.fullName!);
prefs.setInt(prefUserId, cubeUser.id!);
if (cubeUser.avatar != null)
prefs.setString(prefUserAvatar, cubeUser.avatar!);
}
updateUser(CubeUser cubeUser) {
if (cubeUser.password != null)
prefs.setString(prefUserPsw, cubeUser.password!);
if (cubeUser.login != null) prefs.setString(prefUserLogin, cubeUser.login!);
if (cubeUser.email != null) prefs.setString(prefUserEmail, cubeUser.email!);
if (cubeUser.phone != null) prefs.setString(prefUserPhone, cubeUser.phone!);
if (cubeUser.fullName != null)
prefs.setString(prefUserName, cubeUser.fullName!);
if (cubeUser.avatar != null)
prefs.setString(prefUserAvatar, cubeUser.avatar!);
}
CubeUser? getUser() {
if (prefs.getString(prefUserLogin) == null &&
prefs.getString(prefUserEmail) == null) return null;
var user = CubeUser();
user.login = prefs.getString(prefUserLogin);
user.email = prefs.getString(prefUserEmail);
user.phone = prefs.getString(prefUserPhone);
user.password = prefs.getString(prefUserPsw);
user.fullName = prefs.getString(prefUserName);
user.id = prefs.getInt(prefUserId);
user.avatar = prefs.getString(prefUserAvatar);
return user;
}
LoginType? getLoginType() {
var savedLoginType = prefs.getString(prefLoginType);
if (savedLoginType == null) return null;
var loginType = LoginType.values
.firstWhereOrNull((e) => describeEnum(e) == savedLoginType);
return loginType;
}
saveLoginType(LoginType loginType) {
prefs.setString(prefLoginType, describeEnum(loginType));
}
Future<bool> deleteUser() {
return prefs.clear();
}
saveSubscriptionToken(String token) {
prefs.setString(prefSubscriptionToken, token);
}
String getSubscriptionToken() {
return prefs.getString(prefSubscriptionToken) ?? "";
}
saveSubscriptionId(int id) {
prefs.setInt(prefSubscriptionId, id);
}
int getSubscriptionId() {
return prefs.getInt(prefSubscriptionId) ?? 0;
}
saveSelectedDialogId(String dialogId) {
prefs.setString(prefSelectedDialogId, dialogId);
}
String? getSelectedDialogId() {
return prefs.getString(prefSelectedDialogId);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment