Commit fa01087d authored by DatHV's avatar DatHV
Browse files

update brand, detail..

parent c8abf95b
...@@ -166,8 +166,8 @@ class _PaymentWebViewScreenState extends BaseState<PaymentWebViewScreen> with Ba ...@@ -166,8 +166,8 @@ class _PaymentWebViewScreenState extends BaseState<PaymentWebViewScreen> with Ba
if (input.isContract) { if (input.isContract) {
_navigateToContractScreen(); _navigateToContractScreen();
} else if (input.callback != null) { } else if (input.callback != null) {
Get.back();
input.callback!(result); input.callback!(result);
Get.back(); // hoặc điều hướng phù hợp
} else { } else {
_backToRoot(); _backToRoot();
} }
......
...@@ -3,9 +3,11 @@ import 'package:flutter/gestures.dart'; ...@@ -3,9 +3,11 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/widgets/back_button.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 'package:webview_flutter/webview_flutter.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
import '../../base/basic_state.dart'; import '../../base/basic_state.dart';
import '../../directional/directional_screen.dart';
class BaseWebViewInput { class BaseWebViewInput {
final String? title; final String? title;
...@@ -31,7 +33,7 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta ...@@ -31,7 +33,7 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
void initState() { void initState() {
super.initState(); super.initState();
final args = Get.arguments; final args = Get.arguments;
if (args is BaseWebViewInput) { if (args is BaseWebViewInput && args.url.isNotEmpty) {
input = args; input = args;
} else { } else {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
...@@ -52,14 +54,24 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta ...@@ -52,14 +54,24 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
}); });
}, },
onWebResourceError: (error) { onWebResourceError: (error) {
showAlertError(content: error.description); if (error.description != 'about:blank') {
showAlertError(content: error.description);
}
}, },
onNavigationRequest: _handleNavigation,
), ),
) )
..loadRequest(Uri.parse(input.url)); ..loadRequest(Uri.parse(formatUrl(input.url)));
_clearCookies(); _clearCookies();
} }
String formatUrl(String inputUrl) {
if (!inputUrl.startsWith('http://') && !inputUrl.startsWith('https://')) {
return 'https://$inputUrl';
}
return inputUrl;
}
@override @override
Widget createBody() { Widget createBody() {
return Scaffold( return Scaffold(
...@@ -69,19 +81,23 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta ...@@ -69,19 +81,23 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
: AppBar( : AppBar(
title: Text( title: Text(
input.title ?? _dynamicTitle ?? Uri.parse(input.url).host, input.title ?? _dynamicTitle ?? Uri.parse(input.url).host,
style: const TextStyle(fontSize: 16), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87),
), ),
leading: CustomBackButton(onPressed: _handleBack), leading: CustomBackButton(onPressed: _handleBack),
), ),
body: SafeArea( body: Stack(
child: WebViewWidget( children: [
controller: _controller, SafeArea(
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{ child: WebViewWidget(
Factory<VerticalDragGestureRecognizer>( controller: _controller,
VerticalDragGestureRecognizer.new, gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{
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 ...@@ -98,4 +114,22 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
if (context.mounted) Navigator.of(context).pop(); 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;
}
} }
...@@ -2,11 +2,19 @@ import 'package:flutter/cupertino.dart'; ...@@ -2,11 +2,19 @@ import 'package:flutter/cupertino.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/screen/news/news_list_screen.dart'; import 'package:mypoint_flutter_app/screen/news/news_list_screen.dart';
import '../screen/achievement/achievement_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_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/location_address/location_address_screen.dart';
import '../screen/login/login_screen.dart'; import '../screen/login/login_screen.dart';
import '../screen/main_tab_screen/main_tab_screen.dart'; import '../screen/main_tab_screen/main_tab_screen.dart';
import '../screen/membership/membership_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/notification/notification_screen.dart';
import '../screen/onboarding/onboarding_screen.dart'; import '../screen/onboarding/onboarding_screen.dart';
import '../screen/order_menu/order_menu_screen.dart'; import '../screen/order_menu/order_menu_screen.dart';
...@@ -16,6 +24,7 @@ import '../screen/register_campaign/register_form_input_screen.dart'; ...@@ -16,6 +24,7 @@ import '../screen/register_campaign/register_form_input_screen.dart';
import '../screen/setting/setting_screen.dart'; import '../screen/setting/setting_screen.dart';
import '../screen/splash/splash_screen.dart'; import '../screen/splash/splash_screen.dart';
import '../screen/support/support_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/history/transaction_history_detail_screen.dart';
import '../screen/transaction/transaction_detail_screen.dart'; import '../screen/transaction/transaction_detail_screen.dart';
import '../screen/voucher/detail/voucher_detail_screen.dart'; import '../screen/voucher/detail/voucher_detail_screen.dart';
...@@ -49,6 +58,15 @@ const personalEditScreen = '/personalEditScreen'; ...@@ -49,6 +58,15 @@ const personalEditScreen = '/personalEditScreen';
const orderMenuScreen = '/orderMenuScreen'; const orderMenuScreen = '/orderMenuScreen';
const locationAddressScreen = '/locationAddressScreen'; const locationAddressScreen = '/locationAddressScreen';
const membershipScreen = '/membershipScreen'; 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 { class RouterPage {
static List<GetPage> pages() { static List<GetPage> pages() {
...@@ -83,6 +101,15 @@ class RouterPage { ...@@ -83,6 +101,15 @@ class RouterPage {
GetPage(name: orderMenuScreen, page: () => OrderMenuScreen()), GetPage(name: orderMenuScreen, page: () => OrderMenuScreen()),
GetPage(name: locationAddressScreen, page: () => LocationAddressScreen()), GetPage(name: locationAddressScreen, page: () => LocationAddressScreen()),
GetPage(name: membershipScreen, page: () => MembershipScreen()), 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()),
]; ];
} }
} }
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:json_annotation/json_annotation.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/color_extension.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import '../../directional/directional_screen.dart'; import '../../directional/directional_screen.dart';
import 'data_alert_model.dart'; import 'data_alert_model.dart';
part 'button_config_model.g.dart'; part 'button_config_model.g.dart';
@JsonSerializable() @JsonSerializable()
class ButtonConfigModel { class ButtonConfigModel {
final String? text; final String? text;
...@@ -16,12 +18,7 @@ class ButtonConfigModel { ...@@ -16,12 +18,7 @@ class ButtonConfigModel {
@JsonKey(name: "click_action_param") @JsonKey(name: "click_action_param")
final String? clickActionParam; final String? clickActionParam;
ButtonConfigModel({ ButtonConfigModel({this.text, this.color, this.clickActionType, this.clickActionParam});
this.text,
this.color,
this.clickActionType,
this.clickActionParam,
});
AlertButton get alertButton { AlertButton get alertButton {
final bgColor = color?.toColor() ?? Colors.white; final bgColor = color?.toColor() ?? Colors.white;
...@@ -29,23 +26,17 @@ class ButtonConfigModel { ...@@ -29,23 +26,17 @@ class ButtonConfigModel {
text: text ?? "", text: text ?? "",
textColor: bgColor.invert, textColor: bgColor.invert,
bgColor: bgColor, bgColor: bgColor,
onPressed: () { onPressed: () async {
if (directionScreen != null) { DirectionalScreen? directional = DirectionalScreen.build(
directionScreen?.begin(); clickActionType: clickActionType,
} else { clickActionParam: clickActionParam,
Get.back(); );
} Get.back();
directional?.begin();
}, },
); );
} }
factory ButtonConfigModel.fromJson(Map<String, dynamic> json) => _$ButtonConfigModelFromJson(json); factory ButtonConfigModel.fromJson(Map<String, dynamic> json) => _$ButtonConfigModelFromJson(json);
Map<String, dynamic> toJson() => _$ButtonConfigModelToJson(this); Map<String, dynamic> toJson() => _$ButtonConfigModelToJson(this);
DirectionalScreen? get directionScreen {
DirectionalScreen.build(
clickActionType: clickActionType,
clickActionParam: clickActionParam,
);
}
} }
...@@ -55,6 +55,7 @@ class CustomAlertDialog extends StatelessWidget { ...@@ -55,6 +55,7 @@ class CustomAlertDialog extends StatelessWidget {
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
// Buttons // Buttons
const SizedBox(height: 8),
_buildButtons(), _buildButtons(),
], ],
), ),
......
...@@ -18,10 +18,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -18,10 +18,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
/// 🔥 AppBar mặc định với nút back và title /// 🔥 AppBar mặc định với nút back và title
static CustomAppBar back({required String title}) { static CustomAppBar back({required String title}) {
return CustomAppBar( return CustomAppBar(title: title, leftButtons: [CustomBackButton()]);
title: title,
leftButtons: [CustomBackButton()],
);
} }
@override @override
...@@ -35,18 +32,20 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -35,18 +32,20 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [Row(children: leftButtons), Row(children: rightButtons)],
Row(children: leftButtons),
Row(children: rightButtons),
],
), ),
Center( Padding(
child: Text( padding: const EdgeInsets.only(left: 24, right: 24),
title, child: Center(
style: const TextStyle( child: Text(
fontSize: 18, title,
fontWeight: FontWeight.bold, textAlign: TextAlign.center,
color: Colors.black87, maxLines: 1,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
), ),
), ),
), ),
......
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");
// }
// }
...@@ -49,11 +49,14 @@ dependencies: ...@@ -49,11 +49,14 @@ dependencies:
pin_code_fields: pin_code_fields:
intl: ^0.18.1 intl: ^0.18.1
webview_flutter: ^4.2.2 webview_flutter: ^4.2.2
webview_flutter_wkwebview: ^3.9.4
qr_flutter: ^4.0.0 qr_flutter: ^4.0.0
barcode_widget: ^2.0.1 barcode_widget: ^2.0.1
infinite_carousel: ^1.0.3 infinite_carousel: ^1.0.3
package_info_plus: ^4.1.0 package_info_plus: ^4.1.0
dotted_border: ^2.0.0 dotted_border: ^2.0.0
contacts_service: ^0.6.3
permission_handler: ^11.0.0
game_miniapp: game_miniapp:
path: ../mini_app/game_miniapp path: ../mini_app/game_miniapp
dev_dependencies: dev_dependencies:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment