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
f714cdcc
Commit
f714cdcc
authored
Aug 28, 2025
by
DatHV
Browse files
update logic, flutter refactor
parent
cc202df4
Changes
35
Hide whitespace changes
Inline
Side-by-side
assets/images/ic_logo_rank_member.png
0 → 100644
View file @
f714cdcc
132 KB
lib/configs/constants.dart
View file @
f714cdcc
...
...
@@ -3,6 +3,7 @@ class Constants {
static
get
commonError
=>
"Hệ thống không thể xử lý yêu cầu hiện tại. Vui lòng thử lại sau hoặc liên hệ hotline 1900599863 để được trợ giúp."
;
static
var
otpTtl
=
180
;
static
var
directionInApp
=
"IN-APP"
;
static
var
phoneNumberCount
=
10
;
}
class
ErrorCodes
{
...
...
lib/extensions/debouncer.dart
0 → 100644
View file @
f714cdcc
import
'dart:async'
;
class
Debouncer
{
Debouncer
({
this
.
ms
=
300
});
final
int
ms
;
Timer
?
_t
;
void
run
(
void
Function
()
action
)
{
_t
?.
cancel
();
_t
=
Timer
(
Duration
(
milliseconds:
ms
),
action
);
}
void
dispose
()
=>
_t
?.
cancel
();
}
\ No newline at end of file
lib/main.dart
View file @
f714cdcc
...
...
@@ -5,10 +5,12 @@ import 'package:mypoint_flutter_app/networking/app_navigator.dart';
import
'package:mypoint_flutter_app/preference/data_preference.dart'
;
import
'package:mypoint_flutter_app/preference/point/point_manager.dart'
;
import
'package:mypoint_flutter_app/resources/base_color.dart'
;
import
'package:mypoint_flutter_app/screen/home/header_home_viewmodel.dart'
;
import
'package:mypoint_flutter_app/shared/router_gage.dart'
;
void
main
(
)
async
{
WidgetsFlutterBinding
.
ensureInitialized
();
Get
.
put
(
HeaderThemeController
(),
permanent:
true
);
await
DataPreference
.
instance
.
init
();
await
UserPointManager
().
fetchUserPoint
();
runApp
(
const
MyApp
());
...
...
lib/networking/restful_api.dart
View file @
f714cdcc
...
...
@@ -47,6 +47,7 @@ class RestfulAPIClient {
final
isGet
=
method
==
Method
.
GET
;
Json
query
=
isGet
?
params
:
{};
Json
body
=
!
isGet
?
params
:
{};
// body["lang"] = 'vi';
final
option
=
Options
(
method:
method
.
name
)
.
compose
(
_dio
.
options
,
...
...
lib/networking/restful_api_request.dart
View file @
f714cdcc
...
...
@@ -66,7 +66,7 @@ import '../screen/transaction/model/order_product_payment_response_model.dart';
import
'../screen/transaction/model/payment_bank_account_info_model.dart'
;
import
'../screen/transaction/model/payment_method_model.dart'
;
import
'../screen/transaction/model/preview_order_payment_model.dart'
;
import
'../screen/voucher/models/like_product_reponse_model.dart'
;
import
'../screen/voucher/models/like_product_re
s
ponse_model.dart'
;
import
'../screen/voucher/models/my_mobile_card_response.dart'
;
import
'../screen/voucher/models/my_product_status_type.dart'
;
import
'../screen/voucher/models/product_brand_model.dart'
;
...
...
@@ -338,10 +338,10 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
});
}
Future
<
BaseResponseModel
<
LikeProductReponseModel
>>
likeProduct
(
int
id
)
async
{
Future
<
BaseResponseModel
<
LikeProductRe
s
ponseModel
>>
likeProduct
(
int
id
)
async
{
final
body
=
{
"product_id"
:
id
};
return
requestNormal
(
APIPaths
.
productCustomerLikes
,
Method
.
POST
,
body
,
(
data
)
{
return
LikeProductReponseModel
.
fromJson
(
data
as
Json
);
return
LikeProductRe
s
ponseModel
.
fromJson
(
data
as
Json
);
});
}
...
...
@@ -608,7 +608,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
Future
<
BaseResponseModel
<
MembershipInfoResponse
>>
getMembershipLevelInfo
()
async
{
String
?
token
=
DataPreference
.
instance
.
token
??
""
;
final
body
=
{
"access_token"
:
token
};
final
body
=
{
"access_token"
:
token
,
"lang"
:
"vi"
};
return
requestNormal
(
APIPaths
.
getMembershipLevelInfo
,
Method
.
POST
,
body
,
(
data
)
{
return
MembershipInfoResponse
.
fromJson
(
data
as
Json
);
});
...
...
lib/preference/point/point_manager.dart
View file @
f714cdcc
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'../data_preference.dart'
;
import
'header_home_model.dart'
;
class
UserPointManager
extends
RestfulApiViewModel
{
...
...
@@ -13,7 +14,8 @@ class UserPointManager extends RestfulApiViewModel {
get
point
=>
_userPoint
.
value
;
Future
<
int
>
fetchUserPoint
()
async
{
Future
fetchUserPoint
()
async
{
if
(!
DataPreference
.
instance
.
logged
)
return
;
try
{
final
response
=
await
client
.
getHomeHeaderData
();
if
(
response
.
isSuccess
&&
response
.
data
!=
null
)
{
...
...
@@ -25,6 +27,5 @@ class UserPointManager extends RestfulApiViewModel {
}
catch
(
e
)
{
_userPoint
.
value
=
0
;
}
return
_userPoint
.
value
;
}
}
lib/screen/affiliate/affiliate_tab_screen.dart
View file @
f714cdcc
...
...
@@ -51,7 +51,6 @@ class _AffiliateTabScreenState extends BaseState<AffiliateTabScreen> with BasicS
backgroundColor:
Colors
.
grey
.
shade50
,
appBar:
CustomNavigationBar
(
title:
"Mua sắm"
,
backgroundImage:
_headerHomeVM
.
headerData
.
background
??
"assets/images/bg_header_navi.png"
,
leftButtons:
_canBackButton
?
[
CustomBackButton
()]
:
[],
rightButtons:
[
IconButton
(
...
...
lib/screen/data_network_service/data_network_service_screen.dart
View file @
f714cdcc
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/num_extension.dart'
;
...
...
@@ -7,6 +8,7 @@ import 'package:mypoint_flutter_app/widgets/custom_navigation_bar.dart';
import
'package:mypoint_flutter_app/widgets/image_loader.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../extensions/debouncer.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../preference/point/point_manager.dart'
;
import
'../../resources/base_color.dart'
;
...
...
@@ -26,6 +28,7 @@ class DataNetworkServiceScreen extends BaseScreen {
class
_DataNetworkServiceScreenState
extends
BaseState
<
DataNetworkServiceScreen
>
with
BasicState
{
final
DataNetworkServiceViewModel
_viewModel
=
Get
.
put
(
DataNetworkServiceViewModel
());
late
final
TextEditingController
_phoneController
;
final
_deb
=
Debouncer
(
ms:
500
);
@override
void
initState
()
{
...
...
@@ -76,8 +79,7 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen>
Widget
_buildButton
()
{
return
Obx
(()
{
final
isValidInput
=
(
_viewModel
.
phoneNumber
.
value
.
trim
().
length
>=
10
)
&&
(
_viewModel
.
selectedProduct
.
value
!=
null
);
final
isValidInput
=
_viewModel
.
validatePhoneNumber
()
&&
(
_viewModel
.
selectedProduct
.
value
!=
null
);
return
ElevatedButton
(
onPressed:
isValidInput
?
_redeemProductMobileCard
:
null
,
style:
ElevatedButton
.
styleFrom
(
...
...
@@ -234,7 +236,7 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen>
keyboardType:
TextInputType
.
phone
,
onChanged:
(
value
)
{
_viewModel
.
phoneNumber
.
value
=
value
;
_viewModel
.
checkMobileNetwork
();
_deb
.
run
(()
=>
_viewModel
.
checkMobileNetwork
()
)
;
},
),
),
...
...
@@ -356,4 +358,4 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen>
);
}
}
}
}
\ No newline at end of file
lib/screen/data_network_service/data_network_service_viewmodel.dart
View file @
f714cdcc
...
...
@@ -30,6 +30,12 @@ class DataNetworkServiceViewModel extends RestfulApiViewModel {
return
UserPointManager
().
point
>=
payPoint
;
}
bool
validatePhoneNumber
()
{
final
phone
=
phoneNumber
.
value
.
replaceAll
(
RegExp
(
r'\s+'
),
''
);
final
regex
=
RegExp
(
r'^(0|\+84)(3[2-9]|5[6|8|9]|7[0|6-9]|8[1-5]|9[0-4|6-9])[0-9]{7}$'
);
return
regex
.
hasMatch
(
phone
);
}
@override
void
onInit
()
{
super
.
onInit
();
...
...
@@ -49,37 +55,39 @@ class DataNetworkServiceViewModel extends RestfulApiViewModel {
}
firstLoadNetworkData
()
async
{
showLoading
();
await
getNetworkBrands
();
print
(
"topUpBrands
${topUpBrands.length}
"
);
await
checkMobileNetwork
();
hideLoading
();
_getNetworkBrands
();
}
getNetworkBrands
()
{
_getNetworkBrands
()
{
showLoading
();
client
.
productTopUpBrands
().
then
((
response
)
{
topUpBrands
.
value
=
response
.
data
??
[];
hideLoading
();
checkMobileNetwork
();
}).
catchError
((
error
)
{
hideLoading
();
print
(
'Error fetching brands topup:
$error
'
);
});
}
checkMobileNetwork
()
{
showLoading
();
client
.
checkMobileNetwork
(
phoneNumber
.
value
).
then
((
response
)
{
final
brandCode
=
response
.
data
?.
brand
??
''
;
final
brand
=
topUpBrands
.
isNotEmpty
?
topUpBrands
.
firstWhere
(
(
brand
)
=>
brand
.
code
==
brandCode
,
orElse:
()
=>
topUpBrands
.
first
,
)
:
null
;
)
:
null
;
selectedBrand
.
value
=
brand
;
hideLoading
();
getTelcoDetail
();
}).
catchError
((
error
)
{
final
first
=
topUpBrands
.
value
.
firstOrNull
;
if
(
first
!=
null
)
{
selectedBrand
.
value
=
first
;
}
hideLoading
();
getTelcoDetail
();
print
(
'Error checking mobile network:
$error
'
);
});
...
...
lib/screen/game/game_tab_screen.dart
View file @
f714cdcc
...
...
@@ -59,7 +59,6 @@ class _GameTabScreenState extends BaseState<GameTabScreen> with BasicState, Popu
appBar:
CustomNavigationBar
(
title:
"Games"
,
leftButtons:
_canBackButton
?
[
CustomBackButton
()]
:
[],
backgroundImage:
_headerHomeVM
.
headerData
.
background
??
"assets/images/bg_header_navi.png"
,
rightButtons:
[
CompositedTransformTarget
(
link:
_layerLink
,
...
...
lib/screen/home/header_home_viewmodel.dart
View file @
f714cdcc
import
'package:get/get
_rx/src/rx_types/rx_types
.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'../../base/restful_api_viewmodel.dart'
;
import
'../../preference/point/header_home_model.dart'
;
import
'models/notification_unread_model.dart'
;
class
HeaderThemeController
extends
GetxController
{
final
background
=
RxnString
();
void
setBackground
(
String
?
url
)
=>
background
.
value
=
url
;
}
class
HeaderHomeViewModel
extends
RestfulApiViewModel
{
final
Rx
<
HeaderHomeModel
?>
_headerHomeData
=
Rx
<
HeaderHomeModel
?>(
null
);
var
notificationUnreadData
=
Rxn
<
NotificationUnreadData
>();
...
...
@@ -30,6 +35,7 @@ class HeaderHomeViewModel extends RestfulApiViewModel {
try
{
final
result
=
await
client
.
getDynamicHeaderHome
();
_headerHomeData
.
value
=
result
.
data
;
Get
.
find
<
HeaderThemeController
>().
setBackground
(
_headerHomeData
.
value
?.
background
);
}
catch
(
error
)
{
print
(
"Error fetching getDynamicHeaderHome:
$error
"
);
}
...
...
lib/screen/main_tab_screen/main_tab_screen.dart
View file @
f714cdcc
...
...
@@ -92,10 +92,11 @@ class _MainTabScreenState extends State<MainTabScreen> {
const
SizedBox
(
height:
2
),
Text
(
label
,
maxLines:
1
,
style:
TextStyle
(
color:
isSelected
?
Colors
.
white
:
Colors
.
white70
,
fontWeight:
isSelected
?
FontWeight
.
bold
:
FontWeight
.
normal
,
fontSize:
1
4
,
fontSize:
1
2
,
),
),
],
...
...
lib/screen/membership/member_level_header_widget.dart
View file @
f714cdcc
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get_core/src/get_main.dart'
;
import
'package:intl/intl.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
...
...
@@ -10,6 +12,7 @@ import 'models/membership_level_model.dart';
class
MemberLevelHeaderWidget
extends
StatelessWidget
{
final
MembershipLevelModel
?
level
;
const
MemberLevelHeaderWidget
({
super
.
key
,
this
.
level
});
@override
...
...
@@ -38,13 +41,13 @@ class MemberLevelHeaderWidget extends StatelessWidget {
children:
[
Row
(
children:
[
Container
(
width:
72
,
height:
72
,
decoration:
BoxDecoration
(
shape:
BoxShape
.
circle
,
border:
Border
.
all
(
color:
Colors
.
white
,
width:
2
))
,
child:
ClipOval
(
child:
Image
.
a
sset
(
"assets/images/
bg_default_11
.png"
))
,
loadNetworkImage
(
url:
"level?.logo"
,
width:
116
,
height:
116
,
placeholderA
sset
:
"assets/images/
ic_logo_rank_member
.png"
,
),
const
SizedBox
(
width:
12
),
const
SizedBox
(
width:
6
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
...
...
@@ -53,19 +56,20 @@ class MemberLevelHeaderWidget extends StatelessWidget {
style:
const
TextStyle
(
fontSize:
22
,
fontWeight:
FontWeight
.
bold
,
color:
Colors
.
white
),
),
const
SizedBox
(
height:
4
),
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
4
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
20
)),
child:
Text
(
(
level
?.
levelName
??
""
).
capitalizeWords
(),
style:
TextStyle
(
color:
BaseColor
.
primary800
,
fontSize:
14
,
fontWeight:
FontWeight
.
bold
),
if
((
level
?.
levelName
??
""
).
isNotEmpty
)
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
4
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
20
)),
child:
Text
(
(
level
?.
levelName
??
""
).
capitalizeWords
(),
style:
TextStyle
(
color:
BaseColor
.
primary800
,
fontSize:
14
,
fontWeight:
FontWeight
.
bold
),
),
),
),
],
),
],
),
const
SizedBox
(
height:
1
6
),
const
SizedBox
(
height:
6
),
// Progress bar
_buildCardInfo
(),
],
...
...
@@ -79,13 +83,19 @@ class MemberLevelHeaderWidget extends StatelessWidget {
final
int
spendingMax
=
double
.
tryParse
(
level
?.
upgradeGmvThreshold
??
"0"
)?.
toInt
()
??
1
;
return
Container
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
12
,
horizontal:
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
)),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black
.
withOpacity
(
0.3
),
blurRadius:
16
,
spreadRadius:
0
,
offset:
const
Offset
(
0
,
6
)),
],
),
child:
Row
(
children:
[
Expanded
(
child:
GestureDetector
(
onTap:
()
{
print
(
"GestureDetector"
);
Get
.
toNamed
(
'/pointHistoryScreen'
);
},
behavior:
HitTestBehavior
.
opaque
,
child:
Column
(
...
...
@@ -118,7 +128,7 @@ class MemberLevelHeaderWidget extends StatelessWidget {
Expanded
(
child:
GestureDetector
(
onTap:
()
{
print
(
"GestureDetector"
);
Get
.
toNamed
(
'/historyPointCashBackScreen'
);
},
behavior:
HitTestBehavior
.
opaque
,
child:
Column
(
...
...
lib/screen/membership/membership_screen.dart
View file @
f714cdcc
...
...
@@ -45,7 +45,7 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
8
),
child:
Text
(
"Hạng thành viên sẽ được cập nhật sau
${_viewModel.selectedLevel?.levelEndAtDate}
"
,
"Hạng thành viên sẽ được cập nhật sau
${_viewModel.selectedLevel?.levelEndAtDate
?? ''
}
"
,
style:
TextStyle
(
color:
Colors
.
black54
,
fontSize:
13
),
),
),
...
...
@@ -82,7 +82,7 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState
],
),
const
SizedBox
(
height:
8
),
HtmlWidget
(
"
item.content ??
"
),
HtmlWidget
(
item
.
content
??
''
),
],
),
);
...
...
lib/screen/membership/membership_viewmodel.dart
View file @
f714cdcc
import
'dart:convert'
;
import
'package:flutter/services.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/collection_extension.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
...
...
@@ -22,14 +20,13 @@ class MembershipViewModel extends RestfulApiViewModel {
if
(
levels
==
null
||
levels
!.
isEmpty
)
{
return
null
;
}
return
levels
?.
safe
(
selectedTab
.
value
)?.
conditions
?.
whereType
<
MembershipLevelTermAndConditionModel
>().
toList
()
;
return
levels
?.
safe
(
selectedTab
.
value
)?.
conditions
;
}
@override
onInit
()
{
super
.
onInit
();
getMembershipLevelInfo
();
// loadMembershipInfoFromAssets();
}
_makeSelectedLevel
()
{
...
...
@@ -40,22 +37,10 @@ class MembershipViewModel extends RestfulApiViewModel {
selectedLevel
=
levels
!.
firstWhere
((
e
)
=>
e
.
levelStartAtDate
?.
isNotEmpty
==
true
,
orElse:
()
=>
levels
!.
first
);
}
loadMembershipInfoFromAssets
()
async
{
final
jsonStr
=
await
rootBundle
.
loadString
(
'assets/data/membership_info.json'
);
final
jsonMap
=
jsonDecode
(
jsonStr
);
final
result
=
MembershipInfoResponse
.
fromJson
(
jsonMap
[
'data'
]);
membershipInfo
.
value
=
result
;
_makeSelectedLevel
();
}
getMembershipLevelInfo
()
async
{
showLoading
();
try
{
final
response
=
await
client
.
getMembershipLevelInfo
();
print
(
"getMembershipLevelInfo"
);
print
(
response
.
data
?.
membershipRule
);
print
(
response
.
data
?.
levels
?.
first
?.
condition
);
print
(
response
.
data
?.
levels
?.
first
?.
conditions
);
membershipInfo
.
value
=
response
.
data
;
_makeSelectedLevel
();
hideLoading
();
...
...
lib/screen/membership/models/membership_level_model.dart
View file @
f714cdcc
...
...
@@ -59,7 +59,7 @@ class MembershipLevelModel {
final
String
?
downgradeToLevelId
;
@JsonKey
(
name:
'membership_level_term_and_conditions'
)
final
List
<
MembershipLevelTermAndConditionModel
?
>?
conditions
;
final
List
<
MembershipLevelTermAndConditionModel
>?
conditions
;
@JsonKey
(
name:
'accumulated_counter'
)
final
AccumulatedCounter
?
accumulatedCounter
;
...
...
lib/screen/membership/models/membership_level_model.g.dart
View file @
f714cdcc
...
...
@@ -32,12 +32,9 @@ MembershipLevelModel _$MembershipLevelModelFromJson(
conditions:
(
json
[
'membership_level_term_and_conditions'
]
as
List
<
dynamic
>?)
?.
map
(
(
e
)
=>
e
==
null
?
null
:
MembershipLevelTermAndConditionModel
.
fromJson
(
e
as
Map
<
String
,
dynamic
>,
),
(
e
)
=>
MembershipLevelTermAndConditionModel
.
fromJson
(
e
as
Map
<
String
,
dynamic
>,
),
)
.
toList
(),
accumulatedCounter:
...
...
lib/screen/mobile_card/product_mobile_card_screen.dart
View file @
f714cdcc
...
...
@@ -124,13 +124,15 @@ class _ProductMobileCardScreenState extends BaseState<ProductMobileCardScreen> w
}
Widget
_buildProductItem
()
{
const
double
kItemHeight
=
80
;
final
widthItem
=
(
MediaQuery
.
of
(
context
).
size
.
width
-
12
*
3
)/
2
;
return
Expanded
(
child:
GridView
.
count
(
crossAxisCount:
2
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
),
crossAxisSpacing:
12
,
mainAxisSpacing:
12
,
childAspectRatio:
2.4
,
childAspectRatio:
widthItem
/
kItemHeight
,
children:
_viewModel
.
products
.
map
((
product
)
{
final
isSelected
=
_viewModel
.
selectedProduct
?.
id
==
product
.
id
;
...
...
@@ -153,7 +155,7 @@ class _ProductMobileCardScreenState extends BaseState<ProductMobileCardScreen> w
borderRadius:
BorderRadius
.
circular
(
12
),
color:
isSelected
?
Colors
.
orange
.
withOpacity
(
0.1
)
:
Colors
.
white
,
),
padding:
const
EdgeInsets
.
all
(
1
2
),
padding:
const
EdgeInsets
.
all
(
1
0
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
...
...
lib/screen/notification/notification_screen.dart
View file @
f714cdcc
...
...
@@ -7,6 +7,7 @@ import '../../resources/base_color.dart';
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../widgets/back_button.dart'
;
import
'../../widgets/custom_empty_widget.dart'
;
import
'../../widgets/custom_navigation_bar.dart'
;
import
'../../widgets/image_loader.dart'
;
import
'models/notification_item_model.dart'
;
import
'notification_viewmodel.dart'
;
...
...
@@ -44,22 +45,14 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
@override
Widget
createBody
()
{
return
Scaffold
(
appBar:
AppBar
(
scrolledUnderElevation:
0
,
backgroundColor:
Colors
.
white
,
elevation:
0
,
centerTitle:
true
,
title:
const
Text
(
'Thông báo'
,
style:
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
bold
,
color:
Colors
.
black87
),
),
leading:
CustomBackButton
(),
actions:
[
appBar:
CustomNavigationBar
(
title:
"Thông báo"
,
rightButtons:
[
CompositedTransformTarget
(
link:
_layerLink
,
child:
IconButton
(
key:
_infoKey
,
icon:
const
Icon
(
Icons
.
settings
,
color:
Colors
.
black
),
icon:
const
Icon
(
Icons
.
settings
,
color:
Colors
.
black
54
),
onPressed:
_toggleSetting
,
),
),
...
...
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