Commit a6797435 authored by DatHV's avatar DatHV
Browse files

refactor print, log, request

parent f0334970
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart'; import 'package:mypoint_flutter_app/widgets/image_loader.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
......
...@@ -42,9 +42,7 @@ class MembershipViewModel extends RestfulApiViewModel { ...@@ -42,9 +42,7 @@ class MembershipViewModel extends RestfulApiViewModel {
orElse: () => levels!.first orElse: () => levels!.first
); );
} catch (e) { } catch (e) {
if (kDebugMode) { debugPrint('Failed to select level: $e');
print('Failed to select level: $e');
}
selectedLevel = levels!.isNotEmpty ? levels!.first : null; selectedLevel = levels!.isNotEmpty ? levels!.first : null;
} }
} }
......
import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/configs/constants.dart'; import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/screen/mobile_card/models/product_mobile_card_model.dart'; import 'package:mypoint_flutter_app/screen/mobile_card/models/product_mobile_card_model.dart';
import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import '../../preference/point/point_manager.dart'; import '../../preference/point/point_manager.dart';
import 'models/mobile_service_redeem_data.dart'; import 'models/mobile_service_redeem_data.dart';
...@@ -17,6 +18,19 @@ class ProductMobileCardViewModel extends RestfulApiViewModel { ...@@ -17,6 +18,19 @@ class ProductMobileCardViewModel extends RestfulApiViewModel {
return groupedSection[selectedBrandCode.value] ?? []; return groupedSection[selectedBrandCode.value] ?? [];
} }
ProductMobileCardModel? selectedProduct; ProductMobileCardModel? selectedProduct;
bool _productApiLoaded = false;
Future<void> _ensureProductApiLoaded() async {
if (_productApiLoaded) return;
await product_api.loadLibrary();
_productApiLoaded = true;
}
Future<BaseResponseModel<T>> _callProductApi<T>(Future<BaseResponseModel<T>> Function(dynamic api) fn) async {
await _ensureProductApiLoaded();
final api = product_api.ProductApi(client);
return fn(api);
}
int get payPoint { int get payPoint {
return int.tryParse(selectedProduct?.prices?.firstOrNull?.payPoint ?? "0") ?? 0; return int.tryParse(selectedProduct?.prices?.firstOrNull?.payPoint ?? "0") ?? 0;
...@@ -33,7 +47,7 @@ class ProductMobileCardViewModel extends RestfulApiViewModel { ...@@ -33,7 +47,7 @@ class ProductMobileCardViewModel extends RestfulApiViewModel {
Future<void> redeemProductMobileCard() async { Future<void> redeemProductMobileCard() async {
await callApi<MobileServiceRedeemData>( await callApi<MobileServiceRedeemData>(
request: () => client.redeemMobileCard((selectedProduct?.id ?? 0).toString()), request: () => _callProductApi((api) => api.redeemMobileCard((selectedProduct?.id ?? 0).toString())),
onSuccess: (data, _) async { onSuccess: (data, _) async {
final itemId = data.itemId ?? ""; final itemId = data.itemId ?? "";
if (itemId.isEmpty) { if (itemId.isEmpty) {
...@@ -50,7 +64,7 @@ class ProductMobileCardViewModel extends RestfulApiViewModel { ...@@ -50,7 +64,7 @@ class ProductMobileCardViewModel extends RestfulApiViewModel {
Future<void> _getMobileCardCode(String itemId) async { Future<void> _getMobileCardCode(String itemId) async {
await callApi<RedeemProductResponseModel>( await callApi<RedeemProductResponseModel>(
request: () => client.getMobileCardCode(itemId), request: () => _callProductApi((api) => api.getMobileCardCode(itemId)),
onSuccess: (data, _) { onSuccess: (data, _) {
final item = data.item; final item = data.item;
if (item != null) { if (item != null) {
...@@ -67,7 +81,7 @@ class ProductMobileCardViewModel extends RestfulApiViewModel { ...@@ -67,7 +81,7 @@ class ProductMobileCardViewModel extends RestfulApiViewModel {
Future<void> getProductMobileCard() async { Future<void> getProductMobileCard() async {
await callApi<ProductMobileCardResponse>( await callApi<ProductMobileCardResponse>(
request: () => client.productMobileCardGetList(), request: () => _callProductApi((api) => api.productMobileCardGetList()),
onSuccess: (data, _) { onSuccess: (data, _) {
final result = data.products ?? []; final result = data.products ?? [];
final seen = <String>{}; final seen = <String>{};
......
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/networking/api/website_api.dart' deferred as website_api;
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import '../faqs/faqs_model.dart'; import '../faqs/faqs_model.dart';
...@@ -10,6 +10,14 @@ class NewsListViewModel extends RestfulApiViewModel { ...@@ -10,6 +10,14 @@ class NewsListViewModel extends RestfulApiViewModel {
var _canLoadMore = true; var _canLoadMore = true;
int limit = 20; int limit = 20;
bool _websiteApiLoaded = false;
Future<void> _ensureWebsiteApiLoaded() async {
if (_websiteApiLoaded) return;
await website_api.loadLibrary();
_websiteApiLoaded = true;
}
NewsListViewModel({this.folderUri = "TIN-TUC"}); NewsListViewModel({this.folderUri = "TIN-TUC"});
@override @override
...@@ -22,13 +30,13 @@ class NewsListViewModel extends RestfulApiViewModel { ...@@ -22,13 +30,13 @@ class NewsListViewModel extends RestfulApiViewModel {
if (isLoading.value) return; if (isLoading.value) return;
if (!isRefresh && !_canLoadMore) return; if (!isRefresh && !_canLoadMore) return;
isLoading(true); isLoading(true);
final body = { final body = {"folder_uri": folderUri, "start": isRefresh ? 0 : newsList.length, "limit": limit};
"folder_uri": folderUri,
"start": isRefresh ? 0 : newsList.length,
"limit": limit,
};
await callApi<FAQItemModelResponse>( await callApi<FAQItemModelResponse>(
request: () => client.websiteFolderGetPageList(body), request: () async {
await _ensureWebsiteApiLoaded();
final api = website_api.WebsiteApi(client);
return api.websiteFolderGetPageList(body);
},
onSuccess: (data, _) { onSuccess: (data, _) {
_canLoadMore = (data.items?.length ?? 0) == limit; _canLoadMore = (data.items?.length ?? 0) == limit;
if (isRefresh) { if (isRefresh) {
...@@ -39,7 +47,7 @@ class NewsListViewModel extends RestfulApiViewModel { ...@@ -39,7 +47,7 @@ class NewsListViewModel extends RestfulApiViewModel {
withLoading: false, withLoading: false,
onComplete: () { onComplete: () {
isLoading(false); isLoading(false);
} },
); );
} }
} }
\ No newline at end of file
import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/networking/api/notification_api.dart' deferred as notification_api;
import '../../configs/constants.dart'; import '../../configs/constants.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import 'models/notification_detail_model.dart'; import 'models/notification_detail_model.dart';
...@@ -8,6 +8,14 @@ class NotificationDetailViewModel extends RestfulApiViewModel { ...@@ -8,6 +8,14 @@ class NotificationDetailViewModel extends RestfulApiViewModel {
var notification = Rxn<NotificationDetailModel>(); var notification = Rxn<NotificationDetailModel>();
void Function(String message)? onShowAlertError; void Function(String message)? onShowAlertError;
bool _notificationApiLoaded = false;
Future<void> _ensureNotificationApiLoaded() async {
if (_notificationApiLoaded) return;
await notification_api.loadLibrary();
_notificationApiLoaded = true;
}
Future<void> fetchNotificationDetail({String? id, NotificationDetailModel? data}) async { Future<void> fetchNotificationDetail({String? id, NotificationDetailModel? data}) async {
if (data != null) { if (data != null) {
notification.value = data; notification.value = data;
...@@ -15,7 +23,11 @@ class NotificationDetailViewModel extends RestfulApiViewModel { ...@@ -15,7 +23,11 @@ class NotificationDetailViewModel extends RestfulApiViewModel {
} }
if (id == null) return; if (id == null) return;
await callApi<NotificationDetailResponseModel>( await callApi<NotificationDetailResponseModel>(
request: () => client.getNotificationDetail(id ?? ''), request: () async {
await _ensureNotificationApiLoaded();
final api = notification_api.NotificationApi(client);
return api.getNotificationDetail(id ?? '');
},
onSuccess: (data, _) { onSuccess: (data, _) {
final notify = data.notification; final notify = data.notification;
if (notify != null) { if (notify != null) {
...@@ -29,4 +41,4 @@ class NotificationDetailViewModel extends RestfulApiViewModel { ...@@ -29,4 +41,4 @@ class NotificationDetailViewModel extends RestfulApiViewModel {
}, },
); );
} }
} }
\ No newline at end of file
...@@ -5,7 +5,6 @@ import '../../base/base_screen.dart'; ...@@ -5,7 +5,6 @@ import '../../base/base_screen.dart';
import '../../base/basic_state.dart'; import '../../base/basic_state.dart';
import '../../resources/base_color.dart'; import '../../resources/base_color.dart';
import '../../widgets/alert/data_alert_model.dart'; import '../../widgets/alert/data_alert_model.dart';
import '../../widgets/back_button.dart';
import '../../widgets/custom_empty_widget.dart'; import '../../widgets/custom_empty_widget.dart';
import '../../widgets/custom_navigation_bar.dart'; import '../../widgets/custom_navigation_bar.dart';
import '../../widgets/image_loader.dart'; import '../../widgets/image_loader.dart';
...@@ -50,11 +49,7 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS ...@@ -50,11 +49,7 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
rightButtons: [ rightButtons: [
CompositedTransformTarget( CompositedTransformTarget(
link: _layerLink, link: _layerLink,
child: IconButton( child: IconButton(key: _infoKey, icon: const Icon(Icons.settings), onPressed: _toggleSetting),
key: _infoKey,
icon: const Icon(Icons.settings),
onPressed: _toggleSetting,
),
), ),
], ],
), ),
...@@ -66,9 +61,7 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS ...@@ -66,9 +61,7 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
_buildNotificationCategory(), _buildNotificationCategory(),
const Divider(height: 1), const Divider(height: 1),
if (items.isEmpty) if (items.isEmpty)
const Expanded( const Expanded(child: EmptyWidget())
child: EmptyWidget(),
)
else else
Expanded( Expanded(
child: Container( child: Container(
...@@ -110,53 +103,54 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS ...@@ -110,53 +103,54 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
final size = renderBox?.size ?? Size.zero; final size = renderBox?.size ?? Size.zero;
final double widthSize = 270; final double widthSize = 270;
_popupEntry = OverlayEntry( _popupEntry = OverlayEntry(
builder: (context) => Stack( builder:
children: [ (context) => Stack(
Positioned.fill( children: [
child: GestureDetector( Positioned.fill(
onTap: _hidePopup, child: GestureDetector(
behavior: HitTestBehavior.translucent, onTap: _hidePopup,
child: Container(color: Colors.transparent), behavior: HitTestBehavior.translucent,
), child: Container(color: Colors.transparent),
),
Positioned(
top: offset.dy + size.height + 8,
left: MediaQuery.of(context).size.width - widthSize - 16,
child: Material(
borderRadius: BorderRadius.circular(16),
elevation: 4,
child: Container(
width: widthSize,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(16),
), ),
child: Column( ),
mainAxisSize: MainAxisSize.min, Positioned(
children: [ top: offset.dy + size.height + 8,
ListTile( left: MediaQuery.of(context).size.width - widthSize - 16,
title: const Text('Đánh dấu tất cả đã đọc', style: TextStyle(fontWeight: FontWeight.w500)), child: Material(
onTap: () { borderRadius: BorderRadius.circular(16),
_hidePopup(); elevation: 4,
_viewModel.notificationMarkAsSeen(); child: Container(
}, width: widthSize,
), padding: const EdgeInsets.all(16),
const Divider(height: 1, color: Colors.grey), decoration: BoxDecoration(color: Colors.grey.shade50, borderRadius: BorderRadius.circular(16)),
ListTile( child: Column(
title: const Text('Xoá tất cả', style: TextStyle(color: Colors.red, fontWeight: FontWeight.w500)), mainAxisSize: MainAxisSize.min,
onTap: () { children: [
_hidePopup(); ListTile(
_confirmDeleteAllNotifications(); title: const Text('Đánh dấu tất cả đã đọc', style: TextStyle(fontWeight: FontWeight.w500)),
} onTap: () {
_hidePopup();
_viewModel.notificationMarkAsSeen();
},
),
const Divider(height: 1, color: Colors.grey),
ListTile(
title: const Text(
'Xoá tất cả',
style: TextStyle(color: Colors.red, fontWeight: FontWeight.w500),
),
onTap: () {
_hidePopup();
_confirmDeleteAllNotifications();
},
),
],
), ),
], ),
), ),
), ),
), ],
), ),
],
),
); );
overlay.insert(_popupEntry!); overlay.insert(_popupEntry!);
_isPopupShown = true; _isPopupShown = true;
...@@ -262,9 +256,15 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS ...@@ -262,9 +256,15 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
color: Colors.red, color: Colors.red,
child: const Icon(Icons.delete, color: Colors.white), child: const Icon(Icons.delete, color: Colors.white),
), ),
onDismissed: (direction) { onDismissed: (direction) async {
_viewModel.handleRemoveNotification(item); final notifications = _viewModel.notifications;
// _viewModel.notifications.remove(item); final index = notifications.indexOf(item);
if (index < 0) return;
notifications.removeAt(index);
final success = await _viewModel.deleteNotificationItem(item);
if (!success) {
notifications.insert(index, item);
}
}, },
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
...@@ -278,8 +278,8 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS ...@@ -278,8 +278,8 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
margin: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: item.hasSeen ? Colors.white : Colors.pink.shade50, color: item.hasSeen ? Colors.white : Colors.pink.shade50,
borderRadius: BorderRadius.circular(12) borderRadius: BorderRadius.circular(12),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
......
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/networking/api/notification_api.dart' deferred as notification_api;
import '../../base/base_response_model.dart'; import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import '../../preference/data_preference.dart'; import '../../preference/data_preference.dart';
...@@ -19,9 +19,23 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -19,9 +19,23 @@ class NotificationViewModel extends RestfulApiViewModel {
void Function(String message)? onShowAlertError; void Function(String message)? onShowAlertError;
var _hasMoreData = true; var _hasMoreData = true;
bool _notificationApiLoaded = false;
Future<void> _ensureNotificationApiLoaded() async {
if (_notificationApiLoaded) return;
await notification_api.loadLibrary();
_notificationApiLoaded = true;
}
Future<BaseResponseModel<T>> _callNotificationApi<T>(Future<BaseResponseModel<T>> Function(dynamic api) fn) async {
await _ensureNotificationApiLoaded();
final api = notification_api.NotificationApi(client);
return fn(api);
}
CategoryNotifyItemModel? get selectedCategory => CategoryNotifyItemModel? get selectedCategory =>
categories.isNotEmpty ? categories.firstWhere((item) => item.isSelected ?? false) : null; categories.isNotEmpty ? categories.firstWhere((item) => item.isSelected ?? false) : null;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
...@@ -30,7 +44,7 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -30,7 +44,7 @@ class NotificationViewModel extends RestfulApiViewModel {
void _fetchCategories() async { void _fetchCategories() async {
await callApi<List<CategoryNotifyItemModel>>( await callApi<List<CategoryNotifyItemModel>>(
request: () => client.getNotificationCategories(), request: () => _callNotificationApi((api) => api.getNotificationCategories()),
onSuccess: (data, _) { onSuccess: (data, _) {
if (data.isNotEmpty) data[0].isSelected = true; if (data.isNotEmpty) data[0].isSelected = true;
categories.assignAll(data); categories.assignAll(data);
...@@ -44,7 +58,9 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -44,7 +58,9 @@ class NotificationViewModel extends RestfulApiViewModel {
void fetchNotifications({bool refresh = false}) async { void fetchNotifications({bool refresh = false}) async {
if (isLoading.value) return; if (isLoading.value) return;
if (!refresh && !_hasMoreData) { return; } if (!refresh && !_hasMoreData) {
return;
}
if (refresh) { if (refresh) {
_notificationIndex = 0; _notificationIndex = 0;
} }
...@@ -57,7 +73,7 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -57,7 +73,7 @@ class NotificationViewModel extends RestfulApiViewModel {
"noti_group_id": selectedCategory?.id ?? "", "noti_group_id": selectedCategory?.id ?? "",
}; };
await callApi<NotificationListDataModel>( await callApi<NotificationListDataModel>(
request: () => client.getNotifications(body), request: () => _callNotificationApi((api) => api.getNotifications(body)),
onSuccess: (data, _) { onSuccess: (data, _) {
final items = data.items ?? []; final items = data.items ?? [];
if (refresh) { if (refresh) {
...@@ -87,7 +103,7 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -87,7 +103,7 @@ class NotificationViewModel extends RestfulApiViewModel {
void notificationMarkAsSeen() { void notificationMarkAsSeen() {
callApi<EmptyCodable>( callApi<EmptyCodable>(
request: () => client.notificationMarkAsSeen(), request: () => _callNotificationApi((api) => api.notificationMarkAsSeen()),
onSuccess: (_, _) => _fetchCategories(), onSuccess: (_, _) => _fetchCategories(),
onFailure: (msg, _, _) async { onFailure: (msg, _, _) async {
onShowAlertError?.call(msg); onShowAlertError?.call(msg);
...@@ -97,7 +113,7 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -97,7 +113,7 @@ class NotificationViewModel extends RestfulApiViewModel {
void deleteAllNotifications() { void deleteAllNotifications() {
callApi<EmptyCodable>( callApi<EmptyCodable>(
request: () => client.deleteAllNotifications(), request: () => _callNotificationApi((api) => api.deleteAllNotifications()),
onSuccess: (_, _) => _fetchCategories(), onSuccess: (_, _) => _fetchCategories(),
onFailure: (msg, _, _) async { onFailure: (msg, _, _) async {
onShowAlertError?.call(msg); onShowAlertError?.call(msg);
...@@ -105,31 +121,37 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -105,31 +121,37 @@ class NotificationViewModel extends RestfulApiViewModel {
); );
} }
void handleRemoveNotification(NotificationItemModel item) { Future<bool> deleteNotificationItem(NotificationItemModel item) async {
if (item.notificationId == null) return; if (item.notificationId == null) return true;
callApi<EmptyCodable>( var success = true;
request: () => client.deleteNotification(item.notificationId ?? ""), await callApi<EmptyCodable>(
request: () => _callNotificationApi((api) => api.deleteNotification(item.notificationId ?? "")),
onSuccess: (_, _) { onSuccess: (_, _) {
notifications.remove(item);
if (notifications.length <= _pageLimit) { if (notifications.length <= _pageLimit) {
fetchNotifications(refresh: false); fetchNotifications(refresh: false);
} }
}, },
onFailure: (msg, _, _) async { onFailure: (msg, _, _) async {
onShowAlertError?.call(msg); onShowAlertError?.call(msg);
success = false;
}, },
withLoading: false,
); );
return success;
} }
void handleClickNotification(NotificationItemModel item) { void handleClickNotification(NotificationItemModel item) {
callApi<NotificationDetailResponseModel>( callApi<NotificationDetailResponseModel>(
request: () => client.getNotificationDetail(item.notificationId ?? ""), request: () => _callNotificationApi((api) => api.getNotificationDetail(item.notificationId ?? "")),
onSuccess: (data, _) { onSuccess: (data, _) {
final notification = data.notification; final notification = data.notification;
if (notification == null) return; if (notification == null) return;
final pushSuccess = notification.directionalScreen?.begin() ?? false; final pushSuccess = notification.directionalScreen?.begin() ?? false;
if (!pushSuccess) { if (!pushSuccess) {
Get.toNamed(notificationDetailScreen, arguments: {'notification': notification, 'notificationId': item.notificationId}); Get.toNamed(
notificationDetailScreen,
arguments: {'notification': notification, 'notificationId': item.notificationId},
);
} }
}, },
onFailure: (msg, _, _) async { onFailure: (msg, _, _) async {
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/shared/router_gage.dart'; import 'package:mypoint_flutter_app/shared/router_gage.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
import '../../base/basic_state.dart'; import '../../base/basic_state.dart';
import '../../resources/base_color.dart'; import '../../resources/base_color.dart';
import '../faqs/faqs_screen.dart'; import '../faqs/faqs_screen.dart';
import '../otp/otp_screen.dart';
import '../otp/verify_otp_repository.dart';
import '../pageDetail/model/detail_page_rule_type.dart'; import '../pageDetail/model/detail_page_rule_type.dart';
import 'model/check_phone_response_model.dart';
import 'onboarding_viewmodel.dart'; import 'onboarding_viewmodel.dart';
class OnboardingScreen extends BaseScreen { class OnboardingScreen extends BaseScreen {
...@@ -45,10 +43,14 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState ...@@ -45,10 +43,14 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
children: [ children: [
Obx( Obx(
() => Positioned.fill( () => Positioned.fill(
child: child: loadNetworkImage(
_viewModel.url.isNotEmpty url: _viewModel.url,
? Image.network(_viewModel.url, fit: BoxFit.cover) fit: BoxFit.cover,
: Image.asset("assets/images/bg_onboarding.png", fit: BoxFit.cover), placeholderAsset: "assets/images/bg_onboarding.png",
),
// _viewModel.url.isNotEmpty
// ? Image.network(_viewModel.url, fit: BoxFit.cover)
// : Image.asset("assets/images/bg_onboarding.png", fit: BoxFit.cover),
), ),
), ),
SafeArea( SafeArea(
......
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/widgets/custom_empty_widget.dart'; import 'package:mypoint_flutter_app/widgets/custom_empty_widget.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
...@@ -163,9 +164,9 @@ class _CampaignDetailScreenState extends BaseState<CampaignDetailScreen> with Ba ...@@ -163,9 +164,9 @@ class _CampaignDetailScreenState extends BaseState<CampaignDetailScreen> with Ba
SizedBox(height: 12), SizedBox(height: 12),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
print(pageDetail?.directionalScreen); debugPrint(pageDetail?.directionalScreen.toString());
print(pageDetail?.buttonClickActionType); debugPrint(pageDetail?.buttonClickActionType.toString());
print(pageDetail?.buttonClickActionParam); debugPrint(pageDetail?.buttonClickActionParam.toString());
pageDetail?.directionalScreen?.begin(); pageDetail?.directionalScreen?.begin();
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
......
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/configs/constants.dart'; import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/networking/api/website_api.dart' deferred as website_api;
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart';
import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import 'model/campaign_detail_model.dart'; import 'model/campaign_detail_model.dart';
import 'model/detail_page_rule_type.dart'; import 'model/detail_page_rule_type.dart';
...@@ -11,6 +11,14 @@ class CampaignDetailViewModel extends RestfulApiViewModel { ...@@ -11,6 +11,14 @@ class CampaignDetailViewModel extends RestfulApiViewModel {
var campaignDetail = Rxn<CampaignDetailResponseModel>(); var campaignDetail = Rxn<CampaignDetailResponseModel>();
void Function(String message)? onShowAlertError; void Function(String message)? onShowAlertError;
bool _websiteApiLoaded = false;
Future<void> _ensureWebsiteApiLoaded() async {
if (_websiteApiLoaded) return;
await website_api.loadLibrary();
_websiteApiLoaded = true;
}
Future<void> fetchData(DetailPageRuleType? type, String? pageId) async { Future<void> fetchData(DetailPageRuleType? type, String? pageId) async {
if ((pageId ?? "").isNotEmpty) { if ((pageId ?? "").isNotEmpty) {
await fetchWebsitePageGetDetail(pageId!); await fetchWebsitePageGetDetail(pageId!);
...@@ -25,12 +33,13 @@ class CampaignDetailViewModel extends RestfulApiViewModel { ...@@ -25,12 +33,13 @@ class CampaignDetailViewModel extends RestfulApiViewModel {
Future<void> fetchFAQItems() async { Future<void> fetchFAQItems() async {
await callApi<FAQItemModelResponse>( await callApi<FAQItemModelResponse>(
request: () => client.websiteFolderGetPageList({"folder_uri": "ABOUT"}), request: () async {
await _ensureWebsiteApiLoaded();
final api = website_api.WebsiteApi(client);
return api.websiteFolderGetPageList({"folder_uri": "ABOUT"});
},
onSuccess: (data, _) async { onSuccess: (data, _) async {
final pageId = (data.items ?? []) final pageId = (data.items ?? []).firstWhereOrNull((item) => (item.pageId ?? "").isNotEmpty)?.pageId ?? "";
.firstWhereOrNull((item) => (item.pageId ?? "").isNotEmpty)
?.pageId ??
"";
if (pageId.isEmpty) { if (pageId.isEmpty) {
onShowAlertError?.call(Constants.commonError); onShowAlertError?.call(Constants.commonError);
return; return;
...@@ -45,7 +54,11 @@ class CampaignDetailViewModel extends RestfulApiViewModel { ...@@ -45,7 +54,11 @@ class CampaignDetailViewModel extends RestfulApiViewModel {
Future<void> fetchWebsitePage(DetailPageRuleType type) async { Future<void> fetchWebsitePage(DetailPageRuleType type) async {
await callApi<CampaignDetailResponseModel>( await callApi<CampaignDetailResponseModel>(
request: () => client.websitePage(type), request: () async {
await _ensureWebsiteApiLoaded();
final api = website_api.WebsiteApi(client);
return api.websitePage(type);
},
onSuccess: (data, _) { onSuccess: (data, _) {
campaignDetail.value = data; campaignDetail.value = data;
}, },
...@@ -57,7 +70,11 @@ class CampaignDetailViewModel extends RestfulApiViewModel { ...@@ -57,7 +70,11 @@ class CampaignDetailViewModel extends RestfulApiViewModel {
Future<void> fetchWebsitePageGetDetail(String pageId) async { Future<void> fetchWebsitePageGetDetail(String pageId) async {
await callApi<CampaignDetailResponseModel>( await callApi<CampaignDetailResponseModel>(
request: () => client.websitePageGetDetail(pageId), request: () async {
await _ensureWebsiteApiLoaded();
final api = website_api.WebsiteApi(client);
return api.websitePageGetDetail(pageId);
},
onSuccess: (data, response) { onSuccess: (data, response) {
campaignDetail.value = data; campaignDetail.value = data;
}, },
......
import 'package:flutter/foundation.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/preference/data_preference.dart'; import 'package:mypoint_flutter_app/preference/data_preference.dart';
...@@ -126,7 +127,7 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS ...@@ -126,7 +127,7 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS
right: 4, right: 4,
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
print("Change avatar tapped"); debugPrint("Change avatar tapped");
}, },
child: Container( child: Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
......
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mypoint_flutter_app/screen/popup_manager/popup_manager_model.dart'; import 'package:mypoint_flutter_app/screen/popup_manager/popup_manager_model.dart';
import 'package:mypoint_flutter_app/screen/popup_manager/popup_manager_viewmodel.dart'; import 'package:mypoint_flutter_app/screen/popup_manager/popup_manager_viewmodel.dart';
...@@ -94,7 +95,7 @@ class _BasePopupViewState extends State<_BasePopupView> { ...@@ -94,7 +95,7 @@ class _BasePopupViewState extends State<_BasePopupView> {
void _onContentTap() { void _onContentTap() {
logPopupClick(popupId: widget.model.id ?? ''); logPopupClick(popupId: widget.model.id ?? '');
print( debugPrint(
'Popup clicked: ${widget.model.directional?.clickActionType ?? ''} - ${widget.model.directional?.clickActionParam ?? ''}', 'Popup clicked: ${widget.model.directional?.clickActionType ?? ''} - ${widget.model.directional?.clickActionParam ?? ''}',
); );
_timer?.cancel(); _timer?.cancel();
......
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/screen/register_campaign/register_form_input_viewmodel.dart'; import 'package:mypoint_flutter_app/screen/register_campaign/register_form_input_viewmodel.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
...@@ -195,7 +196,7 @@ class _RegisterFormInputScreenState extends BaseState<RegisterFormInputScreen> w ...@@ -195,7 +196,7 @@ class _RegisterFormInputScreenState extends BaseState<RegisterFormInputScreen> w
void _gotoPaymentScreen() { void _gotoPaymentScreen() {
final metaData = (_viewModel.form.value?.submitParams ?? {}).toJsonString(); final metaData = (_viewModel.form.value?.submitParams ?? {}).toJsonString();
print("_gotoPaymentScreen metaData $metaData"); debugPrint("_gotoPaymentScreen metaData $metaData");
Get.toNamed(transactionDetailScreen, arguments: {"product": _product, "quantity": 1, "metaData": metaData}); Get.toNamed(transactionDetailScreen, arguments: {"product": _product, "quantity": 1, "metaData": metaData});
} }
...@@ -219,7 +220,7 @@ class _RegisterFormInputScreenState extends BaseState<RegisterFormInputScreen> w ...@@ -219,7 +220,7 @@ class _RegisterFormInputScreenState extends BaseState<RegisterFormInputScreen> w
final form = _viewModel.form.value?.formRegistration; final form = _viewModel.form.value?.formRegistration;
final inputs = form?.inputRequired ?? []; final inputs = form?.inputRequired ?? [];
for (var input in inputs) { for (var input in inputs) {
print("Input: ${input.title}, Value: ${input.value}"); debugPrint("Input: ${input.title}, Value: ${input.value}");
} }
final isValid = inputs.every((input) { final isValid = inputs.every((input) {
if (input.require == true) { if (input.require == true) {
......
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/screen/splash/splash_screen_viewmodel.dart'; import 'package:mypoint_flutter_app/screen/splash/splash_screen_viewmodel.dart';
import 'package:mypoint_flutter_app/shared/router_gage.dart';
import 'package:mypoint_flutter_app/widgets/alert/custom_alert_dialog.dart'; import 'package:mypoint_flutter_app/widgets/alert/custom_alert_dialog.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
import '../../base/basic_state.dart'; import '../../base/basic_state.dart';
...@@ -32,8 +28,7 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState { ...@@ -32,8 +28,7 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
_viewModel.makeDataFollowInitApp(); _viewModel.makeDataFollowInitApp();
return; return;
} }
var status = updateData?.status ?? UpdateStatus.none; if (updateData.status == UpdateStatus.none) {
if (status == UpdateStatus.none) {
_viewModel.directionWhenTokenInvalid(); _viewModel.directionWhenTokenInvalid();
} else { } else {
_showSuggestUpdateAlert(updateData); _showSuggestUpdateAlert(updateData);
...@@ -62,14 +57,6 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState { ...@@ -62,14 +57,6 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
); );
} }
void _exitApp() {
if (Platform.isAndroid) {
SystemNavigator.pop();
} else {
exit(0);
}
}
void _showSuggestUpdateAlert(CheckUpdateResponseModel data) { void _showSuggestUpdateAlert(CheckUpdateResponseModel data) {
final buttons = data.status == UpdateStatus.force final buttons = data.status == UpdateStatus.force
? [AlertButton( ? [AlertButton(
......
...@@ -64,28 +64,28 @@ class SplashScreenViewModel extends RestfulApiViewModel { ...@@ -64,28 +64,28 @@ class SplashScreenViewModel extends RestfulApiViewModel {
/// Get token from x-app-sdk (web only) /// Get token from x-app-sdk (web only)
Future<String?> _getTokenFromSDK() async { Future<String?> _getTokenFromSDK() async {
if (!kIsWeb) { if (!kIsWeb) {
print('🔍 SplashScreen - Not on web, skipping SDK token retrieval'); debugPrint('🔍 SplashScreen - Not on web, skipping SDK token retrieval');
return null; return null;
} }
try { try {
print('🔍 SplashScreen - Attempting to get token from x-app-sdk...'); debugPrint('🔍 SplashScreen - Attempting to get token from x-app-sdk...');
await webInitializeXAppSDK().timeout(_sdkTimeout); await webInitializeXAppSDK().timeout(_sdkTimeout);
if (!webIsSDKInitialized()) { if (!webIsSDKInitialized()) {
print('⚠️ SplashScreen - SDK not initialized, skipping'); debugPrint('⚠️ SplashScreen - SDK not initialized, skipping');
return null; return null;
} }
// Get token from SDK // Get token from SDK
final token = await webGetToken().timeout(_sdkTimeout); final token = await webGetToken().timeout(_sdkTimeout);
if (token != null && token.isNotEmpty) { if (token != null && token.isNotEmpty) {
print('✅ SplashScreen - Token retrieved from x-app-sdk: ${token.substring(0, 8)}...'); debugPrint('✅ SplashScreen - Token retrieved from x-app-sdk: ${token.substring(0, 8)}...');
return token; return token;
} else { } else {
final error = webGetLastError(); final error = webGetLastError();
print('❌ SplashScreen - Failed to get token from SDK: $error'); debugPrint('❌ SplashScreen - Failed to get token from SDK: $error');
return null; return null;
} }
} catch (e) { } catch (e) {
print('❌ SplashScreen - Error getting token from SDK: $e'); debugPrint('❌ SplashScreen - Error getting token from SDK: $e');
return null; return null;
} }
} }
......
...@@ -32,9 +32,7 @@ class _SupportScreenState extends State<SupportScreen> { ...@@ -32,9 +32,7 @@ class _SupportScreenState extends State<SupportScreen> {
case SupportItemType.phone: case SupportItemType.phone:
final phone = value.trim(); final phone = value.trim();
if (phone.isEmpty) { if (phone.isEmpty) {
if (kDebugMode) { debugPrint('⚠️ SupportScreen: phone number is empty');
print('⚠️ SupportScreen: phone number is empty');
}
return; return;
} }
if (kIsWeb) { if (kIsWeb) {
...@@ -44,9 +42,7 @@ class _SupportScreenState extends State<SupportScreen> { ...@@ -44,9 +42,7 @@ class _SupportScreenState extends State<SupportScreen> {
await _launchTelUrl(phone); await _launchTelUrl(phone);
} }
} catch (e) { } catch (e) {
if (kDebugMode) { debugPrint('❌ webCallPhone failed: $e');
print('❌ webCallPhone failed: $e');
}
await _launchTelUrl(phone); await _launchTelUrl(phone);
} }
} else { } else {
......
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/screen/support/support_item_model.dart'; import 'package:mypoint_flutter_app/screen/support/support_item_model.dart';
...@@ -20,7 +21,7 @@ class SupportViewModel extends GetxController { ...@@ -20,7 +21,7 @@ class SupportViewModel extends GetxController {
supportItems.value = items.map((item) => SupportItemModel.fromJson(item)).toList(); supportItems.value = items.map((item) => SupportItemModel.fromJson(item)).toList();
} catch (e) { } catch (e) {
print("Lỗi load dữ liệu: $e"); debugPrint("Lỗi load dữ liệu: $e");
} }
} }
} }
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/preference/data_preference.dart'; import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/screen/topup/models/brand_network_model.dart'; import 'package:mypoint_flutter_app/screen/topup/models/brand_network_model.dart';
import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import '../../preference/contact_storage_service.dart'; import '../../preference/contact_storage_service.dart';
import '../voucher/models/product_brand_model.dart'; import '../voucher/models/product_brand_model.dart';
...@@ -17,6 +18,19 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -17,6 +18,19 @@ class TopUpViewModel extends RestfulApiViewModel {
var selectedProduct = Rxn<ProductModel>(); var selectedProduct = Rxn<ProductModel>();
final Map<String, List<ProductModel>> _allValue = {}; final Map<String, List<ProductModel>> _allValue = {};
var phoneNumber = ''.obs; var phoneNumber = ''.obs;
bool _productApiLoaded = false;
Future<void> _ensureProductApiLoaded() async {
if (_productApiLoaded) return;
await product_api.loadLibrary();
_productApiLoaded = true;
}
Future<BaseResponseModel<T>> _callProductApi<T>(Future<BaseResponseModel<T>> Function(dynamic api) fn) async {
await _ensureProductApiLoaded();
final api = product_api.ProductApi(client);
return fn(api);
}
@override @override
void onInit() { void onInit() {
...@@ -42,7 +56,7 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -42,7 +56,7 @@ class TopUpViewModel extends RestfulApiViewModel {
_getTopUpBrands() async { _getTopUpBrands() async {
await callApi<List<ProductBrandModel>>( await callApi<List<ProductBrandModel>>(
request: () => client.getTopUpBrands(ProductType.topupMobile), request: () => _callProductApi((api) => api.getTopUpBrands(ProductType.topupMobile)),
onSuccess: (data, _) { onSuccess: (data, _) {
topUpBrands.assignAll(data); topUpBrands.assignAll(data);
checkMobileNetwork(); checkMobileNetwork();
...@@ -53,7 +67,7 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -53,7 +67,7 @@ class TopUpViewModel extends RestfulApiViewModel {
checkMobileNetwork() async { checkMobileNetwork() async {
await callApi<BrandNameCheckResponse>( await callApi<BrandNameCheckResponse>(
request: () => client.checkMobileNetwork(phoneNumber.value), request: () => _callProductApi((api) => api.checkMobileNetwork(phoneNumber.value)),
onSuccess: (data, _) { onSuccess: (data, _) {
final brandCode = data?.brand ?? ''; final brandCode = data?.brand ?? '';
var brand = topUpBrands.isNotEmpty var brand = topUpBrands.isNotEmpty
...@@ -107,7 +121,7 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -107,7 +121,7 @@ class TopUpViewModel extends RestfulApiViewModel {
"brand_id": selectedBrand.value?.id ?? 0, "brand_id": selectedBrand.value?.id ?? 0,
}; };
await callApi<List<ProductModel>>( await callApi<List<ProductModel>>(
request: () => client.getProducts(body), request: () => _callProductApi((api) => api.getProducts(body)),
onSuccess: (data, _) { onSuccess: (data, _) {
_allValue[code] = data; _allValue[code] = data;
products.assignAll(data); products.assignAll(data);
...@@ -116,4 +130,4 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -116,4 +130,4 @@ class TopUpViewModel extends RestfulApiViewModel {
showAppNavigatorDialog: true, showAppNavigatorDialog: true,
); );
} }
} }
\ No newline at end of file
...@@ -21,7 +21,7 @@ class _TrafficServiceDetailScreenState extends State<TrafficServiceDetailScreen> ...@@ -21,7 +21,7 @@ class _TrafficServiceDetailScreenState extends State<TrafficServiceDetailScreen>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
int? serviceId; String? serviceId;
TrafficServiceDetailModel? data; TrafficServiceDetailModel? data;
final args = Get.arguments; final args = Get.arguments;
if (args is Map) { if (args is Map) {
......
import 'package:flutter/foundation.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/extensions/datetime_extensions.dart'; import 'package:mypoint_flutter_app/extensions/datetime_extensions.dart';
...@@ -85,8 +86,8 @@ class _TrafficServiceScreenState extends State<TrafficServiceScreen> { ...@@ -85,8 +86,8 @@ class _TrafficServiceScreenState extends State<TrafficServiceScreen> {
), ),
child: ListTile( child: ListTile(
onTap: () { onTap: () {
print('Tapped on item: ${item.licensePlate}'); debugPrint('Tapped on item: ${item.licensePlate}');
Get.toNamed(trafficServiceDetailScreen, arguments: {'serviceId': item.itemId}); Get.toNamed(trafficServiceDetailScreen, arguments: {'serviceId': item.itemId.toString()});
}, },
leading: SizedBox( leading: SizedBox(
width: 60, // <= giới hạn rõ width: 60, // <= giới hạn rõ
......
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