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
0bf528a4
Commit
0bf528a4
authored
Oct 17, 2025
by
DatHV
Browse files
refactor logic
parent
89983084
Changes
54
Show whitespace changes
Inline
Side-by-side
lib/screen/home/home_tab_viewmodel.dart
View file @
0bf528a4
...
...
@@ -41,31 +41,33 @@ class HomeTabViewModel extends RestfulApiViewModel {
}
Future
<
void
>
getSectionLayoutHome
()
async
{
showLoading
();
try
{
final
response
=
await
client
.
getSectionLayoutHome
();
sectionLayouts
.
assignAll
(
response
.
data
??
[]
);
hideLoading
();
}
catch
(
error
)
{
await
callApi
<
List
<
MainSectionConfigModel
>>(
request:
()
=>
client
.
getSectionLayoutHome
(),
onSuccess:
(
data
,
_
)
{
sectionLayouts
.
assignAll
(
data
);
},
onFailure:
(
_
,
_
,
_
)
async
{
sectionLayouts
.
assignAll
(
await
_loadSectionLayoutHomeFromCache
());
hideLoading
();
}
finally
{
},
onComplete:
()
async
{
if
(
sectionLayouts
.
isEmpty
)
{
sectionLayouts
.
assignAll
(
await
_loadSectionLayoutHomeFromCache
());
}
for
(
final
section
in
sectionLayouts
)
{
await
_processSection
(
section
);
}
}
},
);
}
Future
<
void
>
loadDataPiPiHome
()
async
{
try
{
final
result
=
await
client
.
getDataPiPiHome
();
hoverData
.
value
=
result
.
data
;
}
catch
(
error
)
{
print
(
"Error fetching loadDataPiPiHome:
$error
"
);
}
await
callApi
<
HoverDataModel
>(
request:
()
=>
client
.
getDataPiPiHome
(),
onSuccess:
(
data
,
_
)
{
hoverData
.
value
=
data
;
},
withLoading:
false
,
);
}
Future
<
List
<
MainSectionConfigModel
>>
_loadSectionLayoutHomeFromCache
()
async
{
...
...
lib/screen/invite_friend_campaign/invite_friend_campaign_viewmodel.dart
View file @
0bf528a4
...
...
@@ -26,7 +26,7 @@ class InviteFriendCampaignViewModel extends RestfulApiViewModel {
onShowAlertError
?.
call
(
Constants
.
commonError
,
false
);
}
},
onFailure:
(
msg
,
_
,
_
_
)
async
{
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
,
false
);
},
);
...
...
@@ -38,7 +38,7 @@ class InviteFriendCampaignViewModel extends RestfulApiViewModel {
onSuccess:
(
data
,
_
)
{
inviteFriendDetail
.
value
=
data
;
},
onFailure:
(
msg
,
_
,
_
_
)
async
{
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
,
true
);
},
);
...
...
@@ -50,7 +50,7 @@ class InviteFriendCampaignViewModel extends RestfulApiViewModel {
onSuccess:
(
data
,
_
)
{
campaignDetail
.
value
=
data
;
},
onFailure:
(
msg
,
_
,
_
_
)
async
{
onFailure:
(
msg
,
_
,
_
)
async
{
// Silent failure for this optional call
},
showAppNavigatorDialog:
false
,
...
...
lib/screen/location_address/location_address_viewmodel.dart
View file @
0bf528a4
import
'package:get/get.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:get/get_rx/src/rx_types/rx_types.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'location_address_screen.dart'
;
...
...
@@ -26,31 +24,37 @@ class LocationAddressViewModel extends RestfulApiViewModel {
void
onInit
()
{
super
.
onInit
();
if
(
type
==
LocationAddressType
.
province
)
{
client
.
locationProvinceGetList
().
then
((
value
)
{
final
data
=
value
.
data
?.
items
??
[];
_loadFromProvince
(
data
);
});
callApi
<
ProvinceAddressResponse
>(
request:
()
=>
client
.
locationProvinceGetList
(),
onSuccess:
(
data
,
_
)
{
_loadFromProvince
(
data
.
items
??
[]);
},
withLoading:
false
,
);
}
else
{
client
.
locationDistrictGetList
(
provinceCode
).
then
((
value
)
{
final
data
=
value
.
data
?.
items
??
[];
_loadFromDistrict
(
data
);
});
callApi
<
DistrictAddressResponse
>(
request:
()
=>
client
.
locationDistrictGetList
(
provinceCode
),
onSuccess:
(
data
,
_
)
{
_loadFromDistrict
(
data
.
items
??
[]);
},
withLoading:
false
,
);
}
}
void
_loadFromProvince
(
List
<
ProvinceAddressModel
>
provinces
)
{
_allItems
=
provinces
.
map
((
e
)
=>
AddressBaseModel
(
code:
e
.
cityCode
,
name:
e
.
cityName
)).
toList
();
displayItems
.
value
=
_allItems
;
displayItems
.
assignAll
(
_allItems
)
;
}
void
_loadFromDistrict
(
List
<
DistrictAddressModel
>
districts
)
{
_allItems
=
districts
.
map
((
e
)
=>
AddressBaseModel
(
code:
e
.
districtCode
,
name:
e
.
districtName
)).
toList
();
displayItems
.
value
=
_allItems
;
displayItems
.
assignAll
(
_allItems
)
;
}
void
search
(
String
query
)
{
if
(
query
.
isEmpty
)
{
displayItems
.
value
=
_allItems
;
displayItems
.
assignAll
(
_allItems
)
;
return
;
}
final
lowerQuery
=
_removeDiacritics
(
query
).
toLowerCase
();
...
...
@@ -59,11 +63,10 @@ class LocationAddressViewModel extends RestfulApiViewModel {
final
normalized
=
_removeDiacritics
(
name
).
toLowerCase
();
return
normalized
.
contains
(
lowerQuery
);
}).
toList
();
displayItems
.
value
=
filteredItems
;
displayItems
.
assignAll
(
filteredItems
)
;
}
void
select
(
AddressBaseModel
item
)
{
print
(
" Selected code:
${item.code}
"
);
selectedCode
.
value
=
item
.
code
??
''
;
displayItems
.
refresh
();
Get
.
back
(
result:
item
);
...
...
lib/screen/login/login_viewmodel.dart
View file @
0bf528a4
...
...
@@ -8,15 +8,16 @@ import '../../networking/restful_api_viewmodel.dart';
import
'../../permission/biometric_manager.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../services/login_service.dart'
;
import
'../otp/model/create_otp_response_model.dart'
;
enum
LoginState
{
idle
,
typing
,
error
}
class
LoginViewModel
extends
RestfulApiViewModel
{
var
loginState
=
LoginState
.
idle
.
obs
;
var
isPasswordVisible
=
false
.
obs
;
var
password
=
""
.
obs
;
var
isSupportedBiometric
=
false
.
obs
;
var
biometricType
=
BiometricTypeEnum
.
none
.
obs
;
final
Rx
<
LoginState
>
loginState
=
LoginState
.
idle
.
obs
;
final
RxBool
isPasswordVisible
=
false
.
obs
;
final
RxString
password
=
""
.
obs
;
final
RxBool
isSupportedBiometric
=
false
.
obs
;
final
Rx
<
BiometricTypeEnum
>
biometricType
=
BiometricTypeEnum
.
none
.
obs
;
void
Function
(
String
message
)?
onShowAlertError
;
void
Function
(
String
message
)?
onShowDeviceError
;
...
...
@@ -52,15 +53,9 @@ class LoginViewModel extends RestfulApiViewModel {
Future
<
void
>
onLoginPressed
(
String
phone
)
async
{
if
(
password
.
value
.
isEmpty
)
return
;
showLoading
();
try
{
final
result
=
await
_loginService
.
login
(
phone
,
password
.
value
);
hideLoading
();
_handleLoginResult
(
result
,
phone
);
}
catch
(
e
)
{
hideLoading
();
print
(
'Login error:
${e.toString()}
'
);
onShowAlertError
?.
call
(
Constants
.
commonError
);
}
}
/// REFACTORED: Handle login result with proper error handling
...
...
@@ -84,6 +79,7 @@ class LoginViewModel extends RestfulApiViewModel {
break
;
case
LoginResult
.
invalidCredentials
:
loginState
.
value
=
LoginState
.
error
;
onShowAlertError
?.
call
(
result
.
message
??
Constants
.
commonError
);
break
;
case
LoginResult
.
networkError
:
case
LoginResult
.
unknownError
:
...
...
@@ -103,24 +99,15 @@ class LoginViewModel extends RestfulApiViewModel {
}
Future
<
void
>
onForgotPassPressed
(
String
phone
)
async
{
showLoading
();
try
{
final
response
=
await
client
.
otpCreateNew
(
phone
);
hideLoading
();
if
(!
response
.
isSuccess
)
{
onShowAlertError
?.
call
(
response
.
errorMessage
??
Constants
.
commonError
);
return
;
}
Get
.
to
(
OtpScreen
(
repository:
ForgotPassOTPRepository
(
phone
,
response
.
data
?.
resendAfterSecond
??
Constants
.
otpTtl
),
),
await
callApi
<
CreateOTPResponseModel
>(
request:
()
=>
client
.
otpCreateNew
(
phone
),
onSuccess:
(
data
,
_
)
{
Get
.
to
(
OtpScreen
(
repository:
ForgotPassOTPRepository
(
phone
,
data
.
resendAfterSecond
??
Constants
.
otpTtl
)));
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
catch
(
e
)
{
hideLoading
();
print
(
'OTP error:
${e.toString()}
'
);
onShowAlertError
?.
call
(
Constants
.
commonError
);
}
}
/// REFACTORED: Biometric login using LoginService
...
...
@@ -137,14 +124,8 @@ class LoginViewModel extends RestfulApiViewModel {
return
;
}
showLoading
();
try
{
final
result
=
await
_loginService
.
biometricLogin
(
phone
);
hideLoading
();
_handleLoginResult
(
result
,
phone
);
}
catch
(
e
)
{
hideLoading
();
print
(
'Biometric login error:
${e.toString()}
'
);
onShowAlertError
?.
call
(
Constants
.
commonError
);
}
}
}
lib/screen/membership/membership_screen.dart
View file @
0bf528a4
...
...
@@ -24,6 +24,10 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState
void
initState
()
{
super
.
initState
();
_viewModel
=
Get
.
put
(
MembershipViewModel
());
_viewModel
.
onShowAlertError
=
(
message
)
{
if
(
message
.
isEmpty
)
return
;
showAlertError
(
content:
message
);
};
}
@override
...
...
lib/screen/membership/membership_viewmodel.dart
View file @
0bf528a4
...
...
@@ -8,10 +8,10 @@ import 'models/membership_level_model.dart';
import
'models/membership_level_term_and_condition_model.dart'
;
class
MembershipViewModel
extends
RestfulApiViewModel
{
var
isLoading
=
false
.
obs
;
var
membershipInfo
=
Rxn
<
MembershipInfoResponse
>();
var
selectedTab
=
0
.
obs
;
final
Rxn
<
MembershipInfoResponse
>
membershipInfo
=
Rxn
<
MembershipInfoResponse
>();
final
RxInt
selectedTab
=
0
.
obs
;
MembershipLevelModel
?
selectedLevel
;
void
Function
(
String
message
)?
onShowAlertError
;
List
<
MembershipLevelModel
>?
get
levels
{
return
membershipInfo
.
value
?.
levels
;
...
...
@@ -50,23 +50,15 @@ class MembershipViewModel extends RestfulApiViewModel {
}
Future
<
void
>
getMembershipLevelInfo
()
async
{
showLoading
();
try
{
final
response
=
await
client
.
getMembershipLevelInfo
();
if
(
response
.
isSuccess
&&
response
.
data
!=
null
)
{
membershipInfo
.
value
=
response
.
data
;
await
callApi
<
MembershipInfoResponse
>(
request:
()
=>
client
.
getMembershipLevelInfo
(),
onSuccess:
(
data
,
_
)
{
membershipInfo
.
value
=
data
;
_makeSelectedLevel
();
}
else
{
if
(
kDebugMode
)
{
print
(
"Failed to get membership info:
${response.errorMessage}
"
);
}
}
}
catch
(
e
)
{
if
(
kDebugMode
)
{
print
(
"Error fetching membership level info:
$e
"
);
}
}
finally
{
hideLoading
();
}
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
}
lib/screen/mobile_card/product_mobile_card_viewmodel.dart
View file @
0bf528a4
...
...
@@ -4,15 +4,15 @@ import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.da
import
'package:mypoint_flutter_app/screen/mobile_card/models/product_mobile_card_model.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'../../preference/point/point_manager.dart'
;
import
'models/mobile_service_redeem_data.dart'
;
import
'models/usable_voucher_model.dart'
;
class
ProductMobileCardViewModel
extends
RestfulApiViewModel
{
void
Function
(
String
message
)?
onShowAlertError
;
void
Function
(
UsableVoucherModel
data
)?
onRedeemProductMobileSuccess
;
RxMap
<
String
,
List
<
ProductMobileCardModel
>>
groupedSection
=
RxMap
<
String
,
List
<
ProductMobileCardModel
>>();
var
mobileCardSections
=
RxList
<
ProductMobileCardModel
>();
RxString
selectedBrandCode
=
""
.
obs
;
final
RxMap
<
String
,
List
<
ProductMobileCardModel
>>
groupedSection
=
RxMap
<
String
,
List
<
ProductMobileCardModel
>>();
final
RxList
<
ProductMobileCardModel
>
mobileCardSections
=
<
ProductMobileCardModel
>[].
obs
;
final
RxString
selectedBrandCode
=
""
.
obs
;
List
<
ProductMobileCardModel
>
get
products
{
return
groupedSection
[
selectedBrandCode
.
value
]
??
[];
}
...
...
@@ -32,48 +32,44 @@ class ProductMobileCardViewModel extends RestfulApiViewModel {
}
Future
<
void
>
redeemProductMobileCard
()
async
{
showLoading
();
try
{
final
response
=
await
client
.
redeemMobileCard
((
selectedProduct
?.
id
??
0
).
toString
());
final
itemId
=
response
.
data
?.
itemId
??
""
;
hideLoading
();
await
callApi
<
MobileServiceRedeemData
>(
request:
()
=>
client
.
redeemMobileCard
((
selectedProduct
?.
id
??
0
).
toString
()),
onSuccess:
(
data
,
_
)
async
{
final
itemId
=
data
.
itemId
??
""
;
if
(
itemId
.
isEmpty
)
{
print
(
"redeemMobileCard failed:
${response.errorMessage}
"
);
onShowAlertError
?.
call
(
response
.
errorMessage
??
Constants
.
commonError
);
return
;
}
_getMobileCardCode
(
itemId
);
}
catch
(
error
)
{
hideLoading
();
onShowAlertError
?.
call
(
error
.
toString
());
onShowAlertError
?.
call
(
Constants
.
commonError
);
return
;
}
await
_getMobileCardCode
(
itemId
);
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
Future
<
void
>
_getMobileCardCode
(
String
itemId
)
async
{
showLoading
();
try
{
final
response
=
await
client
.
getMobileCardCode
(
itemId
);
hideLoading
();
final
data
=
response
.
data
?.
item
;
if
(
response
.
isSuccess
&&
data
!=
null
)
{
onRedeemProductMobileSuccess
?.
call
(
data
);
return
;
}
onShowAlertError
?.
call
(
response
.
message
??
Constants
.
commonError
);
}
catch
(
error
)
{
hideLoading
();
onShowAlertError
?.
call
(
error
.
toString
());
return
;
}
await
callApi
<
RedeemProductResponseModel
>(
request:
()
=>
client
.
getMobileCardCode
(
itemId
),
onSuccess:
(
data
,
_
)
{
final
item
=
data
.
item
;
if
(
item
!=
null
)
{
onRedeemProductMobileSuccess
?.
call
(
item
);
}
else
{
onShowAlertError
?.
call
(
Constants
.
commonError
);
}
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
Future
<
void
>
getProductMobileCard
()
async
{
showLoading
();
try
{
final
response
=
await
client
.
productMobileCardGetList
();
final
result
=
response
.
data
?.
products
??
[];
await
callApi
<
ProductMobileCardResponse
>(
request:
()
=>
client
.
productMobileCardGetList
(),
onSuccess:
(
data
,
_
)
{
final
result
=
data
.
products
??
[];
final
seen
=
<
String
>{};
final
uniqueBrandCode
=
<
ProductMobileCardModel
>[];
for
(
final
p
in
result
)
{
...
...
@@ -83,24 +79,18 @@ class ProductMobileCardViewModel extends RestfulApiViewModel {
}
}
selectedBrandCode
.
value
=
uniqueBrandCode
.
isNotEmpty
?
uniqueBrandCode
.
first
.
brandCode
??
""
:
""
;
mobileCardSections
.
value
=
uniqueBrandCode
;
mobileCardSections
.
assignAll
(
uniqueBrandCode
)
;
final
Map
<
String
,
List
<
ProductMobileCardModel
>>
grouped
=
{};
for
(
final
product
in
result
)
{
final
code
=
product
.
brandCode
??
'unknown'
;
if
(!
grouped
.
containsKey
(
code
))
{
grouped
[
code
]
=
[];
}
grouped
[
code
]!.
add
(
product
);
}
groupedSection
.
value
=
grouped
;
hideLoading
();
if
(!
response
.
isSuccess
)
{
onShowAlertError
?.
call
(
response
.
message
??
Constants
.
commonError
);
}
}
catch
(
error
)
{
onShowAlertError
?.
call
(
error
.
toString
());
}
grouped
.
putIfAbsent
(
code
,
()
=>
<
ProductMobileCardModel
>[]).
add
(
product
);
}
groupedSection
.
assignAll
(
grouped
);
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
}
lib/screen/news/news_list_viewmodel.dart
View file @
0bf528a4
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../faqs/faqs_model.dart'
;
class
NewsListViewModel
extends
RestfulApiViewModel
{
String
folderUri
;
var
newsList
=
<
PageItemModel
>[].
obs
;
var
isLoading
=
false
.
obs
;
final
RxList
<
PageItemModel
>
newsList
=
<
PageItemModel
>[].
obs
;
final
RxBool
isLoading
=
false
.
obs
;
var
_canLoadMore
=
true
;
int
start
=
0
;
int
limit
=
20
;
NewsListViewModel
({
this
.
folderUri
=
"TIN-TUC"
});
...
...
@@ -23,21 +21,25 @@ class NewsListViewModel extends RestfulApiViewModel {
Future
<
void
>
getNewsList
({
bool
isRefresh
=
false
})
async
{
if
(
isLoading
.
value
)
return
;
if
(!
isRefresh
&&
!
_canLoadMore
)
return
;
showLoading
();
isLoading
(
true
);
final
body
=
{
"folder_uri"
:
folderUri
,
"start"
:
isRefresh
?
0
:
newsList
.
length
,
"limit"
:
limit
,
};
client
.
websiteFolderGetPageList
(
body
).
then
((
value
)
{
hideLoading
();
isLoading
(
false
);
_canLoadMore
=
value
.
data
?
.
items
?.
length
==
limit
;
await
callApi
<
FAQItemModelResponse
>(
request:
()
=>
client
.
websiteFolderGetPageList
(
body
),
onSuccess:
(
data
,
_
)
{
_canLoadMore
=
(
data
.
items
?.
length
??
0
)
==
limit
;
if
(
isRefresh
)
{
newsList
.
value
.
clear
();
newsList
.
clear
();
}
newsList
.
addAll
(
data
.
items
??
[]);
},
withLoading:
false
,
onComplete:
()
{
isLoading
(
false
);
}
newsList
.
addAll
(
value
.
data
?.
items
??
[]);
});
);
}
}
\ No newline at end of file
lib/screen/notification/notification_screen.dart
View file @
0bf528a4
...
...
@@ -162,7 +162,7 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
_isPopupShown
=
true
;
}
_confirmDeleteAllNotifications
()
{
void
_confirmDeleteAllNotifications
()
{
final
dataAlert
=
DataAlertModel
(
title:
"Xoá tất cả"
,
description:
"Bạn có muốn xoá hết tất cả thông báo không?
\n
Lưu ý: bạn sẽ không thể xem lại thông báo đã xoá"
,
...
...
lib/screen/notification/notification_viewmodel.dart
View file @
0bf528a4
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'
;
import
'../../base/base_response_model.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'../../preference/data_preference.dart'
;
import
'models/category_notify_item_model.dart'
;
import
'models/notification_detail_model.dart'
;
import
'models/notification_item_model.dart'
;
import
'models/notification_list_data_model.dart'
;
import
'notification_detail_screen.dart'
;
class
NotificationViewModel
extends
RestfulApiViewModel
{
var
categories
=
RxList
<
CategoryNotifyItemModel
>
()
;
var
notifications
=
RxList
<
NotificationItemModel
>
()
;
final
RxList
<
CategoryNotifyItemModel
>
categories
=
<
CategoryNotifyItemModel
>
[].
obs
;
final
RxList
<
NotificationItemModel
>
notifications
=
<
NotificationItemModel
>
[].
obs
;
final
RxBool
isLoading
=
false
.
obs
;
final
_pageLimit
=
10
;
var
_notificationIndex
=
0
;
...
...
@@ -25,15 +28,17 @@ class NotificationViewModel extends RestfulApiViewModel {
}
void
_fetchCategories
()
async
{
showLoading
();
client
.
getNotificationCategories
().
then
((
value
)
{
final
results
=
value
.
data
??
[];
if
(
results
.
isNotEmpty
)
{
results
[
0
].
isSelected
=
true
;
}
categories
.
value
=
results
;
await
callApi
<
List
<
CategoryNotifyItemModel
>>(
request:
()
=>
client
.
getNotificationCategories
(),
onSuccess:
(
data
,
_
)
{
if
(
data
.
isNotEmpty
)
data
[
0
].
isSelected
=
true
;
categories
.
assignAll
(
data
);
fetchNotifications
(
refresh:
true
);
});
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
void
fetchNotifications
({
bool
refresh
=
false
})
async
{
...
...
@@ -50,18 +55,26 @@ class NotificationViewModel extends RestfulApiViewModel {
"limit"
:
_pageLimit
,
"noti_group_id"
:
selectedCategory
?.
id
??
""
,
};
client
.
getNotifications
(
body
).
then
((
value
)
{
isLoading
.
value
=
false
;
hideLoading
();
final
items
=
value
.
data
?
.
items
??
[];
await
callApi
<
NotificationListDataModel
>(
request:
()
=>
client
.
getNotifications
(
body
),
onSuccess:
(
data
,
_
)
{
final
items
=
data
.
items
??
[];
if
(
refresh
)
{
notifications
.
value
=
items
;
notifications
.
assignAll
(
items
)
;
}
else
{
notifications
.
addAll
(
items
);
}
_notificationIndex
+=
items
.
length
;
_hasMoreData
=
(
value
.
data
?.
items
?.
length
??
0
)
==
_pageLimit
;
});
_hasMoreData
=
items
.
length
==
_pageLimit
;
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
withLoading:
refresh
,
onComplete:
()
{
isLoading
.
value
=
false
;
},
);
}
void
selectCategory
(
int
index
)
{
...
...
@@ -72,38 +85,55 @@ class NotificationViewModel extends RestfulApiViewModel {
}
void
notificationMarkAsSeen
()
{
client
.
notificationMarkAsSeen
().
then
((
value
)
{
_fetchCategories
();
});
callApi
<
EmptyCodable
>(
request:
()
=>
client
.
notificationMarkAsSeen
(),
onSuccess:
(
_
,
_
)
=>
_fetchCategories
(),
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
void
deleteAllNotifications
()
{
client
.
deleteAllNotifications
().
then
((
value
)
{
_fetchCategories
();
});
callApi
<
EmptyCodable
>(
request:
()
=>
client
.
deleteAllNotifications
(),
onSuccess:
(
_
,
_
)
=>
_fetchCategories
(),
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
void
handleRemoveNotification
(
NotificationItemModel
item
)
{
if
(
item
.
notificationId
==
null
)
{
return
;
}
client
.
deleteNotification
(
item
.
notificationId
??
""
).
then
((
value
)
{
if
(
item
.
notificationId
==
null
)
return
;
callApi
<
EmptyCodable
>(
request:
()
=>
client
.
deleteNotification
(
item
.
notificationId
??
""
),
onSuccess:
(
_
,
_
)
{
notifications
.
remove
(
item
);
if
(
notifications
.
length
<=
_pageLimit
)
{
fetchNotifications
(
refresh:
false
);
}
});
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
void
handleClickNotification
(
NotificationItemModel
item
)
{
showLoading
();
client
.
getNotificationDetail
(
item
.
notificationId
??
""
).
then
((
value
)
{
hideLoading
();
if
(!
value
.
isSuccess
)
return
;
final
notification
=
value
.
data
?.
notification
;
callApi
<
NotificationDetailResponseModel
>(
request:
()
=>
client
.
getNotificationDetail
(
item
.
notificationId
??
""
),
onSuccess:
(
data
,
_
)
{
final
notification
=
data
.
notification
;
if
(
notification
==
null
)
return
;
final
pushSuccess
=
notification
.
directionalScreen
?.
begin
()
??
false
;
if
(!
pushSuccess
)
{
Get
.
to
(()
=>
NotificationDetailScreen
(
notification:
notification
));
}
});
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
}
lib/screen/onboarding/onboarding_screen.dart
View file @
0bf528a4
...
...
@@ -2,18 +2,13 @@ import 'package:flutter/material.dart';
import
'package:flutter/services.dart'
;
import
'package:flutter_widget_from_html/flutter_widget_from_html.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/base/base_response_model.dart'
;
import
'package:mypoint_flutter_app/shared/router_gage.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../configs/constants.dart'
;
import
'../../resources/base_color.dart'
;
import
'../biometric/biometric_screen.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../login/login_screen.dart'
;
import
'../otp/otp_screen.dart'
;
import
'../otp/verify_otp_repository.dart'
;
import
'../pageDetail/campaign_detail_screen.dart'
;
import
'../pageDetail/model/detail_page_rule_type.dart'
;
import
'model/check_phone_response_model.dart'
;
import
'onboarding_viewmodel.dart'
;
...
...
@@ -32,54 +27,16 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
@override
void
initState
()
{
super
.
initState
();
_viewModel
.
fetchOnboardingContent
();
_viewModel
.
checkPhoneRes
.
listen
((
response
)
{
_viewModel
.
onShowAlertError
=
(
message
)
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
hideKeyboard
();
_handleResponseCheckPhoneNumber
(
response
.
data
);
_handleResponseError
(
response
);
});
showAlertError
(
content:
message
);
});
}
void
_handleResponseError
(
BaseResponseModel
<
CheckPhoneResponseModel
>?
response
)
{
if
(
response
?.
isSuccess
??
false
)
return
;
var
errorCode
=
response
?.
errorCode
??
""
;
var
errorMessage
=
response
?.
errorMessage
??
Constants
.
commonError
;
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
showAlertError
(
content:
errorMessage
);
if
(
errorCode
==
ErrorCodes
.
deviceLock
)
{
// show alert error popupErrorCSKH
return
;
}
//show alert error popupError
});
}
void
_handleResponseCheckPhoneNumber
(
CheckPhoneResponseModel
?
response
)
{
if
(
response
==
null
)
return
;
if
(
response
.
requireRecaptcha
==
true
)
return
;
if
((
response
.
mfaToken
??
""
).
isNotEmpty
||
(
response
.
nextAction
==
"signup"
))
{
// show OTP
Get
.
to
(
()
=>
OtpScreen
(
repository:
VerifyOtpRepository
(
_viewModel
.
phoneNumber
.
value
,
response
?.
otpTtl
??
0
,
response
?.
mfaToken
??
""
,
),
),
);
return
;
}
if
(
response
.
nextAction
==
"login"
)
{
Get
.
toNamed
(
loginScreen
,
arguments:
{
'phone'
:
_viewModel
.
phoneNumber
.
value
});
}
};
_viewModel
.
fetchOnboardingContent
();
}
@override
Widget
createBody
()
{
final
double
keyboardHeight
=
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
;
return
GestureDetector
(
onTap:
hideKeyboard
,
child:
Scaffold
(
...
...
@@ -149,6 +106,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
onPressed:
_viewModel
.
isButtonEnabled
?
()
{
hideKeyboard
();
_viewModel
.
checkPhoneNumber
();
}
:
null
,
...
...
lib/screen/onboarding/onboarding_viewmodel.dart
View file @
0bf528a4
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'
;
import
'../../base/base_response_model.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../otp/otp_screen.dart'
;
import
'../otp/verify_otp_repository.dart'
;
import
'model/check_phone_response_model.dart'
;
import
'model/onboarding_info_model.dart'
;
class
OnboardingViewModel
extends
RestfulApiViewModel
{
var
info
=
BaseResponseModel
<
OnboardingInfoModel
>().
obs
;
var
checkPhoneRes
=
BaseResponseModel
<
CheckPhoneResponseModel
>().
obs
;
var
phoneNumber
=
""
.
obs
;
var
isChecked
=
true
.
obs
;
final
RxString
phoneNumber
=
""
.
obs
;
final
RxBool
isChecked
=
true
.
obs
;
final
_info
=
Rxn
<
OnboardingInfoModel
>();
var
checkPhoneRes
=
Rxn
<
CheckPhoneResponseModel
>();
void
Function
(
String
message
)?
onShowAlertError
;
bool
get
isButtonEnabled
=>
isChecked
.
value
&&
phoneNumber
.
value
.
isPhoneValid
();
String
get
content
=>
info
?.
value
?.
data
?.
content
??
""
;
String
get
url
=>
info
?.
value
?.
data
?.
url
??
""
;
String
get
content
=>
_info
?.
value
?.
content
??
""
;
String
get
url
=>
_info
?.
value
?.
url
??
""
;
void
updatePhoneNumber
(
String
value
)
{
phoneNumber
.
value
=
value
;
...
...
@@ -25,16 +30,35 @@ class OnboardingViewModel extends RestfulApiViewModel {
}
Future
<
void
>
fetchOnboardingContent
()
async
{
client
.
getOnboardingInfo
().
then
((
value
)
{
info
.
value
=
value
;
});
await
callApi
<
OnboardingInfoModel
>(
request:
()
=>
client
.
getOnboardingInfo
(),
onSuccess:
(
data
,
_
)
{
_info
.
value
=
data
;
},
withLoading:
false
,
);
}
Future
<
void
>
checkPhoneNumber
()
async
{
showLoading
();
client
.
checkPhoneNumber
(
phoneNumber
.
value
).
then
((
value
)
{
hideLoading
();
checkPhoneRes
.
value
=
value
;
});
await
callApi
<
CheckPhoneResponseModel
>(
request:
()
=>
client
.
checkPhoneNumber
(
phoneNumber
.
value
),
onSuccess:
(
data
,
_
)
{
checkPhoneRes
.
value
=
data
;
if
(
data
.
requireRecaptcha
==
true
)
return
;
final
mfaToken
=
data
.
mfaToken
??
""
;
final
nextAction
=
data
.
nextAction
??
""
;
final
otpTtl
=
data
.
otpTtl
??
0
;
if
(
mfaToken
.
isNotEmpty
||
(
nextAction
==
"signup"
))
{
Get
.
to
(()
=>
OtpScreen
(
repository:
VerifyOtpRepository
(
phoneNumber
.
value
,
otpTtl
,
mfaToken
)));
return
;
}
if
(
nextAction
==
"login"
)
{
Get
.
toNamed
(
loginScreen
,
arguments:
{
'phone'
:
phoneNumber
.
value
});
}
},
onFailure:
(
msg
,
_
,
_
)
{
onShowAlertError
?.
call
(
msg
);
},
);
}
}
lib/screen/quiz_campaign/quiz_campaign_screen.dart
View file @
0bf528a4
...
...
@@ -250,7 +250,7 @@ class _SurveyQuestionScreenState extends BaseState<SurveyQuestionScreen> with Ba
showAlert
(
data:
dataAlert
);
}
_showAlertConfirmQuitSurvey
()
{
void
_showAlertConfirmQuitSurvey
()
{
final
dataAlert
=
DataAlertModel
(
description:
"Có vẻ bạn chưa hoàn thành nhiệm vụ rồi. Tiếp tục nhé!!"
,
localHeaderImage:
"assets/images/ic_pipi_03.png"
,
...
...
lib/services/token_refresh_service.dart
View file @
0bf528a4
...
...
@@ -4,7 +4,7 @@ import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.da
import
'../model/auth/login_token_response_model.dart'
;
import
'../networking/restful_api_viewmodel.dart'
;
import
'../preference/data_preference.dart'
;
import
'../
networking
/app_navigator.dart'
;
import
'../
base
/app_navigator.dart'
;
class
TokenRefreshService
extends
RestfulApiViewModel
{
static
final
TokenRefreshService
_instance
=
TokenRefreshService
.
_internal
();
...
...
Prev
1
2
3
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