Commit 5fb93f2d authored by DatHV's avatar DatHV
Browse files

update logic authen

parent 73074efa
......@@ -105,7 +105,6 @@
4095AD98D6AA41A025D05981 /* Pods-RunnerTests.release.xcconfig */,
40F35D12C549F03EDF2680DB /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
......@@ -470,16 +469,20 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = T3AV8NC2D4;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z99P65VHXA;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.mypointFlutterApp;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.MyPoint;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "MyPoint development";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
......@@ -491,12 +494,16 @@
baseConfigurationReference = DEA7D70911C640B733B46F56 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z99P65VHXA;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.mypointFlutterApp.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.MyPoint;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "MyPoint development";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
......@@ -509,12 +516,16 @@
baseConfigurationReference = 4095AD98D6AA41A025D05981 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z99P65VHXA;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.mypointFlutterApp.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.MyPoint;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "MyPoint development";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
......@@ -525,12 +536,16 @@
baseConfigurationReference = 40F35D12C549F03EDF2680DB /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z99P65VHXA;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.mypointFlutterApp.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.MyPoint;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "MyPoint development";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
......@@ -653,16 +668,20 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = T3AV8NC2D4;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z99P65VHXA;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.mypointFlutterApp;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.MyPoint;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "MyPoint development";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
......@@ -676,16 +695,20 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = T3AV8NC2D4;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z99P65VHXA;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.mypointFlutterApp;
PRODUCT_BUNDLE_IDENTIFIER = com.icom.vn.MyPoint;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "MyPoint development";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
......
......@@ -2,6 +2,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>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
......@@ -24,6 +26,12 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSFaceIDUsageDescription</key>
<string>We need Face ID to authenticate your identity</string>
<key>NSLocalAuthenticationUseFaceID</key>
<string>true</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
......@@ -41,13 +49,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>NSFaceIDUsageDescription</key>
<string>We need Face ID to authenticate your identity</string>
<key>NSLocalAuthenticationUseFaceID</key>
<string>true</string>
</dict>
</plist>
......@@ -97,10 +97,15 @@ abstract class BaseState<Screen extends BaseScreen> extends State<Screen> {
context.showConfirmAlertDialog(message, cancel: cancel, confirm: confirm, callback: callback);
}
showAlert({required DataAlertModel data, bool? barrierDismissibl}) {
showAlert({required DataAlertModel data,
bool? barrierDismissibl,
bool showCloseButton = true,
ButtonsDirection direction = ButtonsDirection.column}) {
Get.dialog(
CustomAlertDialog(
alertData: data,
showCloseButton: showCloseButton,
direction: direction,
),
barrierDismissible: barrierDismissibl ?? false,
);
......
......@@ -19,4 +19,10 @@ class APIPaths {
static const String bioCredential = "/iam/v1/account/me/bio-credential";
static const String accountLoginForPasswordChange = "/accountLoginForPasswordChange/1.0.0";
static const String accountPasswordChange = "/accountPasswordChange/1.0.0";
static const String registerBiometric = "/iam/v1/account/me/bio-credential";
static const String unRegisterBiometric = "/iam/v1/account/me/bio-credential";
static const String customerBalanceGetDetail = "/customerBalanceGetDetail/1.0.0";
static const String headerHome = "/dynamic-home/api/v1.0/header-home";
static const String otpDeleteAccountRequest = "/user/api/v2.0/me/delete/request";
static const String verifyDeleteAccount = "/user/api/v2.0/me/delete/verify";
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/screen/login/login_screen.dart';
import 'package:mypoint_flutter_app/screen/main_tab_screen/main_tab_screen.dart';
import 'package:mypoint_flutter_app/screen/onboarding/onboarding_screen.dart';
import 'package:mypoint_flutter_app/screen/onboarding/onboarding_viewmodel.dart';
import 'package:mypoint_flutter_app/screen/splash/splash_screen.dart';
import 'package:mypoint_flutter_app/shared/router_gage.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await DataPreference.instance.loadLoginToken();
Get.put(OnboardingViewModel());
await DataPreference.instance.init();
runApp(const MyApp());
}
......@@ -21,17 +16,13 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/login',
initialRoute: '/splash',
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.deepPurple),
primaryColor: Colors.deepPurple,
),
home: SplashScreen(),
getPages: [
GetPage(name: '/login', page: () => const LoginScreen(phoneNumber: '091212121',)),
GetPage(name: '/main', page: () => const MainTabScreen()),
GetPage(name: '/onboarding', page: () => const OnboardingScreen()),
],
// home: SplashScreen(),
getPages: RouterPage.pages(),
);
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ part 'update_response_model.g.dart';
@JsonSerializable()
class UpdateResponseModel {
@JsonKey(name: 'update_request')
List<CheckUpdateResponseModel?>? updateRequest;
List<CheckUpdateResponseModel>? updateRequest;
UpdateResponseModel({this.updateRequest});
......
......@@ -6,20 +6,16 @@ part of 'update_response_model.dart';
// JsonSerializableGenerator
// **************************************************************************
UpdateResponseModel _$UpdateResponseModelFromJson(Map<String, dynamic> json) =>
UpdateResponseModel(
updateRequest:
(json['update_request'] as List<dynamic>?)
?.map(
(e) =>
e == null
? null
: CheckUpdateResponseModel.fromJson(
e as Map<String, dynamic>,
),
)
.toList(),
);
UpdateResponseModel _$UpdateResponseModelFromJson(
Map<String, dynamic> json,
) => UpdateResponseModel(
updateRequest:
(json['update_request'] as List<dynamic>?)
?.map(
(e) => CheckUpdateResponseModel.fromJson(e as Map<String, dynamic>),
)
.toList(),
);
Map<String, dynamic> _$UpdateResponseModelToJson(
UpdateResponseModel instance,
......
import 'package:json_annotation/json_annotation.dart';
import 'package:mypoint_flutter_app/model/update_response_model.dart';
part 'update_response_object.g.dart';
@JsonSerializable()
class UpdateResponseObject {
UpdateResponseModel? data;
UpdateResponseObject({this.data});
factory UpdateResponseObject.fromJson(Map<String, dynamic> json) => _$UpdateResponseObjectFromJson(json);
Map<String, dynamic> toJson() => _$UpdateResponseObjectToJson(this);
}
\ No newline at end of file
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'update_response_object.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
UpdateResponseObject _$UpdateResponseObjectFromJson(
Map<String, dynamic> json,
) => UpdateResponseObject(
data:
json['data'] == null
? null
: UpdateResponseModel.fromJson(json['data'] as Map<String, dynamic>),
);
Map<String, dynamic> _$UpdateResponseObjectToJson(
UpdateResponseObject instance,
) => <String, dynamic>{'data': instance.data};
......@@ -9,7 +9,8 @@ import '../configs/device_info.dart';
import '../model/auth/biometric_register_response_model.dart';
import '../model/auth/login_token_response_model.dart';
import '../model/auth/profile_response_model.dart';
import '../model/update_response_object.dart';
import '../model/update_response_model.dart';
import '../preference/point/header_home_model.dart';
import '../screen/faqs/faqs_model.dart';
import '../screen/onboarding/model/check_phone_response_model.dart';
import '../screen/onboarding/model/onboarding_info_model.dart';
......@@ -21,14 +22,14 @@ import '../screen/splash/splash_screen_viewmodel.dart';
import 'model_maker.dart';
extension RestfullAPIClientAllApi on RestfulAPIClient {
Future<BaseResponseModel<UpdateResponseObject>> checkUpdateApp() async {
Future<BaseResponseModel<UpdateResponseModel>> checkUpdateApp() async {
String version = Platform.version;
final body = {"operating_system": "iOS", "software_model": "MyPoint", "version": "1.12.1", "build_number": "1"};
final body = {"operating_system": "iOS", "software_model": "MyPoint", "version": "1.21.7", "build_number": "1"};
return requestNormal(
APIPaths.checkUpdate,
Method.POST,
body,
(data) => UpdateResponseObject.fromJson(data as Json),
(data) => UpdateResponseModel.fromJson(data as Json),
);
}
......@@ -73,6 +74,24 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
);
}
Future<BaseResponseModel<CreateOTPResponseModel>> requestOtpDeleteAccount() async {
return requestNormal(
APIPaths.otpDeleteAccountRequest,
Method.POST,
{},
(data) => CreateOTPResponseModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<CreateOTPResponseModel>> verifyDeleteAccount(String otp) async {
return requestNormal(
APIPaths.verifyDeleteAccount,
Method.POST,
{"otp": otp},
(data) => CreateOTPResponseModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<EmptyCodable>> signup(String phone, String password) async {
var deviceKey = await DeviceInfo.getDeviceId();
final body = {"username": phone, "password": password.toSha256(), "device_key": deviceKey};
......@@ -91,12 +110,13 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
Future<BaseResponseModel<LoginTokenResponseModel>> loginWithBiometric(String phone) async {
var deviceKey = await DeviceInfo.getDeviceId();
var bioToken = await DataPreference.instance.getBioToken(phone) ?? "";
final body = {
"username": phone,
"bioToken": DataPreference.instance.getBioToken(phone) ?? "",
"bioToken": bioToken,
"deviceKey": deviceKey,
"workspaceCode": "8854"};
return requestNormal(APIPaths.login, Method.POST, body, (data) => LoginTokenResponseModel.fromJson(data as Json));
return requestNormal(APIPaths.loginWithBiometric, Method.POST, body, (data) => LoginTokenResponseModel.fromJson(data as Json));
}
Future<BaseResponseModel<ProfileResponseModel>> getUserProfile() async {
......@@ -176,7 +196,8 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future<BaseResponseModel<EmptyCodable>> accountPasswordChange(String phone, String password) async {
final body = {"login_name": phone, "password": password.toSha256(), "access_token": DataPreference.instance.token ?? ""};
String? token = await DataPreference.instance.token ?? "";
final body = {"login_name": phone, "password": password.toSha256(), "access_token": token};
return requestNormal(
APIPaths.accountPasswordChange,
Method.POST,
......@@ -185,6 +206,17 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
);
}
Future<BaseResponseModel<EmptyCodable>> accountLoginForPasswordChange(String phone, String password) async {
String? token = await DataPreference.instance.token ?? "";
final body = {"login_name": phone, "password": password.toSha256(), "access_token": token};
return requestNormal(
APIPaths.accountLoginForPasswordChange,
Method.POST,
body,
(data) => EmptyCodable.fromJson(data as Json),
);
}
Future<BaseResponseModel<BiometricRegisterResponseModel>> accountBioCredential() async {
var deviceKey = await DeviceInfo.getDeviceId();
final body = {"deviceKey": deviceKey};
......@@ -196,13 +228,35 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
);
}
Future<BaseResponseModel<EmptyCodable>> accountCheckForPasswordChange(String password) async {
final body = {"password": password.toSha256()};
Future<BaseResponseModel<BiometricRegisterResponseModel>> registerBiometric() async {
var deviceKey = await DeviceInfo.getDeviceId();
final body = {"deviceKey": deviceKey};
return requestNormal(
APIPaths.accountLoginForPasswordChange,
APIPaths.registerBiometric,
Method.POST,
body,
(data) => BiometricRegisterResponseModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<EmptyCodable>> unRegisterBiometric() async {
var deviceKey = await DeviceInfo.getDeviceId();
final path = "${APIPaths.unRegisterBiometric}/$deviceKey";
final body = {"deviceKey": deviceKey};
return requestNormal(
path,
Method.POST,
body,
(data) => EmptyCodable.fromJson(data as Json),
);
}
Future<BaseResponseModel<HeaderHomeModel>> getHomeHeaderData() async {
return requestNormal(
APIPaths.headerHome,
Method.GET,
{},
(data) => HeaderHomeModel.fromJson(data as Json),
);
}
}
......@@ -49,7 +49,10 @@ class BiometricManager {
try {
final didAuthenticate = await _localAuth.authenticate(
localizedReason: localizedReason,
options: const AuthenticationOptions(biometricOnly: true),
options: const AuthenticationOptions(
biometricOnly: false, // ✅ cho phép passcode hoặc vân tay / face ID
stickyAuth: true, // ✅ giữ lại phiên nếu app vào background
),
);
return didAuthenticate;
} catch (e) {
......
......@@ -10,55 +10,35 @@ class DataPreference {
LoginTokenResponseModel? _loginToken;
ProfileResponseModel? _profile;
ProfileResponseModel? get profile => _profile;
LoginTokenResponseModel? get loginToken => _loginToken;
String? get phone => _profile?.workerSite?.phoneNumber;
Future<bool> get logged async {
final currentToken = await token;
return (currentToken ?? "").isNotEmpty;
}
Future<String?> get token async {
if (_loginToken != null) {
return _loginToken?.accessToken;
} else {
await loadLoginToken();
return _loginToken?.accessToken;
}
}
Future<void> saveUserProfile(ProfileResponseModel profile) async {
_profile = profile;
Future<void> init() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = jsonEncode(profile.toJson());
await prefs.setString('user_profile', jsonString);
}
final tokenJson = prefs.getString('login_token');
if (tokenJson != null) {
_loginToken = LoginTokenResponseModel.fromJson(jsonDecode(tokenJson));
}
Future<void> loadProfile() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString('user_profile');
if (jsonString != null) {
final jsonMap = jsonDecode(jsonString);
_profile = ProfileResponseModel.fromJson(jsonMap);
final profileJson = prefs.getString('user_profile');
if (profileJson != null) {
_profile = ProfileResponseModel.fromJson(jsonDecode(profileJson));
}
}
String? get token => _loginToken?.accessToken;
String? get phone => _profile?.workerSite?.phoneNumber;
bool get logged => (token ?? "").isNotEmpty;
ProfileResponseModel? get profile => _profile;
Future<void> saveLoginToken(LoginTokenResponseModel token) async {
_loginToken = token;
final prefs = await SharedPreferences.getInstance();
final jsonString = jsonEncode(token.toJson());
await prefs.setString('login_token', jsonString);
await prefs.setString('login_token', jsonEncode(token.toJson()));
}
Future<void> loadLoginToken() async {
Future<void> saveUserProfile(ProfileResponseModel profile) async {
_profile = profile;
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString('login_token');
if (jsonString != null) {
final jsonMap = jsonDecode(jsonString);
_loginToken = LoginTokenResponseModel.fromJson(jsonMap);
}
await prefs.setString('user_profile', jsonEncode(profile.toJson()));
}
Future<void> clearLoginToken() async {
......@@ -67,23 +47,31 @@ class DataPreference {
await prefs.remove('login_token');
}
Future<void> clearBioToken(String phone) async {
Future<void> clearUserProfile() async {
_profile = null;
final prefs = await SharedPreferences.getInstance();
await prefs.remove('biometric_login_token_$phone');
await prefs.remove('user_profile');
}
Future<void> clearData() async {
await clearLoginToken();
await clearUserProfile();
}
Future<void> saveBioToken(String bioToken) async {
if (phone == null) return;
final prefs = await SharedPreferences.getInstance();
final jsonString = jsonEncode(bioToken);
await prefs.setString('biometric_login_token_$phone', jsonString);
await prefs.setString('biometric_login_token_$phone', jsonEncode(bioToken));
}
Future<String?> getBioToken(String phone) async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString('biometric_login_token_$phone');
if (jsonString != null) {
return jsonDecode(jsonString);
}
return jsonString != null ? jsonDecode(jsonString) : null;
}
Future<void> clearBioToken(String phone) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('biometric_login_token_$phone');
}
}
\ No newline at end of file
import 'package:json_annotation/json_annotation.dart';
part 'header_home_model.g.dart';
@JsonSerializable()
class HeaderHomeModel {
final String? greeting;
@JsonKey(name: 'total_voucher')
final int? totalVoucher;
@JsonKey(name: 'total_point_active')
final int? totalPointActive;
final String? background;
HeaderHomeModel({
this.greeting,
this.totalVoucher,
this.totalPointActive,
this.background,
});
factory HeaderHomeModel.fromJson(Map<String, dynamic> json) => _$HeaderHomeModelFromJson(json);
Map<String, dynamic> toJson() => _$HeaderHomeModelToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'header_home_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
HeaderHomeModel _$HeaderHomeModelFromJson(Map<String, dynamic> json) =>
HeaderHomeModel(
greeting: json['greeting'] as String?,
totalVoucher: (json['total_voucher'] as num?)?.toInt(),
totalPointActive: (json['total_point_active'] as num?)?.toInt(),
background: json['background'] as String?,
);
Map<String, dynamic> _$HeaderHomeModelToJson(HeaderHomeModel instance) =>
<String, dynamic>{
'greeting': instance.greeting,
'total_voucher': instance.totalVoucher,
'total_point_active': instance.totalPointActive,
'background': instance.background,
};
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import '../../base/restful_api_viewmodel.dart';
import 'header_home_model.dart';
class UserPointManager extends RestfulApiViewModel {
static final UserPointManager _instance = UserPointManager._internal();
factory UserPointManager() => _instance;
UserPointManager._internal();
final RxInt _userPoint = 0.obs;
HeaderHomeModel? _headerInfo;
get point => _userPoint.value;
Future<int> fetchUserPoint() async {
try {
final response = await client.getHomeHeaderData();
if (response.isSuccess && response.data != null) {
_headerInfo = response.data;
_userPoint.value = _headerInfo?.totalPointActive ?? 0;
} else {
_userPoint.value = 0;
}
} catch (e) {
_userPoint.value = 0;
}
return _userPoint.value;
}
}
import 'package:flutter/material.dart';
class AppButtonStyle {
static ButtonStyle primary = ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
minimumSize: const Size.fromHeight(32),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
);
static ButtonStyle secondary = ElevatedButton.styleFrom(
backgroundColor: Colors.grey.shade300,
foregroundColor: Colors.black,
minimumSize: const Size.fromHeight(32),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
);
}
......@@ -84,31 +84,40 @@ TextStyle getTextStyle(TextStyleIconAndText? textType) {
}
}
final BorderRadius _borderRadius = BorderRadius.circular(8.0);
final BorderSide _defaultBorderSide = BorderSide(color: BaseColor.second400);
final BorderSide _focusedBorderSide = BorderSide(color: Colors.blue);
final EdgeInsets _contentPadding = EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0);
class PTTextStyles {
static final InputDecoration textFieldDecoration = InputDecoration(
border: OutlineInputBorder(
borderRadius: _borderRadius,
borderSide: _defaultBorderSide,
),
enabledBorder: OutlineInputBorder(
borderRadius: _borderRadius,
borderSide: _defaultBorderSide,
),
focusedBorder: OutlineInputBorder(
borderRadius: _borderRadius,
borderSide: _focusedBorderSide,
),
labelText: 'Enter text',
labelStyle: TextStyle(color: Colors.grey),
hintText: 'Hint text',
hintStyle: TextStyle(color: Colors.grey),
filled: true,
fillColor: Colors.white,
contentPadding: _contentPadding,
class AppTextStyle {
static const TextStyle title = TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
);
static const TextStyle content = TextStyle(
fontSize: 14,
color: Colors.black87,
);
static const TextStyle boldContent = TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
);
static const TextStyle link = TextStyle(
fontSize: 14,
color: Colors.blue,
decoration: TextDecoration.underline,
);
static const TextStyle buttonPrimary = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white,
);
static const TextStyle buttonSecondary = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.black,
);
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/widgets/alert/data_alert_model.dart';
import '../../base/base_screen.dart';
import '../../base/basic_state.dart';
import '../../preference/data_preference.dart';
import '../../resouce/base_color.dart';
import '../../shared/router_gage.dart';
import '../../widgets/back_button.dart';
import '../../widgets/support_button.dart';
import '../login/login_viewmodel.dart';
......@@ -28,6 +30,10 @@ class _ChangePassScreenState extends BaseState<ChangePassScreen> with BasicState
WidgetsBinding.instance.addPostFrameCallback((_) {
_focusNode.requestFocus();
});
viewModel.onShowAlertError = (message) {
showAlertError(content: message);
};
}
@override
......@@ -155,7 +161,29 @@ class _ChangePassScreenState extends BaseState<ChangePassScreen> with BasicState
children: [
TextButton(
onPressed: () {
viewModel.onForgotPassPressed(_phone);
final dataAlert = DataAlertModel(
title: "Quên mật khẩu",
content: "Bạn cần đăng xuất khỏi tài khoản này để đặt lại mật khẩu. Bạn chắc chứ?.",
background: "assets/images/ic_pipi_03.png",
buttons: [AlertButton(
text: "Đồng ý",
onPressed: () {
DataPreference.instance.clearLoginToken();
_safeBackToLogin();
},
bgColor: BaseColor.primary500,
textColor: Colors.white,
isPrimary: true,
),
AlertButton(
text: "Huỷ",
onPressed: () => Get.back(),
bgColor: Colors.white,
textColor: BaseColor.second500,
isPrimary: false,
),],
);
showAlert(data: dataAlert);
},
child: const Text("Quên mật khẩu?", style: TextStyle(fontSize: 14, color: Color(0xFF3662FE))),
),
......@@ -204,4 +232,22 @@ class _ChangePassScreenState extends BaseState<ChangePassScreen> with BasicState
);
});
}
void _safeBackToLogin() {
bool found = false;
Navigator.popUntil(Get.context!, (route) {
final matched = route.settings.name == loginScreen;
if (matched) found = true;
return matched;
});
final phone = DataPreference.instance.phone;
if (phone != null) {
if (!found) {
Get.offAllNamed(loginScreen, arguments: phone);
}
} else {
DataPreference.instance.clearData();
Get.offAllNamed(onboardingScreen);
}
}
}
......@@ -39,10 +39,10 @@ class ChangePassViewModel extends RestfulApiViewModel {
});
}
void accountCheckForPasswordChange() {
Future<void> accountCheckForPasswordChange() async {
showLoading();
final phone = DataPreference.instance.phone ?? "";
client.accountPasswordChange(phone, password.value).then((value) {
final phone = await DataPreference.instance.phone ?? "";
client.accountLoginForPasswordChange(phone, password.value).then((value) {
hideLoading();
if (value.isSuccess) {
Get.to(CreatePasswordScreen(repository: ChangePasswordRepository(phone)));
......
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import 'package:mypoint_flutter_app/screen/create_pass/signup_create_password_repository.dart';
import 'package:mypoint_flutter_app/widgets/custom_toast_message.dart';
import '../../base/base_response_model.dart';
import '../../base/restful_api_viewmodel.dart';
import '../login/login_screen.dart';
import '../main_tab_screen/main_tab_screen.dart';
import '../splash/splash_screen_viewmodel.dart';
class ChangePasswordRepository extends RestfulApiViewModel implements ICreatePasswordRepository {
......@@ -18,7 +20,8 @@ class ChangePasswordRepository extends RestfulApiViewModel implements ICreatePas
return client.accountPasswordChange(phoneNumber, password).then((value) {
hideLoading();
if (value.status == "success" || value.code == 200) {
print("Change password success");
showToastMessage("Đổi mật khẩu thành công.");
Get.off(() => MainTabScreen());
}
return value;
});
......
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