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
fa01087d
Commit
fa01087d
authored
Jul 04, 2025
by
DatHV
Browse files
update brand, detail..
parent
c8abf95b
Changes
108
Show whitespace changes
Inline
Side-by-side
lib/screen/webview/payment_web_view_screen.dart
View file @
fa01087d
...
...
@@ -166,8 +166,8 @@ class _PaymentWebViewScreenState extends BaseState<PaymentWebViewScreen> with Ba
if
(
input
.
isContract
)
{
_navigateToContractScreen
();
}
else
if
(
input
.
callback
!=
null
)
{
Get
.
back
();
input
.
callback
!(
result
);
Get
.
back
();
// hoặc điều hướng phù hợp
}
else
{
_backToRoot
();
}
...
...
lib/screen/webview/web_view_screen.dart
View file @
fa01087d
...
...
@@ -3,9 +3,11 @@ import 'package:flutter/gestures.dart';
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/widgets/back_button.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'package:webview_flutter/webview_flutter.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'../../directional/directional_screen.dart'
;
class
BaseWebViewInput
{
final
String
?
title
;
...
...
@@ -31,7 +33,7 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
void
initState
()
{
super
.
initState
();
final
args
=
Get
.
arguments
;
if
(
args
is
BaseWebViewInput
)
{
if
(
args
is
BaseWebViewInput
&&
args
.
url
.
isNotEmpty
)
{
input
=
args
;
}
else
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
...
...
@@ -52,14 +54,24 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
});
},
onWebResourceError:
(
error
)
{
if
(
error
.
description
!=
'about:blank'
)
{
showAlertError
(
content:
error
.
description
);
}
},
onNavigationRequest:
_handleNavigation
,
),
)
..
loadRequest
(
Uri
.
parse
(
input
.
url
));
..
loadRequest
(
Uri
.
parse
(
formatUrl
(
input
.
url
))
)
;
_clearCookies
();
}
String
formatUrl
(
String
inputUrl
)
{
if
(!
inputUrl
.
startsWith
(
'http://'
)
&&
!
inputUrl
.
startsWith
(
'https://'
))
{
return
'https://
$inputUrl
'
;
}
return
inputUrl
;
}
@override
Widget
createBody
()
{
return
Scaffold
(
...
...
@@ -69,20 +81,24 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
:
AppBar
(
title:
Text
(
input
.
title
??
_dynamicTitle
??
Uri
.
parse
(
input
.
url
).
host
,
style:
const
TextStyle
(
fontSize:
1
6
),
style:
const
TextStyle
(
fontSize:
1
8
,
fontWeight:
FontWeight
.
bold
,
color:
Colors
.
black87
),
),
leading:
CustomBackButton
(
onPressed:
_handleBack
),
),
body:
SafeArea
(
body:
Stack
(
children:
[
SafeArea
(
child:
WebViewWidget
(
controller:
_controller
,
gestureRecognizers:
const
<
Factory
<
OneSequenceGestureRecognizer
>>{
Factory
<
VerticalDragGestureRecognizer
>(
VerticalDragGestureRecognizer
.
new
,
),
Factory
<
VerticalDragGestureRecognizer
>(
VerticalDragGestureRecognizer
.
new
),
},
),
),
if
(
input
.
isFullScreen
)
Positioned
(
top:
MediaQuery
.
of
(
context
).
padding
.
top
+
8
,
left:
8
,
child:
CustomBackButton
()),
],
),
);
}
...
...
@@ -98,4 +114,22 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
if
(
context
.
mounted
)
Navigator
.
of
(
context
).
pop
();
}
}
NavigationDecision
_handleNavigation
(
NavigationRequest
request
)
{
final
url
=
request
.
url
;
debugPrint
(
"➡️ Navigating:
$url
"
);
if
(
url
.
isEmpty
||
url
==
'about:blank'
)
{
return
NavigationDecision
.
prevent
;
}
if
(
url
.
startsWith
(
'itms-apps://'
))
{
openAppStore
(
url
);
return
NavigationDecision
.
prevent
;
}
if
(
url
.
startsWith
(
'sms:'
))
{
final
uri
=
Uri
.
parse
(
url
);
launchUrl
(
uri
);
return
NavigationDecision
.
prevent
;
}
return
NavigationDecision
.
navigate
;
}
}
lib/shared/router_gage.dart
View file @
fa01087d
...
...
@@ -2,11 +2,19 @@ import 'package:flutter/cupertino.dart';
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/screen/news/news_list_screen.dart'
;
import
'../screen/achievement/achievement_list_screen.dart'
;
import
'../screen/affiliate/affiliate_tab_screen.dart'
;
import
'../screen/affiliate_brand_detail/affiliate_brand_detail_screen.dart'
;
import
'../screen/affiliate_brand_detail/affiliate_brand_list_screen.dart'
;
import
'../screen/affiliate_brand_detail/affiliate_category_grid_screen.dart'
;
import
'../screen/data_network_service/data_network_service_screen.dart'
;
import
'../screen/game/game_cards/game_card_screen.dart'
;
import
'../screen/game/game_tab_screen.dart'
;
import
'../screen/history_point_cashback/history_point_cashback_screen.dart'
;
import
'../screen/location_address/location_address_screen.dart'
;
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_screen.dart'
;
import
'../screen/onboarding/onboarding_screen.dart'
;
import
'../screen/order_menu/order_menu_screen.dart'
;
...
...
@@ -16,6 +24,7 @@ import '../screen/register_campaign/register_form_input_screen.dart';
import
'../screen/setting/setting_screen.dart'
;
import
'../screen/splash/splash_screen.dart'
;
import
'../screen/support/support_screen.dart'
;
import
'../screen/topup/topup_screen.dart'
;
import
'../screen/transaction/history/transaction_history_detail_screen.dart'
;
import
'../screen/transaction/transaction_detail_screen.dart'
;
import
'../screen/voucher/detail/voucher_detail_screen.dart'
;
...
...
@@ -49,6 +58,15 @@ const personalEditScreen = '/personalEditScreen';
const
orderMenuScreen
=
'/orderMenuScreen'
;
const
locationAddressScreen
=
'/locationAddressScreen'
;
const
membershipScreen
=
'/membershipScreen'
;
const
phoneTopUpScreen
=
'/phoneTopUpScreen'
;
const
productMobileCardScreen
=
'/productMobileCardScreen'
;
const
dataNetworkServiceScreen
=
'/dataNetworkServiceScreen'
;
const
affiliateTabScreen
=
'/affiliateTabScreen'
;
const
gameTabScreen
=
'/gameTabScreen'
;
const
historyPointCashBackScreen
=
'/historyPointCashBackScreen'
;
const
affiliateBrandDetailScreen
=
'/affiliateBrandDetailScreen'
;
const
affiliateBrandListScreen
=
'/affiliateBrandListScreen'
;
const
affiliateCategoryGridScreen
=
'/affiliateCategoryGridScreen'
;
class
RouterPage
{
static
List
<
GetPage
>
pages
()
{
...
...
@@ -83,6 +101,15 @@ class RouterPage {
GetPage
(
name:
orderMenuScreen
,
page:
()
=>
OrderMenuScreen
()),
GetPage
(
name:
locationAddressScreen
,
page:
()
=>
LocationAddressScreen
()),
GetPage
(
name:
membershipScreen
,
page:
()
=>
MembershipScreen
()),
GetPage
(
name:
phoneTopUpScreen
,
page:
()
=>
PhoneTopUpScreen
()),
GetPage
(
name:
productMobileCardScreen
,
page:
()
=>
ProductMobileCardScreen
()),
GetPage
(
name:
dataNetworkServiceScreen
,
page:
()
=>
DataNetworkServiceScreen
()),
GetPage
(
name:
affiliateTabScreen
,
page:
()
=>
AffiliateTabScreen
()),
GetPage
(
name:
gameTabScreen
,
page:
()
=>
GameTabScreen
()),
GetPage
(
name:
historyPointCashBackScreen
,
page:
()
=>
HistoryPointCashBackScreen
()),
GetPage
(
name:
affiliateBrandDetailScreen
,
page:
()
=>
AffiliateBrandDetailScreen
()),
GetPage
(
name:
affiliateBrandListScreen
,
page:
()
=>
AffiliateBrandListScreen
()),
GetPage
(
name:
affiliateCategoryGridScreen
,
page:
()
=>
AffiliateCategoryGridScreen
()),
];
}
}
...
...
lib/widgets/alert/button_config_model.dart
View file @
fa01087d
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:json_annotation/json_annotation.dart'
;
import
'package:mypoint_flutter_app/directional/directional_action_type.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
()
class
ButtonConfigModel
{
final
String
?
text
;
...
...
@@ -16,12 +18,7 @@ class ButtonConfigModel {
@JsonKey
(
name:
"click_action_param"
)
final
String
?
clickActionParam
;
ButtonConfigModel
({
this
.
text
,
this
.
color
,
this
.
clickActionType
,
this
.
clickActionParam
,
});
ButtonConfigModel
({
this
.
text
,
this
.
color
,
this
.
clickActionType
,
this
.
clickActionParam
});
AlertButton
get
alertButton
{
final
bgColor
=
color
?.
toColor
()
??
Colors
.
white
;
...
...
@@ -29,23 +26,17 @@ class ButtonConfigModel {
text:
text
??
""
,
textColor:
bgColor
.
invert
,
bgColor:
bgColor
,
onPressed:
()
{
if
(
directionScreen
!=
null
)
{
directionScreen
?.
begin
();
}
else
{
onPressed:
()
async
{
DirectionalScreen
?
directional
=
DirectionalScreen
.
build
(
clickActionType:
clickActionType
,
clickActionParam:
clickActionParam
,
);
Get
.
back
();
}
directional
?.
begin
();
},
);
}
factory
ButtonConfigModel
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
=>
_$ButtonConfigModelFromJson
(
json
);
Map
<
String
,
dynamic
>
toJson
()
=>
_$ButtonConfigModelToJson
(
this
);
DirectionalScreen
?
get
directionScreen
{
DirectionalScreen
.
build
(
clickActionType:
clickActionType
,
clickActionParam:
clickActionParam
,
);
}
}
lib/widgets/alert/custom_alert_dialog.dart
View file @
fa01087d
...
...
@@ -55,6 +55,7 @@ class CustomAlertDialog extends StatelessWidget {
textAlign:
TextAlign
.
center
,
),
// Buttons
const
SizedBox
(
height:
8
),
_buildButtons
(),
],
),
...
...
lib/widgets/custom_app_bar.dart
View file @
fa01087d
...
...
@@ -18,10 +18,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
/// 🔥 AppBar mặc định với nút back và title
static
CustomAppBar
back
({
required
String
title
})
{
return
CustomAppBar
(
title:
title
,
leftButtons:
[
CustomBackButton
()],
);
return
CustomAppBar
(
title:
title
,
leftButtons:
[
CustomBackButton
()]);
}
@override
...
...
@@ -35,14 +32,15 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Row
(
children:
leftButtons
),
Row
(
children:
rightButtons
),
],
children:
[
Row
(
children:
leftButtons
),
Row
(
children:
rightButtons
)],
),
Center
(
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
24
,
right:
24
),
child:
Center
(
child:
Text
(
title
,
textAlign:
TextAlign
.
center
,
maxLines:
1
,
style:
const
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
bold
,
...
...
@@ -50,6 +48,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
),
),
),
),
],
),
),
...
...
lib/widgets/pick_contact.dart
0 → 100644
View file @
fa01087d
import
'package:contacts_service/contacts_service.dart'
;
import
'package:permission_handler/permission_handler.dart'
;
// Future<void> pickContact(BuildContext context) async {
// // Yêu cầu quyền truy cập danh bạ
// final status = await Permission.contacts.request();
// if (!status.isGranted) {
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(content: Text('Bạn cần cấp quyền truy cập danh bạ')),
// );
// return;
// }
//
// // Mở danh sách liên hệ và chọn
// try {
// final Contact? contact = await ContactsService.openDeviceContactPicker();
// if (contact != null && contact.phones != null && contact.phones!.isNotEmpty) {
// final phoneNumber = contact.phones!.first.value;
// print("Số điện thoại được chọn: $phoneNumber");
//
// // TODO: bạn có thể gán vào TextEditingController ở đây
// _phoneController.text = phoneNumber ?? '';
// }
// } catch (e) {
// print("Lỗi khi chọn danh bạ: $e");
// }
// }
pubspec.yaml
View file @
fa01087d
...
...
@@ -49,11 +49,14 @@ dependencies:
pin_code_fields
:
intl
:
^0.18.1
webview_flutter
:
^4.2.2
webview_flutter_wkwebview
:
^3.9.4
qr_flutter
:
^4.0.0
barcode_widget
:
^2.0.1
infinite_carousel
:
^1.0.3
package_info_plus
:
^4.1.0
dotted_border
:
^2.0.0
contacts_service
:
^0.6.3
permission_handler
:
^11.0.0
game_miniapp
:
path
:
../mini_app/game_miniapp
dev_dependencies
:
...
...
Prev
1
2
3
4
5
6
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