Commit 6b980613 authored by DatHV's avatar DatHV
Browse files

update project structure

parent bfff9e47
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/base/app_loading.dart';
import '../../base/app_navigator.dart';
import '../dio_http_service.dart';
import 'package:mypoint_flutter_app/shared/widgets/loading/app_loading.dart';
import '../../../app/routing/app_navigator.dart';
import '../error_mapper.dart';
import '../dio_http_service.dart';
class ExceptionInterceptor extends Interceptor {
static Completer<bool>? _currentRetryPrompt;
......
import 'dart:convert';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/shared/preferences/data_preference.dart';
import 'package:uuid/uuid.dart';
class RequestInterceptor extends Interceptor {
......
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/base/base_response_model.dart';
import '../configs/callbacks.dart';
import '../configs/constants.dart';
import 'package:mypoint_flutter_app/shared/widgets/base_view/base_response_model.dart';
import '../../app/config/callbacks.dart';
import '../../app/config/constants.dart';
enum Method { GET, POST, PUT, DELETE }
......
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client.dart';
import '../base/base_response_model.dart';
import '../base/base_view_model.dart';
import '../configs/constants.dart';
import '../base/app_navigator.dart';
import 'package:mypoint_flutter_app/core/network/restful_api_client.dart';
import '../../shared/widgets/base_view/base_response_model.dart';
import '../../shared/widgets/base_view/base_view_model.dart';
import '../../app/config/constants.dart';
import '../../app/routing/app_navigator.dart';
import 'interceptor/network_error_gate.dart';
import 'dio_extra_keys.dart';
import 'dio_http_service.dart';
import 'error_mapper.dart';
import 'interceptor/network_error_gate.dart';
typedef ApiCall<T> = Future<BaseResponseModel<T>> Function();
typedef OnSuccess<T> =
......@@ -33,9 +33,11 @@ class RestfulApiViewModel extends BaseViewModel {
OnComplete? onComplete,
bool showAppNavigatorDialog = false,
bool withLoading = true,
bool trackLoading = true,
String defaultError = ErrorCodes.commonError,
}) async {
if (withLoading) showLoading();
if (trackLoading) beginTrackedLoading();
BaseResponseModel<T>? res;
try {
res = await request();
......@@ -86,6 +88,7 @@ class RestfulApiViewModel extends BaseViewModel {
}
} finally {
if (withLoading) hideLoading();
if (trackLoading) endTrackedLoading();
onComplete?.call();
}
}
......
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:local_auth/local_auth.dart';
import '../resources/base_color.dart';
import '../widgets/alert/custom_alert_dialog.dart';
import '../widgets/alert/data_alert_model.dart';
import '../theme/base_color.dart';
import '../../shared/widgets/alert/custom_alert_dialog.dart';
import '../../shared/widgets/alert/data_alert_model.dart';
enum BiometricTypeEnum {
none,
......
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_branch_sdk/flutter_branch_sdk.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:uni_links/uni_links.dart';
import 'package:mypoint_flutter_app/directional/directional_screen.dart';
import 'package:mypoint_flutter_app/extensions/crypto.dart' as mycrypto;
import '../directional/directional_action_type.dart';
import 'package:mypoint_flutter_app/shared/navigation/directional_screen.dart';
import 'package:mypoint_flutter_app/core/utils/crypto.dart' as mycrypto;
import '../../app/routing/directional_action_type.dart';
class DeepLinkService {
DeepLinkService._internal();
......@@ -17,6 +17,7 @@ class DeepLinkService {
bool _initialized = false;
Future<void> initialize() async {
if (kIsWeb) return;
if (_initialized) return;
_initialized = true;
debugPrint('🔗 Initializing DeepLinkService...');
......@@ -57,6 +58,10 @@ class DeepLinkService {
} catch (_) {}
}
bool handleIncomingUri(String uri) {
return _routeFromUriString(uri) ?? false;
}
void _listenLinkStream() {
try {
_linkSub = linkStream.listen((uri) {
......@@ -67,10 +72,10 @@ class DeepLinkService {
}
// Firebase Dynamic Links removed due to version constraints.
void _routeFromUriString(String uriStr) {
bool? _routeFromUriString(String uriStr) {
debugPrint('🔗 Deep link received: $uriStr');
final uri = Uri.tryParse(uriStr);
if (uri == null) return;
if (uri == null) return false;
final type = uri.queryParameters[Defines.actionType] ?? uri.queryParameters['action_type'];
final param = uri.queryParameters[Defines.actionParams] ?? uri.queryParameters['action_param'];
......@@ -91,13 +96,12 @@ class DeepLinkService {
direction?.extraData = {
'password': param,
};
direction?.begin();
return; // Use if you need to attach to userInfo later
return direction?.begin(); // Use if you need to attach to userInfo later
}
}
}
final screen = DirectionalScreen.build(clickActionType: type, clickActionParam: param);
screen?.begin();
return screen?.begin();
}
void _handleBranchSession(Map<dynamic, dynamic> data) {
......
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/base/base_response_model.dart';
import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/shared/widgets/base_view/base_response_model.dart';
import 'package:mypoint_flutter_app/app/config/constants.dart';
import 'package:mypoint_flutter_app/core/network/restful_api_client_all_request.dart';
import 'package:mypoint_flutter_app/shared/preferences/data_preference.dart';
import '../firebase/push_token_service.dart';
import '../model/auth/login_token_response_model.dart';
import '../networking/restful_api_viewmodel.dart';
import '../../features/login/model/login_token_response_model.dart';
import '../network/restful_api_viewmodel.dart';
/// Login result enum để handle các trạng thái khác nhau
enum LoginResult {
......@@ -43,15 +43,12 @@ class LoginService extends RestfulApiViewModel {
try {
// Step 1: Authenticate user
final authResponse = await client.login(phone, password);
if (!authResponse.isSuccess || authResponse.data == null) {
debugPrint('Login failed: ${authResponse.errorMessage}');
return _handleAuthError(authResponse);
}
// Step 2: Save token
await DataPreference.instance.saveLoginToken(authResponse.data!);
// Step 3: Get user profile (critical step)
final profileResult = await _getUserProfileWithRetry();
if (profileResult.result != LoginResult.success) {
......@@ -62,16 +59,13 @@ class LoginService extends RestfulApiViewModel {
message: profileResult.message ?? Constants.commonError,
);
}
// Step 4: Upload FCM token (non-critical, don't fail login if this fails)
await _uploadFCMTokenSafely();
return LoginResponse(result: LoginResult.success);
} catch (e) {
return LoginResponse(
result: LoginResult.networkError,
message: 'Đăng nhập thất bại: ${e.toString()}',
message: ErrorCodes.commonError,
);
}
}
......@@ -120,12 +114,10 @@ class LoginService extends RestfulApiViewModel {
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
final response = await client.getUserProfile();
if (response.isSuccess && response.data != null) {
await DataPreference.instance.saveUserProfile(response.data!);
return LoginResponse(result: LoginResult.success);
}
// If not last attempt, wait before retry
if (attempt < maxRetries) {
await Future.delayed(Duration(seconds: attempt * 2));
......@@ -134,16 +126,16 @@ class LoginService extends RestfulApiViewModel {
if (attempt == maxRetries) {
return LoginResponse(
result: LoginResult.networkError,
message: 'Không thể tải thông tin người dùng: ${e.toString()}',
message: ErrorCodes.commonError,
);
}
await Future.delayed(Duration(seconds: attempt * 2));
}
}
debugPrint('Failed to fetch user profile after $maxRetries attempts');
return LoginResponse(
result: LoginResult.networkError,
message: 'Không thể tải thông tin người dùng sau $maxRetries lần thử',
message: ErrorCodes.commonError,
);
}
......@@ -161,13 +153,10 @@ class LoginService extends RestfulApiViewModel {
Future<LoginResponse> biometricLogin(String phone) async {
try {
final response = await client.loginWithBiometric(phone);
if (!response.isSuccess || response.data == null) {
return _handleAuthError(response);
}
await DataPreference.instance.saveLoginToken(response.data!);
final profileResult = await _getUserProfileWithRetry();
if (profileResult.result != LoginResult.success) {
await DataPreference.instance.clearLoginToken();
......@@ -176,14 +165,12 @@ class LoginService extends RestfulApiViewModel {
message: profileResult.message ?? Constants.commonError,
);
}
await _uploadFCMTokenSafely();
return LoginResponse(result: LoginResult.success);
} catch (e) {
return LoginResponse(
result: LoginResult.networkError,
message: 'Đăng nhập sinh trắc thất bại: ${e.toString()}',
message: ErrorCodes.commonError,
);
}
}
......
import 'package:flutter/foundation.dart';
import '../networking/dio_http_service.dart';
import '../networking/restful_api_client.dart';
import '../networking/restful_api_client_all_request.dart';
import '../preference/data_preference.dart';
import '../network/dio_http_service.dart';
import '../network/restful_api_client.dart';
import '../network/restful_api_client_all_request.dart';
import '../../shared/preferences/data_preference.dart';
class LogoutService {
LogoutService._();
......
import 'package:flutter/widgets.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart';
import '../configs/constants.dart';
import '../model/auth/login_token_response_model.dart';
import '../networking/restful_api_viewmodel.dart';
import '../preference/data_preference.dart';
import '../base/app_navigator.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/core/network/restful_api_client_all_request.dart';
import '../../app/config/constants.dart';
import '../../features/login/model/login_token_response_model.dart';
import '../network/restful_api_viewmodel.dart';
import '../../shared/preferences/data_preference.dart';
import '../../app/routing/app_navigator.dart';
class TokenRefreshService extends RestfulApiViewModel {
static final TokenRefreshService _instance = TokenRefreshService._internal();
......
......@@ -41,6 +41,10 @@ void webResetSDK() {
// no-op on non-web
}
void webNotifySplashScreenReady() {
// no-op on non-web
}
Future<dynamic> webConfigUIApp(Map<String, dynamic> config) async {
return null;
}
......
// Web-specific implementations for x-app-sdk
import 'dart:html' as html;
import 'package:flutter/foundation.dart';
import 'x_app_sdk_service.dart';
......@@ -81,6 +82,14 @@ void webResetSDK() {
}
}
void webNotifySplashScreenReady() {
try {
html.window.dispatchEvent(html.CustomEvent('mypoint-splash-ready'));
} catch (e) {
debugPrint('❌ Error notifying splash readiness: $e');
}
}
Future<dynamic> webConfigUIApp(Map<String, dynamic> config) async {
try {
return await XAppSDKService().configUIApp(config);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment