Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Hoàng Văn Đạt
mypoint_flutter_app
Commits
e92ea8bf
Commit
e92ea8bf
authored
Mar 11, 2025
by
DatHV
Browse files
update logic
parent
5413611e
Changes
24
Show whitespace changes
Inline
Side-by-side
lib/configs/api_paths.dart
View file @
e92ea8bf
...
...
@@ -10,4 +10,7 @@ class APIPaths {
static
const
String
otpCreateNew
=
"/otpCreateNew/1.0.0"
;
static
const
String
websitePageGetDetail
=
"/websitePageGetDetail/1.0.0"
;
static
const
String
websitePage
=
"/user/api/v2.0/websitePage"
;
static
const
String
websiteFolderGetPageList
=
"/websiteFolderGetPageList/1.0.0"
;
static
const
String
otpVerifyForDoingNextEvent
=
"/otpVerifyForDoingNextEvent/1.0.0"
;
static
const
String
accountPasswordReset
=
"/accountPasswordReset/1.0.0"
;
}
lib/directional/directional_screen.dart
View file @
e92ea8bf
...
...
@@ -7,20 +7,22 @@ part 'directional_screen.g.dart';
@JsonSerializable
()
class
DirectionalScreen
{
@JsonKey
(
name:
"click_action_type"
)
final
String
clickActionType
;
final
String
?
clickActionType
;
@JsonKey
(
name:
"click_action_param"
)
final
String
?
clickActionParam
;
final
ClickActionType
?
actionType
;
DirectionalScreen
({
required
this
.
clickActionType
,
this
.
clickActionType
,
this
.
clickActionParam
,
this
.
actionType
,
});
factory
DirectionalScreen
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$DirectionalScreenFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$DirectionalScreenToJson
(
this
);
void
begin
()
{
final
type
=
ClickActionTypeExtension
.
fromString
(
clickActionType
);
final
type
=
ClickActionTypeExtension
.
fromString
(
clickActionType
??
actionType
?.
key
??
""
);
if
(
type
==
null
)
{
print
(
"Không nhận diện được action type:
$clickActionType
"
);
return
;
...
...
lib/directional/directional_screen.g.dart
View file @
e92ea8bf
...
...
@@ -8,12 +8,21 @@ part of 'directional_screen.dart';
DirectionalScreen
_$DirectionalScreenFromJson
(
Map
<
String
,
dynamic
>
json
)
=>
DirectionalScreen
(
clickActionType:
json
[
'click_action_type'
]
as
String
,
clickActionType:
json
[
'click_action_type'
]
as
String
?
,
clickActionParam:
json
[
'click_action_param'
]
as
String
?,
actionType:
$enumDecodeNullable
(
_$ClickActionTypeEnumMap
,
json
[
'actionType'
],
),
);
Map
<
String
,
dynamic
>
_$DirectionalScreenToJson
(
DirectionalScreen
instance
)
=>
<
String
,
dynamic
>{
'click_action_type'
:
instance
.
clickActionType
,
'click_action_param'
:
instance
.
clickActionParam
,
'actionType'
:
_$ClickActionTypeEnumMap
[
instance
.
actionType
],
};
const
_$ClickActionTypeEnumMap
=
{
ClickActionType
.
campaignDetail
:
'campaignDetail'
,
};
lib/networking/restful_api_request.dart
View file @
e92ea8bf
...
...
@@ -6,8 +6,10 @@ import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import
'package:mypoint_flutter_app/networking/restful_api.dart'
;
import
'../configs/device_info.dart'
;
import
'../model/update_response_object.dart'
;
import
'../screen/faqs/faqs_model.dart'
;
import
'../screen/onboarding/model/check_phone_response_model.dart'
;
import
'../screen/onboarding/model/onboarding_info_model.dart'
;
import
'../screen/otp/model/create_otp_response_model.dart'
;
import
'../screen/otp/model/otp_verify_response_model.dart'
;
import
'../screen/pageDetail/model/campaign_detail_model.dart'
;
import
'../screen/pageDetail/model/detail_page_rule_type.dart'
;
...
...
@@ -48,7 +50,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future
<
BaseResponseModel
<
OTPVerifyResponseModel
>>
verifyOTP
(
String
otp
,
String
mfaToken
)
async
{
final
body
=
{
"otp"
:
otp
,
"mfaToken"
:
mfaToken
,
};
final
body
=
{
"otp"
:
otp
,
"mfaToken"
:
mfaToken
};
return
requestNormal
(
APIPaths
.
verifyOtpWithAction
,
Method
.
POST
,
...
...
@@ -58,7 +60,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future
<
BaseResponseModel
<
OTPResendResponseModel
>>
resendOTP
(
String
mfaToken
)
async
{
final
body
=
{
"mfaToken"
:
mfaToken
,
};
final
body
=
{
"mfaToken"
:
mfaToken
};
return
requestNormal
(
APIPaths
.
retryOtpWithAction
,
Method
.
POST
,
...
...
@@ -70,27 +72,42 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
Future
<
BaseResponseModel
<
EmptyCodable
>>
signup
(
String
phone
,
String
password
)
async
{
var
deviceKey
=
await
DeviceInfo
.
getDeviceId
();
final
body
=
{
"username"
:
phone
,
"password"
:
password
.
toSha256
(),
"device_key"
:
deviceKey
};
return
requestNormal
(
APIPaths
.
signup
,
Method
.
POST
,
body
,
(
data
)
=>
EmptyCodable
.
fromJson
(
data
as
Json
));
}
Future
<
BaseResponseModel
<
CreateOTPResponseModel
>>
otpCreateNew
(
String
ownerId
)
async
{
var
deviceKey
=
await
DeviceInfo
.
getDeviceId
();
final
body
=
{
"owner_id"
:
ownerId
,
"ttl"
:
Constants
.
otpTtl
,
"resend_after_second"
:
Constants
.
otpTtl
};
return
requestNormal
(
APIPaths
.
signup
,
APIPaths
.
otpCreateNew
,
Method
.
POST
,
body
,
(
data
)
=>
EmptyCodable
.
fromJson
(
data
as
Json
),
(
data
)
=>
CreateOTPResponseModel
.
fromJson
(
data
as
Json
),
);
}
Future
<
BaseResponseModel
<
EmptyCodable
>>
otpCreateNew
(
String
ownerId
,)
async
{
var
deviceKey
=
await
DeviceInfo
.
getDeviceId
();
final
body
=
{
"owner_id"
:
ownerId
,
"ttl"
:
Constants
.
otpTtl
,
"resend_after_second"
:
Constants
.
otpTtl
};
Future
<
BaseResponseModel
<
CreateOTPResponseModel
>>
otpVerifyForDoingNextEvent
(
String
ownerId
,
String
otp
,
String
nextEventName
,
)
async
{
final
body
=
{
"owner_id"
:
ownerId
,
"otp"
:
otp
,
"next_event_name"
:
nextEventName
,
"ttdne"
:
180
,
// TODO
"ttl"
:
Constants
.
otpTtl
,
"resend_after_second"
:
Constants
.
otpTtl
,
};
return
requestNormal
(
APIPaths
.
otp
CreateNew
,
APIPaths
.
otp
VerifyForDoingNextEvent
,
Method
.
POST
,
body
,
(
data
)
=>
EmptyCodable
.
fromJson
(
data
as
Json
),
(
data
)
=>
CreateOTPResponseModel
.
fromJson
(
data
as
Json
),
);
}
Future
<
BaseResponseModel
<
CampaignDetailResponseModel
>>
websitePageGetDetail
(
String
id
)
async
{
final
body
=
{
"website_page_id"
:
"18756"
,
"access_token"
:
""
,
};
final
body
=
{
"website_page_id"
:
id
};
return
requestNormal
(
APIPaths
.
websitePageGetDetail
,
Method
.
POST
,
...
...
@@ -100,7 +117,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}
Future
<
BaseResponseModel
<
CampaignDetailResponseModel
>>
websitePage
(
DetailPageRuleType
rule
)
async
{
final
body
=
{
"code"
:
rule
.
key
,
};
final
body
=
{
"code"
:
rule
.
key
};
return
requestNormal
(
APIPaths
.
websitePage
,
Method
.
GET
,
...
...
@@ -108,4 +125,24 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
(
data
)
=>
CampaignDetailResponseModel
.
fromJson
(
data
as
Json
),
);
}
Future
<
BaseResponseModel
<
FAQItemModelResponse
>>
websiteFolderGetPageList
()
async
{
final
body
=
{
"folder_uri"
:
"FAQ"
};
return
requestNormal
(
APIPaths
.
websiteFolderGetPageList
,
Method
.
POST
,
body
,
(
data
)
=>
FAQItemModelResponse
.
fromJson
(
data
as
Json
),
);
}
Future
<
BaseResponseModel
<
EmptyCodable
>>
accountPasswordReset
(
String
phone
,
String
password
)
async
{
final
body
=
{
"login_name"
:
phone
,
"password"
:
password
.
toSha256
()};
return
requestNormal
(
APIPaths
.
accountPasswordReset
,
Method
.
POST
,
body
,
(
data
)
=>
EmptyCodable
.
fromJson
(
data
as
Json
),
);
}
}
lib/screen/create_pass/create_pass_viewmodel.dart
View file @
e92ea8bf
...
...
@@ -38,13 +38,11 @@ class CreatePasswordViewModel extends GetxController {
Future
<
void
>
onSubmit
()
async
{
if
(!
isButtonEnabled
.
value
)
return
;
try
{
final
response
=
await
repository
.
s
ignup
(
newPassword
.
value
);
final
response
=
await
repository
.
s
etPassword
(
newPassword
.
value
);
if
(
response
.
isSuccess
)
{
errorMessage
.
value
=
""
;
// TODO: Điều hướng sang màn hình tiếp theo
// e.g. Get.offAllNamed("/home");
}
else
{
errorMessage
.
value
=
"Tạo mật khẩu thất bại. Thử lại sau."
;
errorMessage
.
value
=
response
.
errorMessage
??
"Tạo mật khẩu thất bại. Thử lại sau."
;
}
}
catch
(
e
)
{
errorMessage
.
value
=
"Có lỗi xảy ra:
$e
"
;
...
...
lib/screen/create_pass/reset_create_password_repository.dart
0 → 100644
View file @
e92ea8bf
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
'../../base/base_response_model.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'../login/login_screen.dart'
;
import
'../splash/splash_screen_viewmodel.dart'
;
class
ResetCreatePasswordRepository
extends
RestfulApiViewModel
implements
ICreatePasswordRepository
{
@override
late
String
phoneNumber
;
ResetCreatePasswordRepository
(
this
.
phoneNumber
);
@override
Future
<
BaseResponseModel
<
EmptyCodable
>>
setPassword
(
String
password
)
async
{
showLoading
();
return
client
.
accountPasswordReset
(
phoneNumber
,
password
).
then
((
value
)
{
hideLoading
();
if
(
value
.
status
==
"success"
||
value
.
code
==
200
)
{
print
(
"Reset password success"
);
Get
.
off
(()
=>
LoginScreen
(
phoneNumber:
phoneNumber
));
}
return
value
;
});
}
}
lib/screen/create_pass/signup_create_password_repository.dart
View file @
e92ea8bf
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'package:mypoint_flutter_app/screen/login/login_screen.dart'
;
import
'../../base/base_response_model.dart'
;
...
...
@@ -10,8 +9,7 @@ import '../splash/splash_screen_viewmodel.dart';
abstract
class
ICreatePasswordRepository
{
late
String
phoneNumber
;
Future
<
bool
?>
createPassword
(
String
newPassword
);
Future
<
BaseResponseModel
<
EmptyCodable
>>
signup
(
String
password
);
Future
<
BaseResponseModel
<
EmptyCodable
>>
setPassword
(
String
password
);
}
class
SignUpCreatePasswordRepository
extends
RestfulApiViewModel
implements
ICreatePasswordRepository
{
...
...
@@ -21,7 +19,7 @@ class SignUpCreatePasswordRepository extends RestfulApiViewModel implements ICre
SignUpCreatePasswordRepository
(
this
.
phoneNumber
);
@override
Future
<
BaseResponseModel
<
EmptyCodable
>>
s
ignup
(
String
password
)
async
{
Future
<
BaseResponseModel
<
EmptyCodable
>>
s
etPassword
(
String
password
)
async
{
showLoading
();
return
client
.
signup
(
phoneNumber
,
password
).
then
((
value
)
{
hideLoading
();
...
...
@@ -32,10 +30,4 @@ class SignUpCreatePasswordRepository extends RestfulApiViewModel implements ICre
return
value
;
});
}
@override
Future
<
bool
?>
createPassword
(
String
newPassword
)
{
// TODO: implement createPassword
throw
UnimplementedError
();
}
}
lib/screen/faqs/faq_detail_screen.dart
0 → 100644
View file @
e92ea8bf
import
'package:flutter/material.dart'
;
import
'faqs_model.dart'
;
class
FAQDetailScreen
extends
StatelessWidget
{
final
FAQItemModel
faqItem
;
const
FAQDetailScreen
({
super
.
key
,
required
this
.
faqItem
});
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
title:
Text
(
faqItem
.
title
??
""
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
bold
)),
backgroundColor:
Colors
.
white
,
foregroundColor:
Colors
.
black
,
elevation:
0
,
),
body:
Padding
(
padding:
const
EdgeInsets
.
all
(
16.0
),
child:
Text
(
faqItem
.
chapeau
??
""
,
style:
const
TextStyle
(
fontSize:
16
,
color:
Colors
.
black87
),
),
),
);
}
}
lib/screen/faqs/faqs_model.dart
0 → 100644
View file @
e92ea8bf
import
'package:json_annotation/json_annotation.dart'
;
part
'faqs_model.g.dart'
;
@JsonSerializable
()
class
FAQItemModel
{
final
String
?
thumbnail
;
@JsonKey
(
name:
"page_id"
)
final
String
?
pageId
;
final
String
?
title
;
@JsonKey
(
name:
"publish_at_date"
)
final
String
?
publishAtDate
;
final
String
?
chapeau
;
FAQItemModel
({
this
.
thumbnail
,
this
.
pageId
,
this
.
title
,
this
.
publishAtDate
,
this
.
chapeau
,
});
factory
FAQItemModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$FAQItemModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$FAQItemModelToJson
(
this
);
}
@JsonSerializable
()
class
FAQItemModelResponse
{
final
List
<
FAQItemModel
>?
items
;
FAQItemModelResponse
({
this
.
items
,
});
factory
FAQItemModelResponse
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$FAQItemModelResponseFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$FAQItemModelResponseToJson
(
this
);
}
\ No newline at end of file
lib/screen/faqs/faqs_model.g.dart
0 → 100644
View file @
e92ea8bf
// GENERATED CODE - DO NOT MODIFY BY HAND
part of
'faqs_model.dart'
;
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
FAQItemModel
_$FAQItemModelFromJson
(
Map
<
String
,
dynamic
>
json
)
=>
FAQItemModel
(
thumbnail:
json
[
'thumbnail'
]
as
String
?,
pageId:
json
[
'page_id'
]
as
String
?,
title:
json
[
'title'
]
as
String
?,
publishAtDate:
json
[
'publish_at_date'
]
as
String
?,
chapeau:
json
[
'chapeau'
]
as
String
?,
);
Map
<
String
,
dynamic
>
_$FAQItemModelToJson
(
FAQItemModel
instance
)
=>
<
String
,
dynamic
>{
'thumbnail'
:
instance
.
thumbnail
,
'page_id'
:
instance
.
pageId
,
'title'
:
instance
.
title
,
'publish_at_date'
:
instance
.
publishAtDate
,
'chapeau'
:
instance
.
chapeau
,
};
FAQItemModelResponse
_$FAQItemModelResponseFromJson
(
Map
<
String
,
dynamic
>
json
,
)
=>
FAQItemModelResponse
(
items:
(
json
[
'items'
]
as
List
<
dynamic
>?)
?.
map
((
e
)
=>
FAQItemModel
.
fromJson
(
e
as
Map
<
String
,
dynamic
>))
.
toList
(),
);
Map
<
String
,
dynamic
>
_$FAQItemModelResponseToJson
(
FAQItemModelResponse
instance
,
)
=>
<
String
,
dynamic
>{
'items'
:
instance
.
items
};
lib/screen/faqs/faqs_screen.dart
0 → 100644
View file @
e92ea8bf
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/screen/pageDetail/campaign_detail_screen.dart'
;
import
'package:mypoint_flutter_app/widgets/back_button.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resouce/base_color.dart'
;
import
'faqs_viewmodel.dart'
;
class
FAQScreen
extends
BaseScreen
{
const
FAQScreen
({
super
.
key
});
@override
State
<
FAQScreen
>
createState
()
=>
_FAQScreenState
();
}
class
_FAQScreenState
extends
BaseState
<
FAQScreen
>
with
BasicState
{
final
FAQViewModel
_controller
=
Get
.
put
(
FAQViewModel
());
@override
Widget
createBody
()
{
return
Scaffold
(
appBar:
AppBar
(
leading:
CustomBackButton
(),
title:
const
Text
(
"Câu hỏi thường gặp"
,
style:
TextStyle
(
fontWeight:
FontWeight
.
bold
)),
backgroundColor:
Colors
.
white
,
foregroundColor:
Colors
.
black
,
elevation:
0
,
),
body:
Column
(
children:
[
Obx
(()
{
if
(
_controller
.
isLoading
.
value
)
{
return
const
Expanded
(
child:
Center
(
child:
CircularProgressIndicator
()));
}
if
(
_controller
.
faqItems
.
isEmpty
)
{
return
const
Expanded
(
child:
Center
(
child:
Text
(
"Không có dữ liệu."
)));
}
return
Expanded
(
child:
_buildFAQList
());
}),
],
),
);
}
Widget
_buildFAQList
()
{
return
ListView
.
builder
(
itemCount:
_controller
.
faqItems
.
length
,
itemBuilder:
(
context
,
index
)
{
final
item
=
_controller
.
faqItems
[
index
];
return
GestureDetector
(
onTap:
()
{
if
(
item
.
pageId
!=
null
&&
item
.
pageId
!.
isNotEmpty
)
{
Get
.
to
(()
=>
CampaignDetailScreen
(
pageId:
item
.
pageId
));
}
else
{
Get
.
snackbar
(
"Thông báo"
,
"Không thể mở chi tiết vì thiếu ID!"
,
backgroundColor:
Colors
.
redAccent
,
colorText:
Colors
.
white
,
);
}
},
child:
Column
(
children:
[
Container
(
color:
BaseColor
.
second200
,
child:
ListTile
(
leading:
const
Icon
(
Icons
.
help_outline
,
color:
BaseColor
.
second500
),
title:
Text
(
item
.
title
??
""
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
bold
,
color:
BaseColor
.
second700
),
),
trailing:
Icon
(
Icons
.
arrow_forward_ios
,
size:
16
,
color:
BaseColor
.
second500
),
),
),
const
SizedBox
(
height:
8
),
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
56
,
right:
16
,
bottom:
10
),
// 👈 56 = icon width + padding mặc định
child:
Align
(
alignment:
Alignment
.
centerLeft
,
child:
Text
(
item
.
chapeau
??
""
,
style:
const
TextStyle
(
fontSize:
16
,
color:
BaseColor
.
second500
)),
),
),
const
SizedBox
(
height:
8
),
],
),
);
},
);
}
}
lib/screen/faqs/faqs_viewmodel.dart
0 → 100644
View file @
e92ea8bf
import
'dart:convert'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'faqs_model.dart'
;
class
FAQViewModel
extends
RestfulApiViewModel
{
var
faqItems
=
<
FAQItemModel
>[].
obs
;
var
isLoading
=
true
.
obs
;
@override
void
onInit
()
{
super
.
onInit
();
fetchFAQItems
();
}
Future
<
void
>
fetchFAQItems
()
async
{
showLoading
();
isLoading
(
true
);
client
.
websiteFolderGetPageList
().
then
((
value
)
{
hideLoading
();
isLoading
(
false
);
faqItems
.
value
=
value
.
data
?.
items
??
[];
});
}
}
lib/screen/login/login_viewmodel.dart
View file @
e92ea8bf
import
'package:get/get.dart'
;
import
'package:flutter/material.dart'
;
import
'package:mypoint_flutter_app/configs/constants.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'package:mypoint_flutter_app/screen/onboarding/onboarding_screen.dart'
;
import
'package:mypoint_flutter_app/screen/otp/forgot_pass_otp_repository.dart'
;
import
'package:mypoint_flutter_app/screen/otp/otp_screen.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'../../permission/biometric_manager.dart'
;
// login_state_enum.dart
enum
LoginState
{
idle
,
typing
,
done
,
error
,
}
enum
LoginState
{
idle
,
typing
,
done
,
error
}
class
LoginViewModel
extends
RestfulApiViewModel
{
final
BiometricManager
_biometricManager
=
BiometricManager
();
...
...
@@ -70,7 +68,14 @@ class LoginViewModel extends RestfulApiViewModel {
showLoading
();
client
.
otpCreateNew
(
phoneNumber
).
then
((
value
)
{
hideLoading
();
print
(
value
);
// TODO: handle error later
if
(
value
.
isSuccess
)
{
Get
.
to
(
OtpScreen
(
repository:
ForgotPassOTPRepository
(
phoneNumber
,
value
.
data
?.
resendAfterSecond
??
Constants
.
otpTtl
),
),
);
}
});
}
...
...
@@ -79,8 +84,7 @@ class LoginViewModel extends RestfulApiViewModel {
// Kiểm tra thiết bị hỗ trợ
final
canUse
=
await
canUseBiometrics
();
if
(!
canUse
||
biometricType
.
value
==
BiometricTypeEnum
.
none
)
{
Get
.
snackbar
(
"Thông báo"
,
"Thiết bị không hỗ trợ sinh trắc học"
,
snackPosition:
SnackPosition
.
BOTTOM
);
Get
.
snackbar
(
"Thông báo"
,
"Thiết bị không hỗ trợ sinh trắc học"
,
snackPosition:
SnackPosition
.
BOTTOM
);
return
;
}
...
...
@@ -88,7 +92,8 @@ class LoginViewModel extends RestfulApiViewModel {
final
success
=
await
_biometricManager
.
showCustomBiometricDialog
(
context
,
title:
"Xác thực sinh trắc học"
,
content:
(
biometricType
.
value
==
BiometricTypeEnum
.
faceId
)
content:
(
biometricType
.
value
==
BiometricTypeEnum
.
faceId
)
?
"Bạn có muốn đăng nhập bằng Face ID không?"
:
"Bạn có muốn đăng nhập bằng vân tay không?"
,
confirmText:
"Đồng ý"
,
...
...
lib/screen/onboarding/onboarding_screen.dart
View file @
e92ea8bf
...
...
@@ -7,6 +7,7 @@ import '../../base/base_screen.dart';
import
'../../base/basic_state.dart'
;
import
'../../configs/constants.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../login/login_screen.dart'
;
import
'../otp/otp_screen.dart'
;
import
'../otp/verify_otp_repository.dart'
;
...
...
@@ -64,8 +65,8 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
()
=>
OtpScreen
(
repository:
VerifyOtpRepository
(
_viewModel
.
phoneNumber
.
value
,
response
!
.
otpTtl
??
0
,
response
!
.
mfaToken
??
""
,
response
?
.
otpTtl
??
0
,
response
?
.
mfaToken
??
""
,
),
),
);
...
...
@@ -203,7 +204,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
const
TextSpan
(
text:
" và "
),
WidgetSpan
(
child:
GestureDetector
(
onTap:
()
=>
Get
.
to
(
CampaignDetailScreen
(
type:
DetailPageRuleType
.
privacyPolicy
)),
onTap:
()
=>
Get
.
to
(
FAQScreen
()),
//
Get.to(CampaignDetailScreen(type: DetailPageRuleType.privacyPolicy)),
child:
const
Text
(
"Chính sách bảo mật"
,
style:
TextStyle
(
...
...
lib/screen/otp/forgot_pass_otp_repository.dart
0 → 100644
View file @
e92ea8bf
import
'package:get/get.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:mypoint_flutter_app/base/base_response_model.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'package:mypoint_flutter_app/screen/create_pass/create_pass_screen.dart'
;
import
'package:mypoint_flutter_app/screen/create_pass/reset_create_password_repository.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'../splash/splash_screen_viewmodel.dart'
;
import
'otp_viewmodel.dart'
;
class
ForgotPassOTPRepository
extends
RestfulApiViewModel
implements
IOtpRepository
{
ForgotPassOTPRepository
(
this
.
phoneNumber
,
this
.
otpTtl
);
@override
int
otpTtl
;
@override
String
phoneNumber
;
@override
Future
<
int
?>
resendOtp
()
{
throw
UnimplementedError
();
}
@override
Future
<
void
>
sendOtp
()
{
throw
UnimplementedError
();
}
@override
Future
<
BaseResponseModel
<
EmptyCodable
>>
verifyOtp
(
String
otpCode
)
{
showLoading
();
return
client
.
otpVerifyForDoingNextEvent
(
phoneNumber
,
otpCode
,
"RESET_PASSWORD"
).
then
((
value
)
{
hideLoading
();
if
(
value
.
status
==
"success"
||
value
.
code
==
200
)
{
Get
.
off
(()
=>
CreatePasswordScreen
(
repository:
ResetCreatePasswordRepository
(
phoneNumber
)));
}
return
value
;
});
}
}
\ No newline at end of file
lib/screen/otp/model/create_otp_response_model.dart
View file @
e92ea8bf
import
'package:json_annotation/json_annotation.dart'
;
import
'../../splash/splash_screen_viewmodel.dart'
;
part
'create_otp_response_model.g.dart'
;
@JsonSerializable
()
class
CreateOTPResponseModel
{
class
CreateOTPResponseModel
extends
EmptyCodable
{
@JsonKey
(
name:
'resend_after_second'
)
int
?
resendAfterSecond
;
CreateOTPResponseModel
({
this
.
resendAfterSecond
,
});
})
:
super
.
fromJson
(
null
)
;
factory
CreateOTPResponseModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$CreateOTPResponseModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$CreateOTPResponseModelToJson
(
this
);
...
...
lib/screen/otp/model/otp_verify_response_model.dart
View file @
e92ea8bf
import
'package:json_annotation/json_annotation.dart'
;
import
'../../splash/splash_screen_viewmodel.dart'
;
import
'otp_claim_verify_response_model.dart'
;
part
'otp_verify_response_model.g.dart'
;
@JsonSerializable
()
class
OTPVerifyResponseModel
{
class
OTPVerifyResponseModel
extends
EmptyCodable
{
OTPClaimVerifyResponseModel
?
claim
;
OTPVerifyResponseModel
({
this
.
claim
,
});
})
:
super
.
fromJson
(
null
)
;
factory
OTPVerifyResponseModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$OTPVerifyResponseModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$OTPVerifyResponseModelToJson
(
this
);
...
...
lib/screen/otp/otp_viewmodel.dart
View file @
e92ea8bf
...
...
@@ -4,12 +4,13 @@ import 'package:mypoint_flutter_app/base/base_response_model.dart';
import
'package:mypoint_flutter_app/configs/constants.dart'
;
import
'package:mypoint_flutter_app/screen/create_pass/create_pass_screen.dart'
;
import
'package:mypoint_flutter_app/screen/login/login_screen.dart'
;
import
'package:mypoint_flutter_app/screen/splash/splash_screen_viewmodel.dart'
;
import
'../create_pass/signup_create_password_repository.dart'
;
import
'model/otp_verify_response_model.dart'
;
abstract
class
IOtpRepository
{
Future
<
void
>
sendOtp
();
Future
<
BaseResponseModel
<
OTPVerifyResponseModel
>>
verifyOtp
(
String
otpCode
);
Future
<
BaseResponseModel
<
EmptyCodable
>>
verifyOtp
(
String
otpCode
);
Future
<
int
?>
resendOtp
();
late
String
phoneNumber
;
late
int
otpTtl
;
...
...
@@ -40,12 +41,6 @@ class OtpViewModel extends GetxController {
}
Future
<
void
>
sendOtp
()
async
{
try
{
await
repository
.
sendOtp
();
startCountdown
();
}
catch
(
e
)
{
errorMessage
.
value
=
"Gửi OTP thất bại. Vui lòng thử lại."
;
}
}
void
startCountdown
()
{
...
...
@@ -81,14 +76,6 @@ class OtpViewModel extends GetxController {
final
response
=
await
repository
.
verifyOtp
(
otpCode
.
value
);
if
(
response
.
isSuccess
)
{
errorMessage
.
value
=
""
;
if
(
response
.
data
?.
claim
?.
action
==
"signup"
)
{
Get
.
off
(()
=>
CreatePasswordScreen
(
repository:
SignUpCreatePasswordRepository
(
repository
.
phoneNumber
)));
return
;
}
if
(
response
.
data
?.
claim
?.
action
==
"login"
)
{
Get
.
off
(()
=>
LoginScreen
(
phoneNumber:
repository
.
phoneNumber
));
return
;
}
}
else
{
errorMessage
.
value
=
response
.
errorMessage
??
""
;
}
...
...
lib/screen/otp/verify_otp_repository.dart
View file @
e92ea8bf
...
...
@@ -4,6 +4,9 @@ import 'package:get/get.dart';
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'../../base/base_response_model.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'../create_pass/create_pass_screen.dart'
;
import
'../create_pass/signup_create_password_repository.dart'
;
import
'../login/login_screen.dart'
;
import
'model/otp_verify_response_model.dart'
;
import
'otp_viewmodel.dart'
;
...
...
@@ -24,6 +27,11 @@ class VerifyOtpRepository extends RestfulApiViewModel implements IOtpRepository
showLoading
();
return
client
.
verifyOTP
(
otpCode
,
mfaToken
).
then
((
value
)
{
hideLoading
();
if
(
value
.
data
?.
claim
?.
action
==
"signup"
)
{
Get
.
off
(()
=>
CreatePasswordScreen
(
repository:
SignUpCreatePasswordRepository
(
phoneNumber
)));
}
else
if
(
value
.
data
?.
claim
?.
action
==
"login"
)
{
Get
.
off
(()
=>
LoginScreen
(
phoneNumber:
phoneNumber
));
}
return
value
;
});
}
...
...
lib/screen/pageDetail/campaign_detail_screen.dart
View file @
e92ea8bf
...
...
@@ -3,6 +3,8 @@ import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import
'package:get/get.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../directional/directional_action_type.dart'
;
import
'../../directional/directional_screen.dart'
;
import
'../../extensions/string_extension.dart'
;
// tuỳ dự án
import
'../../resouce/base_color.dart'
;
import
'../../widgets/back_button.dart'
;
...
...
@@ -128,7 +130,9 @@ class _CampaignDetailScreenState extends BaseState<CampaignDetailScreen> with Ba
SizedBox
(
height:
12
,),
ElevatedButton
(
onPressed:
()
{
// Xử lý khi bấm nút
DirectionalScreen
(
clickActionType:
pageDetail
?.
buttonClickActionType
,
clickActionParam:
pageDetail
?.
buttonClickActionParam
).
begin
();
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
parseHexColor
(
buttonColor
),
...
...
Prev
1
2
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment