feat: integration of apple signin
This commit is contained in:
parent
a9389070bf
commit
4409aef9e2
|
|
@ -9,12 +9,14 @@
|
||||||
"cont": "ቀጥል",
|
"cont": "ቀጥል",
|
||||||
"register": "ይመዝገቡ",
|
"register": "ይመዝገቡ",
|
||||||
"login_with_google": "በጉግል ይግቡ",
|
"login_with_google": "በጉግል ይግቡ",
|
||||||
|
"login_with_apple": "በአፕል ይግቡ",
|
||||||
"or": "ወይም",
|
"or": "ወይም",
|
||||||
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
||||||
"create_account": "አዲስ መለያ ይፍጠሩ",
|
"create_account": "አዲስ መለያ ይፍጠሩ",
|
||||||
"already_have_account": "መለያ አለዎት?",
|
"already_have_account": "መለያ አለዎት?",
|
||||||
"login": " ይግቡ ",
|
"login": " ይግቡ ",
|
||||||
"register_with_google": "በጉግል ይመዝገቡ",
|
"register_with_google": "በጉግል ይመዝገቡ",
|
||||||
|
"register_with_apple": "በአፕል ይመዝገቡ",
|
||||||
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
||||||
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
||||||
"login_with_email": "በኢሜይል ይግቡ",
|
"login_with_email": "በኢሜይል ይግቡ",
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,14 @@
|
||||||
"cont": "Continue",
|
"cont": "Continue",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
"login_with_google": "Login with Google",
|
"login_with_google": "Login with Google",
|
||||||
|
"login_with_apple": "Login with Apple",
|
||||||
"or": "Or",
|
"or": "Or",
|
||||||
"login_with_phone": "Login with phone number",
|
"login_with_phone": "Login with phone number",
|
||||||
"create_account": "Create an account",
|
"create_account": "Create an account",
|
||||||
"already_have_account": "Already have an account?",
|
"already_have_account": "Already have an account?",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"register_with_google": "Register with Google",
|
"register_with_google": "Register with Google",
|
||||||
|
"register_with_apple": "Register with Apple",
|
||||||
"register_with_phone": "Register with phone number",
|
"register_with_phone": "Register with phone number",
|
||||||
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
||||||
"login_with_email": "Login with email",
|
"login_with_email": "Login with email",
|
||||||
|
|
@ -190,7 +192,7 @@
|
||||||
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
|
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
|
||||||
"track_journey": "Track your learning journey and see your growth over time.",
|
"track_journey": "Track your learning journey and see your growth over time.",
|
||||||
"learn_english": "Learn English",
|
"learn_english": "Learn English",
|
||||||
"keep_momentum":"Great job! Keep the momentum.",
|
"keep_momentum": "Great job! Keep the momentum.",
|
||||||
"completed_practices": "Completed Practices",
|
"completed_practices": "Completed Practices",
|
||||||
"total_practices": "Total Practices",
|
"total_practices": "Total Practices",
|
||||||
"progress_percentage": "Progress Percentage"
|
"progress_percentage": "Progress Percentage"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 60;
|
objectVersion = 54;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
ACEEA7C32CFC6E9900D60211 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
A8C2A6C7D1D99F7BA12EAF94 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
A8C2A6C7D1D99F7BA12EAF94 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
F1F6AAAC52D909E27AEDEFC0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
F1F6AAAC52D909E27AEDEFC0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
F9793345F00B89E38C23EBB8 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
F9793345F00B89E38C23EBB8 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
|
@ -163,6 +164,7 @@
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
8E1B3E492C540A0B00F51C11 /* GoogleService-Info.plist */,
|
8E1B3E492C540A0B00F51C11 /* GoogleService-Info.plist */,
|
||||||
|
ACEEA7C32CFC6E9900D60211 /* Runner.entitlements */,
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
|
@ -236,6 +238,11 @@
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
LastSwiftMigration = 1100;
|
LastSwiftMigration = 1100;
|
||||||
|
SystemCapabilities = {
|
||||||
|
com.apple.SignInWithApple = {
|
||||||
|
enabled = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -249,7 +256,7 @@
|
||||||
);
|
);
|
||||||
mainGroup = 97C146E51CF9000F007C117D;
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
|
@ -345,14 +352,10 @@
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
|
@ -366,14 +369,10 @@
|
||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
|
|
@ -509,6 +508,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
|
@ -698,6 +698,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
|
@ -727,6 +728,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
|
@ -785,7 +787,7 @@
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCLocalSwiftPackageReference section */
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
|
||||||
isa = XCLocalSwiftPackageReference;
|
isa = XCLocalSwiftPackageReference;
|
||||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
10
ios/Runner/Runner.entitlements
Normal file
10
ios/Runner/Runner.entitlements
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.developer.applesignin</key>
|
||||||
|
<array>
|
||||||
|
<string>Default</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -56,6 +56,7 @@ import 'package:yimaru_app/services/localization_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/landing_view.dart';
|
import 'package:yimaru_app/ui/views/landing/landing_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
||||||
import 'package:yimaru_app/services/onboarding_service.dart';
|
import 'package:yimaru_app/services/onboarding_service.dart';
|
||||||
|
import 'package:yimaru_app/services/apple_auth_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
|
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/payment/payment_view.dart';
|
import 'package:yimaru_app/ui/views/payment/payment_view.dart';
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
@ -124,6 +125,7 @@ import 'package:yimaru_app/ui/views/payment/payment_view.dart';
|
||||||
LazySingleton(classType: LearnService),
|
LazySingleton(classType: LearnService),
|
||||||
LazySingleton(classType: LocalizationService),
|
LazySingleton(classType: LocalizationService),
|
||||||
LazySingleton(classType: OnboardingService),
|
LazySingleton(classType: OnboardingService),
|
||||||
|
LazySingleton(classType: AppleAuthService),
|
||||||
// @stacked-service
|
// @stacked-service
|
||||||
],
|
],
|
||||||
bottomsheets: [
|
bottomsheets: [
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import 'package:stacked_services/src/navigation/navigation_service.dart';
|
||||||
import 'package:stacked_shared/stacked_shared.dart';
|
import 'package:stacked_shared/stacked_shared.dart';
|
||||||
|
|
||||||
import '../services/api_service.dart';
|
import '../services/api_service.dart';
|
||||||
|
import '../services/apple_auth_service.dart';
|
||||||
import '../services/audio_player_service.dart';
|
import '../services/audio_player_service.dart';
|
||||||
import '../services/authentication_service.dart';
|
import '../services/authentication_service.dart';
|
||||||
import '../services/course_service.dart';
|
import '../services/course_service.dart';
|
||||||
|
|
@ -67,4 +68,5 @@ Future<void> setupLocator(
|
||||||
locator.registerLazySingleton(() => LearnService());
|
locator.registerLazySingleton(() => LearnService());
|
||||||
locator.registerLazySingleton(() => LocalizationService());
|
locator.registerLazySingleton(() => LocalizationService());
|
||||||
locator.registerLazySingleton(() => OnboardingService());
|
locator.registerLazySingleton(() => OnboardingService());
|
||||||
|
locator.registerLazySingleton(() => AppleAuthService());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,34 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apple auth
|
||||||
|
Future<Map<String, dynamic>> appleAuth(Map<String, dynamic> data) async {
|
||||||
|
try {
|
||||||
|
Response response = await _service.dio.post(
|
||||||
|
'$kBaseUrl/$kAppleAuthUrl',
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.success,
|
||||||
|
'message': 'Logged in successfully',
|
||||||
|
'data': User.fromJson(response.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
'message': '${response.data['message']}, ${response.data['error']}'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
'message': e.response?.data.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify otp
|
// Verify otp
|
||||||
Future<Map<String, dynamic>> verifyOtp(Map<String, dynamic> data) async {
|
Future<Map<String, dynamic>> verifyOtp(Map<String, dynamic> data) async {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
36
lib/services/apple_auth_service.dart
Normal file
36
lib/services/apple_auth_service.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
|
class AppleAuthService with ListenableServiceMixin {
|
||||||
|
AuthorizationCredentialAppleID? _appleCredential;
|
||||||
|
|
||||||
|
AuthorizationCredentialAppleID? get appleCredential => _appleCredential;
|
||||||
|
|
||||||
|
AppleAuthService() {
|
||||||
|
listenToReactiveValues([_appleCredential]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isSupported => Platform.isIOS;
|
||||||
|
|
||||||
|
Future<void> appleAuth() async {
|
||||||
|
if (!isSupported) {
|
||||||
|
throw UnsupportedError('Apple Sign-In is only available on iOS.');
|
||||||
|
}
|
||||||
|
|
||||||
|
_appleCredential = await SignInWithApple.getAppleIDCredential(
|
||||||
|
scopes: [
|
||||||
|
AppleIDAuthorizationScopes.email,
|
||||||
|
AppleIDAuthorizationScopes.fullName,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void logout() {
|
||||||
|
_appleCredential = null;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -101,6 +101,8 @@ String kLessonProgressUrl = 'api/v1/progress/videos';
|
||||||
|
|
||||||
String kGoogleAuthUrl = 'api/v1/auth/google/android';
|
String kGoogleAuthUrl = 'api/v1/auth/google/android';
|
||||||
|
|
||||||
|
String kAppleAuthUrl = 'api/v1/auth/apple';
|
||||||
|
|
||||||
String kCourseProgressUrl = 'api/v1/progress/courses';
|
String kCourseProgressUrl = 'api/v1/progress/courses';
|
||||||
|
|
||||||
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
||||||
|
|
@ -124,5 +126,4 @@ String kTelegramSupportLink = 'https://t.me/yimaruacademy2026';
|
||||||
|
|
||||||
String kErrorUrl = 'https://api.yimaruacademy.com/payment/error';
|
String kErrorUrl = 'https://api.yimaruacademy.com/payment/error';
|
||||||
|
|
||||||
String kSuccessUrl =
|
String kSuccessUrl = 'https://api.yimaruacademy.com/payment/success';
|
||||||
'https://api.yimaruacademy.com/payment/success';
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ enum Voice { sample, recorded }
|
||||||
enum ResponseStatus { success, failure }
|
enum ResponseStatus { success, failure }
|
||||||
|
|
||||||
// Login method
|
// Login method
|
||||||
enum LoginMethod { phone, email, google }
|
enum LoginMethod { phone, email, google, apple }
|
||||||
|
|
||||||
// Sign-up method
|
// Sign-up method
|
||||||
enum SignUpMethod { phone, email, google }
|
enum SignUpMethod { phone, email, google, apple }
|
||||||
|
|
||||||
// Learn practice
|
// Learn practice
|
||||||
enum LearnPractices { course, module, lesson }
|
enum LearnPractices { course, module, lesson }
|
||||||
|
|
@ -61,7 +61,9 @@ enum StateObjects {
|
||||||
profileCompletion,
|
profileCompletion,
|
||||||
learnSubscription,
|
learnSubscription,
|
||||||
learnSubscriptions,
|
learnSubscriptions,
|
||||||
|
loginWithApple,
|
||||||
registerWithGoogle,
|
registerWithGoogle,
|
||||||
|
registerWithApple,
|
||||||
learnPracticeSample,
|
learnPracticeSample,
|
||||||
learnPracticeAnswer,
|
learnPracticeAnswer,
|
||||||
loginWithPhoneNumber,
|
loginWithPhoneNumber,
|
||||||
|
|
|
||||||
|
|
@ -14,204 +14,7 @@ class CodegenLoader extends AssetLoader{
|
||||||
return Future.value(mapLocales[locale.toString()]);
|
return Future.value(mapLocales[locale.toString()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Map<String,dynamic> _am = {
|
static const Map<String,dynamic> _en = {
|
||||||
"loading": "በመጫን ላይ",
|
|
||||||
"welcome_back": "እንኳን በደህና ተመለሱ",
|
|
||||||
"checking_user_info": "የተጠቃሚ መረጃን በማረጋገጥ ላይ",
|
|
||||||
"dont_have_account": "መለያ የለዎትም?",
|
|
||||||
"email": "ኢሜይል",
|
|
||||||
"password": "የይለፍ ቃል",
|
|
||||||
"forgot_password": "የይለፍ ቃል ረሱ?",
|
|
||||||
"cont": "ቀጥል",
|
|
||||||
"register": "ይመዝገቡ",
|
|
||||||
"login_with_google": "በጉግል ይግቡ",
|
|
||||||
"or": "ወይም",
|
|
||||||
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
|
||||||
"create_account": "አዲስ መለያ ይፍጠሩ",
|
|
||||||
"already_have_account": "መለያ አለዎት?",
|
|
||||||
"login": " ይግቡ ",
|
|
||||||
"register_with_google": "በጉግል ይመዝገቡ",
|
|
||||||
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
|
||||||
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
|
||||||
"login_with_email": "በኢሜይል ይግቡ",
|
|
||||||
"create_password": "የይለፍ ቃል ይፍጠሩ",
|
|
||||||
"confirm_password": "የይለፍ ቃል ያረጋግጡ",
|
|
||||||
"eight_character_minimum": "ቢያንስ 8 ፊደላት",
|
|
||||||
"password_match": "የይለፍ ቃሉ ተመሳስሏል",
|
|
||||||
"sign_up_agreement": "‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
|
|
||||||
"terms_of_services": "የአገልግሎት ውሎች",
|
|
||||||
"and": "እና",
|
|
||||||
"privacy_policy": "የግላዊነት ፖሊሲ",
|
|
||||||
"register_with_email": "በኢሜል ይመዝገቡ",
|
|
||||||
"verification_code": "የማረጋገጫ ኮድ",
|
|
||||||
"resend_code": "ኮዱን እንደገና ላክ",
|
|
||||||
"code_sent_to_phone": "ኮዱ ወደ ስልክ ቁጥርዎ ተልኳል",
|
|
||||||
"code_sent_to_email": "ኮዱ ወደ ኢሜል ተልኳል",
|
|
||||||
"resend_code_in": "ኮዱን እንደገና ለመላክ የቀረው ጊዜ",
|
|
||||||
"reset_password": " የይለፍ ቃልን ይቀይሩ",
|
|
||||||
"enter_email_reset_code": "ኢሜይልዎን ያስገቡ። የይለፍ ቃል መለወጫ ኮድ እንልክልዎታለን።",
|
|
||||||
"please_wait": "እባክዎ ይጠብቁ",
|
|
||||||
"reset_code_sent": "የመቀየሪያ ኮድ በተሳካ ሁኔታ ተልኳል",
|
|
||||||
"reset_code": " የመቀየሪያ ኮድ ",
|
|
||||||
"new_password": "አዲስ የይለፍ ቃል",
|
|
||||||
"logged_in_successfully": "በተሳካ ሁኔታ ገብተዋል",
|
|
||||||
"view_course": " ኮርሱን ይመልከቱ",
|
|
||||||
"continue_learning": "መማርን ይቀጥሉ",
|
|
||||||
"start_learning": "ትምህርትን ይጀምሩ",
|
|
||||||
"completed": "ተጠናቋል",
|
|
||||||
"take_practice": "ልምምድ ያድርጉ",
|
|
||||||
"your_current_level": "የአሁኑ ደረጃዎ",
|
|
||||||
"overall_progress": "አጠቃላይ እድገት",
|
|
||||||
"great_work": "በርቱ! በጣም ጥሩ እየሰሩ ነው",
|
|
||||||
"view_module": "ሞጁሉን ይመልከቱ",
|
|
||||||
"progress": "እድገት",
|
|
||||||
"keep_going": "ይቀጥሉ - ከግማሽ በላይ ጨርሰዋል ",
|
|
||||||
"lessons_in_module": "በዚህ ሞጁል ውስጥ ያሉ ትምህርቶች ",
|
|
||||||
"practice": "ልምምድ",
|
|
||||||
"start": "ጀምር",
|
|
||||||
"in_progress": "በሂደት ላይ",
|
|
||||||
"hello": "ሰላም",
|
|
||||||
"ready_to_learn": " ዛሬ እንግሊዝኛ ለመማር ተዘጋጅተዋል? ",
|
|
||||||
"learn": "ይማሩ ",
|
|
||||||
"course": "ኮርስ",
|
|
||||||
"profile": " ፕሮፋይል ",
|
|
||||||
"speaking_partner": "የንግግር ጓደኛ",
|
|
||||||
"practice_what_you_learned": "አሁን የተማሩትን እንለማመድ",
|
|
||||||
"practice_questions": "ጥቂት ጥያቄዎችን እጠይቃለሁ እና መልስ መስጠት ይችላሉ",
|
|
||||||
"start_practice": "ልምምድ ጀምር",
|
|
||||||
"almost_there": "ሊጨርሱ ተቃርበዋል",
|
|
||||||
"finish_session": "እድገትዎን ለማየት ክፍለ ጊዜውን ያጠናቅቁ",
|
|
||||||
"continue_practice": "ልምምዱን ይቀጥሉ",
|
|
||||||
"end_session": "ክፍለ ጊዜውን ያብቁ ",
|
|
||||||
"tap_start_to_listen": "ለማዳመጥ የጀምር ቁልፉን ይጫኑ",
|
|
||||||
"practice_speaking": "ንግግርን ይለማመዱ",
|
|
||||||
"tap_microphone": "ለመናገር ማይክሮፎኑን ይጫኑ",
|
|
||||||
"reply": "እንደገና አዳምጥ",
|
|
||||||
"cancel": "ይቅር",
|
|
||||||
"you_are_speaking": "እየተናገሩ ነው",
|
|
||||||
"practice_completed": "ልምምዱ ተጠናቅቋል",
|
|
||||||
"great_improvement": "በዚህኛው በራስ መተማመንዎ ጨምሯል፤ ትልቅ መሻሻል ነው",
|
|
||||||
"practice_again": "እንደገና ይለማመዱ",
|
|
||||||
"conversation_review": "የንግግር ግምገማ",
|
|
||||||
"result": "ውጤት",
|
|
||||||
"quick_tip": "ጠቃሚ ምክር",
|
|
||||||
"retry": "እንደገና ይሞክሩ",
|
|
||||||
"completed_a1": "እንኳን ደስ አለዎት! A1 ደረጃን አጠናቅቀዋል",
|
|
||||||
"analyzing_speaking": "የንግግር ችሎታዎን እየገመገምን ነው",
|
|
||||||
"view_profile": "ፕሮፋይሎን ይመልከቱ ",
|
|
||||||
"hi": "ሰላም",
|
|
||||||
"edit_profile": "መገለጫ ያስተካክሉ",
|
|
||||||
"first_name": "የመጀመሪያ ስም",
|
|
||||||
"last_name": "የአባት ስም",
|
|
||||||
"gender": "ፆታ",
|
|
||||||
"male": "ወንድ",
|
|
||||||
"female": "ሴት",
|
|
||||||
"phone_number": "የስልክ ቁጥር",
|
|
||||||
"country": "ሀገር",
|
|
||||||
"region": "ክልል",
|
|
||||||
"select_region": "ክልል ይምረጡ",
|
|
||||||
"enter_your_city": "ከተማዎን ያስገቡ",
|
|
||||||
"occupation": "የስራ መስክ",
|
|
||||||
"select_occupation": "ሙያዎን ይምረጡ",
|
|
||||||
"save_changes": "ለውጦችን ያስቀምጡ",
|
|
||||||
"my_progress": "የእኔ እድገት",
|
|
||||||
"track_your_achievement": "ስኬቶችዎን እና ተከታታይ የትምህርት ጉዞዎን ይከታተሉ",
|
|
||||||
"account_and_privacy": "መለያ እና ግላዊነት",
|
|
||||||
"manage_settings": "ቅንብሮችን እና የመተግበሪያ ምርጫዎችን ያስተዳድሩ",
|
|
||||||
"support": "ድጋፍ",
|
|
||||||
"get_help": "በስልክ ወይም በቴሌግራም እገዛ ያግኙ",
|
|
||||||
"logout": "ውጣ",
|
|
||||||
"app_settings": "የመተግበሪያ ቅንብሮች",
|
|
||||||
"legal_and_information": "ሕጋዊ እና መረጃ",
|
|
||||||
"change_language": "ቋንቋ ቀይር",
|
|
||||||
"terms_and_conditions": "ውሎች እና ሁኔታዎች",
|
|
||||||
"delete_account": "መለያ ሰርዝ",
|
|
||||||
"language_preference": "የቋንቋ ምርጫ",
|
|
||||||
"choose_your_language": "ለውጦችን አስቀምጥ",
|
|
||||||
"switch_language_anytime": "ቋንቋዎችን በማንኛውም ጊዜ መቀየር ይችላሉ",
|
|
||||||
"need_help": "እገዛ ይፈልጋሉ?",
|
|
||||||
"call_support": "የስልክ ድጋፍ",
|
|
||||||
"talk_with_support": "በቀጥታ ከድጋፍ ቡድናችን ጋር ይነጋገሩ",
|
|
||||||
"telegram_support": "የቴሌግራም ድጋፍ",
|
|
||||||
"chat_via_telegram": "በቴሌግራም በፍጥነት ይወያዩ",
|
|
||||||
"call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ",
|
|
||||||
"tap_to_call": "ለመደወል ይንኩ",
|
|
||||||
"join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ",
|
|
||||||
"connect_with_support_team": "ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
|
|
||||||
"open_in_telegram": "በቴሌግራም ይክፈቱ",
|
|
||||||
"search_for": "ፈልጉት",
|
|
||||||
"current_level": "የአሁኑ ደረጃ",
|
|
||||||
"keep_up_the_great_work": "በጣም ጥሩ እየሰራህ ነው! ቀጥልበት፣ አስደናቂ ነህ።",
|
|
||||||
"no_practice_available": "ምንም ልምምድ አልተገኘም!",
|
|
||||||
"begin_module_practice": "የሞጁሉን ልምምድ ጀምር",
|
|
||||||
"lets_practice_lesson": "እንለማመድ",
|
|
||||||
"lets_quickly_review": "በዚህ ሞጁል ውስጥ የተማርከውን በፍጥነት እንከልስ!",
|
|
||||||
"lets_practice_module": "አሁን የተማርከውን እንለማመድ!",
|
|
||||||
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
|
||||||
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
|
||||||
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
|
||||||
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
|
||||||
"speaking": "እየተናገረ ነው",
|
|
||||||
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
|
||||||
"view_results": "ውጤቶቼን እይ",
|
|
||||||
"sample_answer": "ናሙና መልስ",
|
|
||||||
"your_answer": "መልስህ",
|
|
||||||
"sound_confident": "በዚህ ጊዜ የበለጠ እምነት ያለህ ይመስላል — በጣም ጥሩ መሻሻል ነው!",
|
|
||||||
"you_have_completed": "አያይ! አጠናቀቅህ",
|
|
||||||
"yes": "አዎ",
|
|
||||||
"no": "አይ",
|
|
||||||
"want_to_quit": "ለመውጣት እርግጠኛ ነህ?",
|
|
||||||
"required_field": "ይህ መስክ ያስፈልጋል",
|
|
||||||
"enter_full_name": "ሙሉ ስምህን አስገባ",
|
|
||||||
"invalid_email": "የማይሰራ የኢሜይል ቅርጸት",
|
|
||||||
"phone_must_start_with": "የስልክ ቁጥር በ251 መጀመር አለበት",
|
|
||||||
"phone_must_be": "የስልክ ቁጥር 12 አሃዞች መሆን አለበት",
|
|
||||||
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
|
||||||
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
|
||||||
"choose_your_gender": "ጾታህን ምረጥ",
|
|
||||||
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
|
||||||
"age_range": "በየትኛው የእድሜ ክልል ውስጥ ነህ?",
|
|
||||||
"age_for_personalization": "በእድሜህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
|
||||||
"educational_background": "አሁን ያለህ የትምህርት ደረጃ ምንድን ነው?",
|
|
||||||
"education_for_personalization": "ይህ ትምህርቶችን ከልምድህ ጋር እንዲስማሙ ለማድረግ ይረዳናል።",
|
|
||||||
"your_occupation": "ስራህ ምንድን ነው?",
|
|
||||||
"occupation_for_personalization": "በስራህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
|
||||||
"location": "ከየት ነህ?",
|
|
||||||
"select_country_region": "አገርህን እና ክልልህን ከተቆልቋይ ዝርዝሩ ምረጥ",
|
|
||||||
"select_country": "አገር ምረጥ",
|
|
||||||
"learning_goal": "የመማር ዓላማህን ምረጥ",
|
|
||||||
"language_goal": "እንግሊዝኛህን ለማሻሻል ዋና ዓላማህ ምንድን ነው?",
|
|
||||||
"your_goal": "ዓላማህ የመማር ጉዞህን እንዲስማማ ለማድረግ ይረዳናል።",
|
|
||||||
"write_your_goal": "ዓላማህን ጻፍ…",
|
|
||||||
"challenge_you_face": "What challenge do you face most with English?",
|
|
||||||
"evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ",
|
|
||||||
"write_your_challenge": "ችግርህን ጻፍ…",
|
|
||||||
"topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?",
|
|
||||||
"favourite_topic": "የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
|
|
||||||
"your_interest": "ፍላጎትህን ጻፍ…",
|
|
||||||
"want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?",
|
|
||||||
"answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።",
|
|
||||||
"skip": "ዝለል",
|
|
||||||
"finish_level": "ደረጃውን አጠናቅቅ",
|
|
||||||
"likely_speaker": "አንተ ምናልባት ተናጋሪ ነህ",
|
|
||||||
"great_job": "በጣም ጥሩ ስራ! ለመሻሻል ቀጣዩ ደረጃህ ይኸው ነው።",
|
|
||||||
"lets_start_practice": "ልምምድህን እንጀምር",
|
|
||||||
"welcome_abroad": "እንኳን ደህና መጣህ",
|
|
||||||
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
|
||||||
"finish": "አጠናቅቅ",
|
|
||||||
"finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
|
|
||||||
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
|
|
||||||
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
|
|
||||||
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
|
|
||||||
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ",
|
|
||||||
"track_journey": "የትምህርት ጉዞዎን ይከታተሉ እና በጊዜ ሂደት ያሳዩትን እድገት ይመልከቱ።",
|
|
||||||
"learn_english": "እንግሊዝኛ ይማሩ",
|
|
||||||
"keep_momentum": "በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
|
|
||||||
"completed_practices": "የተጠናቀቁ ልምምዶች",
|
|
||||||
"total_practices": "ጠቅላላ ልምምዶች",
|
|
||||||
"progress_percentage": "የእድገት መቶኛ"
|
|
||||||
};
|
|
||||||
static const Map<String,dynamic> _en = {
|
|
||||||
"loading": "Loading",
|
"loading": "Loading",
|
||||||
"welcome_back": "Welcome back",
|
"welcome_back": "Welcome back",
|
||||||
"checking_user_info": "Checking user info",
|
"checking_user_info": "Checking user info",
|
||||||
|
|
@ -222,12 +25,14 @@ static const Map<String,dynamic> _en = {
|
||||||
"cont": "Continue",
|
"cont": "Continue",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
"login_with_google": "Login with Google",
|
"login_with_google": "Login with Google",
|
||||||
|
"login_with_apple": "Login with Apple",
|
||||||
"or": "Or",
|
"or": "Or",
|
||||||
"login_with_phone": "Login with phone number",
|
"login_with_phone": "Login with phone number",
|
||||||
"create_account": "Create an account",
|
"create_account": "Create an account",
|
||||||
"already_have_account": "Already have an account?",
|
"already_have_account": "Already have an account?",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"register_with_google": "Register with Google",
|
"register_with_google": "Register with Google",
|
||||||
|
"register_with_apple": "Register with Apple",
|
||||||
"register_with_phone": "Register with phone number",
|
"register_with_phone": "Register with phone number",
|
||||||
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
|
||||||
"login_with_email": "Login with email",
|
"login_with_email": "Login with email",
|
||||||
|
|
@ -408,5 +213,204 @@ static const Map<String,dynamic> _en = {
|
||||||
"total_practices": "Total Practices",
|
"total_practices": "Total Practices",
|
||||||
"progress_percentage": "Progress Percentage"
|
"progress_percentage": "Progress Percentage"
|
||||||
};
|
};
|
||||||
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
|
static const Map<String,dynamic> _am = {
|
||||||
|
"loading": "በመጫን ላይ",
|
||||||
|
"welcome_back": "እንኳን በደህና ተመለሱ",
|
||||||
|
"checking_user_info": "የተጠቃሚ መረጃን በማረጋገጥ ላይ",
|
||||||
|
"dont_have_account": "መለያ የለዎትም?",
|
||||||
|
"email": "ኢሜይል",
|
||||||
|
"password": "የይለፍ ቃል",
|
||||||
|
"forgot_password": "የይለፍ ቃል ረሱ?",
|
||||||
|
"cont": "ቀጥል",
|
||||||
|
"register": "ይመዝገቡ",
|
||||||
|
"login_with_google": "በጉግል ይግቡ",
|
||||||
|
"login_with_apple": "በአፕል ይግቡ",
|
||||||
|
"or": "ወይም",
|
||||||
|
"login_with_phone": "በስልክ ቁጥር ይግቡ",
|
||||||
|
"create_account": "አዲስ መለያ ይፍጠሩ",
|
||||||
|
"already_have_account": "መለያ አለዎት?",
|
||||||
|
"login": " ይግቡ ",
|
||||||
|
"register_with_google": "በጉግል ይመዝገቡ",
|
||||||
|
"register_with_apple": "በአፕል ይመዝገቡ",
|
||||||
|
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
|
||||||
|
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
|
||||||
|
"login_with_email": "በኢሜይል ይግቡ",
|
||||||
|
"create_password": "የይለፍ ቃል ይፍጠሩ",
|
||||||
|
"confirm_password": "የይለፍ ቃል ያረጋግጡ",
|
||||||
|
"eight_character_minimum": "ቢያንስ 8 ፊደላት",
|
||||||
|
"password_match": "የይለፍ ቃሉ ተመሳስሏል",
|
||||||
|
"sign_up_agreement": "‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
|
||||||
|
"terms_of_services": "የአገልግሎት ውሎች",
|
||||||
|
"and": "እና",
|
||||||
|
"privacy_policy": "የግላዊነት ፖሊሲ",
|
||||||
|
"register_with_email": "በኢሜል ይመዝገቡ",
|
||||||
|
"verification_code": "የማረጋገጫ ኮድ",
|
||||||
|
"resend_code": "ኮዱን እንደገና ላክ",
|
||||||
|
"code_sent_to_phone": "ኮዱ ወደ ስልክ ቁጥርዎ ተልኳል",
|
||||||
|
"code_sent_to_email": "ኮዱ ወደ ኢሜል ተልኳል",
|
||||||
|
"resend_code_in": "ኮዱን እንደገና ለመላክ የቀረው ጊዜ",
|
||||||
|
"reset_password": " የይለፍ ቃልን ይቀይሩ",
|
||||||
|
"enter_email_reset_code": "ኢሜይልዎን ያስገቡ። የይለፍ ቃል መለወጫ ኮድ እንልክልዎታለን።",
|
||||||
|
"please_wait": "እባክዎ ይጠብቁ",
|
||||||
|
"reset_code_sent": "የመቀየሪያ ኮድ በተሳካ ሁኔታ ተልኳል",
|
||||||
|
"reset_code": " የመቀየሪያ ኮድ ",
|
||||||
|
"new_password": "አዲስ የይለፍ ቃል",
|
||||||
|
"logged_in_successfully": "በተሳካ ሁኔታ ገብተዋል",
|
||||||
|
"view_course": " ኮርሱን ይመልከቱ",
|
||||||
|
"continue_learning": "መማርን ይቀጥሉ",
|
||||||
|
"start_learning": "ትምህርትን ይጀምሩ",
|
||||||
|
"completed": "ተጠናቋል",
|
||||||
|
"take_practice": "ልምምድ ያድርጉ",
|
||||||
|
"your_current_level": "የአሁኑ ደረጃዎ",
|
||||||
|
"overall_progress": "አጠቃላይ እድገት",
|
||||||
|
"great_work": "በርቱ! በጣም ጥሩ እየሰሩ ነው",
|
||||||
|
"view_module": "ሞጁሉን ይመልከቱ",
|
||||||
|
"progress": "እድገት",
|
||||||
|
"keep_going": "ይቀጥሉ - ከግማሽ በላይ ጨርሰዋል ",
|
||||||
|
"lessons_in_module": "በዚህ ሞጁል ውስጥ ያሉ ትምህርቶች ",
|
||||||
|
"practice": "ልምምድ",
|
||||||
|
"start": "ጀምር",
|
||||||
|
"in_progress": "በሂደት ላይ",
|
||||||
|
"hello": "ሰላም",
|
||||||
|
"ready_to_learn": " ዛሬ እንግሊዝኛ ለመማር ተዘጋጅተዋል? ",
|
||||||
|
"learn": "ይማሩ ",
|
||||||
|
"course": "ኮርስ",
|
||||||
|
"profile": " ፕሮፋይል ",
|
||||||
|
"speaking_partner": "የንግግር ጓደኛ",
|
||||||
|
"practice_what_you_learned": "አሁን የተማሩትን እንለማመድ",
|
||||||
|
"practice_questions": "ጥቂት ጥያቄዎችን እጠይቃለሁ እና መልስ መስጠት ይችላሉ",
|
||||||
|
"start_practice": "ልምምድ ጀምር",
|
||||||
|
"almost_there": "ሊጨርሱ ተቃርበዋል",
|
||||||
|
"finish_session": "እድገትዎን ለማየት ክፍለ ጊዜውን ያጠናቅቁ",
|
||||||
|
"continue_practice": "ልምምዱን ይቀጥሉ",
|
||||||
|
"end_session": "ክፍለ ጊዜውን ያብቁ ",
|
||||||
|
"tap_start_to_listen": "ለማዳመጥ የጀምር ቁልፉን ይጫኑ",
|
||||||
|
"practice_speaking": "ንግግርን ይለማመዱ",
|
||||||
|
"tap_microphone": "ለመናገር ማይክሮፎኑን ይጫኑ",
|
||||||
|
"reply": "እንደገና አዳምጥ",
|
||||||
|
"cancel": "ይቅር",
|
||||||
|
"you_are_speaking": "እየተናገሩ ነው",
|
||||||
|
"practice_completed": "ልምምዱ ተጠናቅቋል",
|
||||||
|
"great_improvement": "በዚህኛው በራስ መተማመንዎ ጨምሯል፤ ትልቅ መሻሻል ነው",
|
||||||
|
"practice_again": "እንደገና ይለማመዱ",
|
||||||
|
"conversation_review": "የንግግር ግምገማ",
|
||||||
|
"result": "ውጤት",
|
||||||
|
"quick_tip": "ጠቃሚ ምክር",
|
||||||
|
"retry": "እንደገና ይሞክሩ",
|
||||||
|
"completed_a1": "እንኳን ደስ አለዎት! A1 ደረጃን አጠናቅቀዋል",
|
||||||
|
"analyzing_speaking": "የንግግር ችሎታዎን እየገመገምን ነው",
|
||||||
|
"view_profile": "ፕሮፋይሎን ይመልከቱ ",
|
||||||
|
"hi": "ሰላም",
|
||||||
|
"edit_profile": "መገለጫ ያስተካክሉ",
|
||||||
|
"first_name": "የመጀመሪያ ስም",
|
||||||
|
"last_name": "የአባት ስም",
|
||||||
|
"gender": "ፆታ",
|
||||||
|
"male": "ወንድ",
|
||||||
|
"female": "ሴት",
|
||||||
|
"phone_number": "የስልክ ቁጥር",
|
||||||
|
"country": "ሀገር",
|
||||||
|
"region": "ክልል",
|
||||||
|
"select_region": "ክልል ይምረጡ",
|
||||||
|
"enter_your_city": "ከተማዎን ያስገቡ",
|
||||||
|
"occupation": "የስራ መስክ",
|
||||||
|
"select_occupation": "ሙያዎን ይምረጡ",
|
||||||
|
"save_changes": "ለውጦችን ያስቀምጡ",
|
||||||
|
"my_progress": "የእኔ እድገት",
|
||||||
|
"track_your_achievement": "ስኬቶችዎን እና ተከታታይ የትምህርት ጉዞዎን ይከታተሉ",
|
||||||
|
"account_and_privacy": "መለያ እና ግላዊነት",
|
||||||
|
"manage_settings": "ቅንብሮችን እና የመተግበሪያ ምርጫዎችን ያስተዳድሩ",
|
||||||
|
"support": "ድጋፍ",
|
||||||
|
"get_help": "በስልክ ወይም በቴሌግራም እገዛ ያግኙ",
|
||||||
|
"logout": "ውጣ",
|
||||||
|
"app_settings": "የመተግበሪያ ቅንብሮች",
|
||||||
|
"legal_and_information": "ሕጋዊ እና መረጃ",
|
||||||
|
"change_language": "ቋንቋ ቀይር",
|
||||||
|
"terms_and_conditions": "ውሎች እና ሁኔታዎች",
|
||||||
|
"delete_account": "መለያ ሰርዝ",
|
||||||
|
"language_preference": "የቋንቋ ምርጫ",
|
||||||
|
"choose_your_language": "ለውጦችን አስቀምጥ",
|
||||||
|
"switch_language_anytime": "ቋንቋዎችን በማንኛውም ጊዜ መቀየር ይችላሉ",
|
||||||
|
"need_help": "እገዛ ይፈልጋሉ?",
|
||||||
|
"call_support": "የስልክ ድጋፍ",
|
||||||
|
"talk_with_support": "በቀጥታ ከድጋፍ ቡድናችን ጋር ይነጋገሩ",
|
||||||
|
"telegram_support": "የቴሌግራም ድጋፍ",
|
||||||
|
"chat_via_telegram": "በቴሌግራም በፍጥነት ይወያዩ",
|
||||||
|
"call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ",
|
||||||
|
"tap_to_call": "ለመደወል ይንኩ",
|
||||||
|
"join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ",
|
||||||
|
"connect_with_support_team": "ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
|
||||||
|
"open_in_telegram": "በቴሌግራም ይክፈቱ",
|
||||||
|
"search_for": "ፈልጉት",
|
||||||
|
"current_level": "የአሁኑ ደረጃ",
|
||||||
|
"keep_up_the_great_work": "በጣም ጥሩ እየሰራህ ነው! ቀጥልበት፣ አስደናቂ ነህ።",
|
||||||
|
"no_practice_available": "ምንም ልምምድ አልተገኘም!",
|
||||||
|
"begin_module_practice": "የሞጁሉን ልምምድ ጀምር",
|
||||||
|
"lets_practice_lesson": "እንለማመድ",
|
||||||
|
"lets_quickly_review": "በዚህ ሞጁል ውስጥ የተማርከውን በፍጥነት እንከልስ!",
|
||||||
|
"lets_practice_module": "አሁን የተማርከውን እንለማመድ!",
|
||||||
|
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
||||||
|
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
||||||
|
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
||||||
|
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
||||||
|
"speaking": "እየተናገረ ነው",
|
||||||
|
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
||||||
|
"view_results": "ውጤቶቼን እይ",
|
||||||
|
"sample_answer": "ናሙና መልስ",
|
||||||
|
"your_answer": "መልስህ",
|
||||||
|
"sound_confident": "በዚህ ጊዜ የበለጠ እምነት ያለህ ይመስላል — በጣም ጥሩ መሻሻል ነው!",
|
||||||
|
"you_have_completed": "አያይ! አጠናቀቅህ",
|
||||||
|
"yes": "አዎ",
|
||||||
|
"no": "አይ",
|
||||||
|
"want_to_quit": "ለመውጣት እርግጠኛ ነህ?",
|
||||||
|
"required_field": "ይህ መስክ ያስፈልጋል",
|
||||||
|
"enter_full_name": "ሙሉ ስምህን አስገባ",
|
||||||
|
"invalid_email": "የማይሰራ የኢሜይል ቅርጸት",
|
||||||
|
"phone_must_start_with": "የስልክ ቁጥር በ251 መጀመር አለበት",
|
||||||
|
"phone_must_be": "የስልክ ቁጥር 12 አሃዞች መሆን አለበት",
|
||||||
|
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
||||||
|
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
||||||
|
"choose_your_gender": "ጾታህን ምረጥ",
|
||||||
|
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
||||||
|
"age_range": "በየትኛው የእድሜ ክልል ውስጥ ነህ?",
|
||||||
|
"age_for_personalization": "በእድሜህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
||||||
|
"educational_background": "አሁን ያለህ የትምህርት ደረጃ ምንድን ነው?",
|
||||||
|
"education_for_personalization": "ይህ ትምህርቶችን ከልምድህ ጋር እንዲስማሙ ለማድረግ ይረዳናል።",
|
||||||
|
"your_occupation": "ስራህ ምንድን ነው?",
|
||||||
|
"occupation_for_personalization": "በስራህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
|
||||||
|
"location": "ከየት ነህ?",
|
||||||
|
"select_country_region": "አገርህን እና ክልልህን ከተቆልቋይ ዝርዝሩ ምረጥ",
|
||||||
|
"select_country": "አገር ምረጥ",
|
||||||
|
"learning_goal": "የመማር ዓላማህን ምረጥ",
|
||||||
|
"language_goal": "እንግሊዝኛህን ለማሻሻል ዋና ዓላማህ ምንድን ነው?",
|
||||||
|
"your_goal": "ዓላማህ የመማር ጉዞህን እንዲስማማ ለማድረግ ይረዳናል።",
|
||||||
|
"write_your_goal": "ዓላማህን ጻፍ…",
|
||||||
|
"challenge_you_face": "What challenge do you face most with English?",
|
||||||
|
"evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ",
|
||||||
|
"write_your_challenge": "ችግርህን ጻፍ…",
|
||||||
|
"topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?",
|
||||||
|
"favourite_topic": "የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
|
||||||
|
"your_interest": "ፍላጎትህን ጻፍ…",
|
||||||
|
"want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?",
|
||||||
|
"answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።",
|
||||||
|
"skip": "ዝለል",
|
||||||
|
"finish_level": "ደረጃውን አጠናቅቅ",
|
||||||
|
"likely_speaker": "አንተ ምናልባት ተናጋሪ ነህ",
|
||||||
|
"great_job": "በጣም ጥሩ ስራ! ለመሻሻል ቀጣዩ ደረጃህ ይኸው ነው።",
|
||||||
|
"lets_start_practice": "ልምምድህን እንጀምር",
|
||||||
|
"welcome_abroad": "እንኳን ደህና መጣህ",
|
||||||
|
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
||||||
|
"finish": "አጠናቅቅ",
|
||||||
|
"finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
|
||||||
|
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
|
||||||
|
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
|
||||||
|
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
|
||||||
|
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ",
|
||||||
|
"track_journey": "የትምህርት ጉዞዎን ይከታተሉ እና በጊዜ ሂደት ያሳዩትን እድገት ይመልከቱ።",
|
||||||
|
"learn_english": "እንግሊዝኛ ይማሩ",
|
||||||
|
"keep_momentum": "በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
|
||||||
|
"completed_practices": "የተጠናቀቁ ልምምዶች",
|
||||||
|
"total_practices": "ጠቅላላ ልምምዶች",
|
||||||
|
"progress_percentage": "የእድገት መቶኛ"
|
||||||
|
};
|
||||||
|
static const Map<String, Map<String,dynamic>> mapLocales = {"en": _en, "am": _am};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,14 @@ abstract class LocaleKeys {
|
||||||
static const cont = 'cont';
|
static const cont = 'cont';
|
||||||
static const register = 'register';
|
static const register = 'register';
|
||||||
static const login_with_google = 'login_with_google';
|
static const login_with_google = 'login_with_google';
|
||||||
|
static const login_with_apple = 'login_with_apple';
|
||||||
static const or = 'or';
|
static const or = 'or';
|
||||||
static const login_with_phone = 'login_with_phone';
|
static const login_with_phone = 'login_with_phone';
|
||||||
static const create_account = 'create_account';
|
static const create_account = 'create_account';
|
||||||
static const already_have_account = 'already_have_account';
|
static const already_have_account = 'already_have_account';
|
||||||
static const login = 'login';
|
static const login = 'login';
|
||||||
static const register_with_google = 'register_with_google';
|
static const register_with_google = 'register_with_google';
|
||||||
|
static const register_with_apple = 'register_with_apple';
|
||||||
static const register_with_phone = 'register_with_phone';
|
static const register_with_phone = 'register_with_phone';
|
||||||
static const enter_phone_number = 'enter_phone_number';
|
static const enter_phone_number = 'enter_phone_number';
|
||||||
static const login_with_email = 'login_with_email';
|
static const login_with_email = 'login_with_email';
|
||||||
|
|
@ -43,10 +45,10 @@ abstract class LocaleKeys {
|
||||||
static const reset_code = 'reset_code';
|
static const reset_code = 'reset_code';
|
||||||
static const new_password = 'new_password';
|
static const new_password = 'new_password';
|
||||||
static const logged_in_successfully = 'logged_in_successfully';
|
static const logged_in_successfully = 'logged_in_successfully';
|
||||||
static const view_course = 'view_course';
|
|
||||||
static const continue_learning = 'continue_learning';
|
static const continue_learning = 'continue_learning';
|
||||||
static const start_learning = 'start_learning';
|
static const start_learning = 'start_learning';
|
||||||
static const completed = 'completed';
|
static const completed = 'completed';
|
||||||
|
static const view_course = 'view_course';
|
||||||
static const take_practice = 'take_practice';
|
static const take_practice = 'take_practice';
|
||||||
static const your_current_level = 'your_current_level';
|
static const your_current_level = 'your_current_level';
|
||||||
static const overall_progress = 'overall_progress';
|
static const overall_progress = 'overall_progress';
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:yimaru_app/app/app.router.dart';
|
||||||
import 'package:yimaru_app/models/user.dart';
|
import 'package:yimaru_app/models/user.dart';
|
||||||
|
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
|
import '../../../services/apple_auth_service.dart';
|
||||||
import '../../../services/authentication_service.dart';
|
import '../../../services/authentication_service.dart';
|
||||||
import '../../../services/google_auth_service.dart';
|
import '../../../services/google_auth_service.dart';
|
||||||
import '../../../services/localization_service.dart';
|
import '../../../services/localization_service.dart';
|
||||||
|
|
@ -25,19 +26,23 @@ class LoginViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
final _appleAuthService = locator<AppleAuthService>();
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_googleAuthService, _localizationService];
|
[_googleAuthService, _appleAuthService, _localizationService];
|
||||||
|
|
||||||
// Google user
|
// Google user
|
||||||
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
||||||
|
|
||||||
GoogleSignInAccount? get googleUser => _googleUser;
|
GoogleSignInAccount? get googleUser => _googleUser;
|
||||||
|
|
||||||
|
bool get isAppleSignInAvailable => _appleAuthService.isSupported;
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
Map<String, dynamic> get _selectedLanguage =>
|
Map<String, dynamic> get _selectedLanguage =>
|
||||||
_localizationService.selectedLanguage;
|
_localizationService.selectedLanguage;
|
||||||
|
|
@ -235,6 +240,50 @@ class LoginViewModel extends ReactiveViewModel
|
||||||
Future<void> signInWithGoogle() async => await runBusyFuture(_googleAuth(),
|
Future<void> signInWithGoogle() async => await runBusyFuture(_googleAuth(),
|
||||||
busyObject: StateObjects.loginWithGoogle);
|
busyObject: StateObjects.loginWithGoogle);
|
||||||
|
|
||||||
|
// Sign-in with Apple
|
||||||
|
Future<void> _appleAuth() async {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
await _appleAuthService.appleAuth();
|
||||||
|
|
||||||
|
final credential = _appleAuthService.appleCredential;
|
||||||
|
final identityToken = credential?.identityToken;
|
||||||
|
|
||||||
|
if (identityToken == null || identityToken.isEmpty) {
|
||||||
|
showErrorToast('Apple login failed. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'id_token': identityToken,
|
||||||
|
'email': credential?.email,
|
||||||
|
'first_name': credential?.givenName,
|
||||||
|
'last_name': credential?.familyName,
|
||||||
|
};
|
||||||
|
|
||||||
|
data.removeWhere((_, value) => value == null || value == '');
|
||||||
|
|
||||||
|
Map<String, dynamic> response = await _apiService.appleAuth(data);
|
||||||
|
|
||||||
|
if (response['status'] == ResponseStatus.success) {
|
||||||
|
User user = response['data'] as User;
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'userId': user.userId,
|
||||||
|
'accessToken': user.accessToken,
|
||||||
|
'refreshToken': user.refreshToken
|
||||||
|
};
|
||||||
|
await _authenticationService.saveUserCredential(data);
|
||||||
|
clearUserData();
|
||||||
|
await replaceWithStartUp();
|
||||||
|
showSuccessToast(response['message']);
|
||||||
|
} else {
|
||||||
|
showErrorToast(response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signInWithApple() async => await runBusyFuture(_appleAuth(),
|
||||||
|
busyObject: StateObjects.loginWithApple);
|
||||||
|
|
||||||
// Login with phone
|
// Login with phone
|
||||||
Future<void> loginWithPhoneNumber() async =>
|
Future<void> loginWithPhoneNumber() async =>
|
||||||
await runBusyFuture(_loginWithPhoneNumber(),
|
await runBusyFuture(_loginWithPhoneNumber(),
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
Stack(children: [
|
Stack(children: [
|
||||||
_buildScaffold(context: context, viewModel: viewModel),
|
_buildScaffold(context: context, viewModel: viewModel),
|
||||||
_buildLoginWithEmailState(viewModel),
|
_buildLoginWithEmailState(viewModel),
|
||||||
_buildLoginWithGoogleState(viewModel)
|
_buildLoginWithGoogleState(viewModel),
|
||||||
|
_buildLoginWithAppleState(viewModel)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
Widget _buildScaffold(
|
||||||
|
|
@ -232,6 +233,8 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
List<Widget> _buildLowerColumnChildren(LoginViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(LoginViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
_buildLoginWithGoogleButton(viewModel),
|
_buildLoginWithGoogleButton(viewModel),
|
||||||
|
if (viewModel.isAppleSignInAvailable)
|
||||||
|
_buildLoginWithAppleButton(viewModel),
|
||||||
_buildOptionTextDivider(),
|
_buildOptionTextDivider(),
|
||||||
_buildLoginWithPhoneButton(viewModel),
|
_buildLoginWithPhoneButton(viewModel),
|
||||||
verticalSpaceMedium
|
verticalSpaceMedium
|
||||||
|
|
@ -265,6 +268,18 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
onTap: () async => await viewModel.signInWithGoogle(),
|
onTap: () async => await viewModel.signInWithGoogle(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Widget _buildLoginWithAppleButton(LoginViewModel viewModel) =>
|
||||||
|
CustomElevatedButton(
|
||||||
|
height: 55,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: kcWhite,
|
||||||
|
borderColor: kcPrimaryColor,
|
||||||
|
foregroundColor: kcPrimaryColor,
|
||||||
|
text: LocaleKeys.login_with_apple.tr(),
|
||||||
|
leadingIcon: Icons.apple,
|
||||||
|
onTap: () async => await viewModel.signInWithApple(),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||||
|
|
||||||
Widget _buildLoginWithPhoneButton(LoginViewModel viewModel) =>
|
Widget _buildLoginWithPhoneButton(LoginViewModel viewModel) =>
|
||||||
|
|
@ -287,4 +302,9 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
viewModel.busy(StateObjects.loginWithGoogle)
|
viewModel.busy(StateObjects.loginWithGoogle)
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
|
Widget _buildLoginWithAppleState(LoginViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.loginWithApple)
|
||||||
|
? const PageLoadingIndicator()
|
||||||
|
: Container();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../models/user.dart';
|
import '../../../models/user.dart';
|
||||||
|
import '../../../services/apple_auth_service.dart';
|
||||||
import '../../../services/google_auth_service.dart';
|
import '../../../services/google_auth_service.dart';
|
||||||
import '../../../services/localization_service.dart';
|
import '../../../services/localization_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
|
|
@ -25,19 +26,23 @@ class RegisterViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
final _appleAuthService = locator<AppleAuthService>();
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_googleAuthService, _localizationService];
|
[_googleAuthService, _appleAuthService, _localizationService];
|
||||||
|
|
||||||
// Google user
|
// Google user
|
||||||
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
GoogleSignInAccount? get _googleUser => _googleAuthService.googleUser;
|
||||||
|
|
||||||
GoogleSignInAccount? get googleUser => _googleUser;
|
GoogleSignInAccount? get googleUser => _googleUser;
|
||||||
|
|
||||||
|
bool get isAppleSignInAvailable => _appleAuthService.isSupported;
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
Map<String, dynamic> get _selectedLanguage =>
|
Map<String, dynamic> get _selectedLanguage =>
|
||||||
_localizationService.selectedLanguage;
|
_localizationService.selectedLanguage;
|
||||||
|
|
@ -337,6 +342,50 @@ class RegisterViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register with Apple
|
||||||
|
Future<void> registerWithApple() async => await runBusyFuture(_appleLogin(),
|
||||||
|
busyObject: StateObjects.registerWithApple);
|
||||||
|
|
||||||
|
Future<void> _appleLogin() async {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
await _appleAuthService.appleAuth();
|
||||||
|
|
||||||
|
final credential = _appleAuthService.appleCredential;
|
||||||
|
final identityToken = credential?.identityToken;
|
||||||
|
|
||||||
|
if (identityToken == null || identityToken.isEmpty) {
|
||||||
|
showErrorToast('Apple login failed. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'id_token': identityToken,
|
||||||
|
'email': credential?.email,
|
||||||
|
'first_name': credential?.givenName,
|
||||||
|
'last_name': credential?.familyName,
|
||||||
|
};
|
||||||
|
|
||||||
|
data.removeWhere((_, value) => value == null || value == '');
|
||||||
|
|
||||||
|
Map<String, dynamic> response = await _apiService.appleAuth(data);
|
||||||
|
|
||||||
|
if (response['status'] == ResponseStatus.success) {
|
||||||
|
User user = response['data'] as User;
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'userId': user.userId,
|
||||||
|
'accessToken': user.accessToken,
|
||||||
|
'refreshToken': user.refreshToken
|
||||||
|
};
|
||||||
|
await _authenticationService.saveUserCredential(data);
|
||||||
|
clearUserData();
|
||||||
|
await replaceWithStartUp();
|
||||||
|
showSuccessToast(response['message']);
|
||||||
|
} else {
|
||||||
|
showErrorToast(response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> verifyOtp() async =>
|
Future<void> verifyOtp() async =>
|
||||||
await runBusyFuture(_verifyOtp(), busyObject: StateObjects.verifyOtp);
|
await runBusyFuture(_verifyOtp(), busyObject: StateObjects.verifyOtp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,9 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildScaffold(context: context, viewModel: viewModel),
|
_buildScaffold(context: context, viewModel: viewModel),
|
||||||
_buildRegisterWithEmailState(viewModel)
|
_buildRegisterWithEmailState(viewModel),
|
||||||
|
_buildRegisterWithGoogleState(viewModel),
|
||||||
|
_buildRegisterWithAppleState(viewModel)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -191,6 +193,8 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
List<Widget> _buildLowerColumnChildren(RegisterViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(RegisterViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
_buildRegisterWithGoogleButton(viewModel),
|
_buildRegisterWithGoogleButton(viewModel),
|
||||||
|
if (viewModel.isAppleSignInAvailable)
|
||||||
|
_buildRegisterWithAppleButton(viewModel),
|
||||||
_buildOptionTextDivider(),
|
_buildOptionTextDivider(),
|
||||||
_buildRegisterWithEmailButton(viewModel),
|
_buildRegisterWithEmailButton(viewModel),
|
||||||
verticalSpaceMedium
|
verticalSpaceMedium
|
||||||
|
|
@ -225,6 +229,18 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
onTap: () async => await viewModel.registerWithGoogle(),
|
onTap: () async => await viewModel.registerWithGoogle(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Widget _buildRegisterWithAppleButton(RegisterViewModel viewModel) =>
|
||||||
|
CustomElevatedButton(
|
||||||
|
height: 55,
|
||||||
|
borderRadius: 12,
|
||||||
|
backgroundColor: kcWhite,
|
||||||
|
borderColor: kcPrimaryColor,
|
||||||
|
foregroundColor: kcPrimaryColor,
|
||||||
|
text: LocaleKeys.register_with_apple.tr(),
|
||||||
|
leadingIcon: Icons.apple,
|
||||||
|
onTap: () async => await viewModel.registerWithApple(),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||||
|
|
||||||
Widget _buildRegisterWithEmailButton(RegisterViewModel viewModel) =>
|
Widget _buildRegisterWithEmailButton(RegisterViewModel viewModel) =>
|
||||||
|
|
@ -243,4 +259,14 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
viewModel.busy(StateObjects.register)
|
viewModel.busy(StateObjects.register)
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
|
Widget _buildRegisterWithGoogleState(RegisterViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.registerWithGoogle)
|
||||||
|
? const PageLoadingIndicator()
|
||||||
|
: Container();
|
||||||
|
|
||||||
|
Widget _buildRegisterWithAppleState(RegisterViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.registerWithApple)
|
||||||
|
? const PageLoadingIndicator()
|
||||||
|
: Container();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import google_sign_in_ios
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import record_macos
|
import record_macos
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
import sign_in_with_apple
|
||||||
import sqflite_darwin
|
import sqflite_darwin
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import video_player_avfoundation
|
import video_player_avfoundation
|
||||||
|
|
@ -35,6 +36,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
||||||
|
|
|
||||||
28
pubspec.lock
28
pubspec.lock
|
|
@ -1557,6 +1557,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
sign_in_with_apple:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sign_in_with_apple
|
||||||
|
sha256: "5568378c3cc5993931955357d85e4c3344fa4365006915bdef965fa3de1dc0a5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.0"
|
||||||
|
sign_in_with_apple_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sign_in_with_apple_platform_interface
|
||||||
|
sha256: "981bca52cf3bb9c3ad7ef44aace2d543e5c468bb713fd8dda4275ff76dfa6659"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
sign_in_with_apple_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sign_in_with_apple_web
|
||||||
|
sha256: f316400827f52cafcf50d00e1a2e8a0abc534ca1264e856a81c5f06bd5b10fed
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -2011,5 +2035,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.10.3 <4.0.0"
|
dart: ">=3.11.0 <4.0.0"
|
||||||
flutter: ">=3.38.4"
|
flutter: ">=3.41.0"
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ dependencies:
|
||||||
flutter_phone_direct_caller: ^2.2.1
|
flutter_phone_direct_caller: ^2.2.1
|
||||||
flutter_local_notifications: ^20.1.0
|
flutter_local_notifications: ^20.1.0
|
||||||
internet_connection_checker_plus: ^2.9.1+2
|
internet_connection_checker_plus: ^2.9.1+2
|
||||||
|
sign_in_with_apple: ^8.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user