diff --git a/i18n/en.json b/i18n/en.json index e549413..4ce1721 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -330,7 +330,7 @@ "Progressindicator for the tests":"Where do you stand achieving your tests?", "Progressindicator_desc":"

It shows which muscle group test did your achieved already.

When do you reach the 100% test round?


If you have sucessfully tested one of the base exercises of each muscle group

", - "Unleash Your Development Now!":"Unleash Your Development Now!", + "Unleash Your Development Now!":"Commit To Your Development", "Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts.":"Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts.", "Subscription Conditions":"Subscription Conditions", "Payment will be charged to your account. Subscription automatically renews unless auto-renew is turned off at least 24 hours before the end of the current period":"Payment will be charged to your account. Subscription automatically renews unless auto-renew is turned off at least 24 hours before the end of the current period", @@ -471,6 +471,13 @@ "Please take a short tour in the app":"Please take a short tour in the app", "No Login":"No Login", "You will skip the login.":"You will skip the login.", - "The app functionalitity will be restricted, but please take a tour!":"The app functionalitity will be restricted, but please take a tour!" + "The app functionalitity will be restricted, but please take a tour!":"The app functionalitity will be restricted, but please take a tour!", + + "Activating the basic tutorial":"Activating the basic tutorial", + "Basic Tutorial":"Basic Tutorial", + "Activate":"Activate", + + "Try free for 3 days!":"Try it without risk for 3 days! In this period you can cancel any time without lasting your account.", + "View other alternatives":"View other alternatives" } \ No newline at end of file diff --git a/i18n/hu.json b/i18n/hu.json index 52f8310..409279b 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -463,5 +463,12 @@ "Please take a short tour in the app":"Kérlek tégy egy rövid túrát az applikációban", "No Login":"Bejelentkezés kimaradt", "You will skip the login.":"Átugrod a bejelentkezést.", - "The app functionalitity will be restricted, but please take a tour!":"Az applikációt korlátozottan tudod így használni, de tégy egy túrát!" + "The app functionalitity will be restricted, but please take a tour!":"Az applikációt korlátozottan tudod így használni, de tégy egy túrát!", + + "Activating the basic tutorial":"Bemutató aktiválása", + "Basic Tutorial":"Alap bemutató", + "Activate":"Aktivál", + + "Try free for 3 days!":"Próbáld ki kockázat nélkül 3 napig! Ebben az időszakban bármikor lemondhatod, anélkül, hogy megterhelnénk a számládat.", + "View other alternatives":"Megnézek egy másik lehetőséget" } \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 47f524b..8e3f912 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -18,74 +18,108 @@ PODS: - FBSDKLoginKit/Login (= 9.1.0) - FBSDKLoginKit/Login (9.1.0): - FBSDKCoreKit (~> 9.1.0) - - Firebase/Analytics (7.3.0): + - Firebase/Analytics (7.11.0): - Firebase/Core - - Firebase/Auth (7.3.0): + - Firebase/Auth (7.11.0): - Firebase/CoreOnly - - FirebaseAuth (~> 7.3.0) - - Firebase/Core (7.3.0): + - FirebaseAuth (~> 7.11.0) + - Firebase/Core (7.11.0): - Firebase/CoreOnly - - FirebaseAnalytics (= 7.3.0) - - Firebase/CoreOnly (7.3.0): - - FirebaseCore (= 7.3.0) - - Firebase/Messaging (7.3.0): + - FirebaseAnalytics (~> 7.11.0) + - Firebase/CoreOnly (7.11.0): + - FirebaseCore (= 7.11.0) + - Firebase/Messaging (7.11.0): - Firebase/CoreOnly - - FirebaseMessaging (~> 7.3.0) - - firebase_analytics (8.0.0-dev.2): - - Firebase/Analytics (= 7.3.0) + - FirebaseMessaging (~> 7.11.0) + - Firebase/RemoteConfig (7.11.0): + - Firebase/CoreOnly + - FirebaseRemoteConfig (~> 7.11.0) + - firebase_analytics (8.0.2): + - Firebase/Analytics (= 7.11.0) - firebase_core - Flutter - - firebase_auth (1.0.3): - - Firebase/Auth (= 7.3.0) + - firebase_auth (1.1.2): + - Firebase/Auth (= 7.11.0) - firebase_core - Flutter - - firebase_core (1.0.3): - - Firebase/CoreOnly (= 7.3.0) + - firebase_core (1.1.0): + - Firebase/CoreOnly (= 7.11.0) - Flutter - - firebase_messaging (9.1.1): - - Firebase/Messaging (= 7.3.0) + - firebase_messaging (9.1.3): + - Firebase/Messaging (= 7.11.0) - firebase_core - Flutter - - FirebaseAnalytics (7.3.0): + - firebase_remote_config (0.10.0-dev.2): + - Firebase/RemoteConfig (= 7.11.0) + - firebase_core + - Flutter + - FirebaseABTesting (7.11.0): + - FirebaseCore (~> 7.0) + - FirebaseAnalytics (7.11.0): + - FirebaseAnalytics/AdIdSupport (= 7.11.0) - FirebaseCore (~> 7.0) - FirebaseInstallations (~> 7.0) - - GoogleAppMeasurement (= 7.3.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/MethodSwizzler (~> 7.0) - GoogleUtilities/Network (~> 7.0) - "GoogleUtilities/NSData+zlib (~> 7.0)" - - nanopb (~> 2.30906.0) - - FirebaseAuth (7.3.0): + - nanopb (~> 2.30908.0) + - FirebaseAnalytics/AdIdSupport (7.11.0): + - FirebaseAnalytics/Base (= 7.11.0) + - FirebaseCore (~> 7.0) + - FirebaseInstallations (~> 7.0) + - GoogleAppMeasurement/AdIdSupport (= 7.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.0) + - GoogleUtilities/MethodSwizzler (~> 7.0) + - GoogleUtilities/Network (~> 7.0) + - "GoogleUtilities/NSData+zlib (~> 7.0)" + - nanopb (~> 2.30908.0) + - FirebaseAnalytics/Base (7.11.0): + - FirebaseCore (~> 7.0) + - FirebaseInstallations (~> 7.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.0) + - GoogleUtilities/MethodSwizzler (~> 7.0) + - GoogleUtilities/Network (~> 7.0) + - "GoogleUtilities/NSData+zlib (~> 7.0)" + - nanopb (~> 2.30908.0) + - FirebaseAuth (7.11.0): - FirebaseCore (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/Environment (~> 7.0) - GTMSessionFetcher/Core (~> 1.4) - - FirebaseCore (7.3.0): - - FirebaseCoreDiagnostics (~> 7.0) + - FirebaseCore (7.11.0): + - FirebaseCoreDiagnostics (~> 7.4) - GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Logger (~> 7.0) - - FirebaseCoreDiagnostics (7.3.0): - - GoogleDataTransport (~> 8.0) + - FirebaseCoreDiagnostics (7.11.0): + - GoogleDataTransport (~> 8.4) - GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Logger (~> 7.0) - - nanopb (~> 2.30906.0) - - FirebaseInstallations (7.9.0): + - nanopb (~> 2.30908.0) + - FirebaseInstallations (7.11.0): - FirebaseCore (~> 7.0) - GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/UserDefaults (~> 7.0) - PromisesObjC (~> 1.2) - - FirebaseInstanceID (7.9.0): + - FirebaseInstanceID (7.11.0): - FirebaseCore (~> 7.0) - FirebaseInstallations (~> 7.0) - GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/UserDefaults (~> 7.0) - - FirebaseMessaging (7.3.0): + - FirebaseMessaging (7.11.0): - FirebaseCore (~> 7.0) + - FirebaseInstallations (~> 7.0) - FirebaseInstanceID (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/Environment (~> 7.0) - GoogleUtilities/Reachability (~> 7.0) - GoogleUtilities/UserDefaults (~> 7.0) + - FirebaseRemoteConfig (7.11.0): + - FirebaseABTesting (~> 7.0) + - FirebaseCore (~> 7.0) + - FirebaseInstallations (~> 7.0) + - GoogleUtilities/Environment (~> 7.0) + - "GoogleUtilities/NSData+zlib (~> 7.0)" - flurry (0.0.4): - Flurry-iOS-SDK/FlurrySDK - Flutter @@ -110,36 +144,38 @@ PODS: - google_sign_in (0.0.1): - Flutter - GoogleSignIn (~> 5.0) - - GoogleAppMeasurement (7.3.0): + - GoogleAppMeasurement/AdIdSupport (7.11.0): - GoogleUtilities/AppDelegateSwizzler (~> 7.0) - GoogleUtilities/MethodSwizzler (~> 7.0) - GoogleUtilities/Network (~> 7.0) - "GoogleUtilities/NSData+zlib (~> 7.0)" - - nanopb (~> 2.30906.0) - - GoogleDataTransport (8.1.0): - - nanopb (~> 2.30906.0) + - nanopb (~> 2.30908.0) + - GoogleDataTransport (8.4.0): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (~> 1.2) - GoogleSignIn (5.0.2): - AppAuth (~> 1.2) - GTMAppAuth (~> 1.0) - GTMSessionFetcher/Core (~> 1.1) - - GoogleUtilities/AppDelegateSwizzler (7.3.1): + - GoogleUtilities/AppDelegateSwizzler (7.4.0): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (7.3.1): + - GoogleUtilities/Environment (7.4.0): - PromisesObjC (~> 1.2) - - GoogleUtilities/Logger (7.3.1): + - GoogleUtilities/Logger (7.4.0): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.3.1): + - GoogleUtilities/MethodSwizzler (7.4.0): - GoogleUtilities/Logger - - GoogleUtilities/Network (7.3.1): + - GoogleUtilities/Network (7.4.0): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.3.1)" - - GoogleUtilities/Reachability (7.3.1): + - "GoogleUtilities/NSData+zlib (7.4.0)" + - GoogleUtilities/Reachability (7.4.0): - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.3.1): + - GoogleUtilities/UserDefaults (7.4.0): - GoogleUtilities/Logger - GTMAppAuth (1.1.0): - AppAuth/Core (~> 1.4) @@ -151,11 +187,11 @@ PODS: - GTMSessionFetcher/Core (= 1.5.0) - modal_progress_hud_nsn (0.0.1): - Flutter - - nanopb (2.30906.0): - - nanopb/decode (= 2.30906.0) - - nanopb/encode (= 2.30906.0) - - nanopb/decode (2.30906.0) - - nanopb/encode (2.30906.0) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) - package_info (0.0.1): - Flutter - package_info_plus (0.4.5): @@ -197,6 +233,7 @@ DEPENDENCIES: - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) + - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) - flurry (from `.symlinks/plugins/flurry/ios`) - Flutter (from `Flutter`) - flutter_app_badger (from `.symlinks/plugins/flutter_app_badger/ios`) @@ -223,6 +260,7 @@ SPEC REPOS: - FBSDKCoreKit - FBSDKLoginKit - Firebase + - FirebaseABTesting - FirebaseAnalytics - FirebaseAuth - FirebaseCore @@ -230,6 +268,7 @@ SPEC REPOS: - FirebaseInstallations - FirebaseInstanceID - FirebaseMessaging + - FirebaseRemoteConfig - Flurry-iOS-SDK - FMDB - GoogleAppMeasurement @@ -259,6 +298,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" firebase_messaging: :path: ".symlinks/plugins/firebase_messaging/ios" + firebase_remote_config: + :path: ".symlinks/plugins/firebase_remote_config/ios" flurry: :path: ".symlinks/plugins/flurry/ios" Flutter: @@ -304,18 +345,21 @@ SPEC CHECKSUMS: devicelocale: b22617f40038496deffba44747101255cee005b0 FBSDKCoreKit: a00fe2efd780c195a5e09201bf51c56106245b40 FBSDKLoginKit: d98498c598ec09de657385a9349a1f21119b7f86 - Firebase: 26223c695fe322633274198cb19dca8cb7e54416 - firebase_analytics: 4c032e04324c47ee6dd7a28bfff831e0ac0d09b6 - firebase_auth: c2c27e1081671b02f90981e70dad54722198491f - firebase_core: b5d81dfd4fb2d6f700e67de34d9a633ae325c4e9 - firebase_messaging: 7547c99f31466371f9cfcb733d5a1bf32a819872 - FirebaseAnalytics: 2580c2d62535ae7b644143d48941fcc239ea897a - FirebaseAuth: c224a0cf1afa0949bd5c7bfcf154b4f5ce8ddef2 - FirebaseCore: 4d3c72622ce0e2106aaa07bb4b2935ba2c370972 - FirebaseCoreDiagnostics: d50e11039e5984d92c8a512be2395f13df747350 - FirebaseInstallations: 5e777e6640fa060405cc7632447b6c5ca5af4742 - FirebaseInstanceID: 53140c03b9f6136f890d7901399f85a4c90ab2d0 - FirebaseMessaging: 68d1bcb14880189558a8ae57167abe0b7e417232 + Firebase: c121feb35e4126c0b355e3313fa9b487d47319fd + firebase_analytics: 620e8cc1705feb6b9c40b6127bea9b39e03e3970 + firebase_auth: e7065954aa2a7c8ef1a8502fba3009bcdd8fc91a + firebase_core: 84dcd80ac6d29c3d1039071b7306ee99688eb9c7 + firebase_messaging: 7aecb08eada5e5cde85b10875141706a8d18b818 + firebase_remote_config: f855065886b7d6ccc38144c9a3cecbdc7887f33e + FirebaseABTesting: e66f1f80747792630d9b292966de206d5df9853b + FirebaseAnalytics: cd3bd84d722a24a8923918af8af8e5236f615d77 + FirebaseAuth: 5fe4585c2ed847319f0ea68bd1d82c77e49ff9a0 + FirebaseCore: 907447d8917a4d3eb0cce2829c5a0ad21d90b432 + FirebaseCoreDiagnostics: 68ad972f99206cef818230f3f3179d52ccfb7f8c + FirebaseInstallations: a58d4f72ec5861840b84df489f2668d970df558a + FirebaseInstanceID: ad5135045a498d7775903efd39762d2cdfa1be27 + FirebaseMessaging: 163435fb6db065e3b6228f1e577b10ed2cc506d2 + FirebaseRemoteConfig: 0ea30de5fb0231df8c1bdcdf3b6c23bdc5066131 flurry: 15b01f664ab1367c62b50291541ea7f78ca85aad Flurry-iOS-SDK: 6636d30c30f12010e7c7c71d84b443416a168efc Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c @@ -326,14 +370,14 @@ SPEC CHECKSUMS: flutter_uxcam: 87dd981feb200bc81a2f062edb5ca2d16dae595a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc - GoogleAppMeasurement: 8d3c0aeede16ab7764144b5a4ca8e1d4323841b7 - GoogleDataTransport: 116c84c4bdeb76be2a7a46de51244368f9794eab + GoogleAppMeasurement: fd19169c3034975cb934e865e5667bfdce59df7f + GoogleDataTransport: cd9db2180fcecd8da1b561aea31e3e56cf834aa7 GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213 - GoogleUtilities: e1d9ed4e544fc32a93e00e721400cbc3f377200d + GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9 GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52 modal_progress_hud_nsn: f6fb744cd060653d66ed8f325360ef3650eb2fde - nanopb: 1bf24dd71191072e120b83dd02d08f3da0d65e53 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7116abd..bb311a3 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -388,7 +388,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -531,7 +531,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -566,7 +566,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 86c6d65..51bcb99 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -44,7 +44,7 @@ fbshareextension LSMinimumSystemVersion - 12.0 + 11.0 LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/lib/bloc/sales/sales_bloc.dart b/lib/bloc/sales/sales_bloc.dart index acf7a07..a20ba25 100644 --- a/lib/bloc/sales/sales_bloc.dart +++ b/lib/bloc/sales/sales_bloc.dart @@ -6,6 +6,7 @@ import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/product.dart'; import 'package:aitrainer_app/model/product_test.dart'; import 'package:aitrainer_app/model/purchase.dart'; +import 'package:aitrainer_app/repository/description_repository.dart'; import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/purchase_service.dart'; import 'package:aitrainer_app/util/enums.dart'; @@ -13,6 +14,7 @@ import 'package:aitrainer_app/util/purchases.dart'; import 'package:aitrainer_app/util/track.dart'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:purchases_flutter/offering_wrapper.dart'; part 'sales_event.dart'; @@ -22,8 +24,29 @@ class SalesBloc extends Bloc with Logging { List? tests = []; List product2Display = []; int productSet = -1; + final DescriptionRepository descriptionRepository = DescriptionRepository(); SalesBloc() : super(SalesInitial()); + String? salesText; + + String salesButtonText = "

Workout Test Monthly

localizedPrice

cancel any time

"; + Product? offeredProduct; + + Product? getProductByName(String name) { + Product? product; + if (product2Display.isNotEmpty) { + product2Display.forEach((element) { + if (element.type == name) { + product = element; + salesButtonText = salesButtonText.replaceFirst(RegExp(r'localizedPrice'), product!.localizedPrice!); + print("Localized Price ${product!.localizedPrice!} - Text: $salesButtonText"); + } + }); + } + + return product; + } + @override Stream mapEventToState( SalesEvent event, @@ -32,9 +55,30 @@ class SalesBloc extends Bloc with Logging { if (event is SalesLoad) { yield SalesLoading(); log("Load Sales"); - Track().track(TrackingEvent.sales_page); + if (Cache().userLoggedIn == null) { + throw Exception("Please log in"); + } + + String descriptionName = "sales_page_text"; + RemoteConfig? remoteConfig = Cache().remoteConfig; + if (remoteConfig != null) { + remoteConfig.fetchAndActivate(); + Map config = remoteConfig.getAll(); + RemoteConfigValue? value = config['sales_page_text_a']; + if (value != null) { + log("RemoteConfig sales_page_text value: ${value.asString()}"); + if (value.asString() == "1") { + descriptionName = "sales_page_text_a"; + } + } + } await RevenueCatPurchases().getOfferings(); this.getProductSet(); + salesText = descriptionRepository.getDescriptionByName(descriptionName); + log(salesText!); + salesButtonText = descriptionRepository.getDescriptionByName("sales_button_monthly"); + offeredProduct = getProductByName("wt_sub_2_3"); + Track().track(TrackingEvent.sales_page); yield SalesReady(); } else if (event is SalesPurchase) { if (Cache().hasPurchased) { @@ -60,6 +104,22 @@ class SalesBloc extends Bloc with Logging { } else { yield SalesError(message: "No selected product"); } + } else if (event is SalesChangeSubscription) { + yield SalesLoading(); + print("offered product .. $offeredProduct"); + if (offeredProduct != null) { + if (offeredProduct!.type == "wt_sub_2_3") { + print("go yearly"); + salesButtonText = descriptionRepository.getDescriptionByName("sales_button_yearly"); + offeredProduct = getProductByName("wt_sub_2_1"); + } else { + print("go monthly"); + salesButtonText = descriptionRepository.getDescriptionByName("sales_button_monthly"); + offeredProduct = getProductByName("wt_sub_2_3"); + } + } + + yield SalesReady(); } } on Exception catch (ex) { yield SalesError(message: ex.toString()); @@ -76,7 +136,7 @@ class SalesBloc extends Bloc with Logging { return prod; } - String getLocalizedPrice(String productId) { + String getLocalizedPrice(String productId, Product product) { String price = ""; Offering? offering = RevenueCatPurchases().offering; if (offering != null) { @@ -86,7 +146,7 @@ class SalesBloc extends Bloc with Logging { price = package.product.priceString; if (price.contains(r'HUF')) { price = price.replaceAll(RegExp(r'HUF'), 'Ft'); - price = price.replaceAll(RegExp(r',00'), ""); + price = price.replaceAll(RegExp(r'\,00'), ""); } break; } @@ -94,18 +154,21 @@ class SalesBloc extends Bloc with Logging { } else { log(" !!! No Offering"); } + if (price.isEmpty) { + price = Platform.isAndroid ? product.priceAndroid.toString() : product.priceIos.toString(); + } return price; } void getProductSet() { int productId = 0; - this.tests = Cache().productTests; + //this.tests = Cache().productTests; List? products = Cache().products; if (products == null) { return; } - if (tests != null && tests!.isEmpty) { + /* if (tests != null && tests!.isEmpty) { var rand = math.Random.secure(); productSet = rand.nextInt(5) + 1; } else { @@ -118,9 +181,9 @@ class SalesBloc extends Bloc with Logging { break; } } - } + } */ - ProductTest productTest = ProductTest(); + //ProductTest productTest = ProductTest(); productSet = 2; log("ProductSet: " + productSet.toString()); @@ -130,7 +193,8 @@ class SalesBloc extends Bloc with Logging { if (product.productSet == productSet) { productId = product.productId; final String platformProductId = Platform.isAndroid ? product.productIdAndroid! : product.productIdIos!; - product.localizedPrice = getLocalizedPrice(platformProductId); + product.localizedPrice = getLocalizedPrice(platformProductId, product); + log("product with localized price: $product"); product2Display.add(product); } } @@ -139,9 +203,9 @@ class SalesBloc extends Bloc with Logging { return a.sort < b.sort ? -1 : 1; }); - productTest.productId = productId; - productTest.customerId = Cache().userLoggedIn!.customerId!; - productTest.dateView = DateTime.now(); + //productTest.productId = productId; + //productTest.customerId = Cache().userLoggedIn!.customerId!; + //productTest.dateView = DateTime.now(); //ProductTestApi().saveProductTest(productTest); //Cache().productTests.add(productTest); } diff --git a/lib/bloc/sales/sales_event.dart b/lib/bloc/sales/sales_event.dart index af62439..8f400e1 100644 --- a/lib/bloc/sales/sales_event.dart +++ b/lib/bloc/sales/sales_event.dart @@ -15,3 +15,7 @@ class SalesPurchase extends SalesEvent { final int productId; const SalesPurchase({required this.productId}); } + +class SalesChangeSubscription extends SalesEvent { + const SalesChangeSubscription(); +} diff --git a/lib/bloc/session/session_bloc.dart b/lib/bloc/session/session_bloc.dart index d76dee4..b2b940c 100644 --- a/lib/bloc/session/session_bloc.dart +++ b/lib/bloc/session/session_bloc.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:aitrainer_app/bloc/settings/settings_bloc.dart'; +import 'package:aitrainer_app/service/firebase_api.dart'; import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/util/session.dart'; @@ -26,6 +27,7 @@ class SessionBloc extends Bloc with Logging { // ignore: close_sinks SettingsBloc settingsBloc = event.settingsBloc; await session.fetchSessionAndNavigate(); + FirebaseApi().setupRemoteConfig(); String lang = AppLanguage().appLocal.languageCode; log("Change lang to $lang"); settingsBloc.add(SettingsChangeLanguage(language: lang)); diff --git a/lib/bloc/tutorial/tutorial_bloc.dart b/lib/bloc/tutorial/tutorial_bloc.dart index f7bc352..9d5ec66 100644 --- a/lib/bloc/tutorial/tutorial_bloc.dart +++ b/lib/bloc/tutorial/tutorial_bloc.dart @@ -12,6 +12,7 @@ part 'tutorial_state.dart'; class TutorialBloc extends Bloc with Logging { late String tutorialName; + final double mediaHeightBase = 390; bool isActive = false; bool canActivate = false; @@ -46,6 +47,7 @@ class TutorialBloc extends Bloc with Logging { setNextStepData(step); isActive = true; + canActivate = true; } }); } @@ -58,8 +60,9 @@ class TutorialBloc extends Bloc with Logging { } if (tutorial != null && tutorial!.steps != null) { actualText = tutorial!.steps![step].tutorialTextTranslation; - print("Step: $step, text: $actualText"); + this.actualCheck = tutorial!.steps![step].checkText; + print("Step: $step, text: $actualCheck"); this.checks = []; if (this.actualCheck != null) { @@ -78,27 +81,31 @@ class TutorialBloc extends Bloc with Logging { calculateHeight(); } - /* else { - this.add(TutorialFinished()); - } */ } - bool activateTutorial() { - if (!canActivate) { - print("Tutorial canActivate false"); - return false; - } + bool isTutorialDone() { ActivityDone? activityDone = ActivityDone.tutorialBasic.searchByString(tutorialName); if (activityDone == null) { - return false; + return true; } bool? isActivityDone = Cache().activitiesDone[activityDone.toStr()]; - log("isActivityDone? $isActivityDone"); + + log("$tutorialName isActivityDone? $isActivityDone"); if (isActivityDone == null || isActivityDone == true) { + return true; + } + canActivate = true; + return false; + } + + bool activateTutorial() { + if (isTutorialDone()) { + isActive = false; + canActivate = false; return false; } - log("Running tutorial $activityDone"); + init(); return true; } @@ -135,20 +142,9 @@ class TutorialBloc extends Bloc with Logging { if (action == null) { return step + 1; } - /* bool found = false; - if (tutorial != null && tutorial!.steps != null) { - for (var nextStep in tutorial!.steps!) { - print("step $step parent: ${nextStep.action!.parent}"); - if (step + 1 == nextStep.step) { - next = nextStep.step!; - found = true; - break; - } - } - } */ step++; next = step; - print("Next step:! $next"); + print("Next step:! $step"); if (step >= tutorial!.steps!.length) { next = -1; this.add(TutorialFinished()); @@ -172,6 +168,7 @@ class TutorialBloc extends Bloc with Logging { menuBloc!.add(MenuCreate()); } } else if (event is TutorialNext) { + print("Tutorial Next: ${event.text}"); if (tutorial != null) { yield TutorialLoading(); @@ -195,7 +192,6 @@ class TutorialBloc extends Bloc with Logging { yield TutorialReady(); } else if (event is TutorialStart) { yield TutorialLoading(); - isActive = true; canActivate = true; step = 0; yield TutorialReady(); diff --git a/lib/library/button_animations.dart b/lib/library/button_animations.dart new file mode 100644 index 0000000..01e7e6f --- /dev/null +++ b/lib/library/button_animations.dart @@ -0,0 +1,304 @@ +import 'package:flutter/material.dart'; + +enum PredefinedThemes { + success, + successOutline, + danger, + dangerOutline, + warning, + warningOutline, + info, + infoOutline, + primary, + primaryOutline, + secondary, + secondaryOutline, + dark, + darkOutline, + light, +} + +List definedColors = [ + // success + {"color": Color(0xFF5CB85C), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // successOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFF5CB85C), "shadowColor": Color(0xFF5CB85C), "blurColor": Color(0xFF5CB85C)}, + // danger + {"color": Color(0xFFD9534F), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // dangerOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFFD9534F), "shadowColor": Color(0xFFD9534F), "blurColor": Color(0xFFD9534F)}, + // warning + {"color": Color(0xFFF0AD4E), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // warningOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFFF0AD4E), "shadowColor": Color(0xFFF0AD4E), "blurColor": Color(0xFFF0AD4E)}, + // info + {"color": Color(0xFF5BC0DE), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // infoOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFF5BC0DE), "shadowColor": Color(0xFF5BC0DE), "blurColor": Color(0xFF5BC0DE)}, + // primary + {"color": Color(0xFF0275D8), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // primaryOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFF0275D8), "shadowColor": Color(0xFF0275D8), "blurColor": Color(0xFF0275D8)}, + // secondary + {"color": Color(0xFF6B5B95), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // secondaryOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFF6B5B95), "shadowColor": Color(0xFF6B5B95), "blurColor": Color(0xFF6B5B95)}, + // dark + {"color": Color(0xFF292B2C), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + // darkOutline + {"color": Color(0xFFFAFAFA), "borderColor": Color(0xFF292B2C), "shadowColor": Color(0xFF292B2C), "blurColor": Color(0xFF292B2C)}, + {"color": Color(0xFFF7F7F7), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black}, + {"color": Color(0xFFBFBFC4), "borderColor": Colors.black, "shadowColor": Colors.black, "blurColor": Colors.black} +]; + +class AnimatedButton extends StatefulWidget { + // * @param onTap The function that is called whenever the widget is tapped + final GestureTapCallback onTap; + final Widget child; + // * @param type There are 16 predefined themes from which you can choose from if you dont want to customize the widget yourself + final PredefinedThemes type; + // * @param animationCurve The curve that the animation will follow + final Curve animationCurve; + // * @param enabled To check whether the button is enabbled or not + final bool enabled; + // * @param isMultiColor To check whether the button has multiple color gradient or not + final bool isMultiColor; + // * @param isOutline To check whether the button has a outline or not + final bool isOutline; + // * @param darkShadow To check whether the button has dark or light shadow + final bool darkShadow; + + // * @param duration The time that the animation takes in milliseconds + final int duration; + + // * @param height The height of the widget + final double height; + // * @param width The width of the widget + final double width; + // * @param blurRadius The radius of the blur effect of the widget + final double blurRadius; + // * @param borderRadius The radius of the borders of the widget + final double borderRadius; + // * @param shadowHeightBottom The height of the shadow and the animation of the widget from the bottom of the child widget + final double shadowHeightBottom; + // * @param shadowHeightLeft The height of the shadow and the animation of the widget from the left of the child widget + final double shadowHeightLeft; + // * @param borderWidth The width of the border of the widget + final double borderWidth; + + // * @param borderColor The color of the border of the widget(if type is not null, this will not work, is Outline should be true for this to work) + final Color borderColor; + // * @param blurColor The color of the blur of the widget(if type is not null, this will not work) + final Color blurColor; + // * @param color The color of the widget(if type is not null, this will not work) + final Color color; + // * @param shadowColor The color of the shadow of the widget(if type is not null, this will not work) + final Color? shadowColor; + + // * @param colors The list of colors for the gradient for the background of the widget(isMulticolor should be true for this to work) + final List? colors; + + AnimatedButton({ + Key? key, + required this.onTap, + required this.child, + this.enabled = true, + this.type = PredefinedThemes.primary, + this.color = Colors.blue, + this.height = 64, + this.colors, + this.isMultiColor = false, + this.darkShadow = true, + this.width = 200, + this.duration = 70, + this.blurRadius = 0, + this.borderRadius = 12, + this.animationCurve = Curves.easeIn, + this.shadowHeightBottom = 4, + this.shadowHeightLeft = 0, + this.isOutline = false, + this.borderColor = Colors.black, + this.borderWidth = 1, + this.blurColor = Colors.black, + this.shadowColor, + }) : assert(child != null), + super(key: key); + + @override + _AnimatedButtonState createState() => _AnimatedButtonState( + type: this.type, + color: this.color, + blurColor: this.blurColor, + borderColor: this.borderColor, + ); +} + +class _AnimatedButtonState extends State { + late double btnPositionBottom; + late double btnPositionTop; + late double btnPositionLeft; + late double btnPositionRight; + PredefinedThemes? type; + Color? color; + Color? shadowColor; + Color? borderColor; + Color? blurColor; + _AnimatedButtonState({ + this.type, + this.color, + this.shadowColor, + this.borderColor, + this.blurColor, + }); + + @override + void initState() { + super.initState(); + // check if there is a PredefinedThemes type used in the widget + // if yes, over-ride all the colors of the widget + if (type != null) { + int index = type!.index; + setState(() { + color = definedColors[index]["color"]; + shadowColor = definedColors[index]["shadowColor"]; + blurColor = definedColors[index]["blurColor"]; + borderColor = definedColors[index]["borderColor"]; + }); + } else { + setState(() { + color = widget.color; + shadowColor = widget.shadowColor; + blurColor = widget.blurColor; + borderColor = widget.borderColor; + }); + } + // initialize the top widget with the defined bottom and left height + setState(() { + btnPositionBottom = widget.shadowHeightBottom; + btnPositionLeft = widget.shadowHeightLeft; + }); + } + + @override + Widget build(BuildContext context) { + final double height = widget.height - btnPositionBottom; + + return GestureDetector( + child: Center( + child: Container( + width: widget.width + btnPositionLeft, + height: height + btnPositionBottom, + child: Stack( + children: [ + Positioned( + bottom: 0, + child: Container( + height: height, + width: widget.width, + decoration: BoxDecoration( + gradient: widget.isMultiColor + ? LinearGradient( + colors: shadow(widget.colors!, widget.darkShadow), + ) + : null, + color: (widget.shadowColor != null) + ? widget.shadowColor + : shadow((widget.isOutline) ? [color!] : [borderColor!], widget.darkShadow), + borderRadius: BorderRadius.all( + Radius.circular( + widget.borderRadius, + ), + ), + border: widget.isOutline + ? Border.all( + color: borderColor!, + width: widget.borderWidth, + ) + : null, + boxShadow: [ + BoxShadow( + color: blurColor!, + blurRadius: widget.blurRadius, + offset: Offset(0.0, 0.0), + ), + ], + ), + ), + ), + AnimatedPositioned( + curve: widget.animationCurve, + duration: Duration(milliseconds: widget.duration), + bottom: btnPositionBottom, + left: btnPositionLeft, + child: Container( + height: height, + width: widget.width, + decoration: BoxDecoration( + gradient: widget.isMultiColor + ? LinearGradient( + colors: widget.colors!, + ) + : null, + color: color, + borderRadius: BorderRadius.all( + Radius.circular( + widget.borderRadius, + ), + ), + border: widget.isOutline + ? Border.all( + color: borderColor!, + width: widget.borderWidth, + ) + : null, + ), + child: Center( + child: widget.child, + ), + ), + ), + ], + ), + ), + ), + onTapDown: widget.enabled ? _tapDown : null, + onTapUp: widget.enabled ? _tapUp : null, + onTapCancel: widget.enabled ? _unTap : null, + ); + } + + void _tapDown(_) { + // when the widget is pressed make both the heights, bottom and left to zero + setState(() { + btnPositionBottom = 0; + btnPositionLeft = 0; + }); + } + + // when the widget is released after being pressed, it returns to the given heights, bottom and left + void _tapUp(_) => _unTap(); + + void _unTap() { + setState(() { + btnPositionLeft = widget.shadowHeightLeft; + + btnPositionBottom = widget.shadowHeightBottom; + }); + widget.onTap(); + } + + // returns a list of color shades according to the params + // * @param colors list of colors + // * @param darkshadow whether to return a darker shadow or lighter shadow + shadow(List colors, bool darkShadow) { + List w = []; + + colors.forEach((color) { + double amount = darkShadow ? 0.22 : 0.1; + final hsl = HSLColor.fromColor(color); + final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + w.add(hslDark.toColor()); + }); + return (w.length == 1) ? w[0] : w; + } +} diff --git a/lib/model/cache.dart b/lib/model/cache.dart index c9e7661..cfb077e 100644 --- a/lib/model/cache.dart +++ b/lib/model/cache.dart @@ -2,6 +2,7 @@ import 'dart:collection'; import 'dart:convert'; import 'package:aitrainer_app/model/customer.dart'; import 'package:aitrainer_app/model/customer_activity.dart'; +import 'package:aitrainer_app/model/description.dart'; import 'package:aitrainer_app/model/evaluation.dart'; import 'package:aitrainer_app/model/exercise_plan.dart'; import 'package:aitrainer_app/model/exercise_plan_detail.dart'; @@ -25,6 +26,7 @@ import 'package:aitrainer_app/main.dart'; import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/env.dart'; import 'package:aitrainer_app/util/track.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flurry/flurry.dart'; import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; import 'package:flutter_uxcam/flutter_uxcam.dart'; @@ -58,7 +60,14 @@ enum SharePrefsChange { - is_logged_in */ -enum ActivityDone { tutorialBasic, tutorialDevelopment, isExerciseLogSeen, isMuscleDevelopmentSeen } +enum ActivityDone { + tutorialBasic, + tutorialBasicChestPress, + tutorialBasicLegPress, + tutorialDevelopment, + isExerciseLogSeen, + isMuscleDevelopmentSeen +} extension ActivityDoneExt on ActivityDone { String toStr() => this.toString().split(".").last; @@ -131,6 +140,7 @@ class Cache with Logging { List? _customerDevices; List? _customerActivities; List? _tutorials; + List? _descriptions; LinkedHashMap _myExercisesPlanDetails = LinkedHashMap(); @@ -141,6 +151,8 @@ class Cache with Logging { List? _exercisesTrainee; ExercisePlan? _traineeExercisePlan; + RemoteConfig? remoteConfig; + LinkedHashMap _badges = LinkedHashMap(); List? deviceLanguages; @@ -664,4 +676,10 @@ class Cache with Logging { List? get tutorials => this._tutorials; setTutorials(List? value) => this._tutorials = value; + + RemoteConfig? getRemoteConfig() => this.remoteConfig; + setRemoteConfig(RemoteConfig? remoteConfig) => this.remoteConfig = remoteConfig; + + List? getDescriptions() => this._descriptions; + setDescriptions(List? value) => this._descriptions = value; } diff --git a/lib/model/description.dart b/lib/model/description.dart new file mode 100644 index 0000000..a42a6b8 --- /dev/null +++ b/lib/model/description.dart @@ -0,0 +1,40 @@ +import 'package:aitrainer_app/util/app_language.dart'; +import 'dart:ui'; + +class Description { + late int descriptionId; + late String name; + late String description; + int? version; + DateTime? validFrom; + DateTime? validTo; + + String? descriptionTranslation; + + Description.fromJson(Map json) { + this.descriptionId = json['descriptionId']; + this.name = json['name']; + this.description = json['description']; + this.version = json['version']; + this.validFrom = json['validFrom']; + this.validTo = json['validTo']; + + if (json['translations'] != null && json['translations'].length > 0) { + this.descriptionTranslation = + AppLanguage().appLocal == Locale('hu') ? json['translations'][0]['descriptionTranslation'] : json['description']; + } + } + + Map toJson() => { + "descriptionId": this.descriptionId, + "name": this.name, + "description": this.description, + "version": this.version, + "validFrom": this.validFrom, + "validTo": this.validTo, + "descriptionTranslation": this.descriptionTranslation + }; + + @override + String toString() => this.toJson().toString(); +} diff --git a/lib/model/product.dart b/lib/model/product.dart index 3cbbfb3..0d3744e 100644 --- a/lib/model/product.dart +++ b/lib/model/product.dart @@ -46,6 +46,7 @@ class Product { 'productIdAndroid': this.productIdAndroid, 'priceIos': this.priceIos, 'priceAndroid': this.priceAndroid, + 'localizedPrice': this.localizedPrice }; return json.toString(); } diff --git a/lib/model/tutorial.dart b/lib/model/tutorial.dart index 2a2204e..9136131 100644 --- a/lib/model/tutorial.dart +++ b/lib/model/tutorial.dart @@ -14,6 +14,19 @@ class Tutorial { if (json['steps'] != null && json['steps'].length > 0) { steps = json['steps'].map((step) => TutorialStep.fromJson(step)).toList(); + if (steps != null) { + steps!.sort((a, b) { + if (a.step == null || b.step == null) { + return -1; + } else { + if (a.step! <= b.step!) { + return -1; + } else { + return 1; + } + } + }); + } } } diff --git a/lib/model/tutorial_step.dart b/lib/model/tutorial_step.dart index 7ec14f5..fa49b29 100644 --- a/lib/model/tutorial_step.dart +++ b/lib/model/tutorial_step.dart @@ -71,7 +71,6 @@ class TutorialStep { this.condition = json['condition']; if (this.condition != null) { this.condition = condition!.replaceAll(r'\\', "replace"); - print("Json condition $condition"); this.action = TutorialStepAction.fromJson(jsonDecode(condition!)); } diff --git a/lib/push_notifications.dart b/lib/push_notifications.dart index cdf31b6..f4d7797 100644 --- a/lib/push_notifications.dart +++ b/lib/push_notifications.dart @@ -27,5 +27,7 @@ class PushNotificationsManager with Logging { badge: true, sound: true, ); + String? token = await FirebaseMessaging.instance.getToken(); + print("FirebaseMessaging tokne $token"); } } diff --git a/lib/repository/description_repository.dart b/lib/repository/description_repository.dart new file mode 100644 index 0000000..b00b3f8 --- /dev/null +++ b/lib/repository/description_repository.dart @@ -0,0 +1,23 @@ +import 'package:aitrainer_app/model/cache.dart'; +import 'package:aitrainer_app/model/description.dart'; + +class DescriptionRepository { + List? descriptions; + + DescriptionRepository() { + this.descriptions = Cache().getDescriptions(); + } + + String getDescriptionByName(String name) { + String descriptionText = ""; + if (descriptions != null) { + this.descriptions!.forEach((element) { + print("Desc ${element.name} - $name"); + if (element.name == name) { + descriptionText = element.descriptionTranslation != null ? element.descriptionTranslation! : element.description; + } + }); + } + return descriptionText; + } +} diff --git a/lib/service/firebase_api.dart b/lib/service/firebase_api.dart index b224a3d..36a776c 100644 --- a/lib/service/firebase_api.dart +++ b/lib/service/firebase_api.dart @@ -3,6 +3,7 @@ import 'package:aitrainer_app/service/logging.dart' as logging; import 'package:apple_sign_in/apple_sign_in.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flutter_facebook_auth/flutter_facebook_auth.dart'; import 'package:google_sign_in/google_sign_in.dart'; @@ -28,7 +29,8 @@ class FirebaseApi with logging.Logging { Future initializeFlutterFire() async { try { // Wait for Firebase to initialize and set `_initialized` state to true - await Firebase.initializeApp(); + FirebaseApp app = await Firebase.initializeApp(); + this.appleSignInAvailable = await AppleSignIn.isAvailable(); } catch (e) { // Set `_error` state to true if Firebase initialization fails @@ -286,4 +288,23 @@ class FirebaseApi with logging.Logging { Future resetPassword(String email) async { await FirebaseAuth.instance.sendPasswordResetEmail(email: email); } + + Future setupRemoteConfig() async { + initializeFlutterFire(); + final RemoteConfig remoteConfig = RemoteConfig.instance; + await remoteConfig.setConfigSettings(RemoteConfigSettings( + fetchTimeout: const Duration(seconds: 10), + minimumFetchInterval: const Duration(seconds: 1), + )); + await remoteConfig.setDefaults({ + 'sales_page_text': '0', + 'sales_page_bkg': 'dark', + 'sales_page_offer': 'monthly', + }); + RemoteConfigValue(null, ValueSource.valueStatic); + Cache().setRemoteConfig(remoteConfig); + + Map config = remoteConfig.getAll(); + print("RemoteConfig sales_page_text Value : ${config['sales_page_text'].asString()}"); + } } diff --git a/lib/service/package_service.dart b/lib/service/package_service.dart index d08ce1a..43bbb1f 100644 --- a/lib/service/package_service.dart +++ b/lib/service/package_service.dart @@ -5,6 +5,7 @@ import 'package:aitrainer_app/model/customer.dart'; import 'package:aitrainer_app/model/customer_activity.dart'; import 'package:aitrainer_app/model/customer_exercise_device.dart'; import 'package:aitrainer_app/model/customer_property.dart'; +import 'package:aitrainer_app/model/description.dart'; import 'package:aitrainer_app/model/evaluation.dart'; import 'package:aitrainer_app/model/exercise.dart'; import 'package:aitrainer_app/model/exercise_device.dart'; @@ -72,8 +73,13 @@ class PackageApi { } else if (headRecord[0] == "Tutorial") { final Iterable json = jsonDecode(headRecord[1]); final List tutorials = json.map((tutorial) => Tutorial.fromJson(tutorial)).toList(); - print("Tutorial: $tutorials"); + Cache().setTutorials(tutorials); + } else if (headRecord[0] == "Description") { + final Iterable json = jsonDecode(headRecord[1]); + final List? descriptions = json.map((description) => Description.fromJson(description)).toList(); + //print("Description: $descriptions"); + Cache().setDescriptions(descriptions); } }); diff --git a/lib/util/session.dart b/lib/util/session.dart index da96042..7fbc1e1 100644 --- a/lib/util/session.dart +++ b/lib/util/session.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:aitrainer_app/service/firebase_api.dart'; import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/util/app_localization.dart'; import 'package:aitrainer_app/service/api.dart'; @@ -7,6 +8,8 @@ import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/package_service.dart'; import 'package:aitrainer_app/util/purchases.dart'; import 'package:devicelocale/devicelocale.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_remote_config/firebase_remote_config.dart'; import 'package:flutter/services.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:package_info/package_info.dart'; diff --git a/lib/util/track.dart b/lib/util/track.dart index 969058f..3bf721a 100644 --- a/lib/util/track.dart +++ b/lib/util/track.dart @@ -4,11 +4,13 @@ import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/tracking_service.dart'; import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/model/tracking.dart' as model; +import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flurry/flurry.dart'; import 'package:flutter_uxcam/flutter_uxcam.dart'; class Track with Logging { static final Track _singleton = Track._internal(); + static FirebaseAnalytics analytics = FirebaseAnalytics(); factory Track() { return _singleton; @@ -22,6 +24,7 @@ class Track with Logging { // Smartlook.setGlobalEventProperty(event.toString(), eventValue, false); FlutterUxcam.logEventWithProperties(event.enumToString(), {"value": eventValue}); model.Tracking tracking = model.Tracking(); + analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue}); tracking.customerId = Cache().userLoggedIn == null ? 0 : Cache().userLoggedIn!.customerId!; tracking.event = event.enumToString(); if (eventValue.isNotEmpty) { diff --git a/lib/view/exercise_control_page.dart b/lib/view/exercise_control_page.dart index d4d8706..2a2d9d1 100644 --- a/lib/view/exercise_control_page.dart +++ b/lib/view/exercise_control_page.dart @@ -2,6 +2,7 @@ import 'dart:collection'; import 'package:aitrainer_app/bloc/exercise_control/exercise_control_bloc.dart'; import 'package:aitrainer_app/bloc/timer/timer_bloc.dart'; +import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/model/cache.dart'; @@ -267,6 +268,7 @@ class _ExerciseControlPage extends State with Trans { String title = (step + 1).toString() + "/4 " + t("Control Exercise:"); LinkedHashMap args = LinkedHashMap(); + final TutorialBloc tutorialBloc = BlocProvider.of(context); List listWidgets = [ Text( @@ -332,15 +334,20 @@ class _ExerciseControlPage extends State with Trans { primary: Colors.white, onSurface: Colors.blueAccent, ), - onPressed: () => { - exerciseBloc.add(ExerciseControlSubmit(step: step)), - if (step == 3) - { - Navigator.of(context).pop(), - args['exerciseRepository'] = exerciseBloc.exerciseRepository, - Navigator.of(context).pushNamed('evaluationPage', arguments: args) - } - }, + onPressed: () { + if (tutorialBloc.isActive) { + if (!tutorialBloc.checkAction("Save")) { + return; + } + } + + exerciseBloc.add(ExerciseControlSubmit(step: step)); + if (step == 3) { + Navigator.of(context).pop(); + args['exerciseRepository'] = exerciseBloc.exerciseRepository; + Navigator.of(context).pushNamed('evaluationPage', arguments: args); + } + }, child: step == exerciseBloc.step ? Stack( alignment: Alignment.center, diff --git a/lib/view/sales_page.dart b/lib/view/sales_page.dart index 65c4680..d3975a0 100644 --- a/lib/view/sales_page.dart +++ b/lib/view/sales_page.dart @@ -1,4 +1,5 @@ import 'package:aitrainer_app/bloc/sales/sales_bloc.dart'; +import 'package:aitrainer_app/library/button_animations.dart'; import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar_min.dart'; @@ -6,6 +7,8 @@ import 'package:aitrainer_app/widgets/dialog_common.dart'; import 'package:aitrainer_app/widgets/sales_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_html/style.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; @@ -22,7 +25,6 @@ class SalesPage extends StatelessWidget with Trans, Logging { create: (context) => SalesBloc()..add(SalesLoad()), child: BlocConsumer(listener: (context, state) { if (state is SalesError) { - log("Error: " + state.message); ScaffoldMessenger.of(context).showSnackBar( SnackBar(backgroundColor: Colors.orange, content: Text(t(state.message), style: TextStyle(color: Colors.white)))); } else if (state is SalesSuccessful) { @@ -57,6 +59,9 @@ class SalesPage extends StatelessWidget with Trans, Logging { } Widget salesWidget(SalesBloc bloc) { + final salesText = bloc.salesText != null ? bloc.salesText! : ""; + final String html = salesText; + return Container( decoration: BoxDecoration( image: DecorationImage( @@ -68,55 +73,144 @@ class SalesPage extends StatelessWidget with Trans, Logging { child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [ SliverList( delegate: SliverChildListDelegate([ - Divider(), - Container( - padding: EdgeInsets.only(left: 65, right: 65), - child: Text(t("Unleash Your Development Now!"), + Html( + data: html, + //Optional parameters: + style: { + "p": Style( + color: Colors.white, + fontSize: FontSize(16), + padding: const EdgeInsets.only(left: 20, right: 8, bottom: 4), + ), + "strong": Style( + color: Colors.yellow[600], + fontSize: FontSize(16), + ), + "h3": Style( + color: Colors.yellow[600], + fontSize: FontSize(16), + textAlign: TextAlign.center, + padding: const EdgeInsets.all(12), + ), + "li": Style( + color: Colors.white, + fontSize: FontSize(14), + padding: const EdgeInsets.only(left: 20, bottom: 10, right: 8), + //before: "*", + display: Display.LIST_ITEM), + "h2": Style( + color: Colors.yellow[600], + fontWeight: FontWeight.bold, + fontSize: FontSize(24), + textAlign: TextAlign.center, + //padding: const EdgeInsets.all(4), + ), + "h1": Style( + color: Colors.yellow[400], + fontWeight: FontWeight.bold, + fontSize: FontSize.larger, + alignment: Alignment.center, + padding: const EdgeInsets.all(4), + ), + }, + ), // final Color bgrColor = Color(0xffb4f500); + //final Color bgrColorEnd = Colors.blue; + AnimatedButton( + child: Html( + data: bloc.salesButtonText, + //Optional parameters: + style: { + "p": Style( + color: Colors.black, + fontSize: FontSize(16), + padding: const EdgeInsets.all(4), textAlign: TextAlign.center, - maxLines: 4, - softWrap: true, - style: GoogleFonts.archivoBlack( - fontSize: 30, - color: Colors.white, - shadows: [ - Shadow( - offset: Offset(5.0, 5.0), - blurRadius: 12.0, - color: Colors.black54, - ), - Shadow( - offset: Offset(-3.0, 3.0), - blurRadius: 12.0, - color: Colors.black54, - ), - ], - ))), - Divider(), - Container( - padding: EdgeInsets.only(left: 45, right: 45), - child: Text(t("Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts."), - textAlign: TextAlign.left, - maxLines: 4, - softWrap: true, - style: GoogleFonts.inter( - fontSize: 16, - color: Colors.white, - ))), - SizedBox( - height: 50, + textShadow: [ + Shadow( + offset: Offset(2.0, 2.0), + blurRadius: 6.0, + color: Colors.black54, + ) + ], + ), + "li": Style( + color: Colors.white, + fontSize: FontSize(14), + padding: const EdgeInsets.only(left: 10, bottom: 10), + before: "*", + ), + "h2": Style( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: FontSize.larger, + textAlign: TextAlign.center, + textShadow: [ + Shadow( + offset: Offset(2.0, 2.0), + blurRadius: 12.0, + color: Colors.black54, + ) + ], + //padding: const EdgeInsets.all(4), + ), + "h1": Style( + color: Colors.yellow[600], + fontWeight: FontWeight.bold, + fontSize: FontSize.xLarge, + alignment: Alignment.center, + padding: const EdgeInsets.all(4), + textAlign: TextAlign.center, + textShadow: [ + Shadow( + offset: Offset(5.0, 5.0), + blurRadius: 12.0, + color: Colors.black54, + ) + ], + ), + }, + ), + duration: 600, + darkShadow: true, + blurRadius: 12, + animationCurve: Curves.easeIn, + height: 120, + width: 320, + onTap: () => bloc.add(SalesPurchase(productId: bloc.offeredProduct!.productId)), + //color: Color(0xffb4f500), + isMultiColor: true, + colors: [ + Colors.blue, + Color(0xffb4f500), + Color(0xffb4f500), + ], ), - ])), - SliverGrid( - delegate: SliverChildListDelegate(getButtons(bloc)), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10.0, - crossAxisSpacing: 10.0, - childAspectRatio: 0.55, + + getTrialDescription(), + //Divider(), + AnimatedButton( + child: Html( + data: "

" + t("View other alternatives") + "

", + //Optional parameters: + style: { + "p": Style( + color: Colors.black, + fontSize: FontSize(14), + padding: const EdgeInsets.all(4), + textAlign: TextAlign.center, + ), + }, + ), + onTap: () => bloc.add(SalesChangeSubscription()), + width: 320, + blurRadius: 6, + isMultiColor: true, + colors: [ + Colors.white, + Colors.yellow[300]!, + ], ), - ), - SliverList( - delegate: SliverChildListDelegate([ + SizedBox( height: 30, ), @@ -144,6 +238,35 @@ class SalesPage extends StatelessWidget with Trans, Logging { ])); } + Widget getTrialDescription() { + final trialText = t("Try free for 3 days!"); + return Container( + padding: EdgeInsets.only(left: 55, right: 55), + child: Html( + data: "

" + trialText + "

", + //Optional parameters: + style: { + "p": Style( + color: Colors.white, + fontSize: FontSize(13), + padding: const EdgeInsets.all(4), + textAlign: TextAlign.center, + textShadow: [ + Shadow( + offset: Offset(2.0, 2.0), + blurRadius: 6.0, + color: Colors.black54, + ) + ], + ), + "strong": Style( + color: Colors.yellow[600], + fontSize: FontSize(13), + ), + }, + )); + } + List getButtons(SalesBloc bloc) { List buttons = []; diff --git a/lib/view/settings.dart b/lib/view/settings.dart index 7518021..0189004 100644 --- a/lib/view/settings.dart +++ b/lib/view/settings.dart @@ -139,7 +139,7 @@ class SettingsPage extends StatelessWidget with Trans { final TutorialBloc tutorialBloc = BlocProvider.of(context); return ListTile( leading: Icon(CustomIcon.question_circle), - subtitle: Text("Activating the basic tutorial"), + subtitle: Text(t("Activating the basic tutorial")), title: ToggleSwitch( minWidth: 120.0, minHeight: 30.0, @@ -151,7 +151,15 @@ class SettingsPage extends StatelessWidget with Trans { inactiveFgColor: Colors.grey[900], labels: [t('Basic Tutorial'), t('Activate')], onToggle: (index) { - settingsBloc.add(SettingsActivateTutorial(activity: ActivityDone.tutorialBasic)); + ActivityDone activity = ActivityDone.tutorialBasic; + if (Cache().userLoggedIn != null) { + if (Cache().userLoggedIn!.sex == "m") { + activity = ActivityDone.tutorialBasicChestPress; + } else { + activity = ActivityDone.tutorialBasicLegPress; + } + } + settingsBloc.add(SettingsActivateTutorial(activity: activity)); tutorialBloc.add(TutorialStart()); }, ), diff --git a/lib/view/test_set_edit.dart b/lib/view/test_set_edit.dart index 3801f75..91185c1 100644 --- a/lib/view/test_set_edit.dart +++ b/lib/view/test_set_edit.dart @@ -9,6 +9,7 @@ import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/dialog_common.dart'; +import 'package:aitrainer_app/widgets/dialog_html.dart'; import 'package:aitrainer_app/widgets/menu_image.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/cupertino.dart'; @@ -190,12 +191,9 @@ class TestSetEdit extends StatelessWidget with Trans { context: context, barrierDismissible: false, builder: (BuildContext context) { - return DialogCommon( + return DialogHTML( title: bloc.templateNameTranslation, - descriptions: bloc.templateDescription, - text: "OK", - onTap: () => {Navigator.of(context).pop()}, - onCancel: () => {Navigator.of(context).pop()}, + htmlData: bloc.templateDescription, ); }), child: Icon( diff --git a/lib/widgets/menu_page_widget.dart b/lib/widgets/menu_page_widget.dart index 813378a..8e3899e 100644 --- a/lib/widgets/menu_page_widget.dart +++ b/lib/widgets/menu_page_widget.dart @@ -67,17 +67,25 @@ class _MenuPageWidgetState extends State with Trans, Logging { } Future runDelayedEvent() async { - print("runDelayedEvent start"); bool isFirst = false; await Future.delayed(Duration(milliseconds: 600), () async { - if (tutorialBloc.isActive == false) { - print("Activate tutorial"); - tutorialBloc.canActivate = true; - tutorialBloc.isActive = true; - tutorialBloc.menuBloc = menuBloc; - tutorialBloc.add(TutorialLoad()); - tutorialBloc.init(); - isFirst = true; + if (Cache().userLoggedIn != null) { + if (Cache().userLoggedIn!.sex == "m") { + tutorialBloc.tutorialName = ActivityDone.tutorialBasicChestPress.toStr(); + } else { + tutorialBloc.tutorialName = ActivityDone.tutorialBasicLegPress.toStr(); + } + } + if (!tutorialBloc.isTutorialDone()) { + if (tutorialBloc.isActive == false && tutorialBloc.canActivate) { + print("Activate tutorial"); + tutorialBloc.canActivate = true; + tutorialBloc.isActive = true; + tutorialBloc.menuBloc = menuBloc; + tutorialBloc.add(TutorialLoad()); + tutorialBloc.init(); + isFirst = true; + } } }); final bool canActivate = tutorialBloc.activateTutorial(); @@ -351,6 +359,7 @@ class _MenuPageWidgetState extends State with Trans, Logging { void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc) { if (tutorialBloc.isActive) { final String checkText = workoutTree.nameEnglish; + print("Click: tutorial is active $checkText"); if (!tutorialBloc.checkAction(checkText)) { return; } diff --git a/lib/widgets/sales_button.dart b/lib/widgets/sales_button.dart index 7bf70b9..85a0199 100644 --- a/lib/widgets/sales_button.dart +++ b/lib/widgets/sales_button.dart @@ -66,7 +66,8 @@ class SalesButton extends StatelessWidget { fontSize: 1, )), child: Container( - child: Center( + child: Text( + "ho") /* Center( child: Column( children: [ Divider( @@ -92,7 +93,8 @@ class SalesButton extends StatelessWidget { child: Text(desc4!, maxLines: 2, style: GoogleFonts.inter(fontSize: 10, color: Colors.red[800]))) ], ), - )), + ) */ + ), ))); } } diff --git a/lib/widgets/tutorial_widget.dart b/lib/widgets/tutorial_widget.dart index e0c8441..e2266ef 100644 --- a/lib/widgets/tutorial_widget.dart +++ b/lib/widgets/tutorial_widget.dart @@ -40,10 +40,13 @@ class TutorialWidget with Trans, Logging { area = bloc.action!.showBubble == true ? Rect.fromLTWH(targetGlobalCenter.dx - bloc.action!.bubbleX, targetGlobalCenter.dy - bloc.action!.bubbleY, bloc.action!.bubbleWidth.toDouble(), bloc.action!.bubbleHeight.toDouble()) + //? Rect.fromLTWH(targetGlobalCenter.dx - 60, targetGlobalCenter.dy + 120, 420, 320) : null; } final double mediaSize = MediaQuery.of(context).size.width; + final double mediaHeight = MediaQuery.of(context).size.width; + final double distortion = mediaHeight / bloc.mediaHeightBase; double fontSize = 14; if (mediaSize > 400) { @@ -51,8 +54,16 @@ class TutorialWidget with Trans, Logging { } else if (mediaSize < 375) { fontSize = 13; } + + double calculatedTop = bloc.top! / distortion; + //-((1 - distortion) * 100 * (fontSize)); + if (calculatedTop < 0) { + calculatedTop = 10; + } + print("Height: $mediaHeight, distortion: $distortion top: ${bloc.top!} calculated $calculatedTop"); + tooltip = SuperTooltip( - top: bloc.top, + top: calculatedTop, left: bloc.left, backgroundColor: Colors.black.withOpacity(0.7), popupDirection: bloc.action == null || bloc.action!.direction == "up" ? TooltipDirection.up : TooltipDirection.down, diff --git a/pubspec.lock b/pubspec.lock index 5f8060c..4751a46 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,6 +15,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + animated_widgets: + dependency: "direct main" + description: + name: animated_widgets + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.6" apple_sign_in: dependency: "direct main" description: @@ -315,49 +322,49 @@ packages: name: firebase_analytics url: "https://pub.dartlang.org" source: hosted - version: "8.0.0-dev.2" + version: "8.0.2" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.0-dev.0" + version: "2.0.0" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web url: "https://pub.dartlang.org" source: hosted - version: "0.3.0-dev.0" + version: "0.3.0" firebase_auth: dependency: "direct main" description: name: firebase_auth url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.1.2" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.0.2" + version: "4.2.0" firebase_auth_web: dependency: transitive description: name: firebase_auth_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.1.0" firebase_core_platform_interface: dependency: transitive description: @@ -378,21 +385,35 @@ packages: name: firebase_messaging url: "https://pub.dartlang.org" source: hosted - version: "9.1.1" + version: "9.1.3" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.6" + firebase_remote_config: + dependency: "direct main" + description: + name: firebase_remote_config + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.0-dev.2" + firebase_remote_config_platform_interface: + dependency: transitive + description: + name: firebase_remote_config_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0-dev.2" fixnum: dependency: transitive description: @@ -419,6 +440,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_app_badger: + dependency: "direct main" + description: + name: flutter_app_badger + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" flutter_bloc: dependency: "direct main" description: @@ -447,6 +475,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.4.1+1" + flutter_fadein: + dependency: "direct main" + description: + name: flutter_fadein + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" flutter_html: dependency: "direct main" description: @@ -506,6 +541,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_uxcam: + dependency: "direct main" + description: + name: flutter_uxcam + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2" flutter_web_plugins: dependency: transitive description: flutter @@ -707,6 +749,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_linux: + dependency: transitive + description: + name: package_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_macos: + dependency: transitive + description: + name: package_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_web: + dependency: transitive + description: + name: package_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_windows: + dependency: transitive + description: + name: package_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -876,12 +960,19 @@ packages: source: hosted version: "0.26.0" sentry: - dependency: "direct main" + dependency: transitive description: name: sentry url: "https://pub.dartlang.org" source: hosted version: "5.0.0" + sentry_flutter: + dependency: "direct main" + description: + name: sentry_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" shared_preferences: dependency: "direct dev" description: @@ -957,13 +1048,6 @@ packages: description: flutter source: sdk version: "0.0.99" - smartlook: - dependency: "direct main" - description: - name: smartlook - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.7" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 24c2cd8..8f311e8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,12 +57,14 @@ dependencies: convex_bottom_bar: ^3.0.0 flutter_app_badger: ^1.2.0 #super_tooltip: ^1.0.1 - - firebase_core: ^1.0.3 - firebase_analytics: ^8.0.0-dev.2 - firebase_messaging: ^9.1.1 + + firebase_core: ^1.1.0 + firebase_analytics: ^8.0.2 + firebase_messaging: ^9.1.3 flutter_local_notifications: ^5.0.0 - firebase_auth: ^1.0.3 + firebase_auth: ^1.1.2 + firebase_remote_config: ^0.10.0-dev.2 + flutter_facebook_auth: ^3.3.2 google_sign_in: ^5.0.1 apple_sign_in: ^0.1.0