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
56e8b038
Commit
56e8b038
authored
May 09, 2025
by
DatHV
Browse files
update game, shopping
parent
c285d072
Changes
39
Hide whitespace changes
Inline
Side-by-side
lib/screen/login/login_screen.dart
View file @
56e8b038
...
...
@@ -41,9 +41,9 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
Get
.
dialog
(
CustomAlertDialog
(
alertData:
DataAlertModel
(
background
:
"assets/images/bg_alert_header.png"
,
localHeaderImage
:
"assets/images/bg_alert_header.png"
,
title:
"Cài đặt mật khẩu"
,
content
:
message
,
description
:
message
,
buttons:
[
AlertButton
(
text:
"Cài đặt ngay"
,
...
...
@@ -52,7 +52,6 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
},
bgColor:
BaseColor
.
primary500
,
textColor:
Colors
.
white
,
isPrimary:
true
,
),
],
),
...
...
@@ -68,9 +67,9 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
Get
.
dialog
(
CustomAlertDialog
(
alertData:
DataAlertModel
(
background
:
"assets/images/bg_alert_header.png"
,
localHeaderImage
:
"assets/images/bg_alert_header.png"
,
title:
""
,
content
:
message
,
description
:
message
,
buttons:
[
AlertButton
(
text:
"Quên mật khẩu"
,
...
...
@@ -79,7 +78,6 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
},
bgColor:
BaseColor
.
primary500
,
textColor:
Colors
.
white
,
isPrimary:
true
,
),
AlertButton
(
text:
"Đã hiểu"
,
...
...
@@ -88,7 +86,6 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
},
bgColor:
Colors
.
white
,
textColor:
Colors
.
black
,
isPrimary:
true
,
),
],
),
...
...
lib/screen/main_tab_screen/main_tab_screen.dart
View file @
56e8b038
...
...
@@ -3,7 +3,7 @@ import '../../resouce/base_color.dart';
import
'../game/game_tab_screen.dart'
;
import
'../home/home_screen.dart'
;
import
'../personal/personal_screen.dart'
;
import
'../s
upport/transaction_history
_screen.dart'
;
import
'../s
hopping/shopping_tab
_screen.dart'
;
import
'../voucher/voucher_tab_screen.dart'
;
class
MainTabScreen
extends
StatefulWidget
{
...
...
@@ -20,7 +20,7 @@ class _MainTabScreenState extends State<MainTabScreen> {
HomeScreen
(),
VoucherTabScreen
(),
GameTabScreen
(),
TransactionHistory
Screen
(),
ShoppingTab
Screen
(),
PersonalScreen
(),
];
...
...
@@ -43,7 +43,7 @@ class _MainTabScreenState extends State<MainTabScreen> {
children:
[
_buildTabItem
(
icon:
Icons
.
home
,
label:
'Trang chủ'
,
index:
0
),
_buildTabItem
(
icon:
Icons
.
star
,
label:
'Ưu đãi'
,
index:
1
),
_buildTabItem
(
icon:
Icons
.
videogame_asset
,
label:
'Game'
,
index:
2
),
_buildTabItem
(
icon:
null
,
label:
'Game'
,
index:
2
,
gift:
'assets/images/ic_tabbar_game.gif'
),
_buildTabItem
(
icon:
Icons
.
shopping_cart
,
label:
'Mua sắm'
,
index:
3
),
_buildTabItem
(
icon:
Icons
.
person
,
label:
'Cá nhân'
,
index:
4
),
],
...
...
@@ -54,7 +54,7 @@ class _MainTabScreenState extends State<MainTabScreen> {
);
}
Widget
_buildTabItem
({
required
IconData
icon
,
required
String
label
,
required
int
index
})
{
Widget
_buildTabItem
({
required
IconData
?
icon
,
required
String
label
,
required
int
index
,
String
?
gift
})
{
final
isSelected
=
_currentIndex
==
index
;
return
Expanded
(
child:
GestureDetector
(
...
...
@@ -65,9 +65,18 @@ class _MainTabScreenState extends State<MainTabScreen> {
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Icon
(
icon
,
if
(
icon
!=
null
)
Icon
(
icon
,
size:
28
,
color:
isSelected
?
Colors
.
white
:
Colors
.
white70
),
if
(
gift
!=
null
)
Image
.
asset
(
gift
,
width:
40
,
height:
28
,
fit:
BoxFit
.
cover
,
color:
isSelected
?
Colors
.
white
:
Colors
.
white70
,
),
const
SizedBox
(
height:
2
),
Text
(
label
,
...
...
lib/screen/shopping/model/brand_model.dart
0 → 100644
View file @
56e8b038
import
'package:json_annotation/json_annotation.dart'
;
part
'brand_model.g.dart'
;
@JsonSerializable
()
class
BrandModel
{
@JsonKey
(
name:
'product_name'
)
final
String
?
productName
;
@JsonKey
(
name:
'product_price'
)
final
String
?
productPrice
;
@JsonKey
(
name:
'product_link'
)
final
String
?
productLink
;
final
String
?
commision
;
final
String
?
logo
;
@JsonKey
(
name:
'thumnail_link'
)
final
String
?
thumnailLink
;
@JsonKey
(
name:
'quantity_sold'
)
final
String
?
quantitySold
;
final
String
?
direction
;
BrandModel
({
this
.
productName
,
this
.
productPrice
,
this
.
productLink
,
this
.
commision
,
this
.
logo
,
this
.
thumnailLink
,
this
.
quantitySold
,
this
.
direction
,
});
factory
BrandModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$BrandModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$BrandModelToJson
(
this
);
}
lib/screen/shopping/model/brand_model.g.dart
0 → 100644
View file @
56e8b038
// GENERATED CODE - DO NOT MODIFY BY HAND
part of
'brand_model.dart'
;
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BrandModel
_$BrandModelFromJson
(
Map
<
String
,
dynamic
>
json
)
=>
BrandModel
(
productName:
json
[
'product_name'
]
as
String
?,
productPrice:
json
[
'product_price'
]
as
String
?,
productLink:
json
[
'product_link'
]
as
String
?,
commision:
json
[
'commision'
]
as
String
?,
logo:
json
[
'logo'
]
as
String
?,
thumnailLink:
json
[
'thumnail_link'
]
as
String
?,
quantitySold:
json
[
'quantity_sold'
]
as
String
?,
direction:
json
[
'direction'
]
as
String
?,
);
Map
<
String
,
dynamic
>
_$BrandModelToJson
(
BrandModel
instance
)
=>
<
String
,
dynamic
>{
'product_name'
:
instance
.
productName
,
'product_price'
:
instance
.
productPrice
,
'product_link'
:
instance
.
productLink
,
'commision'
:
instance
.
commision
,
'logo'
:
instance
.
logo
,
'thumnail_link'
:
instance
.
thumnailLink
,
'quantity_sold'
:
instance
.
quantitySold
,
'direction'
:
instance
.
direction
,
};
lib/screen/shopping/model/product_brand_model.dart
0 → 100644
View file @
56e8b038
import
'package:json_annotation/json_annotation.dart'
;
part
'product_brand_model.g.dart'
;
@JsonSerializable
()
class
ProductBrandModel
{
@JsonKey
(
name:
'brand_id'
)
final
String
brandId
;
@JsonKey
(
name:
'brand_name'
)
final
String
?
brandName
;
final
String
?
commision
;
final
String
?
logo
;
@JsonKey
(
name:
'brand_url'
)
final
String
?
brandUrl
;
@JsonKey
(
name:
'category_name'
)
final
String
?
categoryName
;
final
String
?
direction
;
ProductBrandModel
({
required
this
.
brandId
,
this
.
brandName
,
this
.
commision
,
this
.
logo
,
this
.
brandUrl
,
this
.
categoryName
,
this
.
direction
,
});
factory
ProductBrandModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$ProductBrandModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$ProductBrandModelToJson
(
this
);
}
lib/screen/shopping/model/product_brand_model.g.dart
0 → 100644
View file @
56e8b038
// GENERATED CODE - DO NOT MODIFY BY HAND
part of
'product_brand_model.dart'
;
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ProductBrandModel
_$ProductBrandModelFromJson
(
Map
<
String
,
dynamic
>
json
)
=>
ProductBrandModel
(
brandId:
json
[
'brand_id'
]
as
String
,
brandName:
json
[
'brand_name'
]
as
String
?,
commision:
json
[
'commision'
]
as
String
?,
logo:
json
[
'logo'
]
as
String
?,
brandUrl:
json
[
'brand_url'
]
as
String
?,
categoryName:
json
[
'category_name'
]
as
String
?,
direction:
json
[
'direction'
]
as
String
?,
);
Map
<
String
,
dynamic
>
_$ProductBrandModelToJson
(
ProductBrandModel
instance
)
=>
<
String
,
dynamic
>{
'brand_id'
:
instance
.
brandId
,
'brand_name'
:
instance
.
brandName
,
'commision'
:
instance
.
commision
,
'logo'
:
instance
.
logo
,
'brand_url'
:
instance
.
brandUrl
,
'category_name'
:
instance
.
categoryName
,
'direction'
:
instance
.
direction
,
};
lib/screen/shopping/shopping_screen.dart
deleted
100644 → 0
View file @
c285d072
import
'package:flutter/material.dart'
;
class
ShoppingScreen
extends
StatelessWidget
{
const
ShoppingScreen
({
super
.
key
});
@override
Widget
build
(
BuildContext
context
)
{
return
const
Center
(
child:
Text
(
'Mua sắm'
));
}
}
\ No newline at end of file
lib/screen/shopping/shopping_tab_screen.dart
0 → 100644
View file @
56e8b038
import
'package:flutter/material.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../../widgets/custom_navigation_bar.dart'
;
class
ShoppingTabScreen
extends
StatefulWidget
{
const
ShoppingTabScreen
({
super
.
key
});
@override
State
<
ShoppingTabScreen
>
createState
()
=>
_ShoppingTabScreenState
();
}
class
_ShoppingTabScreenState
extends
State
<
ShoppingTabScreen
>
{
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
backgroundColor:
Colors
.
grey
.
shade50
,
appBar:
CustomNavigationBar
(
title:
"Mua sắm"
,
showBackButton:
false
,
rightButtons:
[
IconButton
(
icon:
const
Icon
(
Icons
.
info
,
color:
Colors
.
white
),
onPressed:
()
{
},
),
],
),
body:
SingleChildScrollView
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
12
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
start
,
children:
[
Container
(
padding:
const
EdgeInsets
.
all
(
12
),
decoration:
BoxDecoration
(
color:
Colors
.
amber
.
shade100
,
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
Row
(
children:
[
const
Text
(
"Điểm hoàn:"
,
style:
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
normal
)),
const
SizedBox
(
width:
8
),
Image
.
asset
(
'assets/images/ic_point.png'
,
width:
20
,
height:
20
),
const
SizedBox
(
width:
4
),
const
Text
(
"0"
,
style:
TextStyle
(
fontSize:
20
,
color:
BaseColor
.
primary400
,
fontWeight:
FontWeight
.
bold
)),
const
Spacer
(),
Icon
(
Icons
.
arrow_forward_ios
,
color:
BaseColor
.
primary400
,
size:
16
),
],
),
),
const
SizedBox
(
height:
16
),
SizedBox
(
height:
130
,
child:
ListView
(
scrollDirection:
Axis
.
horizontal
,
children:
[
_buildStepCard
(
"assets/images/banner_tutorial_refund_point_step1.png"
),
const
SizedBox
(
width:
12
),
_buildStepCard
(
"assets/images/banner_tutorial_refund_point_step2.png"
),
const
SizedBox
(
width:
12
),
_buildStepCard
(
"assets/images/banner_tutorial_refund_point_step3.png"
),
const
SizedBox
(
width:
12
),
_buildStepCard
(
"assets/images/banner_tutorial_refund_point_step4.png"
),
],
),
),
const
SizedBox
(
height:
24
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
const
[
Text
(
"Thương Hiệu Hoàn Điểm"
,
style:
TextStyle
(
fontWeight:
FontWeight
.
bold
,
fontSize:
20
)),
Text
(
"Xem tất cả"
,
style:
TextStyle
(
color:
BaseColor
.
primary400
,
fontSize:
14
,
fontWeight:
FontWeight
.
w600
)),
],
),
const
SizedBox
(
height:
12
),
GridView
.
count
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
crossAxisCount:
3
,
childAspectRatio:
3
/
3.2
,
crossAxisSpacing:
8
,
mainAxisSpacing:
8
,
children:
[
_buildBrandItem
(
"Lazada"
,
"30%"
,
"assets/images/ic_pipi_06.png"
),
_buildBrandItem
(
"Newshop"
,
"5,3%"
,
"assets/images/ic_pipi_06.png"
),
_buildBrandItem
(
"Tiki"
,
"0,78%"
,
"assets/images/ic_pipi_06.png"
),
_buildBrandItem
(
"MyTour MyTour MyTour"
,
"3,1%"
,
"assets/images/ic_pipi_06.png"
),
_buildBrandItem
(
"Pierre Cardin"
,
"10,2%"
,
"assets/images/ic_pipi_06.png"
),
_buildBrandItem
(
"Adidas"
,
"2,9%"
,
"assets/images/ic_pipi_06.png"
),
],
),
Text
(
"Lĩnh Vực Hoàn Điểm"
,
style:
TextStyle
(
fontWeight:
FontWeight
.
bold
,
fontSize:
20
)),
const
SizedBox
(
height:
12
),
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black
.
withOpacity
(
0.05
),
blurRadius:
5
,
offset:
const
Offset
(
0
,
2
),
)
],
),
child:
GridView
.
count
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
crossAxisCount:
3
,
childAspectRatio:
3
/
3.2
,
// crossAxisSpacing: 8,
children:
[
_fieldCashBackItem
(
"Lazada"
,
"30%"
,
"assets/images/ic_pipi_06.png"
),
_fieldCashBackItem
(
"Newshop"
,
"5,3%"
,
"assets/images/ic_pipi_06.png"
),
_fieldCashBackItem
(
"Tiki"
,
"0,78%"
,
"assets/images/ic_pipi_06.png"
),
_fieldCashBackItem
(
"MyTour MyTour MyTour"
,
"3,1%"
,
"assets/images/ic_pipi_06.png"
),
_fieldCashBackItem
(
"Pierre Cardin"
,
"10,2%"
,
"assets/images/ic_pipi_06.png"
),
_fieldCashBackItem
(
"Adidas"
,
"2,9%"
,
"assets/images/ic_pipi_06.png"
),
],
),
),
],
),
),
);
}
Widget
_buildStepCard
(
String
imagePath
)
{
return
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
16
),
child:
Image
.
asset
(
imagePath
,
fit:
BoxFit
.
cover
,
width:
250
),
);
}
Widget
_fieldCashBackItem
(
String
name
,
String
cashback
,
String
logoPath
)
{
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
final
double
imageWidth
=
constraints
.
maxWidth
/
2
;
return
Container
(
padding:
const
EdgeInsets
.
all
(
12
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
SizedBox
(
width:
imageWidth
,
height:
imageWidth
,
// ✅ 1:1 ratio
child:
Image
.
asset
(
logoPath
,
fit:
BoxFit
.
contain
),
),
const
SizedBox
(
height:
4
),
Text
(
textAlign:
TextAlign
.
center
,
name
,
maxLines:
2
,
overflow:
TextOverflow
.
ellipsis
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
w600
,
fontSize:
16
,
color:
BaseColor
.
second500
),
),
],
),
);
},
);
}
Widget
_buildBrandItem
(
String
name
,
String
cashback
,
String
logoPath
)
{
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
final
double
imageWidth
=
constraints
.
maxWidth
/
2
;
return
Container
(
padding:
const
EdgeInsets
.
all
(
12
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
black
.
withOpacity
(
0.05
),
blurRadius:
5
,
offset:
const
Offset
(
0
,
2
),
)
],
),
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
SizedBox
(
width:
imageWidth
,
height:
imageWidth
,
// ✅ 1:1 ratio
child:
Image
.
asset
(
logoPath
,
fit:
BoxFit
.
contain
),
),
const
SizedBox
(
height:
4
),
Text
(
name
,
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
style:
const
TextStyle
(
fontWeight:
FontWeight
.
w600
,
fontSize:
16
),
),
const
SizedBox
(
height:
4
),
RichText
(
textAlign:
TextAlign
.
center
,
text:
TextSpan
(
style:
const
TextStyle
(
fontSize:
12
),
children:
[
const
TextSpan
(
text:
"Hoàn đến: "
,
style:
TextStyle
(
color:
Colors
.
grey
),
),
TextSpan
(
text:
cashback
,
style:
const
TextStyle
(
color:
Colors
.
orange
,
fontWeight:
FontWeight
.
bold
,
),
),
],
),
),
],
),
);
},
);
}
}
lib/screen/shopping/shopping_tab_viewmodel.dart
0 → 100644
View file @
56e8b038
import
'../../base/restful_api_viewmodel.dart'
;
class
ShoppingTabViewModel
extends
RestfulApiViewModel
{
}
\ No newline at end of file
lib/screen/splash/splash_screen.dart
View file @
56e8b038
...
...
@@ -95,7 +95,6 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState, ApiHel
},
bgColor:
BaseColor
.
primary500
,
textColor:
Colors
.
white
,
isPrimary:
true
,
),]
:
[
AlertButton
(
text:
"Cập nhật"
,
...
...
@@ -104,7 +103,6 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState, ApiHel
},
bgColor:
BaseColor
.
primary500
,
textColor:
Colors
.
white
,
isPrimary:
true
,
),
AlertButton
(
text:
"Để sau"
,
...
...
@@ -114,12 +112,11 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState, ApiHel
},
bgColor:
Colors
.
white
,
textColor:
BaseColor
.
primary500
,
isPrimary:
false
,
),];
final
model
=
DataAlertModel
(
background
:
"assets/images/ic_pipi_03.png"
,
localHeaderImage
:
"assets/images/ic_pipi_03.png"
,
title:
data
.
updateTitle
??
"Cập nhật phiên bản mới"
,
content
:
data
.
updateMessage
??
"Cập nhật phiên bản mới"
,
description
:
data
.
updateMessage
??
"Cập nhật phiên bản mới"
,
buttons:
buttons
,
);
showAlert
(
data:
model
,
showCloseButton:
false
,
direction:
ButtonsDirection
.
row
);
...
...
lib/screen/voucher/detail/voucher_detail_screen.dart
View file @
56e8b038
...
...
@@ -9,7 +9,6 @@ import '../../../resouce/base_color.dart';
import
'../../../widgets/back_button.dart'
;
import
'../../../widgets/custom_empty_widget.dart'
;
import
'../../../widgets/custom_point_text_tag.dart'
;
import
'../../../widgets/custom_price_tag.dart'
;
import
'../../../widgets/dashed_line.dart'
;
import
'../../../widgets/image_loader.dart'
;
import
'../../../widgets/measure_size.dart'
;
...
...
@@ -30,7 +29,6 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
late
final
int
productId
;
late
final
VoucherDetailViewModel
_viewModel
;
double
_infoHeight
=
0
;
final
_quantity
=
1
.
obs
;
@override
void
initState
()
{
...
...
@@ -410,15 +408,14 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
child:
IconButton
(
icon:
const
Icon
(
Icons
.
remove
,
color:
Colors
.
black
),
onPressed:
()
{
if
(
_quantity
.
value
>
1
)
{
_quantity
.
value
--;
// TODO: update state
if
(
_viewModel
.
quantity
.
value
>
1
)
{
_viewModel
.
quantity
.
value
--;
}
},
),
),
const
SizedBox
(
width:
12
),
Obx
(()
=>
Text
(
'
${_quantity.value}
'
,
style:
const
TextStyle
(
fontSize:
16
))),
Obx
(()
=>
Text
(
'
${_
viewModel.
quantity.value}
'
,
style:
const
TextStyle
(
fontSize:
16
))),
const
SizedBox
(
width:
12
),
Container
(
decoration:
BoxDecoration
(
...
...
@@ -429,8 +426,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
child:
IconButton
(
icon:
const
Icon
(
Icons
.
add
,
color:
Colors
.
white
),
onPressed:
()
{
_quantity
.
value
++;
// TODO: update state
_viewModel
.
quantity
.
value
++;
},
),
),
...
...
@@ -442,7 +438,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
height:
48
,
child:
ElevatedButton
(
onPressed:
()
{
// TODO: Handle mua ngay
_viewModel
.
verifyOrderProduct
();
},
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
BaseColor
.
primary500
,
...
...
lib/screen/voucher/detail/voucher_detail_viewmodel.dart
View file @
56e8b038
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/networking/restful_api_request.dart'
;
import
'../../../base/restful_api_viewmodel.dart'
;
import
'../../../configs/constants.dart'
;
import
'../models/product_model.dart'
;
import
'../models/product_store_model.dart'
;
...
...
@@ -12,6 +13,7 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
var
isLoading
=
false
.
obs
;
var
liked
=
false
.
obs
;
void
Function
(
String
message
)?
onShowAlertError
;
var
quantity
=
1
.
obs
;
@override
void
onInit
()
{
...
...
@@ -63,4 +65,28 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
print
(
"Error product stores:
$error
"
);
}
finally
{}
}
verifyOrderProduct
()
async
{
final
value
=
product
.
value
;
var
body
=
{
"product_id"
:
productId
,
"price"
:
value
?.
amountToBePaid
,
"quantity"
:
quantity
.
value
,
};
if
(
value
?.
previewFlashSale
?.
isFlashSalePrice
==
true
)
{
final
flashSaleId
=
value
?.
previewFlashSale
?.
id
;
if
(
flashSaleId
!=
null
)
{
body
[
"flash_sale_id"
]
=
flashSaleId
;
}
}
showLoading
();
client
.
verifyOrderProduct
(
body
).
then
((
value
)
{
hideLoading
();
if
(!
value
.
isSuccess
)
{
onShowAlertError
?.
call
(
value
.
errorMessage
??
Constants
.
commonError
);
}
else
{
onShowAlertError
?.
call
(
"Verify Order Product Success -> Go To Payment Detail"
);
}
});
}
}
lib/
directional
/button_config_model.dart
→
lib/
widgets/alert
/button_config_model.dart
View file @
56e8b038
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:json_annotation/json_annotation.dart'
;
import
'directional_screen.dart'
;
import
'package:mypoint_flutter_app/extensions/color_extension.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'../../directional/directional_screen.dart'
;
import
'data_alert_model.dart'
;
part
'button_config_model.g.dart'
;
@JsonSerializable
()
...
...
@@ -10,16 +15,30 @@ class ButtonConfigModel {
final
String
?
clickActionType
;
@JsonKey
(
name:
"click_action_param"
)
final
String
?
clickActionParam
;
final
bool
?
hiden
;
ButtonConfigModel
({
this
.
text
,
this
.
color
,
this
.
clickActionType
,
this
.
clickActionParam
,
this
.
hiden
,
});
AlertButton
get
alertButton
{
final
bgColor
=
color
?.
toColor
()
??
Colors
.
white
;
return
AlertButton
(
text:
text
??
""
,
textColor:
bgColor
.
invert
,
bgColor:
bgColor
,
onPressed:
()
{
if
(
directionScreen
!=
null
)
{
directionScreen
?.
begin
();
}
else
{
Get
.
back
();
}
},
);
}
factory
ButtonConfigModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$ButtonConfigModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$ButtonConfigModelToJson
(
this
);
...
...
lib/
directional
/button_config_model.g.dart
→
lib/
widgets/alert
/button_config_model.g.dart
View file @
56e8b038
...
...
@@ -12,7 +12,6 @@ ButtonConfigModel _$ButtonConfigModelFromJson(Map<String, dynamic> json) =>
color:
json
[
'color'
]
as
String
?,
clickActionType:
json
[
'click_action_type'
]
as
String
?,
clickActionParam:
json
[
'click_action_param'
]
as
String
?,
hiden:
json
[
'hiden'
]
as
bool
?,
);
Map
<
String
,
dynamic
>
_$ButtonConfigModelToJson
(
ButtonConfigModel
instance
)
=>
...
...
@@ -21,5 +20,4 @@ Map<String, dynamic> _$ButtonConfigModelToJson(ButtonConfigModel instance) =>
'color'
:
instance
.
color
,
'click_action_type'
:
instance
.
clickActionType
,
'click_action_param'
:
instance
.
clickActionParam
,
'hiden'
:
instance
.
hiden
,
};
lib/widgets/alert/custom_alert_dialog.dart
View file @
56e8b038
import
'package:flutter/material.dart'
;
import
'package:flutter_widget_from_html/flutter_widget_from_html.dart'
;
import
'package:get/get.dart'
;
import
'../../resouce/base_color.dart'
;
import
'../image_loader.dart'
;
import
'data_alert_model.dart'
;
enum
ButtonsDirection
{
row
,
column
}
...
...
@@ -10,7 +12,12 @@ class CustomAlertDialog extends StatelessWidget {
final
ButtonsDirection
direction
;
final
bool
showCloseButton
;
const
CustomAlertDialog
({
super
.
key
,
required
this
.
alertData
,
this
.
direction
=
ButtonsDirection
.
column
,
this
.
showCloseButton
=
true
,});
const
CustomAlertDialog
({
super
.
key
,
required
this
.
alertData
,
this
.
direction
=
ButtonsDirection
.
column
,
this
.
showCloseButton
=
true
,
});
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -20,22 +27,11 @@ class CustomAlertDialog extends StatelessWidget {
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
16
),
color:
Colors
.
white
),
child:
Stack
(
children:
[
Container
(
child:
Column
(
children:
[
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
// Header Image
if
(
alertData
.
background
!=
null
)
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
12
),
child:
Image
.
asset
(
alertData
.
background
!),
// .network(
// alertData.background!,
// height: 120,
// width: 120,
// fit: BoxFit.cover,
// ),
),
_buildHeaderImage
(),
const
SizedBox
(
height:
2
),
// Title
if
(
alertData
.
title
!=
null
)
...
...
@@ -45,26 +41,23 @@ class CustomAlertDialog extends StatelessWidget {
textAlign:
TextAlign
.
center
,
),
const
SizedBox
(
height:
8
),
// HTML Content
if
(
alertData
.
description
!=
null
)
HtmlWidget
(
'''
<div style="text-align: center;">
${alertData.description!}
</div>
'''
),
const
SizedBox
(
height:
4
),
if
(
alertData
.
content
!=
null
)
HtmlWidge
t
(
Tex
t
(
alertData
.
content
!,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w600
,
color:
BaseColor
.
primary500
),
textAlign:
TextAlign
.
center
,
),
// Html(
// data: alertData.content!,
// style: {
// "body": Style(
// textAlign: TextAlign.center,
// fontSize: FontSize.medium,
// ),
// },
// ),
const
SizedBox
(
height:
10
),
// Buttons
_buildButtons
(),
],
),
),
// Close Button (X) ở góc phải trên
if
(
showCloseButton
)
Positioned
(
...
...
@@ -75,30 +68,47 @@ class CustomAlertDialog extends StatelessWidget {
child:
const
Icon
(
Icons
.
close
,
color:
Colors
.
black
,
size:
24
),
),
),
]
]
,
),
),
);
}
Widget
_buildHeaderImage
()
{
if
((
alertData
.
urlHeaderImage
??
""
).
isNotEmpty
)
{
return
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
12
),
child:
loadNetworkImage
(
url:
alertData
.
urlHeaderImage
,
fit:
BoxFit
.
cover
,
placeholderAsset:
"assets/images/ic_pipi_06.png"
,
),
);
}
final
localHeaderImage
=
(
alertData
.
localHeaderImage
??
""
);
final
localImage
=
localHeaderImage
.
isNotEmpty
?
localHeaderImage
:
"assets/images/ic_pipi_06.png"
;
return
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
12
),
child:
Image
.
asset
(
localImage
));
}
Widget
_buildButtons
()
{
return
direction
==
ButtonsDirection
.
column
?
Column
(
children:
alertData
.
buttons
?.
map
(
?.
whereType
<
AlertButton
>()
.
map
(
(
btn
)
=>
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
4
),
child:
ElevatedButton
(
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
btn
.
bgColor
,
backgroundColor:
btn
?
.
bgColor
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
24
)),
minimumSize:
const
Size
(
double
.
infinity
,
48
),
),
onPressed:
btn
.
onPressed
,
onPressed:
btn
?
.
onPressed
,
child:
Text
(
btn
.
text
,
style:
TextStyle
(
color:
btn
.
textColor
,
fontSize:
14
,
fontWeight:
FontWeight
.
bold
),
btn
?
.
text
??
""
,
style:
TextStyle
(
color:
btn
?
.
textColor
,
fontSize:
14
,
fontWeight:
FontWeight
.
bold
),
),
),
),
...
...
@@ -110,20 +120,21 @@ class CustomAlertDialog extends StatelessWidget {
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
children:
alertData
.
buttons
?.
map
(
?.
whereType
<
AlertButton
>()
.
map
(
(
btn
)
=>
Expanded
(
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
4
),
child:
ElevatedButton
(
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
btn
.
bgColor
,
backgroundColor:
btn
?
.
bgColor
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
24
)),
minimumSize:
const
Size
(
100
,
48
),
),
onPressed:
btn
.
onPressed
,
onPressed:
btn
?
.
onPressed
,
child:
Text
(
btn
.
text
,
style:
TextStyle
(
color:
btn
.
textColor
,
fontSize:
14
,
fontWeight:
FontWeight
.
bold
),
btn
?
.
text
??
""
,
style:
TextStyle
(
color:
btn
?
.
textColor
,
fontSize:
14
,
fontWeight:
FontWeight
.
bold
),
),
),
),
...
...
lib/widgets/alert/data_alert_model.dart
View file @
56e8b038
import
'dart:ui'
;
import
'package:flutter/material.dart'
;
import
'../../resouce/base_color.dart'
;
class
DataAlertModel
{
final
String
?
background
;
final
String
?
localHeaderImage
;
final
String
?
urlHeaderImage
;
final
String
?
title
;
final
String
?
description
;
final
String
?
content
;
final
List
<
AlertButton
>?
buttons
;
final
List
<
AlertButton
?
>?
buttons
;
DataAlertModel
({
this
.
background
,
this
.
localHeaderImage
,
this
.
urlHeaderImage
,
this
.
title
,
this
.
description
,
this
.
content
,
this
.
buttons
=
const
[],
});
...
...
@@ -20,14 +23,12 @@ class AlertButton {
final
String
text
;
final
Color
textColor
;
final
Color
bgColor
;
final
bool
isPrimary
;
final
VoidCallback
onPressed
;
AlertButton
({
required
this
.
text
,
required
this
.
textColor
,
required
this
.
bgColor
,
required
this
.
isPrimary
,
required
this
.
onPressed
,
});
}
...
...
lib/widgets/alert/popup_data_model.dart
0 → 100644
View file @
56e8b038
import
'../../resouce/base_color.dart'
;
import
'button_config_model.dart'
;
import
'package:json_annotation/json_annotation.dart'
;
import
'data_alert_model.dart'
;
part
'popup_data_model.g.dart'
;
@JsonSerializable
()
class
PopupDataModel
{
@JsonKey
(
name:
"header_img"
)
final
String
?
urlHeaderImg
;
final
String
?
title
;
final
String
?
description
;
final
String
?
value
;
@JsonKey
(
name:
"button_confirm"
)
final
ButtonConfigModel
?
buttonConfirm
;
@JsonKey
(
name:
"button_cancel"
)
final
ButtonConfigModel
?
buttonCancel
;
@JsonKey
(
name:
"local_img"
)
final
String
?
localHeaderImg
;
DataAlertModel
get
dataAlertModel
{
return
DataAlertModel
(
urlHeaderImage:
urlHeaderImg
,
localHeaderImage:
localHeaderImg
,
title:
title
,
description:
description
,
buttons:
[
buttonConfirm
?.
alertButton
,
buttonCancel
?.
alertButton
],
);
}
PopupDataModel
({
this
.
urlHeaderImg
,
this
.
title
,
this
.
description
,
this
.
value
,
this
.
buttonConfirm
,
this
.
buttonCancel
,
this
.
localHeaderImg
,
});
factory
PopupDataModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$PopupDataModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$PopupDataModelToJson
(
this
);
}
\ No newline at end of file
lib/widgets/alert/popup_data_model.g.dart
0 → 100644
View file @
56e8b038
// GENERATED CODE - DO NOT MODIFY BY HAND
part of
'popup_data_model.dart'
;
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
PopupDataModel
_$PopupDataModelFromJson
(
Map
<
String
,
dynamic
>
json
)
=>
PopupDataModel
(
urlHeaderImg:
json
[
'header_img'
]
as
String
?,
title:
json
[
'title'
]
as
String
?,
description:
json
[
'description'
]
as
String
?,
value:
json
[
'value'
]
as
String
?,
buttonConfirm:
json
[
'button_confirm'
]
==
null
?
null
:
ButtonConfigModel
.
fromJson
(
json
[
'button_confirm'
]
as
Map
<
String
,
dynamic
>,
),
buttonCancel:
json
[
'button_cancel'
]
==
null
?
null
:
ButtonConfigModel
.
fromJson
(
json
[
'button_cancel'
]
as
Map
<
String
,
dynamic
>,
),
localHeaderImg:
json
[
'local_img'
]
as
String
?,
);
Map
<
String
,
dynamic
>
_$PopupDataModelToJson
(
PopupDataModel
instance
)
=>
<
String
,
dynamic
>{
'header_img'
:
instance
.
urlHeaderImg
,
'title'
:
instance
.
title
,
'description'
:
instance
.
description
,
'value'
:
instance
.
value
,
'button_confirm'
:
instance
.
buttonConfirm
,
'button_cancel'
:
instance
.
buttonCancel
,
'local_img'
:
instance
.
localHeaderImg
,
};
pubspec.yaml
View file @
56e8b038
...
...
@@ -48,7 +48,8 @@ dependencies:
local_auth
:
pin_code_fields
:
intl
:
^0.18.1
game_miniapp
:
path
:
../mini_app/game_miniapp
dev_dependencies
:
flutter_test
:
sdk
:
flutter
...
...
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