WT 1.1.20 Training Plan improvements, InApp Messageing
This commit is contained in:
+128
-23
@@ -1,15 +1,20 @@
|
||||
import 'dart:math' as math;
|
||||
import 'dart:convert';
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart' as logging;
|
||||
import 'package:apple_sign_in/apple_sign_in.dart';
|
||||
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||
import 'package:awesome_notifications/awesome_notifications.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:firebase_remote_config/firebase_remote_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
|
||||
import 'package:google_sign_in/google_sign_in.dart';
|
||||
|
||||
class FirebaseApi with logging.Logging {
|
||||
bool appleSignInAvailable = false;
|
||||
//late FirebaseApi _instance;
|
||||
|
||||
static final FirebaseAuth auth = FirebaseAuth.instance;
|
||||
|
||||
@@ -29,15 +34,69 @@ class FirebaseApi with logging.Logging {
|
||||
Future<void> initializeFlutterFire() async {
|
||||
try {
|
||||
// Wait for Firebase to initialize and set `_initialized` state to true
|
||||
FirebaseApp app = await Firebase.initializeApp();
|
||||
await Firebase.initializeApp();
|
||||
|
||||
this.appleSignInAvailable = await AppleSignIn.isAvailable();
|
||||
this.appleSignInAvailable = await SignInWithApple.isAvailable();
|
||||
AwesomeNotifications().initialize(
|
||||
// set the icon to null if you want to use the default app icon
|
||||
null,
|
||||
[
|
||||
NotificationChannel(
|
||||
channelKey: 'basic_channel',
|
||||
channelName: 'Basic notifications',
|
||||
channelDescription: 'Notification channel for basic tests',
|
||||
defaultColor: Color(0xFF9D50DD),
|
||||
ledColor: Colors.white)
|
||||
]);
|
||||
|
||||
AwesomeNotifications().isNotificationAllowed().then((isAllowed) {
|
||||
if (!isAllowed) {
|
||||
// Insert here your friendly dialog box before call the request method
|
||||
// This is very important to not harm the user experience
|
||||
AwesomeNotifications().requestPermissionToSendNotifications();
|
||||
}
|
||||
});
|
||||
|
||||
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
|
||||
alert: true, // Required to display a heads up notification
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
String? token = await FirebaseMessaging.instance.getToken();
|
||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||
log("FirebaseMessaging token $token");
|
||||
} catch (e) {
|
||||
// Set `_error` state to true if Firebase initialization fails
|
||||
log("Error initializing Firebase");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
print('Handling a background message: ${message.messageId}');
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) ||
|
||||
!StringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)) {
|
||||
print('message also contained a notification: ${message.notification}');
|
||||
|
||||
String? imageUrl;
|
||||
imageUrl ??= message.notification!.android?.imageUrl;
|
||||
imageUrl ??= message.notification!.apple?.imageUrl;
|
||||
|
||||
Map<String, dynamic> notificationAdapter = {
|
||||
NOTIFICATION_CHANNEL_KEY: 'basic_channel',
|
||||
NOTIFICATION_ID: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_ID] ?? message.messageId ?? math.Random().nextInt(2147483647),
|
||||
NOTIFICATION_TITLE: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_TITLE] ?? message.notification?.title,
|
||||
NOTIFICATION_BODY: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_BODY] ?? message.notification?.body,
|
||||
NOTIFICATION_LAYOUT: StringUtils.isNullOrEmpty(imageUrl) ? 'Default' : 'BigPicture',
|
||||
NOTIFICATION_BIG_PICTURE: imageUrl
|
||||
};
|
||||
|
||||
AwesomeNotifications().createNotificationFromJsonData(notificationAdapter);
|
||||
} else {
|
||||
AwesomeNotifications().createNotificationFromJsonData(message.data);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> signInEmail(String? email, String? password) async {
|
||||
if (email == null) {
|
||||
throw Exception("Please type an email address");
|
||||
@@ -85,20 +144,33 @@ class FirebaseApi with logging.Logging {
|
||||
return rc;
|
||||
}
|
||||
|
||||
String generateNonce([int length = 32]) {
|
||||
final charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
|
||||
final random = math.Random.secure();
|
||||
return List.generate(length, (_) => charset[random.nextInt(charset.length)]).join();
|
||||
}
|
||||
|
||||
/// Returns the sha256 hash of [input] in hex notation.
|
||||
String sha256ofString(String input) {
|
||||
final bytes = utf8.encode(input);
|
||||
final digest = sha256.convert(bytes);
|
||||
return digest.toString();
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> signInWithApple() async {
|
||||
Map<String, dynamic> userData = Map();
|
||||
|
||||
final AuthorizationResult result = await AppleSignIn.performRequests([
|
||||
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
|
||||
/* final apple.AuthorizationResult result = await SignInWithApple.performRequests([
|
||||
apple.AppleIdRequest(requestedScopes: [apple.Scope.email, apple.Scope.fullName])
|
||||
]);
|
||||
switch (result.status) {
|
||||
case AuthorizationStatus.authorized:
|
||||
case apple.AuthorizationStatus.authorized:
|
||||
print('User authorized');
|
||||
break;
|
||||
case AuthorizationStatus.error:
|
||||
case apple.AuthorizationStatus.error:
|
||||
print('User error');
|
||||
throw Exception("Apple Sign-In failed");
|
||||
case AuthorizationStatus.cancelled:
|
||||
case apple.AuthorizationStatus.cancelled:
|
||||
print('User cancelled');
|
||||
throw Exception("Apple Sign-In cancelled");
|
||||
}
|
||||
@@ -106,20 +178,36 @@ class FirebaseApi with logging.Logging {
|
||||
// Create an `OAuthCredential` from the credential returned by Apple.
|
||||
final oauthCredential = OAuthProvider("apple.com").credential(
|
||||
idToken: String.fromCharCodes(result.credential.identityToken),
|
||||
accessToken: String.fromCharCodes(result.credential.authorizationCode));
|
||||
accessToken: String.fromCharCodes(result.credential.authorizationCode!));
|
||||
*/
|
||||
// To prevent replay attacks with the credential returned from Apple, we
|
||||
// include a nonce in the credential request. When signing in with
|
||||
// Firebase, the nonce in the id token returned by Apple, is expected to
|
||||
// match the sha256 hash of `rawNonce`.
|
||||
final rawNonce = generateNonce();
|
||||
final nonce = sha256ofString(rawNonce);
|
||||
|
||||
// Request credential for the currently signed in Apple account.
|
||||
final appleCredential = await SignInWithApple.getAppleIDCredential(
|
||||
scopes: [
|
||||
AppleIDAuthorizationScopes.email,
|
||||
AppleIDAuthorizationScopes.fullName,
|
||||
],
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
// Create an `OAuthCredential` from the credential returned by Apple.
|
||||
final oauthCredential = OAuthProvider("apple.com").credential(
|
||||
idToken: appleCredential.identityToken,
|
||||
rawNonce: rawNonce,
|
||||
);
|
||||
// Sign in the user with Firebase. If the nonce we generated earlier does
|
||||
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
|
||||
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
|
||||
Cache().firebaseUid = userCredential.user!.uid;
|
||||
log("userCredential: " + userCredential.toString());
|
||||
|
||||
log("Apple Credentials: " +
|
||||
result.credential.user.toString() +
|
||||
" state " +
|
||||
result.credential.state.toString() +
|
||||
" email " +
|
||||
userCredential.user!.email!);
|
||||
log("Apple Credentials: ${appleCredential.userIdentifier} state ${appleCredential.state} email ${userCredential.user!.email!}");
|
||||
userData['email'] = userCredential.user!.email;
|
||||
|
||||
return userData;
|
||||
@@ -127,26 +215,43 @@ class FirebaseApi with logging.Logging {
|
||||
|
||||
Future<Map<String, dynamic>> registerWithApple() async {
|
||||
Map<String, dynamic> userData = Map();
|
||||
final AuthorizationResult result = await AppleSignIn.performRequests([
|
||||
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
|
||||
/* final apple.AuthorizationResult result = await apple.TheAppleSignIn.performRequests([
|
||||
apple.AppleIdRequest(requestedScopes: [apple.Scope.email, apple.Scope.fullName])
|
||||
]);
|
||||
switch (result.status) {
|
||||
case AuthorizationStatus.authorized:
|
||||
case apple.AuthorizationStatus.authorized:
|
||||
print('Apple User authorized');
|
||||
break;
|
||||
case AuthorizationStatus.error:
|
||||
case apple.AuthorizationStatus.error:
|
||||
print('Apple User error');
|
||||
throw Exception("Apple Sign-In failed");
|
||||
case AuthorizationStatus.cancelled:
|
||||
case apple.AuthorizationStatus.cancelled:
|
||||
print('User cancelled');
|
||||
throw Exception("Apple Sign-In cancelled");
|
||||
}
|
||||
*/
|
||||
final rawNonce = generateNonce();
|
||||
final nonce = sha256ofString(rawNonce);
|
||||
|
||||
// Create an `OAuthCredential` from the credential returned by Apple.
|
||||
// Request credential for the currently signed in Apple account.
|
||||
final appleCredential = await SignInWithApple.getAppleIDCredential(
|
||||
scopes: [
|
||||
AppleIDAuthorizationScopes.email,
|
||||
AppleIDAuthorizationScopes.fullName,
|
||||
],
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
final oauthCredential = OAuthProvider("apple.com").credential(
|
||||
idToken: appleCredential.identityToken,
|
||||
rawNonce: rawNonce,
|
||||
);
|
||||
|
||||
/* // Create an `OAuthCredential` from the credential returned by Apple.
|
||||
final oauthCredential = OAuthProvider("apple.com").credential(
|
||||
idToken: String.fromCharCodes(result.credential.identityToken),
|
||||
accessToken: String.fromCharCodes(result.credential.authorizationCode));
|
||||
|
||||
*/
|
||||
// Sign in the user with Firebase. If the nonce we generated earlier does
|
||||
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
|
||||
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
|
||||
|
||||
@@ -19,7 +19,9 @@ import 'package:aitrainer_app/model/property.dart';
|
||||
import 'package:aitrainer_app/model/purchase.dart';
|
||||
import 'package:aitrainer_app/model/split_test.dart';
|
||||
import 'package:aitrainer_app/model/training_plan.dart';
|
||||
import 'package:aitrainer_app/model/training_plan_day.dart';
|
||||
import 'package:aitrainer_app/model/tutorial.dart';
|
||||
import 'package:aitrainer_app/repository/training_plan_day_repository.dart';
|
||||
import 'package:aitrainer_app/service/api.dart';
|
||||
import 'package:aitrainer_app/service/exercise_type_service.dart';
|
||||
import 'package:aitrainer_app/util/not_found_exception.dart';
|
||||
@@ -105,6 +107,10 @@ class PackageApi {
|
||||
final List<SplitTest>? tests = json.map((test) => SplitTest.fromJson(test)).toList();
|
||||
//print("A/B tests: $tests");
|
||||
Cache().setSplitTests(tests);
|
||||
} else if (headRecord[0] == "TrainingPlanDay") {
|
||||
final Iterable json = jsonDecode(headRecord[1]);
|
||||
final List<TrainingPlanDay>? days = json.map((day) => TrainingPlanDay.fromJson(day)).toList();
|
||||
Cache().setTrainingPlanDays(days);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -114,9 +120,11 @@ class PackageApi {
|
||||
ExerciseTree tree = element as ExerciseTree;
|
||||
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
|
||||
});
|
||||
//print("tree: $exerciseTree");
|
||||
Cache().setExerciseTree(exerciseTree);
|
||||
|
||||
TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository();
|
||||
trainingPlanDayRepository.assignTrainingPlanDays();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user