WT1.1.3 build 2 iOS. Apple SignIn, Google SignIn

This commit is contained in:
bossanyit 2021-01-17 09:30:57 +01:00
parent 4bd1950ffd
commit d44fefe9af
31 changed files with 811 additions and 249 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
asset/image/button_fb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
asset/image/vest_weight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -7,13 +7,16 @@
"TRAINING!": "TRAINING!",
"Login": "Login",
"Logout": "Logout",
"SignUp with Email": "SignUp with Email",
"Tests": "Tests",
"Change Language": "Change Language",
"Password too short": "Password too short (at least 9 characters)",
"Please type an email address": "Please type an email address",
"Exception: Please accept our data policy":"Please accept our data policy",
"Please accept our data protection policy. For more information please click on 'Privacy'":"Please accept our data protection policy. For more information please click on 'Privacy'",
"SignUp": "SignUp",
"Please accept our data protection policy.":"Please accept our data protection policy.",
"For more information please click on 'Privacy'":"For more information please click on 'Privacy'",
"SignUp": "SignUp with Email",
"SignUpLink": "SignUp",
"Privacy": "Privacy",
"Change App Language": "Change App Language",
"English": "English",
@ -26,9 +29,17 @@
"Please log in": "Please log in",
"Exception: Customer does not exist or the password is wrong": "The email does not exist or the password is wrong",
"Exception: Facebook signup was not successful. Please try another method": "Facebook signup was not successful. Please try another method",
"Exception: Customer exists": "The email address has been registered already",
"Exception: The email address has been registered already":"The email address has been registered already",
"Exception: Please type an email address": "Please type an email address",
"Exception: Password too short": "Password too short (at least 9 characters)",
"Exception: Google Sign In failed":"Google Sign In failed",
"Exception: Apple Sign-In failed":"Apple Sign-In failed",
"Exception: Apple Sign-In cancelled":"Apple Sign-In cancelled",
"Exception: Apple Sign In failure: email address is necessary": "Apple Sign In failure: email address is necessary",
"There is an error: during registration:": "There is an error: during registration:",
"Please select an exercise": "Please select an exercise",
"Cardio": "Cardio",
@ -199,7 +210,7 @@
"Persistence!": "Persistence!",
"Greetings!": "Greetings!",
"The purpose is to measure you physical condition": "The purpose is to measure your physical condition.",
"The purpose is to measure you physical condition": "The purpose is to measure your physical condition. Your first goal is to test all your muscle regions with a 'base' exercise.",
"The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.": "The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.",
"Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.": "Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.",
"Please continue your tests with a": "Please continue your tests with a",
@ -286,6 +297,7 @@
"Unleash your potential with WorkoutTest Premium!":"Unleash your potential with WorkoutTest Premium!",
"feature is reachable after you finished":"feature is reachable after you finished",
"100% test circles":"100% test circles",
"Keep testing":"Keep Testing",
"Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.":"Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.",

View File

@ -12,8 +12,11 @@
"Password too short": "A jelszó min. 9 karakterből álljon",
"Please type an email address": "Kérlek írj be egy email címet",
"SignUp": "Regisztráció",
"SignUpLink": "Regisztráció",
"SignUp with Email": "Email Regisztráció",
"Exception: Please accept our data policy":"Kérlek fogadd el az adatvédelmi szabályzatunkat",
"Please accept our data protection policy. For more information please click on 'Privacy'":"Kérlek fogadd el az adatvédelmi szabályzatunkat. További információkért kattints az 'Adatkezelés' linkre.",
"Please accept our data protection policy.":"Kérlek fogadd el az adatvédelmi szabályzatunkat.",
"For more information please click on 'Privacy'":"További információkért kattints az 'Adatkezelés' linkre.",
"Privacy": "Adatkezelés",
"Change App Language": "Nyelvválasztás",
"English": "Angol",
@ -29,11 +32,17 @@
"Customer does not exist or the password is wrong": "A felhasználó nem létezik vagy a jelszó rossz.",
"The email does not exist or the password is wrong": "A felhasználó nem létezik vagy a jelszó rossz.",
"Exception: Facebook login was not successful": "Facebook bejelentkezés sikertelen",
"Exception: Facebook signup was not successful. Please try another method": "Facebook regisztráció sikertelen. Kérlek próbálj mással regisztrálni",
"Exception: Please type an email address": "Kérlek írj be egy email címet",
"Exception: Password too short": "A jelszó min. 9 karakterből álljon",
"Exception: You have a previous Facebook login operation in progress":"Az előző bejelentkezés még folyamatban van.",
"Exception: Facebook login cancelled":"Facebook bejelentkezés megszakítva ",
"Exception: Facebook login failed":"Facebook bejelentkezés sikertelen",
"Exception: The email address has been registered already":"Ezzel email címmel már regisztráltak",
"Exception: Google Sign In failed":"Google bejelentkezés sikertelen",
"Exception: Apple Sign-In failed":"Apple bejelentkezés sikertelen",
"Exception: Apple Sign-In cancelled":"Apple bejelentkezés megszakítva",
"Exception: Apple Sign In failure: email address is necessary": "Apple bejelentkezés sikertelen: email cím szükséges.",
"Please select an exercise": "Válassz ki egy gyakorlatot",
"There is an error: during registration:": "Hiba lépett fel a regisztráció során:",
@ -73,7 +82,7 @@
"Endurance_desc":"<p>Erőállóképességi teszt lényege, ahogy az 1RM tesztnél is, hogy a Neked megfelelő SÚLY és ISMÉTLÉS számot tudjuk javasolni. </p><p>Nagyon fontos, hogy szabályosan és a kért ismétléssel dolgozz!</p><p> Ha a célod a hosszabb távú erő fenntartása, netán sportoló vagy, akkor feltétlen teszteld az erőállóképességi modulunkat is.</p><br/><h2>Miért az erőállóképesség?</h2><p>Javítja az izmok oxigén és tápanyagellátottságát és ezáltal képes leszel egyre nagyobb súlyok egyre hosszabbtávon való megmozgatására. Például egyre több fekvőtámaszra és húzódzkodásra. </p><p>Kevésbé tömegnövelő hatású, ámbár atlétikus és nagyon erős testalkatot kölcsönöz, ha hosszútávon gyakorlod.</p>",
"OneRepMax_desc":"<p>Az egy ismétléses maximum, vagy más néven 1RM ismerete számodra fontos lehet a Neked megfelelő SÚLY és ISMÉTLÉS kiszámításában. <p>Végezd el szabályosan(!) a tesztet, hogy a Neked legmegfelelőbb súlyokat és ismétléseket tudjuk javasolni a későbbiekben.</p> <p>Ha a célod az izom, vagy az erőnövelés, akkor feltétlen csináld meg az 1RM teszteket!</p><br/><h2>Mi az 1RM?</h2><p>Az a súly, amit egyetlen egyszer lennél képes szabályosan megmozgatni. Az egyszer szabályosan végrehajtott maximális súlyú gyakorlatból származtatjuk a céloknak megfelelő súly és ismétlésszámokat.</p>",
"Name": "Név",
"Name": "Vezetkéknév",
"Exercise": "Gyakorlat",
"Quantity": "Mennyiség",
"Unit": "Egység",
@ -197,7 +206,7 @@
"Persistence!": "Kitartás!",
"Greetings!": "Üdvözöllek!",
"The purpose is to measure you physical condition": "A cél a jelenlegi fizikai kondíciód felmérése.",
"The purpose is to measure you physical condition": "A cél a jelenlegi fizikai kondíciód felmérése. Az első célod az összes izomcsoport tesztelése egy 'base' gyakorlattal.",
"The suggested order of the exercises: chest - biceps - triceps - back - shoulders - core - tigh - calf.": "A gyakorlatok javasolt végrehajtási sorrendje: mell - bicepsz - tricepsz - hát - váll - has - comb - vádli.",
"Go to the menu Strength - One Rep Max - Chest, and select your favourite exercise.": "Menj a menüben az Erő - Max Erő - Mell menüpontba, és válaszd ki a kedvenc gyakorlatod.",
"Please continue your tests with a": "Kérlek folytasd a gyakorlatokat egy",
@ -284,6 +293,7 @@
"Unleash your potential with WorkoutTest Premium!":"Bontakoztasd ki az erősségeidet WorkoutTest Prémiummal!",
"feature is reachable after you finished":"funkció elérhető számodra, miután teljesítetted",
"100% test circles":"100%-os teszt-köröd",
"Keep testing":"Folytasd a tesztelést",
"Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.":"Élvezd ezt a prémium funkciót is, amely megjeleníti a korábbi gyakorlatok teljes kiértékelését",

View File

@ -1,4 +1,11 @@
PODS:
- AppAuth (1.4.0):
- AppAuth/Core (= 1.4.0)
- AppAuth/ExternalUserAgent (= 1.4.0)
- AppAuth/Core (1.4.0)
- AppAuth/ExternalUserAgent (1.4.0)
- apple_sign_in (0.0.1):
- Flutter
- devicelocale (0.0.1):
- Flutter
- FBSDKCoreKit (8.2.0):
@ -11,14 +18,24 @@ PODS:
- FBSDKLoginKit/Login (= 8.2.0)
- FBSDKLoginKit/Login (8.2.0):
- FBSDKCoreKit (~> 8.2.0)
- Firebase/Analytics (6.33.0):
- Firebase/Core
- Firebase/Auth (6.33.0):
- Firebase/CoreOnly
- FirebaseAuth (~> 6.9.2)
- Firebase/Core (6.33.0):
- Firebase/CoreOnly
- FirebaseAnalytics (= 6.8.3)
- Firebase/CoreOnly (6.33.0):
- FirebaseCore (= 6.10.3)
- Firebase/Messaging (6.33.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 4.7.0)
- firebase_analytics (6.3.0):
- Firebase/Analytics (~> 6.33.0)
- Firebase/CoreOnly (~> 6.33.0)
- firebase_core
- Flutter
- firebase_auth (0.18.4-1):
- Firebase/Auth (~> 6.33.0)
- Firebase/CoreOnly (~> 6.33.0)
@ -32,6 +49,15 @@ PODS:
- Firebase/Messaging (~> 6.33.0)
- firebase_core
- Flutter
- FirebaseAnalytics (6.8.3):
- FirebaseCore (~> 6.10)
- FirebaseInstallations (~> 1.6)
- GoogleAppMeasurement (= 6.8.3)
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
- GoogleUtilities/MethodSwizzler (~> 6.7)
- GoogleUtilities/Network (~> 6.7)
- "GoogleUtilities/NSData+zlib (~> 6.7)"
- nanopb (~> 1.30906.0)
- FirebaseAuth (6.9.2):
- FirebaseCore (~> 6.10)
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
@ -73,15 +99,26 @@ PODS:
- FBSDKCoreKit (~> 8.2.0)
- FBSDKLoginKit (~> 8.2.0)
- Flutter
- flutter_inapp_purchase (0.0.1):
- Flutter
- flutter_keyboard_visibility (0.0.1):
- Flutter
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- google_sign_in (0.0.1):
- Flutter
- GoogleSignIn (~> 5.0)
- GoogleAppMeasurement (6.8.3):
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
- GoogleUtilities/MethodSwizzler (~> 6.7)
- GoogleUtilities/Network (~> 6.7)
- "GoogleUtilities/NSData+zlib (~> 6.7)"
- nanopb (~> 1.30906.0)
- GoogleDataTransport (7.5.1):
- nanopb (~> 1.30906.0)
- GoogleSignIn (5.0.2):
- AppAuth (~> 1.2)
- GTMAppAuth (~> 1.0)
- GTMSessionFetcher/Core (~> 1.1)
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
@ -90,6 +127,8 @@ PODS:
- PromisesObjC (~> 1.2)
- GoogleUtilities/Logger (6.7.2):
- GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (6.7.2):
- GoogleUtilities/Logger
- GoogleUtilities/Network (6.7.2):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
@ -99,7 +138,14 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (6.7.2):
- GoogleUtilities/Logger
- GTMAppAuth (1.1.0):
- AppAuth/Core (~> 1.4)
- GTMSessionFetcher (~> 1.4)
- GTMSessionFetcher (1.5.0):
- GTMSessionFetcher/Full (= 1.5.0)
- GTMSessionFetcher/Core (1.5.0)
- GTMSessionFetcher/Full (1.5.0):
- GTMSessionFetcher/Core (= 1.5.0)
- nanopb (1.30906.0):
- nanopb/decode (= 1.30906.0)
- nanopb/encode (= 1.30906.0)
@ -122,15 +168,17 @@ PODS:
- Flutter
DEPENDENCIES:
- apple_sign_in (from `.symlinks/plugins/apple_sign_in/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- flurry (from `.symlinks/plugins/flurry/ios`)
- Flutter (from `Flutter`)
- flutter_facebook_auth (from `.symlinks/plugins/flutter_facebook_auth/ios`)
- flutter_inapp_purchase (from `.symlinks/plugins/flutter_inapp_purchase/ios`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- google_sign_in (from `.symlinks/plugins/google_sign_in/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
@ -140,9 +188,11 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- AppAuth
- FBSDKCoreKit
- FBSDKLoginKit
- Firebase
- FirebaseAnalytics
- FirebaseAuth
- FirebaseCore
- FirebaseCoreDiagnostics
@ -151,16 +201,23 @@ SPEC REPOS:
- FirebaseMessaging
- Flurry-iOS-SDK
- FMDB
- GoogleAppMeasurement
- GoogleDataTransport
- GoogleSignIn
- GoogleUtilities
- GTMAppAuth
- GTMSessionFetcher
- nanopb
- PromisesObjC
- Protobuf
EXTERNAL SOURCES:
apple_sign_in:
:path: ".symlinks/plugins/apple_sign_in/ios"
devicelocale:
:path: ".symlinks/plugins/devicelocale/ios"
firebase_analytics:
:path: ".symlinks/plugins/firebase_analytics/ios"
firebase_auth:
:path: ".symlinks/plugins/firebase_auth/ios"
firebase_core:
@ -173,10 +230,10 @@ EXTERNAL SOURCES:
:path: Flutter
flutter_facebook_auth:
:path: ".symlinks/plugins/flutter_facebook_auth/ios"
flutter_inapp_purchase:
:path: ".symlinks/plugins/flutter_inapp_purchase/ios"
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
google_sign_in:
:path: ".symlinks/plugins/google_sign_in/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
shared_preferences:
@ -191,13 +248,17 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter/ios"
SPEC CHECKSUMS:
AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7
apple_sign_in: 7716c7ddfa195aeab7dec0dc374ef4ff45d1adb4
devicelocale: feebbe5e7a30adb8c4f83185de1b50ff19b44f00
FBSDKCoreKit: 4afd6ff53d8133a433dbcda44451c9498f8c6ce4
FBSDKLoginKit: 7181765f2524d7ebf82d9629066c8e6caafc99d0
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
firebase_analytics: 36a619088c46224900829f14f4daa71585693a6f
firebase_auth: d5159db3873478d1ac839af7b10d2f831516136a
firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75
FirebaseAnalytics: 5dd088bd2e67bb9d13dbf792d1164ceaf3052193
FirebaseAuth: c92d49ada7948d1a23466e3db17bc4c2039dddc3
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
@ -208,11 +269,14 @@ SPEC CHECKSUMS:
Flurry-iOS-SDK: 8f3f7fce27177002f15f145eede88dc1b9ac0cd0
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_facebook_auth: bad08a3d465e7b7ba9d8468a9dc7df3f69c136b8
flutter_inapp_purchase: 5c6a1ac3f11b11d0c8c0321c0c41c1f05805e4c8
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc
GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
GoogleSignIn: 7137d297ddc022a7e0aa4619c86d72c909fa7213
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
GTMAppAuth: 197a8dabfea5d665224aa00d17f164fc2248dab9
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c

View File

@ -156,6 +156,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
EB0A62903CC30EC853FC7908 /* [CP] Embed Pods Frameworks */,
C1BA2CB9D651F269CCBE06B3 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -265,6 +266,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
C1BA2CB9D651F269CCBE06B3 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
EB0A62903CC30EC853FC7908 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -366,7 +384,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -509,7 +527,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -544,7 +562,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (

View File

@ -24,6 +24,7 @@
<key>CFBundleURLSchemes</key>
<array>
<string>fb584181112271127</string>
<string>com.googleusercontent.apps.926782702216-2nsi7d9at3pc5ts8gkobt5697v590kb9</string>
</array>
</dict>
</array>

View File

@ -4,6 +4,10 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.developer.authentication-services.autofill-credential-provider</key>
<true/>
</dict>

View File

@ -21,6 +21,7 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
final BuildContext context;
final bool isRegistration;
bool dataPolicyAllowed = false;
bool obscure = true;
LoginBloc({this.accountBloc, this.userRepository, this.context, this.isRegistration}) : super(LoginInitial());
@override
@ -51,6 +52,20 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Flurry.logEvent("Login");
Flurry.logEvent("LoginFB");
yield LoginSuccess();
} else if (event is LoginGoogle) {
yield LoginLoading();
await userRepository.getUserByGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
Flurry.logEvent("Login");
Flurry.logEvent("LoginGoogle");
yield LoginSuccess();
} else if (event is LoginApple) {
yield LoginLoading();
await userRepository.getUserByApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
Flurry.logEvent("Login");
Flurry.logEvent("LoginApple");
yield LoginSuccess();
} else if (event is RegistrationSubmit) {
yield LoginLoading();
if (!this.dataPolicyAllowed) {
@ -75,9 +90,36 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Flurry.logEvent("RegistrationFB");
Flurry.logEvent("Registration");
yield LoginSuccess();
} else if (event is RegistrationGoogle) {
yield LoginLoading();
if (!this.dataPolicyAllowed) {
yield LoginError();
throw Exception("Please accept our data policy");
}
await userRepository.addUserGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
await saveCustomer();
Flurry.logEvent("RegistrationGoogle");
Flurry.logEvent("Registration");
yield LoginSuccess();
} else if (event is RegistrationApple) {
yield LoginLoading();
if (!this.dataPolicyAllowed) {
yield LoginError();
throw Exception("Please accept our data policy");
}
await userRepository.addUserApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn));
await saveCustomer();
Flurry.logEvent("RegistrationApple");
Flurry.logEvent("Registration");
yield LoginSuccess();
} else if (event is DataProtectionClicked) {
this.dataPolicyAllowed = event.marked;
yield LoginLoading();
this.dataPolicyAllowed = !dataPolicyAllowed;
yield LoginReady();
} else if (event is LoginPasswordChangeObscure) {
this.obscure = !this.obscure;
}
} on Exception catch (e) {
yield LoginError(message: e.toString());

View File

@ -35,6 +35,14 @@ class LoginFB extends LoginEvent {
const LoginFB();
}
class LoginGoogle extends LoginEvent {
const LoginGoogle();
}
class LoginApple extends LoginEvent {
const LoginApple();
}
class DataProtectionClicked extends LoginEvent {
final bool marked;
const DataProtectionClicked({this.marked});
@ -47,3 +55,11 @@ class RegistrationSubmit extends LoginEvent {
class RegistrationFB extends LoginEvent {
const RegistrationFB();
}
class RegistrationGoogle extends LoginEvent {
const RegistrationGoogle();
}
class RegistrationApple extends LoginEvent {
const RegistrationApple();
}

View File

@ -29,14 +29,14 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
if (event is SalesLoad) {
yield SalesLoading();
//Flurry.logEvent("SalesPageOpen");
await PlatformPurchaseApi().initPurchasePlatformState();
this.getProductSet();
// await PlatformPurchaseApi().initPurchasePlatformState();
// this.getProductSet();
yield SalesReady();
} else if (event is SalesPurchase) {
final int productId = event.productId;
trace("Requesting purchase for" + productId.toString());
//Flurry.logEvent("PurchaseRequest");
PlatformPurchaseApi().purchase(getSelectedProduct(productId));
// PlatformPurchaseApi().purchase(getSelectedProduct(productId));
}
} on Exception catch (ex) {
yield SalesError(message: ex.toString());
@ -53,7 +53,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
return prod;
}
String getLocalizedPrice(String productId) {
/* String getLocalizedPrice(String productId) {
String price = "";
for (var product in PlatformPurchaseApi().getIAPItems()) {
if (Platform.isAndroid) {
@ -109,5 +109,5 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
productTest.dateView = DateTime.now();
//ProductTestApi().saveProductTest(productTest);
//Cache().productTests.add(productTest);
}
} */
}

View File

@ -42,7 +42,7 @@ class SessionBloc extends Bloc<SessionEvent, SessionState> with Logging {
@override
Future<void> close() async {
await this.close();
PlatformPurchaseApi().close();
//PlatformPurchaseApi().close();
super.close();
}
}

View File

@ -32,6 +32,8 @@ import 'package:aitrainer_app/view/reset_password.dart';
import 'package:aitrainer_app/view/sales_page.dart';
import 'package:aitrainer_app/view/settings.dart';
import 'package:aitrainer_app/widgets/home.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:flurry/flurry.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -163,7 +165,7 @@ class WorkoutTestApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
//final FirebaseAnalytics analytics = FirebaseAnalytics();
final FirebaseAnalytics analytics = FirebaseAnalytics();
initFlurry();
PushNotificationsManager().init();
return MaterialApp(
@ -233,7 +235,7 @@ class WorkoutTestApp extends StatelessWidget {
bodyText1: GoogleFonts.openSans(textStyle: TextStyle(fontSize: 14.0)),
)),
navigatorObservers: [
//FirebaseAnalyticsObserver(analytics: analytics),
FirebaseAnalyticsObserver(analytics: analytics),
],
home: AitrainerHome(),
);

View File

@ -73,7 +73,6 @@ class Cache with Logging {
AccessToken accessTokenFacebook;
Customer userLoggedIn;
String firebaseUid;
String facebookUid;
bool hasPurchased = false;
@ -201,7 +200,7 @@ class Cache with Logging {
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
userLoggedIn = customer;
final String uid = Cache().firebaseUid == null ? Cache().facebookUid : Cache().firebaseUid;
final String uid = Cache().firebaseUid;
await setPreferences(prefs, SharePrefsChange.registration, customer.customerId, uid);
}
@ -219,7 +218,7 @@ class Cache with Logging {
afterFacebookLogin() async {
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
await setPreferences(prefs, SharePrefsChange.login, userLoggedIn.customerId, Cache().facebookUid);
await setPreferences(prefs, SharePrefsChange.login, userLoggedIn.customerId, Cache().firebaseUid);
}
logout() async {
@ -457,7 +456,4 @@ class Cache with Logging {
AccessToken get getAccessTokenFacebook => accessTokenFacebook;
set setAccessTokenFacebook(AccessToken accessTokenFacebook) => this.accessTokenFacebook = accessTokenFacebook;
String get getFacebookUid => facebookUid;
set setFacebookUid(String facebookUid) => this.facebookUid = facebookUid;
}

View File

@ -2,8 +2,12 @@ import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/user.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/service/firebase_api.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
class UserRepository {
class UserRepository with Logging {
User user;
UserRepository() {
@ -31,29 +35,166 @@ class UserRepository {
await CustomerApi().addUser(modelUser);
}
} catch (e) {
print(e.toString());
log(e.toString());
throw new Exception(e);
}
}
Future<void> addUserFB() async {
final User modelUser = this.user;
try {
Map<String, dynamic> userData = await FirebaseApi().registerWithFacebook();
if (userData != null) {
modelUser.email = userData['email'];
if (modelUser.email == null) {
throw new Exception("Facebook signup was not successful. Please try another method");
}
modelUser.password = Cache().firebaseUid;
modelUser.firebaseUid = Cache().firebaseUid;
await CustomerApi().addUser(modelUser);
} else {
throw new Exception("Facebook signup was not successful. Please try another method");
}
} on auth.FirebaseAuthException catch (e) {
if (e.code == 'email-already-in-use') {
log('The account already exists for that email.');
throw Exception("The email address has been registered already");
}
} on WorkoutTestException catch (ex) {
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
log('The account already exists for that email.');
throw Exception("The email address has been registered already");
}
} on Exception catch (ex) {
log("Google exception: " + ex.toString());
throw Exception("Google Sign In failed");
}
}
Map<String, dynamic> userData = await FirebaseApi().signInWithFacebook();
if (userData != null) {
modelUser.email = userData['email'];
modelUser.password = "1234567";
modelUser.firebaseUid = Cache().facebookUid;
await CustomerApi().addUser(modelUser);
Future<void> addUserGoogle() async {
final User modelUser = this.user;
try {
Map<String, dynamic> userData = await FirebaseApi().registerWithGoogle();
if (userData != null) {
modelUser.email = userData['email'];
if (modelUser.email == null) {
throw new Exception("Google signup was not successful. Please try another method");
}
modelUser.password = Cache().firebaseUid;
modelUser.firebaseUid = Cache().firebaseUid;
await CustomerApi().addUser(modelUser);
} else {
throw new Exception("Google signup was not successful. Please try another method");
}
} on auth.FirebaseAuthException catch (e) {
if (e.code == 'email-already-in-use') {
log('The account already exists for that email.');
throw Exception("The email address has been registered already");
}
} on WorkoutTestException catch (ex) {
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
log('The account already exists for that email.');
throw Exception("The email address has been registered already");
}
} on Exception catch (ex) {
log("Google exception: " + ex.toString());
throw Exception("Google Sign In failed");
}
}
Future<void> addUserApple() async {
final User modelUser = this.user;
try {
Map<String, dynamic> userData = await FirebaseApi().registerWithApple();
if (userData != null) {
modelUser.email = userData['email'];
if (modelUser.email == null) {
throw new Exception("Apple signup was not successful. Please try another method");
}
modelUser.password = Cache().firebaseUid;
modelUser.firebaseUid = Cache().firebaseUid;
await CustomerApi().addUser(modelUser);
} else {
throw new Exception("Apple signup was not successful. Please try another method");
}
} on auth.FirebaseAuthException catch (e) {
if (e.code == 'email-already-in-use') {
log('The account already exists for that email.');
throw Exception("The email address has been registered already");
}
} on WorkoutTestException catch (ex) {
if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
log('The account already exists for that email.');
throw Exception("The email address has been registered already");
}
} on Exception catch (ex) {
log("Apple exception: " + ex.toString());
throw Exception(ex);
}
}
Future<void> getUserByFB() async {
final User modelUser = this.user;
Map<String, dynamic> userData = await FirebaseApi().signInWithFacebook();
try {
Map<String, dynamic> userData = await FirebaseApi().signInWithFacebook();
if (userData == null) {
throw new Exception("Facebook login was not successful");
}
modelUser.email = userData['email'];
await CustomerApi().getUserByEmail(modelUser.email);
await Cache().afterFirebaseLogin();
} on FacebookAuthException catch (e) {
switch (e.errorCode) {
case FacebookAuthErrorCode.OPERATION_IN_PROGRESS:
throw Exception("You have a previous Facebook login operation in progress");
break;
case FacebookAuthErrorCode.CANCELLED:
throw Exception("Facebook login cancelled");
break;
case FacebookAuthErrorCode.FAILED:
throw Exception("Facebook login failed");
break;
}
} on NotFoundException catch (ex) {
log("FB exception: " + ex.toString());
throw Exception("Customer does not exist or the password is wrong");
} on Exception catch (e) {
log(e.toString());
throw new Exception(e);
}
}
Future<void> getUserByGoogle() async {
final User modelUser = this.user;
Map<String, dynamic> userData = await FirebaseApi().signInWithGoogle();
if (userData == null || userData['email'] == null) {
throw new Exception("Google login was not successful");
}
modelUser.email = userData['email'];
await CustomerApi().getUserByEmail(modelUser.email);
await Cache().afterFacebookLogin();
try {
await CustomerApi().getUserByEmail(modelUser.email);
await Cache().afterFirebaseLogin();
} on Exception catch (ex) {
log("Google exception: " + ex.toString());
throw Exception("Customer does not exist or the password is wrong");
}
}
Future<void> getUserByApple() async {
final User modelUser = this.user;
Map<String, dynamic> userData = await FirebaseApi().signInWithApple();
if (userData == null || userData['email'] == null) {
throw new Exception("Apple login was not successful");
}
modelUser.email = userData['email'];
try {
await CustomerApi().getUserByEmail(modelUser.email);
await Cache().afterFirebaseLogin();
} on Exception catch (ex) {
log("Apple exception: " + ex.toString());
throw Exception("Customer does not exist or the password is wrong");
}
}
Future<void> getUser() async {
@ -64,7 +205,7 @@ class UserRepository {
await CustomerApi().getUserByEmail(modelUser.email);
await Cache().afterFirebaseLogin();
} else {
print("Exception: user not found or password is wrong");
log("Exception: user not found or password is wrong");
throw Exception("Customer does not exist or the password is wrong");
}
}

View File

@ -7,6 +7,7 @@ import 'package:aitrainer_app/model/user.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
class CustomerApi with Logging {
final APIClient _client = new APIClient();
@ -44,12 +45,16 @@ class CustomerApi with Logging {
try {
int status = jsonDecode(responseBody)['status'];
if (status != null) {
throw new Exception(jsonDecode(responseBody)['error']);
String error = jsonDecode(responseBody)['error'];
throw new Exception(error);
} else {
customer = Customer.fromJson(jsonDecode(responseBody));
await Cache().afterRegistration(customer);
}
} on FormatException {
if (responseBody == "Customer exists") {
throw WorkoutTestException(code: WorkoutTestException.CUSTOMER_EXISTS, message: responseBody);
}
throw new Exception(responseBody);
}
}

View File

@ -1,10 +1,13 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
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:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class FirebaseApi with Logging {
class FirebaseApi with logging.Logging {
bool appleSignInAvailable = false;
static FirebaseApi _instance;
static final FirebaseAuth auth = FirebaseAuth.instance;
@ -28,6 +31,7 @@ class FirebaseApi with Logging {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
this.appleSignInAvailable = await AppleSignIn.isAvailable();
} catch (e) {
// Set `_error` state to true if Firebase initialization fails
log("Error initializing Firebase");
@ -81,34 +85,200 @@ class FirebaseApi with Logging {
return rc;
}
Future<Map<String, dynamic>> signInWithApple() async {
Map<String, dynamic> userData = Map();
final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
switch (result.status) {
case AuthorizationStatus.authorized:
print('User authorized');
break;
case AuthorizationStatus.error:
print('User error');
throw Exception("Apple Sign-In failed");
break;
case AuthorizationStatus.cancelled:
print('User cancelled');
throw Exception("Apple Sign-In cancelled");
break;
}
// 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);
log("userCredential: " + userCredential.toString());
log("Apple Credentials: " +
result.credential.user.toString() +
" state " +
result.credential.state.toString() +
" email " +
userCredential.user.email);
userData['email'] = userCredential.user.email;
return userData;
}
Future<Map<String, dynamic>> registerWithApple() async {
Map<String, dynamic> userData = Map();
final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
switch (result.status) {
case AuthorizationStatus.authorized:
print('Apple User authorized');
break;
case AuthorizationStatus.error:
print('Apple User error');
throw Exception("Apple Sign-In failed");
break;
case AuthorizationStatus.cancelled:
print('User cancelled');
throw Exception("Apple Sign-In cancelled");
break;
}
// 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);
Cache().firebaseUid = userCredential.user.uid;
userData['email'] = userCredential.user.email;
return userData;
}
Future<Map<String, dynamic>> signInWithGoogle() async {
Map<String, dynamic> userData = Map();
try {
// Trigger the authentication flow
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
if (googleUser == null) {
throw Exception("Google Sign In failed");
}
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
// Create a new credential
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
if (googleUser != null) {
log("GoogleUser: " + googleUser.toString());
userData['email'] = googleUser.email;
userData['id'] = googleUser.id;
userData['name'] = googleUser.displayName;
}
} on Exception catch (ex) {
log("Google exception: " + ex.toString());
throw Exception("Google Sign In failed");
}
return userData;
}
Future<Map<String, dynamic>> registerWithGoogle() async {
Map<String, dynamic> userData = Map();
// Trigger the authentication flow
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
if (googleUser == null) {
throw Exception("Google Sign In failed");
}
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
// Create a new credential
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final userCredential = await FirebaseAuth.instance.signInWithCredential(credential);
log("Google credentials: " + credential.toString() + " GoogleUser: " + googleUser.toString());
Cache().firebaseUid = userCredential.user.uid;
userData['email'] = googleUser.email;
return userData;
}
Future<Map<String, dynamic>> signInWithFacebook() async {
Map<String, dynamic> userData;
try {
// by default the login method has the next permissions ['email','public_profile']
AccessToken accessToken = await FacebookAuth.instance.login();
if (accessToken != null) {
log(accessToken.toJson().toString());
Cache().accessTokenFacebook = accessToken;
// get the user data
userData = await FacebookAuth.instance.getUserData();
Cache().facebookUid = userData['id'];
log(userData.toString());
} else {
throw Exception("Facebook login was not successful");
}
} on FacebookAuthException catch (e) {
switch (e.errorCode) {
case FacebookAuthErrorCode.OPERATION_IN_PROGRESS:
throw Exception("You have a previous Facebook login operation in progress");
break;
case FacebookAuthErrorCode.CANCELLED:
throw Exception("Facebook login cancelled");
break;
case FacebookAuthErrorCode.FAILED:
throw Exception("Facebook login failed");
break;
}
// by default the login method has the next permissions ['email','public_profile']
AccessToken accessToken = await FacebookAuth.instance.login();
if (accessToken != null) {
log(accessToken.toJson().toString());
Cache().accessTokenFacebook = accessToken;
// get the user data
userData = await FacebookAuth.instance.getUserData();
Cache().firebaseUid = userData['id'];
log(userData.toString());
} else {
throw Exception("Facebook login was not successful");
}
return userData;
}
Future<Map<String, dynamic>> registerWithFacebook() async {
Map<String, dynamic> userData;
// by default the login method has the next permissions ['email','public_profile']
AccessToken accessToken = await FacebookAuth.instance.login();
if (accessToken != null) {
Cache().accessTokenFacebook = accessToken;
// get the user data
userData = await FacebookAuth.instance.getUserData();
// Create a credential from the access token
final FacebookAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(accessToken.token);
// Once signed in, return the UserCredential
final userCredential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
Cache().firebaseUid = userCredential.user.uid;
log(userData.toString());
} else {
throw Exception("Facebook login was not successful");
}
return userData;
}

View File

@ -1,4 +1,13 @@
class NotFoundException implements Exception {
final String message;
const NotFoundException({this.message});
}
}
class WorkoutTestException implements Exception {
static const String CUSTOMER_EXISTS = "customer-exists";
static const String LOGIN_CANCELLED = "login-cancelled";
final String message;
final String code;
const WorkoutTestException({this.message, this.code});
}

View File

@ -1,6 +1,6 @@
import 'dart:async';
import 'dart:io';
/*
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/service/logging.dart';
@ -21,15 +21,7 @@ class PlatformPurchaseApi with Logging {
List getProductList() => _productList;
/* Platform.isAndroid
? [
'android.test.purchased',
'point_1000',
'5000_point',
'android.test.canceled',
]
: ['com.cooni.point1000', 'com.cooni.point5000'];
*/
factory PlatformPurchaseApi() {
return _singleton;
@ -167,3 +159,4 @@ class PlatformPurchaseApi with Logging {
this._purchases = items;
}
}
*/

View File

@ -10,6 +10,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
// ignore: must_be_immutable
class CustomerExerciseDevicePage extends StatelessWidget with Trans {
@ -37,19 +38,20 @@ class CustomerExerciseDevicePage extends StatelessWidget with Trans {
..add(CustomerExerciseDeviceLoad()),
child: BlocConsumer<CustomerExerciseDeviceBloc, CustomerExerciseDeviceState>(
listener: (context, state) {
if (state is CustomerExerciseDeviceLoading) {
Scaffold.of(context).showSnackBar(SnackBar(
duration: Duration(milliseconds: 100),
backgroundColor: Colors.transparent,
content: Container(child: Center(child: CircularProgressIndicator()))));
} else if (state is CustomerExerciseDeviceError) {
if (state is CustomerExerciseDeviceError) {
Scaffold.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
}
},
builder: (context, state) {
final bloc = BlocProvider.of<CustomerExerciseDeviceBloc>(context);
return getPage(bloc, cWidth, cHeight);
return ModalProgressHUD(
child: getPage(bloc, cWidth, cHeight),
inAsyncCall: state is CustomerExerciseDeviceLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
))));
}

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
@ -68,29 +70,40 @@ class LoginPage extends StatelessWidget with Trans {
return Form(
key: _scaffoldKey,
child: Container(
padding: const EdgeInsets.only(left: 15, right: 50),
child: ListView(shrinkWrap: false, padding: EdgeInsets.only(top: 100.0), children: <Widget>[
FlatButton(
child: new Image.asset(
'asset/image/login_fb.png',
width: MediaQuery.of(context).size.width * .85,
),
onPressed: () => {loginBloc.add(LoginFB())},
),
Text(AppLocalizations.of(context).translate("OR")),
Divider(),
padding: const EdgeInsets.only(left: 20, right: 20),
child: ListView(shrinkWrap: false, padding: EdgeInsets.only(top: 150.0), children: <Widget>[
ListTile(title: Text(t("Login"), style: GoogleFonts.inter())),
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
new InkWell(
child: new Text(AppLocalizations.of(context).translate('Login'),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
FlatButton(
child: Image.asset(
'asset/image/button_fb.png',
width: 60,
),
onPressed: () => {loginBloc.add(LoginFB())},
),
FlatButton(
child: Image.asset(
'asset/image/button_google.png',
width: 60,
),
onPressed: () => {loginBloc.add(LoginGoogle())},
),
Platform.isIOS
? FlatButton(
child: Image.asset(
'asset/image/button_apple.png',
width: 60,
),
onPressed: () => {loginBloc.add(LoginApple())},
)
: Offstage(),
],
),
Divider(
color: Colors.transparent,
),
Divider(),
ListTile(title: Text(t("OR"), style: GoogleFonts.inter())),
Divider(),
TextFormField(
key: LibraryKeys.loginEmailField,
decoration: InputDecoration(
@ -118,7 +131,7 @@ class LoginPage extends StatelessWidget with Trans {
),
TextFormField(
key: LibraryKeys.loginPasswordField,
obscureText: true,
obscureText: loginBloc.obscure,
decoration: InputDecoration(
labelStyle: TextStyle(fontSize: 14),
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
@ -168,7 +181,7 @@ class LoginPage extends StatelessWidget with Trans {
),
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
InkWell(
child: Text(AppLocalizations.of(context).translate('SignUp')),
child: Text(AppLocalizations.of(context).translate('SignUpLink')),
onTap: () => Navigator.of(context).pushNamed('registration'),
),
Spacer(flex: 2),

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
@ -11,7 +13,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:toggle_switch/toggle_switch.dart';
import '../library_keys.dart';
@ -74,28 +75,48 @@ class RegistrationPage extends StatelessWidget with Trans {
return Form(
key: _scaffoldKey,
child: Container(
padding: const EdgeInsets.only(left: 15, right: 50),
padding: const EdgeInsets.only(left: 20, right: 20),
child: ListView(shrinkWrap: false, padding: EdgeInsets.only(top: 150.0), children: <Widget>[
FlatButton(
child: Image.asset(
'asset/image/fb_registration.png',
width: MediaQuery.of(context).size.width * .85,
),
onPressed: () => {loginBloc.add(RegistrationFB())},
),
ListTile(title: Text(AppLocalizations.of(context).translate("OR"))),
ListTile(title: Text(t("SignUp"), style: GoogleFonts.inter())),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlatButton(
child: Image.asset(
'asset/image/button_fb.png',
width: 60,
),
onPressed: () => {loginBloc.add(RegistrationFB())},
),
FlatButton(
child: Image.asset(
'asset/image/button_google.png',
width: 60,
),
onPressed: () => {loginBloc.add(RegistrationGoogle())},
),
Platform.isIOS
? FlatButton(
child: Image.asset(
'asset/image/button_apple.png',
width: 60,
),
onPressed: () => {loginBloc.add(RegistrationApple())},
)
: Offstage(),
],
),
ListTile(title: Text(t("OR"), style: GoogleFonts.inter())),
/* Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
InkWell(
child:
Text(AppLocalizations.of(context).translate('SignUp'), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
child: Text(AppLocalizations.of(context).translate('SignUp with Email'),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
),
],
),
Divider(
color: Colors.transparent,
),
), */
TextFormField(
key: LibraryKeys.loginEmailField,
decoration: InputDecoration(
@ -123,7 +144,7 @@ class RegistrationPage extends StatelessWidget with Trans {
),
TextFormField(
key: LibraryKeys.loginPasswordField,
obscureText: true,
obscureText: loginBloc.obscure,
decoration: InputDecoration(
labelStyle: TextStyle(fontSize: 14),
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
@ -153,6 +174,9 @@ class RegistrationPage extends StatelessWidget with Trans {
color: Colors.transparent,
),
getDataProtection(loginBloc),
Divider(
color: Colors.transparent,
),
Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
FlatButton(
key: LibraryKeys.loginOKButton,
@ -196,22 +220,16 @@ class RegistrationPage extends StatelessWidget with Trans {
}
Widget getDataProtection(LoginBloc loginBloc) {
return ListTile(
subtitle: Text(t("Please accept our data protection policy. For more information please click on 'Privacy'")),
title: ToggleSwitch(
minWidth: 100.0,
minHeight: 30.0,
fontSize: 14.0,
initialLabelIndex: loginBloc.dataPolicyAllowed ? 0 : 1,
activeBgColor: Colors.indigo,
activeFgColor: Colors.white,
inactiveBgColor: Colors.white30,
inactiveFgColor: Colors.black,
labels: [t('Yes'), t('No')],
onToggle: (index) {
loginBloc.add(DataProtectionClicked(marked: index == 0));
},
),
return CheckboxListTile(
title: Text(t("Please accept our data protection policy.")),
subtitle: Text(t("For more information please click on 'Privacy'")),
dense: true,
value: loginBloc.dataPolicyAllowed,
activeColor: Colors.indigo,
onChanged: (value) {
loginBloc.add(DataProtectionClicked(marked: value));
},
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
}
}

View File

@ -12,7 +12,7 @@ class DialogPremium extends StatefulWidget {
String description, function, unlockedText;
final int unlockRound;
final bool unlocked;
bool unlocked;
DialogPremium(
{Key key,
@ -27,6 +27,8 @@ class DialogPremium extends StatefulWidget {
description = description ?? "";
function = function ?? "";
unlockedText = unlockedText ?? "";
unlocked = true;
}
@override
@ -88,9 +90,9 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
alignment: AlignmentDirectional.topEnd,
children: [
Text(
t("Go Premium") + " ",
widget.unlocked ? t("Keep testing") : t("Go Premium") + " ",
style: GoogleFonts.archivoBlack(
fontSize: 24,
fontSize: widget.unlocked ? 18 : 24,
color: Colors.yellow[400],
shadows: <Shadow>[
Shadow(
@ -106,32 +108,34 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
],
),
),
Positioned(
right: 3,
top: 0,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 900),
//reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(child: child, opacity: animation);
},
child: isStart
? Icon(
CustomIcon.star_2,
color: Colors.yellow[300],
)
: Offstage() /* Icon(
!widget.unlocked
? Positioned(
right: 3,
top: 0,
child: AnimatedSwitcher(
duration: Duration(milliseconds: 900),
//reverseDuration: Duration(milliseconds: 200),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(child: child, opacity: animation);
},
child: isStart
? Icon(
CustomIcon.star_2,
color: Colors.yellow[300],
)
: Offstage() /* Icon(
CustomIcon.exclamation_circle,
color: Colors.yellow[300],
) */
)),
))
: Offstage(),
],
),
SizedBox(
height: 35,
),
Text(
t("Unleash your potential with WorkoutTest Premium!"),
widget.unlocked ? "" : t("Unleash your potential with WorkoutTest Premium!"),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.white,
@ -160,7 +164,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () => Navigator.of(context).pushNamed("salesPage"),
onTap: () => widget.unlocked ? Navigator.of(context).pop() : Navigator.of(context).pushNamed("salesPage"),
child: Stack(
alignment: Alignment.center,
children: [
@ -222,61 +226,60 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
List<TextSpan> getDescriptionText() {
List<TextSpan> list = List();
if (widget.unlocked) {
/* if (widget.unlocked) {
list.add(TextSpan(text: widget.unlockedText));
} else {
list.add(TextSpan(text: t("The")));
list.add(TextSpan(text: t(" ")));
list.add(
TextSpan(
text: t(widget.function),
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.yellow[300],
shadows: <Shadow>[
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,
),
],
),
} */
list.add(TextSpan(text: t("The")));
list.add(TextSpan(text: t(" ")));
list.add(
TextSpan(
text: t(widget.function),
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.yellow[300],
shadows: <Shadow>[
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,
),
],
),
);
list.add(TextSpan(text: t(" ")));
list.add(TextSpan(text: t("feature is reachable after you finished")));
list.add(TextSpan(text: t(" ")));
list.add(
TextSpan(
text: widget.unlockRound == 1 ? t("the first") : t("the second"),
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.yellow[300],
shadows: <Shadow>[
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,
),
],
),
),
);
list.add(TextSpan(text: t(" ")));
list.add(TextSpan(text: t("feature is reachable after you finished")));
list.add(TextSpan(text: t(" ")));
list.add(
TextSpan(
text: widget.unlockRound == 1 ? t("the first") : t("the second"),
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.yellow[300],
shadows: <Shadow>[
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,
),
],
),
);
list.add(TextSpan(text: t(" ")));
list.add(TextSpan(text: t("100% test circles")));
}
),
);
list.add(TextSpan(text: t(" ")));
list.add(TextSpan(text: t("100% test circles")));
return list;
}

View File

@ -91,6 +91,6 @@ class _HomePageState extends State<AitrainerHome> with Logging {
@override
void dispose() async {
super.dispose();
await PlatformPurchaseApi().close();
//await PlatformPurchaseApi().close();
}
}

View File

@ -54,7 +54,7 @@ class ImageButton extends StatelessWidget {
//print("Top: " + top.toStringAsFixed(0) + " length: " + ((style.fontSize - 5) * text.length).toString());
}
final double width = MediaQuery.of(context).size.width;
print("Mediawidth: " + width.toStringAsFixed(0));
//print("Mediawidth: " + width.toStringAsFixed(0));
return Stack(alignment: AlignmentDirectional.bottomStart, children: [
FlatButton(
child: image == null
@ -152,11 +152,11 @@ class ImageButton extends StatelessWidget {
imageName,
fit: BoxFit.fitWidth,
alignment: Alignment.center,
errorBuilder: (context, error, stackTrace) {
String url = Cache.mediaUrl + '/' + imageName; //.substring(11);
/* errorBuilder: (context, error, stackTrace) {
String url = Cache.mediaUrl + imageName; //.substring(11);
Widget image = FadeInImage.assetNetwork(placeholder: 'asset/image/dots.gif', image: url, height: this.height);
return image;
},
}, */
);
} on Exception catch (_) {
String url = Cache.mediaUrl + '/images/' + imageName;

View File

@ -22,6 +22,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.6"
apple_sign_in:
dependency: "direct main"
description:
name: apple_sign_in
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
archive:
dependency: transitive
description:
@ -205,7 +212,7 @@ packages:
source: hosted
version: "0.14.2"
crypto:
dependency: transitive
dependency: "direct main"
description:
name: crypto
url: "https://pub.dartlang.org"
@ -281,6 +288,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.1"
firebase:
dependency: transitive
description:
name: firebase
url: "https://pub.dartlang.org"
source: hosted
version: "7.3.3"
firebase_analytics:
dependency: "direct main"
description:
name: firebase_analytics
url: "https://pub.dartlang.org"
source: hosted
version: "6.3.0"
firebase_analytics_platform_interface:
dependency: transitive
description:
name: firebase_analytics_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
firebase_analytics_web:
dependency: transitive
description:
name: firebase_analytics_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
firebase_auth:
dependency: "direct main"
description:
@ -398,13 +433,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
flutter_inapp_purchase:
dependency: "direct main"
description:
name: flutter_inapp_purchase
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
flutter_keyboard_visibility:
dependency: transitive
description:
@ -448,20 +476,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.19.1"
freezed:
dependency: "direct main"
description:
name: freezed
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.6"
freezed_annotation:
dependency: transitive
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0"
glob:
dependency: transitive
description:
@ -476,6 +490,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
google_sign_in:
dependency: "direct main"
description:
name: google_sign_in
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.9"
google_sign_in_platform_interface:
dependency: transitive
description:
name: google_sign_in_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
google_sign_in_web:
dependency: transitive
description:
name: google_sign_in_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.2"
gradient_bottom_navigation_bar:
dependency: "direct main"
description:

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.4+45
version: 1.1.4+46
environment:
sdk: ">=2.7.0 <3.0.0"
@ -30,7 +30,7 @@ dependencies:
sentry: ^3.0.1
flutter_bloc: ^6.1.1
equatable: ^1.2.5
freezed: ^0.12.2
#freezed: ^0.12.2
flutter_form_bloc: ^0.19.0
spider_chart: ^0.1.5
rainbow_color: ^0.1.1
@ -45,17 +45,21 @@ dependencies:
#health: ^3.0.0
stop_watch_timer: ^0.6.0+1
#geolocator: ^6.1.13
flutter_inapp_purchase: ^3.0.1
#flutter_inapp_purchase: ^3.0.1
modal_progress_hud: ^0.1.3
flutter_html: ^1.1.1
wakelock: ^0.2.1+1
firebase_core: ^0.5.2
#firebase_analytics: ^6.2.0
firebase_messaging: ^7.0.3
firebase_core: ^0.5.0
firebase_analytics: ^6.2.0
firebase_messaging: ^7.0.0
firebase_auth: ^0.18.3
flutter_facebook_auth: ^2.0.0+1
google_sign_in: ^4.5.9
apple_sign_in: ^0.1.0
crypto: ^2.1.5
flurry: ^0.0.7
animated_widgets: ^1.0.6
@ -121,6 +125,7 @@ flutter:
- asset/image/WT_black_background.png
- asset/image/WT_black_G_background.png
- asset/image/WT_plainblack_background.png
- asset/image/WT_reg_light_background.png
- asset/image/WT_menu.png
- asset/image/WT_login.png
- asset/image/WT_OK.png
@ -136,8 +141,9 @@ flutter:
- asset/image/WT_Results_for_runners.png
- asset/image/WT_Results_for_female.png
- asset/image/WT_Results_for_men.png
- asset/image/login_fb.png
- asset/image/fb_registration.png
- asset/image/button_fb.png
- asset/image/button_apple.png
- asset/image/button_google.png
- asset/image/lock.png
- asset/image/Congrats_N1.jpg
- asset/image/testemfejl400x400.jpg
@ -178,6 +184,8 @@ flutter:
- asset/image/equipment_home_place.jpg
- asset/image/equipment_gym_place.jpg
- asset/image/equipment_street_place.jpg
- asset/image/ankle_weight.png
- asset/image/vest_weight.png
- asset/image/haken.png
- asset/image/pict_calorie.png
- asset/image/pict_development_by_bodypart_percent.png