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
417358c5
Commit
417358c5
authored
Aug 15, 2025
by
DatHV
Browse files
update authen 401, device manager, interestied category
parent
efb4662c
Changes
99
Hide whitespace changes
Inline
Side-by-side
lib/screen/login/login_screen.dart
View file @
417358c5
...
@@ -3,7 +3,7 @@ import 'package:get/get.dart';
...
@@ -3,7 +3,7 @@ import 'package:get/get.dart';
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../permission/biometric_manager.dart'
;
import
'../../permission/biometric_manager.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../widgets/alert/custom_alert_dialog.dart'
;
import
'../../widgets/alert/custom_alert_dialog.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/back_button.dart'
;
...
@@ -29,11 +29,9 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
...
@@ -29,11 +29,9 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
final
args
=
Get
.
arguments
;
final
args
=
Get
.
arguments
;
if
(
args
is
String
)
{
if
(
args
is
Map
)
{
phoneNumber
=
args
;
}
else
if
(
args
is
Map
)
{
phoneNumber
=
args
[
'phone'
];
phoneNumber
=
args
[
'phone'
];
fullName
=
args
[
'fullName'
];
fullName
=
args
[
'fullName'
]
??
''
;
}
}
loginVM
.
onShowChangePass
=
(
message
)
{
loginVM
.
onShowChangePass
=
(
message
)
{
Get
.
dialog
(
Get
.
dialog
(
...
...
lib/screen/main_tab_screen/main_tab_screen.dart
View file @
417358c5
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../affiliate/affiliate_tab_screen.dart'
;
import
'../affiliate/affiliate_tab_screen.dart'
;
import
'../game/game_tab_screen.dart'
;
import
'../game/game_tab_screen.dart'
;
import
'../home/header_home_viewmodel.dart'
;
import
'../home/header_home_viewmodel.dart'
;
...
...
lib/screen/membership/member_level_header_widget.dart
View file @
417358c5
...
@@ -3,7 +3,7 @@ import 'package:intl/intl.dart';
...
@@ -3,7 +3,7 @@ import 'package:intl/intl.dart';
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../widgets/image_loader.dart'
;
import
'../../widgets/image_loader.dart'
;
import
'../../widgets/measure_size.dart'
;
import
'../../widgets/measure_size.dart'
;
import
'models/membership_level_model.dart'
;
import
'models/membership_level_model.dart'
;
...
...
lib/screen/mobile_card/product_mobile_card_screen.dart
View file @
417358c5
...
@@ -3,13 +3,13 @@ import 'package:get/get.dart';
...
@@ -3,13 +3,13 @@ import 'package:get/get.dart';
import
'package:get/get_core/src/get_main.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'
;
import
'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart'
;
import
'package:mypoint_flutter_app/extensions/num_extension.dart'
;
import
'package:mypoint_flutter_app/extensions/num_extension.dart'
;
import
'package:mypoint_flutter_app/resouce/base_color.dart'
;
import
'package:mypoint_flutter_app/screen/mobile_card/product_mobile_card_viewmodel.dart'
;
import
'package:mypoint_flutter_app/screen/mobile_card/product_mobile_card_viewmodel.dart'
;
import
'package:mypoint_flutter_app/screen/mobile_card/usable_mobile_card_popup.dart'
;
import
'package:mypoint_flutter_app/screen/mobile_card/usable_mobile_card_popup.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_app_bar.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_app_bar.dart'
;
import
'package:mypoint_flutter_app/widgets/image_loader.dart'
;
import
'package:mypoint_flutter_app/widgets/image_loader.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resources/base_color.dart'
;
import
'../../widgets/alert/custom_alert_dialog.dart'
;
import
'../../widgets/alert/custom_alert_dialog.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
...
...
lib/screen/mobile_card/usable_mobile_card_popup.dart
View file @
417358c5
...
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
...
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import
'package:flutter/services.dart'
;
import
'package:flutter/services.dart'
;
import
'package:mypoint_flutter_app/extensions/datetime_extensions.dart'
;
import
'package:mypoint_flutter_app/extensions/datetime_extensions.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'
package:mypoint_flutter_app
/resouce/base_color.dart'
;
import
'
../..
/resou
r
ce
s
/base_color.dart'
;
import
'models/usable_voucher_model.dart'
;
import
'models/usable_voucher_model.dart'
;
class
UsableMobileCardPopup
extends
StatelessWidget
{
class
UsableMobileCardPopup
extends
StatelessWidget
{
...
...
lib/screen/notification/notification_screen.dart
View file @
417358c5
...
@@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
...
@@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
import
'package:get/get.dart'
;
import
'package:get/get.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/custom_empty_widget.dart'
;
import
'../../widgets/custom_empty_widget.dart'
;
...
...
lib/screen/onboarding/onboarding_screen.dart
View file @
417358c5
...
@@ -7,7 +7,7 @@ import 'package:mypoint_flutter_app/shared/router_gage.dart';
...
@@ -7,7 +7,7 @@ import 'package:mypoint_flutter_app/shared/router_gage.dart';
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../configs/constants.dart'
;
import
'../../configs/constants.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../biometric/biometric_screen.dart'
;
import
'../biometric/biometric_screen.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../login/login_screen.dart'
;
import
'../login/login_screen.dart'
;
...
@@ -73,7 +73,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
...
@@ -73,7 +73,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
return
;
return
;
}
}
if
(
response
.
nextAction
==
"login"
)
{
if
(
response
.
nextAction
==
"login"
)
{
Get
.
toNamed
(
loginScreen
,
arguments:
_viewModel
.
phoneNumber
.
value
);
Get
.
toNamed
(
loginScreen
,
arguments:
{
'phone'
:
_viewModel
.
phoneNumber
.
value
}
);
}
}
}
}
...
...
lib/screen/otp/otp_screen.dart
View file @
417358c5
...
@@ -3,7 +3,7 @@ import 'package:get/get.dart';
...
@@ -3,7 +3,7 @@ import 'package:get/get.dart';
import
'package:pin_code_fields/pin_code_fields.dart'
;
import
'package:pin_code_fields/pin_code_fields.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/support_button.dart'
;
import
'../../widgets/support_button.dart'
;
import
'otp_viewmodel.dart'
;
import
'otp_viewmodel.dart'
;
...
...
lib/screen/otp/verify_otp_repository.dart
View file @
417358c5
...
@@ -31,7 +31,7 @@ class VerifyOtpRepository extends RestfulApiViewModel implements IOtpRepository
...
@@ -31,7 +31,7 @@ class VerifyOtpRepository extends RestfulApiViewModel implements IOtpRepository
if
(
value
.
data
?.
claim
?.
action
==
"signup"
)
{
if
(
value
.
data
?.
claim
?.
action
==
"signup"
)
{
Get
.
off
(()
=>
CreatePasswordScreen
(
repository:
SignUpCreatePasswordRepository
(
phoneNumber
)));
Get
.
off
(()
=>
CreatePasswordScreen
(
repository:
SignUpCreatePasswordRepository
(
phoneNumber
)));
}
else
if
(
value
.
data
?.
claim
?.
action
==
"login"
)
{
}
else
if
(
value
.
data
?.
claim
?.
action
==
"login"
)
{
Get
.
offNamed
(
loginScreen
,
arguments:
phoneNumber
);
Get
.
offNamed
(
loginScreen
,
arguments:
{
'phone'
:
phoneNumber
}
);
}
}
return
value
;
return
value
;
});
});
...
...
lib/screen/pageDetail/campaign_detail_screen.dart
View file @
417358c5
...
@@ -4,7 +4,7 @@ import 'package:get/get.dart';
...
@@ -4,7 +4,7 @@ import 'package:get/get.dart';
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../extensions/string_extension.dart'
;
import
'../../extensions/string_extension.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/network_image_with_aspect_ratio.dart'
;
import
'../../widgets/network_image_with_aspect_ratio.dart'
;
...
...
lib/screen/personal/personal_edit_screen.dart
View file @
417358c5
...
@@ -7,7 +7,7 @@ import 'package:mypoint_flutter_app/screen/personal/personal_gender.dart';
...
@@ -7,7 +7,7 @@ import 'package:mypoint_flutter_app/screen/personal/personal_gender.dart';
import
'package:mypoint_flutter_app/widgets/custom_app_bar.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_app_bar.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/bottom_sheet_helper.dart'
;
import
'../../widgets/bottom_sheet_helper.dart'
;
...
...
lib/screen/personal/personal_screen.dart
View file @
417358c5
...
@@ -7,7 +7,7 @@ import '../../base/base_screen.dart';
...
@@ -7,7 +7,7 @@ import '../../base/base_screen.dart';
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../preference/package_info.dart'
;
import
'../../preference/package_info.dart'
;
import
'../../preference/point/header_home_model.dart'
;
import
'../../preference/point/header_home_model.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../home/header_home_viewmodel.dart'
;
import
'../home/header_home_viewmodel.dart'
;
...
@@ -115,12 +115,17 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState {
...
@@ -115,12 +115,17 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState {
const
Spacer
(),
const
Spacer
(),
Row
(
Row
(
children:
[
children:
[
Row
(
GestureDetector
(
children:
[
onTap:
()
{
Image
.
asset
(
"assets/images/ic_rank_gray.png"
,
width:
30
,
height:
30
,
color:
Colors
.
white
),
Get
.
toNamed
(
membershipScreen
);
const
SizedBox
(
width:
4
),
},
Text
(
level
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
,
fontWeight:
FontWeight
.
bold
)),
child:
Row
(
],
children:
[
Image
.
asset
(
"assets/images/ic_rank_gray.png"
,
width:
30
,
height:
30
,
color:
Colors
.
white
),
const
SizedBox
(
width:
4
),
Text
(
level
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
,
fontWeight:
FontWeight
.
bold
)),
],
),
),
),
const
Spacer
(),
const
Spacer
(),
Row
(
Row
(
...
@@ -286,14 +291,13 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState {
...
@@ -286,14 +291,13 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState {
if
(
matched
)
found
=
true
;
if
(
matched
)
found
=
true
;
return
matched
;
return
matched
;
});
});
final
phone
=
DataPreference
.
instance
.
phone
;
final
phone
=
DataPreference
.
instance
.
phoneNumberUsedForLoginScreen
;
if
(
phone
!=
null
)
{
final
displayName
=
DataPreference
.
instance
.
displayName
;
if
(!
found
)
{
if
(
phone
!=
null
&&
!
found
)
{
Get
.
offAllNamed
(
loginScreen
,
arguments:
phone
);
Get
.
offAllNamed
(
loginScreen
,
arguments:
{
"phone"
:
phone
,
'fullName'
:
displayName
});
}
}
else
{
}
else
{
DataPreference
.
instance
.
clearData
();
DataPreference
.
instance
.
clearData
();
Get
.
offAllNamed
(
log
inScreen
);
Get
.
offAllNamed
(
onboard
in
g
Screen
);
}
}
}
}
}
}
lib/screen/popup_manager/popup_manager_model.dart
0 → 100644
View file @
417358c5
import
'package:json_annotation/json_annotation.dart'
;
part
'popup_manager_model.g.dart'
;
@JsonSerializable
()
class
PopupManagerModel
{
final
String
?
id
;
@JsonKey
(
name:
'screen_to_show'
)
final
String
?
screenToShow
;
@JsonKey
(
name:
'click_action_type'
)
final
String
?
clickActionType
;
@JsonKey
(
name:
'click_action_param'
)
final
String
?
clickActionParam
;
@JsonKey
(
name:
'pos_action_id'
)
final
String
?
posActionID
;
@JsonKey
(
name:
'pos_action_code'
)
final
String
?
posActionCode
;
@JsonKey
(
name:
'time_to_show'
)
String
?
timeToShow
;
@JsonKey
(
name:
'time_count_down'
)
final
String
?
timeCountDown
;
@JsonKey
(
name:
'hour_start_in_day'
)
final
String
?
hourStartInDay
;
@JsonKey
(
name:
'hour_stop_in_day'
)
final
String
?
hourStopInDay
;
@JsonKey
(
name:
'after_pos_id'
)
final
String
?
afterPosID
;
@JsonKey
(
name:
'after_pos_code'
)
final
String
?
afterPosCode
;
@JsonKey
(
name:
'after_pos_name'
)
final
String
?
afterPosName
;
@JsonKey
(
name:
'marketing_request_description'
)
final
String
?
marketingRequestDescription
;
@JsonKey
(
name:
'effective_from_date'
)
final
String
?
effectiveFromDate
;
@JsonKey
(
name:
'effective_to_date'
)
final
String
?
effectiveToDate
;
@JsonKey
(
name:
'schedule_run_type_code'
)
final
String
?
scheduleRunTypeCode
;
@JsonKey
(
name:
'schedule_run_type_name'
)
final
String
?
scheduleRunTypeName
;
@JsonKey
(
name:
'schedule_at_time'
)
final
String
?
scheduleAtTime
;
@JsonKey
(
name:
'popup_title_template'
)
final
String
?
popupTitleTemplate
;
@JsonKey
(
name:
'popup_body_template'
)
final
String
?
popupBodyTemplate
;
@JsonKey
(
name:
'image_id'
)
final
String
?
imageID
;
@JsonKey
(
name:
'image_url'
)
final
String
?
imageURL
;
@JsonKey
(
name:
'message_name'
)
final
String
?
messageName
;
@JsonKey
(
name:
'request_id'
)
final
String
?
requestId
;
PopupManagerModel
({
this
.
id
,
this
.
screenToShow
,
this
.
clickActionType
,
this
.
clickActionParam
,
this
.
posActionID
,
this
.
posActionCode
,
this
.
timeToShow
,
this
.
timeCountDown
,
this
.
hourStartInDay
,
this
.
hourStopInDay
,
this
.
afterPosID
,
this
.
afterPosCode
,
this
.
afterPosName
,
this
.
marketingRequestDescription
,
this
.
effectiveFromDate
,
this
.
effectiveToDate
,
this
.
scheduleRunTypeCode
,
this
.
scheduleRunTypeName
,
this
.
scheduleAtTime
,
this
.
popupTitleTemplate
,
this
.
popupBodyTemplate
,
this
.
imageID
,
this
.
imageURL
,
this
.
messageName
,
this
.
requestId
,
});
factory
PopupManagerModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$PopupManagerModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$PopupManagerModelToJson
(
this
);
}
lib/screen/popup_manager/popup_manager_model.g.dart
0 → 100644
View file @
417358c5
// GENERATED CODE - DO NOT MODIFY BY HAND
part of
'popup_manager_model.dart'
;
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
PopupManagerModel
_$PopupManagerModelFromJson
(
Map
<
String
,
dynamic
>
json
)
=>
PopupManagerModel
(
id:
json
[
'id'
]
as
String
?,
screenToShow:
json
[
'screen_to_show'
]
as
String
?,
clickActionType:
json
[
'click_action_type'
]
as
String
?,
clickActionParam:
json
[
'click_action_param'
]
as
String
?,
posActionID:
json
[
'pos_action_id'
]
as
String
?,
posActionCode:
json
[
'pos_action_code'
]
as
String
?,
timeToShow:
json
[
'time_to_show'
]
as
String
?,
timeCountDown:
json
[
'time_count_down'
]
as
String
?,
hourStartInDay:
json
[
'hour_start_in_day'
]
as
String
?,
hourStopInDay:
json
[
'hour_stop_in_day'
]
as
String
?,
afterPosID:
json
[
'after_pos_id'
]
as
String
?,
afterPosCode:
json
[
'after_pos_code'
]
as
String
?,
afterPosName:
json
[
'after_pos_name'
]
as
String
?,
marketingRequestDescription:
json
[
'marketing_request_description'
]
as
String
?,
effectiveFromDate:
json
[
'effective_from_date'
]
as
String
?,
effectiveToDate:
json
[
'effective_to_date'
]
as
String
?,
scheduleRunTypeCode:
json
[
'schedule_run_type_code'
]
as
String
?,
scheduleRunTypeName:
json
[
'schedule_run_type_name'
]
as
String
?,
scheduleAtTime:
json
[
'schedule_at_time'
]
as
String
?,
popupTitleTemplate:
json
[
'popup_title_template'
]
as
String
?,
popupBodyTemplate:
json
[
'popup_body_template'
]
as
String
?,
imageID:
json
[
'image_id'
]
as
String
?,
imageURL:
json
[
'image_url'
]
as
String
?,
messageName:
json
[
'message_name'
]
as
String
?,
requestId:
json
[
'request_id'
]
as
String
?,
);
Map
<
String
,
dynamic
>
_$PopupManagerModelToJson
(
PopupManagerModel
instance
)
=>
<
String
,
dynamic
>{
'id'
:
instance
.
id
,
'screen_to_show'
:
instance
.
screenToShow
,
'click_action_type'
:
instance
.
clickActionType
,
'click_action_param'
:
instance
.
clickActionParam
,
'pos_action_id'
:
instance
.
posActionID
,
'pos_action_code'
:
instance
.
posActionCode
,
'time_to_show'
:
instance
.
timeToShow
,
'time_count_down'
:
instance
.
timeCountDown
,
'hour_start_in_day'
:
instance
.
hourStartInDay
,
'hour_stop_in_day'
:
instance
.
hourStopInDay
,
'after_pos_id'
:
instance
.
afterPosID
,
'after_pos_code'
:
instance
.
afterPosCode
,
'after_pos_name'
:
instance
.
afterPosName
,
'marketing_request_description'
:
instance
.
marketingRequestDescription
,
'effective_from_date'
:
instance
.
effectiveFromDate
,
'effective_to_date'
:
instance
.
effectiveToDate
,
'schedule_run_type_code'
:
instance
.
scheduleRunTypeCode
,
'schedule_run_type_name'
:
instance
.
scheduleRunTypeName
,
'schedule_at_time'
:
instance
.
scheduleAtTime
,
'popup_title_template'
:
instance
.
popupTitleTemplate
,
'popup_body_template'
:
instance
.
popupBodyTemplate
,
'image_id'
:
instance
.
imageID
,
'image_url'
:
instance
.
imageURL
,
'message_name'
:
instance
.
messageName
,
'request_id'
:
instance
.
requestId
,
};
lib/screen/popup_manager/popup_manager_popup.dart
0 → 100644
View file @
417358c5
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:mypoint_flutter_app/screen/popup_manager/popup_manager_model.dart'
;
/// Giao diện điều hướng để bạn nối với router của app
typedef
PopupNavigator
=
void
Function
({
required
String
name
,
required
String
identifier
,
String
?
title
,
String
?
body
,
});
/// Logger tuỳ bạn hook vào hệ thống hiện có (Firebase, MoEngage, …)
void
logPopupShowing
(
{
required
String
popupId
,
required
String
requestId
})
{
// UserFollowLogger(.popup_showing, data: trackingInfo).log()
// FirebaseAnalyticManager.shared.trackEvent(.popupShowing, info: trackingInfo)
debugPrint
(
'[Popup] showing: popup_id=
$popupId
, request_id=
$requestId
'
);
}
void
logPopupClick
(
{
required
String
popupId
})
{
// FirebaseAnalyticManager.shared.add(event: LogEventFollowInfo(name: .popup, id: popupId))
debugPrint
(
'[Popup] click: popup_id=
$popupId
'
);
}
/// ==== API hiển thị popup (gọi giống hàm Swift) ====
Future
<
void
>
showPopup
(
BuildContext
context
,
{
required
PopupManagerModel
modelPopup
,
required
PopupNavigator
onNavigate
,
VoidCallback
?
onDismissed
,
// thay cho NotificationCenter
})
async
{
int
timeCountDown
=
int
.
tryParse
(
modelPopup
.
timeCountDown
??
'1000000'
)
??
1000000
;
final
popupId
=
modelPopup
.
id
??
''
;
final
requestId
=
modelPopup
.
requestId
??
''
;
logPopupShowing
(
popupId:
popupId
,
requestId:
requestId
);
await
showGeneralDialog
(
context:
context
,
barrierDismissible:
false
,
// giống SwiftEntryKit, user không chạm ra ngoài để tắt
barrierLabel:
'popup'
,
transitionDuration:
const
Duration
(
milliseconds:
220
),
pageBuilder:
(
_
,
__
,
___
)
{
return
_BasePopupView
(
model:
modelPopup
,
initialCountdown:
timeCountDown
,
onNavigate:
onNavigate
,
onDismissed:
()
{
onDismissed
?.
call
();
},
);
},
transitionBuilder:
(
_
,
anim
,
__
,
child
)
{
return
Transform
.
scale
(
scale:
0.96
+
(
0.04
*
anim
.
value
),
child:
Opacity
(
opacity:
anim
.
value
,
child:
child
),
);
},
);
}
/// ==== Widget nền của popup (tương đương BasePopupView + SwiftEntryKit display) ====
class
_BasePopupView
extends
StatefulWidget
{
final
PopupManagerModel
model
;
final
int
initialCountdown
;
final
PopupNavigator
onNavigate
;
final
VoidCallback
onDismissed
;
const
_BasePopupView
({
required
this
.
model
,
required
this
.
initialCountdown
,
required
this
.
onNavigate
,
required
this
.
onDismissed
,
});
@override
State
<
_BasePopupView
>
createState
()
=>
_BasePopupViewState
();
}
class
_BasePopupViewState
extends
State
<
_BasePopupView
>
{
Timer
?
_timer
;
late
int
_countdown
;
double
?
_imageAspectRatio
;
// width / height
bool
_imageLoaded
=
false
;
@override
void
initState
()
{
super
.
initState
();
_countdown
=
widget
.
initialCountdown
;
_startTimer
();
}
@override
void
dispose
()
{
_timer
?.
cancel
();
super
.
dispose
();
}
void
_startTimer
()
{
_timer
=
Timer
.
periodic
(
const
Duration
(
seconds:
1
),
(
t
)
{
if
(!
mounted
)
return
;
if
(
_countdown
>
0
)
{
setState
(()
=>
_countdown
-=
1
);
}
else
{
_dismiss
();
}
});
}
void
_dismiss
()
{
_timer
?.
cancel
();
widget
.
onDismissed
();
if
(
mounted
)
Navigator
.
of
(
context
).
pop
();
}
void
_onImageTap
()
{
final
model
=
widget
.
model
;
if
((
model
.
clickActionType
??
''
).
isEmpty
)
return
;
_timer
?.
cancel
();
logPopupClick
(
popupId:
model
.
id
??
''
);
// Điều hướng tương đương DirectionalScreen.begin(...)
widget
.
onNavigate
(
name:
model
.
clickActionType
!,
identifier:
model
.
clickActionParam
??
''
,
title:
model
.
popupTitleTemplate
??
''
,
body:
model
.
popupBodyTemplate
??
''
,
);
_dismiss
();
}
void
_onCancelTap
()
async
{
final
model
=
widget
.
model
;
if
((
model
.
clickActionType
??
''
)
==
'VIEW_GIFT'
)
{
// Show "GiftMessageView" dạng bottom sheet
await
showModalBottomSheet
(
context:
context
,
backgroundColor:
Colors
.
transparent
,
builder:
(
_
)
=>
_GiftMessageSheet
(
model:
model
,
onNavigate:
widget
.
onNavigate
),
);
}
_dismiss
();
}
@override
Widget
build
(
BuildContext
context
)
{
final
model
=
widget
.
model
;
final
title
=
(
model
.
popupTitleTemplate
??
''
).
trim
();
final
body
=
(
model
.
popupBodyTemplate
??
''
).
trim
();
final
hasTitle
=
title
.
isNotEmpty
;
final
hasBody
=
body
.
isNotEmpty
;
// Tính phần height phụ theo Swift (55 + 50, trừ bớt khi ẩn)
int
extra
=
55
+
50
;
if
(!
hasTitle
)
extra
-=
55
;
if
(!
hasBody
)
extra
-=
50
;
final
media
=
MediaQuery
.
of
(
context
);
final
screenW
=
media
.
size
.
width
;
final
maxPopupHeight
=
media
.
size
.
height
-
200
;
// Card radius phụ thuộc điều kiện
final
imageCornerRadius
=
(!
hasTitle
&&
!
hasBody
)
?
12.0
:
12.0
;
// ảnh trên cùng vẫn bo 12
final
subHeaderRadius
=
(
hasBody
&&
!
hasTitle
)
?
12.0
:
0.0
;
return
Material
(
color:
Colors
.
black54
,
child:
Center
(
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
20
),
child:
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
// Nếu đã biết tỷ lệ ảnh: tính height theo công thức Swift
double
imageHeight
=
0
;
if
(
_imageAspectRatio
!=
null
&&
_imageAspectRatio
!
>
0
)
{
// image.size.height*(screenW - 40)/image.size.width
imageHeight
=
(
screenW
-
40
)
/
_imageAspectRatio
!;
}
final
content
=
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
// Nút đóng
Align
(
alignment:
Alignment
.
topRight
,
child:
IconButton
(
icon:
const
Icon
(
Icons
.
close
,
color:
Colors
.
white
),
onPressed:
_onCancelTap
,
),
),
ConstrainedBox
(
constraints:
BoxConstraints
(
maxHeight:
maxPopupHeight
,
minWidth:
double
.
infinity
,
),
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
12
),
child:
Material
(
color:
Colors
.
white
,
child:
SingleChildScrollView
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
stretch
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
// Ảnh
_buildImage
(
url:
model
.
imageURL
,
heightHint:
imageHeight
>
0
?
imageHeight
:
null
,
cornerRadius:
imageCornerRadius
,
),
// Header
if
(
hasTitle
)
Padding
(
padding:
const
EdgeInsets
.
fromLTRB
(
16
,
16
,
16
,
0
),
child:
Text
(
title
,
style:
const
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
w700
,
),
),
),
// SubHeader
if
(
hasBody
)
Container
(
decoration:
BoxDecoration
(
color:
const
Color
(
0xFFF6F7F9
),
borderRadius:
BorderRadius
.
vertical
(
bottom:
Radius
.
circular
(
subHeaderRadius
),
),
),
padding:
const
EdgeInsets
.
fromLTRB
(
16
,
10
,
16
,
16
),
child:
Text
(
body
,
style:
const
TextStyle
(
fontSize:
15
,
height:
1.4
),
),
),
// Dòng trạng thái đếm ngược (tuỳ chọn)
Padding
(
padding:
const
EdgeInsets
.
fromLTRB
(
16
,
10
,
16
,
16
),
child:
Text
(
_countdown
>
0
?
'
$_countdown
seconds dismiss popup'
:
'Closing…'
,
style:
TextStyle
(
fontSize:
12
,
color:
Colors
.
grey
.
shade600
,
),
textAlign:
TextAlign
.
right
,
),
),
],
),
),
),
),
),
],
);
return
content
;
},
),
),
),
);
}
Widget
_buildImage
({
required
String
?
url
,
double
?
heightHint
,
required
double
cornerRadius
,
})
{
final
imageUrl
=
(
url
??
''
).
trim
();
if
(
imageUrl
.
isEmpty
)
{
// Placeholder fallback
return
Container
(
height:
160
,
color:
const
Color
(
0xFFE9ECF1
),
alignment:
Alignment
.
center
,
child:
const
Icon
(
Icons
.
image
,
size:
48
,
color:
Colors
.
grey
),
);
}
return
GestureDetector
(
onTap:
_onImageTap
,
child:
ClipRRect
(
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
cornerRadius
)),
child:
_NetworkImageWithInfo
(
imageUrl:
imageUrl
,
heightHint:
heightHint
,
onResolved:
(
width
,
height
)
{
if
(!
_imageLoaded
&&
width
>
0
&&
height
>
0
)
{
setState
(()
{
_imageLoaded
=
true
;
_imageAspectRatio
=
width
/
height
;
// width/height
});
}
},
),
),
);
}
}
/// Image.network nhưng lấy được kích thước ảnh thật để tính tỉ lệ
class
_NetworkImageWithInfo
extends
StatefulWidget
{
final
String
imageUrl
;
final
double
?
heightHint
;
final
void
Function
(
int
width
,
int
height
)
onResolved
;
const
_NetworkImageWithInfo
({
required
this
.
imageUrl
,
required
this
.
onResolved
,
this
.
heightHint
,
});
@override
State
<
_NetworkImageWithInfo
>
createState
()
=>
_NetworkImageWithInfoState
();
}
class
_NetworkImageWithInfoState
extends
State
<
_NetworkImageWithInfo
>
{
ImageStream
?
_stream
;
ImageInfo
?
_info
;
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
_resolve
();
}
@override
void
didUpdateWidget
(
covariant
_NetworkImageWithInfo
oldWidget
)
{
super
.
didUpdateWidget
(
oldWidget
);
if
(
oldWidget
.
imageUrl
!=
widget
.
imageUrl
)
_resolve
();
}
void
_resolve
()
{
_stream
?.
removeListener
(
ImageStreamListener
(
_handleImage
));
final
provider
=
NetworkImage
(
widget
.
imageUrl
);
final
stream
=
provider
.
resolve
(
createLocalImageConfiguration
(
context
));
_stream
=
stream
;
stream
.
addListener
(
ImageStreamListener
(
_handleImage
));
}
void
_handleImage
(
ImageInfo
info
,
bool
_
)
{
_info
=
info
;
widget
.
onResolved
(
info
.
image
.
width
,
info
.
image
.
height
);
setState
(()
{});
}
@override
void
dispose
()
{
_stream
?.
removeListener
(
ImageStreamListener
(
_handleImage
));
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
if
(
_info
==
null
&&
widget
.
heightHint
==
null
)
{
// loading skeleton
return
AspectRatio
(
aspectRatio:
16
/
9
,
child:
Container
(
color:
const
Color
(
0xFFE9ECF1
)),
);
}
final
height
=
widget
.
heightHint
;
return
Image
.
network
(
widget
.
imageUrl
,
height:
height
,
width:
double
.
infinity
,
fit:
BoxFit
.
cover
,
);
}
}
/// ==== GiftMessageView tương đương (bottom sheet) ====
class
_GiftMessageSheet
extends
StatelessWidget
{
final
PopupManagerModel
model
;
final
PopupNavigator
onNavigate
;
const
_GiftMessageSheet
({
required
this
.
model
,
required
this
.
onNavigate
,
ff
});
@override
Widget
build
(
BuildContext
context
)
{
final
radius
=
const
Radius
.
circular
(
16
);
return
Container
(
decoration:
const
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
vertical
(
top:
Radius
.
circular
(
16
)),
),
padding:
const
EdgeInsets
.
fromLTRB
(
16
,
16
,
16
,
16
+
24
),
child:
SafeArea
(
top:
false
,
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Container
(
width:
36
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade300
,
borderRadius:
BorderRadius
.
circular
(
2
))),
const
SizedBox
(
height:
12
),
Text
(
model
.
popupTitleTemplate
?.
isNotEmpty
==
true
?
model
.
popupTitleTemplate
!
:
'Quà tặng của bạn'
,
style:
const
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
w700
),
),
const
SizedBox
(
height:
8
),
Text
(
model
.
popupBodyTemplate
?.
isNotEmpty
==
true
?
model
.
popupBodyTemplate
!
:
'Nhấn "Sử dụng ngay" để tiếp tục.'
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Colors
.
black87
),
textAlign:
TextAlign
.
center
,
),
const
SizedBox
(
height:
16
),
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
{
if
((
model
.
clickActionType
??
''
).
isEmpty
)
{
Navigator
.
of
(
context
).
pop
();
return
;
}
onNavigate
(
name:
model
.
clickActionType
!,
identifier:
model
.
clickActionParam
??
''
,
title:
model
.
popupTitleTemplate
??
''
,
body:
model
.
popupBodyTemplate
??
''
,
);
Navigator
.
of
(
context
).
pop
();
},
style:
ElevatedButton
.
styleFrom
(
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
12
)),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
14
),
),
child:
const
Text
(
'Sử dụng ngay'
),
),
),
const
SizedBox
(
height:
8
),
TextButton
(
onPressed:
()
=>
Navigator
.
of
(
context
).
pop
(),
child:
const
Text
(
'Để sau'
),
),
],
),
),
);
}
}
lib/screen/quiz_campaign/quiz_campaign_screen.dart
View file @
417358c5
...
@@ -6,7 +6,7 @@ import 'package:mypoint_flutter_app/screen/quiz_campaign/quiz_campaign_model.dar
...
@@ -6,7 +6,7 @@ import 'package:mypoint_flutter_app/screen/quiz_campaign/quiz_campaign_model.dar
import
'package:mypoint_flutter_app/screen/quiz_campaign/quiz_campaign_viewmodel.dart'
;
import
'package:mypoint_flutter_app/screen/quiz_campaign/quiz_campaign_viewmodel.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/custom_empty_widget.dart'
;
import
'../../widgets/custom_empty_widget.dart'
;
...
...
lib/screen/register_campaign/register_form_input_screen.dart
View file @
417358c5
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_widget_from_html/flutter_widget_from_html.dart'
;
import
'package:flutter_widget_from_html/flutter_widget_from_html.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/resouce/base_color.dart'
;
import
'package:mypoint_flutter_app/screen/register_campaign/register_form_input_viewmodel.dart'
;
import
'package:mypoint_flutter_app/screen/register_campaign/register_form_input_viewmodel.dart'
;
import
'../../resources/base_color.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../widgets/custom_app_bar.dart'
;
import
'../../widgets/custom_app_bar.dart'
;
import
'../voucher/models/product_model.dart'
;
import
'../voucher/models/product_model.dart'
;
...
...
lib/screen/setting/setting_screen.dart
View file @
417358c5
...
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
...
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import
'package:get/get.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:mypoint_flutter_app/screen/setting/setting_viewmodel.dart'
;
import
'package:mypoint_flutter_app/screen/setting/setting_viewmodel.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../widgets/bottom_sheet_helper.dart'
;
import
'../../widgets/bottom_sheet_helper.dart'
;
import
'../../widgets/custom_app_bar.dart'
;
import
'../../widgets/custom_app_bar.dart'
;
import
'../change_pass/change_pass_screen.dart'
;
import
'../change_pass/change_pass_screen.dart'
;
...
@@ -46,7 +47,9 @@ class _SettingScreenState extends State<SettingScreen> {
...
@@ -46,7 +47,9 @@ class _SettingScreenState extends State<SettingScreen> {
_buildSettingItem
(
_buildSettingItem
(
icon:
Icons
.
apps
,
icon:
Icons
.
apps
,
title:
'Các lĩnh vực quan tâm'
,
title:
'Các lĩnh vực quan tâm'
,
onTap:
()
{},
onTap:
()
{
Get
.
toNamed
(
interestCategoriesScreen
);
},
),
),
_buildDivider
(),
_buildDivider
(),
_buildSettingItem
(
_buildSettingItem
(
...
@@ -78,7 +81,9 @@ class _SettingScreenState extends State<SettingScreen> {
...
@@ -78,7 +81,9 @@ class _SettingScreenState extends State<SettingScreen> {
_buildSettingItem
(
_buildSettingItem
(
icon:
Icons
.
devices_other
,
icon:
Icons
.
devices_other
,
title:
'Quản lý thiết bị đăng nhập'
,
title:
'Quản lý thiết bị đăng nhập'
,
onTap:
()
{},
onTap:
()
{
Get
.
toNamed
(
deviceManagerScreen
);
},
),
),
_buildDivider
(),
_buildDivider
(),
_buildSettingItem
(
_buildSettingItem
(
...
...
lib/screen/splash/splash_screen.dart
View file @
417358c5
...
@@ -10,7 +10,7 @@ import 'package:mypoint_flutter_app/widgets/alert/custom_alert_dialog.dart';
...
@@ -10,7 +10,7 @@ import 'package:mypoint_flutter_app/widgets/alert/custom_alert_dialog.dart';
import
'../../base/base_screen.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../model/check_update_response_model.dart'
;
import
'../../model/check_update_response_model.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../resou
r
ce
s
/base_color.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../onboarding/onboarding_screen.dart'
;
import
'../onboarding/onboarding_screen.dart'
;
...
...
lib/screen/support/support_screen.dart
View file @
417358c5
...
@@ -4,8 +4,7 @@ import 'package:mypoint_flutter_app/screen/support/support_item_model.dart';
...
@@ -4,8 +4,7 @@ import 'package:mypoint_flutter_app/screen/support/support_item_model.dart';
import
'package:mypoint_flutter_app/screen/support/support_screen_viewmodel.dart'
;
import
'package:mypoint_flutter_app/screen/support/support_screen_viewmodel.dart'
;
import
'package:mypoint_flutter_app/shared/router_gage.dart'
;
import
'package:mypoint_flutter_app/shared/router_gage.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'../../resources/base_color.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../pageDetail/campaign_detail_screen.dart'
;
import
'../pageDetail/campaign_detail_screen.dart'
;
...
...
Prev
1
2
3
4
5
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