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
f0334970
Commit
f0334970
authored
Oct 31, 2025
by
DatHV
Browse files
update flash sale
parent
b93b2948
Changes
31
Hide whitespace changes
Inline
Side-by-side
lib/screen/home/models/flash_sale_model.dart
View file @
f0334970
import
'package:json_annotation/json_annotation.dart'
;
import
'../../flash_sale/preview_flash_sale_model.dart'
;
import
'../../flash_sale/
models/
preview_flash_sale_model.dart'
;
import
'../../voucher/models/product_model.dart'
;
part
'flash_sale_model.g.dart'
;
...
...
lib/screen/home/models/main_section_config_model.dart
View file @
f0334970
import
'package:json_annotation/json_annotation.dart'
;
import
'package:mypoint_flutter_app/directional/directional_screen.dart'
;
import
'../../flash_sale/preview_flash_sale_model.dart'
;
import
'../../flash_sale/
models/
preview_flash_sale_model.dart'
;
import
'header_section_type.dart'
;
part
'main_section_config_model.g.dart'
;
...
...
lib/screen/notification/notification_detail_screen.dart
View file @
f0334970
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_app_bar.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../widgets/image_loader.dart'
;
import
'models/notification_detail_model.dart'
;
import
'notification_detail_viewmodel.dart'
;
class
NotificationDetailScreen
extends
StatelessWidget
{
final
NotificationDetail
Model
notification
;
class
NotificationDetailScreen
extends
BaseScreen
{
const
NotificationDetail
Screen
({
super
.
key
})
;
const
NotificationDetailScreen
({
super
.
key
,
required
this
.
notification
});
@override
State
<
NotificationDetailScreen
>
createState
()
=>
_NotificationDetailScreenState
();
}
class
_NotificationDetailScreenState
extends
BaseState
<
NotificationDetailScreen
>
with
BasicState
{
final
_viewModel
=
Get
.
put
(
NotificationDetailViewModel
());
@override
void
initState
()
{
super
.
initState
();
NotificationDetailModel
?
notification
;
String
?
notificationId
;
String
?
title
;
String
?
body
;
final
args
=
Get
.
arguments
;
if
(
args
is
Map
)
{
notification
=
args
[
'notification'
];
notificationId
=
args
[
'notificationId'
];
title
=
args
[
'title'
];
body
=
args
[
'body'
];
}
if
(
title
.
orEmpty
.
isNotEmpty
&&
body
.
orEmpty
.
isNotEmpty
)
{
notification
??=
NotificationDetailModel
(
title:
title
,
body:
body
);
}
if
(
notificationId
==
null
&&
notification
==
null
)
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
Get
.
back
();
});
return
;
}
_viewModel
.
onShowAlertError
=
(
message
)
{
if
(
message
.
isEmpty
)
return
;
showAlertError
(
content:
message
,
onConfirmed:
()
{
Get
.
back
();
},
);
};
_viewModel
.
fetchNotificationDetail
(
id:
notificationId
,
data:
notification
);
}
@override
Widget
build
(
BuildContext
context
)
{
Widget
createBody
(
)
{
return
Scaffold
(
appBar:
CustomAppBar
.
back
(
title:
"Chi tiết thông báo"
),
body:
Container
(
color:
Colors
.
grey
.
shade100
,
padding:
const
EdgeInsets
.
all
(
16
),
child:
IntrinsicHeight
(
child:
Container
(
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
)),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
8
),
child:
loadNetworkImage
(
url:
notification
.
workingSite
?.
avatar
??
""
,
fit:
BoxFit
.
cover
,
width:
40
,
height:
40
,
placeholderAsset:
'assets/images/ic_logo.png'
,
body:
Obx
(
()
=>
Container
(
color:
Colors
.
grey
.
shade100
,
padding:
const
EdgeInsets
.
all
(
16
),
child:
IntrinsicHeight
(
child:
Container
(
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
)),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
8
),
child:
loadNetworkImage
(
url:
_viewModel
.
notification
.
value
?.
workingSite
?.
avatar
??
""
,
fit:
BoxFit
.
cover
,
width:
40
,
height:
40
,
placeholderAsset:
'assets/images/ic_logo.png'
,
),
),
),
const
SizedBox
(
width:
12
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
notification
.
title
??
''
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
bold
,
fontSize:
16
)),
const
SizedBox
(
height:
6
),
Text
(
notification
.
body
??
''
,
style:
const
TextStyle
(
fontSize:
14
)),
const
SizedBox
(
height:
10
),
Text
(
_timeAgo
(
notification
.
createTime
),
style:
const
TextStyle
(
color:
Colors
.
grey
,
fontSize:
13
)),
],
const
SizedBox
(
width:
12
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
_viewModel
.
notification
.
value
?.
title
??
''
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
bold
,
fontSize:
16
),
),
const
SizedBox
(
height:
6
),
Text
(
_viewModel
.
notification
.
value
?.
body
??
''
,
style:
const
TextStyle
(
fontSize:
14
)),
const
SizedBox
(
height:
10
),
if
(
_viewModel
.
notification
.
value
?.
createTime
.
orEmpty
.
isNotEmpty
==
true
)
Text
(
_timeAgo
(
_viewModel
.
notification
.
value
?.
createTime
),
style:
const
TextStyle
(
color:
Colors
.
grey
,
fontSize:
13
),
),
],
),
),
)
,
]
,
]
,
)
,
),
),
),
...
...
lib/screen/notification/notification_detail_viewmodel.dart
0 → 100644
View file @
f0334970
import
'package:get/get_rx/src/rx_types/rx_types.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'
;
import
'../../configs/constants.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'models/notification_detail_model.dart'
;
class
NotificationDetailViewModel
extends
RestfulApiViewModel
{
var
notification
=
Rxn
<
NotificationDetailModel
>();
void
Function
(
String
message
)?
onShowAlertError
;
Future
<
void
>
fetchNotificationDetail
({
String
?
id
,
NotificationDetailModel
?
data
})
async
{
if
(
data
!=
null
)
{
notification
.
value
=
data
;
return
;
}
if
(
id
==
null
)
return
;
await
callApi
<
NotificationDetailResponseModel
>(
request:
()
=>
client
.
getNotificationDetail
(
id
??
''
),
onSuccess:
(
data
,
_
)
{
final
notify
=
data
.
notification
;
if
(
notify
!=
null
)
{
notification
.
value
=
data
.
notification
;
}
else
{
onShowAlertError
?.
call
(
Constants
.
commonError
);
}
},
onFailure:
(
msg
,
_
,
_
)
async
{
onShowAlertError
?.
call
(
msg
);
},
);
}
}
\ No newline at end of file
lib/screen/notification/notification_viewmodel.dart
View file @
f0334970
...
...
@@ -3,6 +3,7 @@ import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.da
import
'../../base/base_response_model.dart'
;
import
'../../networking/restful_api_viewmodel.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../shared/router_gage.dart'
;
import
'models/category_notify_item_model.dart'
;
import
'models/notification_detail_model.dart'
;
import
'models/notification_item_model.dart'
;
...
...
@@ -128,7 +129,7 @@ class NotificationViewModel extends RestfulApiViewModel {
if
(
notification
==
null
)
return
;
final
pushSuccess
=
notification
.
directionalScreen
?.
begin
()
??
false
;
if
(!
pushSuccess
)
{
Get
.
to
(()
=>
N
otificationDetailScreen
(
notification
:
notification
)
);
Get
.
to
Named
(
n
otificationDetailScreen
,
arguments:
{
'notification'
:
notification
,
'
notification
Id'
:
item
.
notification
Id
}
);
}
},
onFailure:
(
msg
,
_
,
_
)
async
{
...
...
lib/screen/splash/splash_screen_viewmodel.dart
View file @
f0334970
import
'dart:async'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
...
...
lib/screen/transaction/transaction_detail_screen.dart
View file @
f0334970
import
'dart:core'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:
intl/intl
.dart'
;
import
'package:
mypoint_flutter_app/extensions/num_extension
.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../resources/base_color.dart'
;
...
...
@@ -22,7 +22,6 @@ class TransactionDetailScreen extends BaseScreen {
class
_TransactionDetailScreenState
extends
BaseState
<
TransactionDetailScreen
>
with
BasicState
{
late
final
TransactionDetailViewModel
_viewModel
;
final
currencyFormatter
=
NumberFormat
.
currency
(
locale:
'vi_VN'
,
symbol:
'đ'
,
decimalDigits:
0
);
ProductModel
?
_product
;
String
?
_metaData
;
int
_quantity
=
1
;
...
...
@@ -211,9 +210,6 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
}
Widget
_buildTotalRow
(
String
label
,
int
amount
,
bool
isHighlighted
)
{
final
formattedAmount
=
currencyFormatter
.
format
(
amount
);
final
displayAmount
=
amount
<
0
?
formattedAmount
:
formattedAmount
;
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
8
),
child:
Row
(
...
...
@@ -221,7 +217,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
children:
[
Text
(
label
,
style:
TextStyle
(
fontSize:
16
,
color:
Colors
.
grey
.
shade700
)),
Text
(
displayAmount
,
amount
.
money
(
CurrencyUnit
.
vnd
)
,
style:
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w500
,
...
...
@@ -469,7 +465,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
const
Text
(
'Tổng thanh toán'
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
)),
const
SizedBox
(
height:
4
),
Text
(
currencyFormatter
.
format
(
_viewModel
.
finalTotal
),
_viewModel
.
finalTotal
.
money
(
CurrencyUnit
.
vnd
),
style:
const
TextStyle
(
fontSize:
22
,
fontWeight:
FontWeight
.
bold
),
),
],
...
...
lib/screen/voucher/detail/voucher_detail_screen.dart
View file @
f0334970
...
...
@@ -159,6 +159,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
}
Widget
_buildInfo
(
ProductModel
product
,
{
Key
?
key
})
{
final
double
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
return
Container
(
key:
key
,
padding:
const
EdgeInsets
.
all
(
16
),
...
...
@@ -198,9 +199,59 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
const
SizedBox
(
width:
8
),
Expanded
(
child:
Text
(
product
.
brand
?.
name
??
''
,
style:
const
TextStyle
(
fontSize:
14
))),
// PriceTagWidget(point: product.amountToBePaid ?? 0),
if
(
product
.
percentDiscount
!=
null
)
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
6
,
vertical:
2
),
decoration:
BoxDecoration
(
color:
Colors
.
red
,
borderRadius:
BorderRadius
.
circular
(
20
)),
child:
Text
(
'-
${product.percentDiscount}
%'
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontWeight:
FontWeight
.
bold
,
fontSize:
12
),
),
),
const
SizedBox
(
width:
4
),
CustomPointText
(
point:
product
.
amountToBePaid
??
0
,
type:
product
.
price
?.
method
),
const
SizedBox
(
width:
4
),
if
(
product
.
price
?.
value
!=
null
&&
product
.
previewFlashSale
?.
isFlashSalePrice
==
true
)
Text
(
'
${product.price?.value?.money(CurrencyUnit.noneSpace)}
đ'
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
,
decoration:
TextDecoration
.
lineThrough
,
),
),
],
),
if
(
product
.
isShowProsessSoldItem
)
const
SizedBox
(
height:
16
),
if
(
product
.
isShowProsessSoldItem
)
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
// Thanh tiến trình
SizedBox
(
width:
screenWidth
-
64
-
90
,
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
6
),
child:
LinearProgressIndicator
(
value:
product
.
progress
,
minHeight:
10
,
backgroundColor:
Colors
.
grey
.
shade300
,
valueColor:
AlwaysStoppedAnimation
<
Color
>(
product
.
inStock
?
Colors
.
orange
:
Colors
.
red
,
),
),
),
),
const
SizedBox
(
width:
2
),
Text
(
product
.
inStock
?
'Đã bán
${product.previewFlashSale?.fsQuantitySold ?? 0}
'
:
'Đã bán hết'
,
style:
TextStyle
(
fontSize:
12
,
color:
product
.
inStock
?
Colors
.
black
:
Colors
.
grey
),
),
],
),
],
),
);
...
...
@@ -218,7 +269,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
if
(
hasExpire
)
Text
(
product
.
expired
?
"Hết hạn"
:
product
.
expire
,
style:
const
TextStyle
(
color:
Base
Color
.
primary500
,
fontWeight:
FontWeight
.
bold
,
fontSize:
1
2
),
style:
const
TextStyle
(
color:
Color
s
.
orange
,
fontWeight:
FontWeight
.
bold
,
fontSize:
1
4
),
),
if
(
isOutOfStock
&&
!
_viewModel
.
isMyProduct
)
Container
(
...
...
lib/screen/voucher/models/product_model.dart
View file @
f0334970
...
...
@@ -11,7 +11,7 @@ import 'package:mypoint_flutter_app/screen/voucher/models/product_price_model.da
import
'package:mypoint_flutter_app/screen/voucher/models/product_properties_model.dart'
;
import
'package:mypoint_flutter_app/screen/voucher/models/product_type.dart'
;
import
'package:mypoint_flutter_app/widgets/alert/popup_data_model.dart'
;
import
'../../flash_sale/preview_flash_sale_model.dart'
;
import
'../../flash_sale/
models/
preview_flash_sale_model.dart'
;
import
'media_type.dart'
;
import
'my_product_status_type.dart'
;
...
...
lib/shared/router_gage.dart
View file @
f0334970
...
...
@@ -14,6 +14,7 @@ import '../screen/data_network_service/data_network_service_screen.dart';
import
'../screen/device_manager/device_manager_screen.dart'
;
import
'../screen/electric_payment/electric_payment_history_screen.dart'
;
import
'../screen/electric_payment/electric_payment_screen.dart'
;
import
'../screen/flash_sale/flash_sale_screen.dart'
;
import
'../screen/game/game_cards/game_card_screen.dart'
;
import
'../screen/game/game_tab_screen.dart'
;
import
'../screen/health_book/health_book_card_detail.dart'
;
...
...
@@ -27,6 +28,7 @@ import '../screen/login/login_screen.dart';
import
'../screen/main_tab_screen/main_tab_screen.dart'
;
import
'../screen/membership/membership_screen.dart'
;
import
'../screen/mobile_card/product_mobile_card_screen.dart'
;
import
'../screen/notification/notification_detail_screen.dart'
;
import
'../screen/notification/notification_screen.dart'
;
import
'../screen/onboarding/onboarding_screen.dart'
;
import
'../screen/order_menu/order_menu_screen.dart'
;
...
...
@@ -56,6 +58,7 @@ const onboardingScreen = '/onboarding';
const
loginScreen
=
'/login'
;
const
mainScreen
=
'/main'
;
const
settingScreen
=
'/setting'
;
const
flashSaleScreen
=
'/flashSale'
;
const
vouchersScreen
=
'/vouchers'
;
const
voucherDetailScreen
=
'/voucherDetail'
;
const
gameCardScreen
=
'/gameCardScreen'
;
...
...
@@ -103,6 +106,7 @@ const historyPointScreen = '/historyPointScreen';
const
qrCodeScreen
=
'/qrCodeScreen'
;
const
myMobileCardDetailScreen
=
'/myMobileCardDetailScreen'
;
const
healthBookCardDetail
=
'/healthBookCardDetail'
;
const
notificationDetailScreen
=
'/notificationDetailScreen'
;
class
RouterPage
{
static
List
<
GetPage
>
pages
()
{
...
...
@@ -125,6 +129,7 @@ class RouterPage {
),
GetPage
(
name:
settingScreen
,
page:
()
=>
SettingScreen
()),
GetPage
(
name:
vouchersScreen
,
page:
()
=>
VoucherListScreen
()),
GetPage
(
name:
flashSaleScreen
,
page:
()
=>
const
FlashSaleScreen
()),
GetPage
(
name:
voucherDetailScreen
,
page:
()
=>
VoucherDetailScreen
()),
GetPage
(
name:
gameCardScreen
,
page:
()
=>
GameCardScreen
()),
GetPage
(
name:
registerFormInputScreen
,
page:
()
=>
RegisterFormInputScreen
()),
...
...
@@ -171,6 +176,7 @@ class RouterPage {
GetPage
(
name:
myMobileCardDetailScreen
,
page:
()
=>
MyMobileCardDetailScreen
()),
GetPage
(
name:
healthBookScreen
,
page:
()
=>
HealthBookScreen
()),
GetPage
(
name:
healthBookCardDetail
,
page:
()
=>
HealthBookCardDetail
()),
GetPage
(
name:
notificationDetailScreen
,
page:
()
=>
NotificationDetailScreen
()),
];
}
}
\ No newline at end of file
lib/widgets/custom_point_text_tag.dart
View file @
f0334970
...
...
@@ -25,7 +25,7 @@ class CustomPointText extends StatelessWidget {
Text
(
isFree
?
'Miễn phí'
:
point
.
money
(
currencyUnit
),
style:
TextStyle
(
fontSize:
1
2
,
fontSize:
1
4
,
color:
Colors
.
black
,
fontWeight:
FontWeight
.
bold
,
),
...
...
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