Commit 6b980613 authored by DatHV's avatar DatHV
Browse files

update project structure

parent bfff9e47
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:mypoint_flutter_app/screen/splash/models/check_update_response_model.dart'; import 'package:mypoint_flutter_app/features/splash/models/check_update_response_model.dart';
part 'update_response_model.g.dart'; part 'update_response_model.g.dart';
......
import 'package:flutter/foundation.dart'; 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/screen/splash/splash_screen_viewmodel.dart'; import 'package:mypoint_flutter_app/features/splash/splash_screen_viewmodel.dart';
import 'package:mypoint_flutter_app/widgets/alert/custom_alert_dialog.dart'; import 'package:mypoint_flutter_app/shared/widgets/alert/custom_alert_dialog.dart';
import '../../base/base_screen.dart'; import 'package:mypoint_flutter_app/core/services/web/web_helper.dart';
import '../../base/basic_state.dart'; import '../../shared/widgets/base_view/base_screen.dart';
import '../../shared/widgets/base_view/basic_state.dart';
import 'models/check_update_response_model.dart'; import 'models/check_update_response_model.dart';
import '../../resources/base_color.dart'; import '../../core/theme/base_color.dart';
import '../../widgets/alert/data_alert_model.dart'; import '../../shared/widgets/alert/data_alert_model.dart';
class SplashScreen extends BaseScreen { class SplashScreen extends BaseScreen {
const SplashScreen({super.key}); const SplashScreen({super.key});
...@@ -18,11 +19,12 @@ class SplashScreen extends BaseScreen { ...@@ -18,11 +19,12 @@ class SplashScreen extends BaseScreen {
class _SplashScreenState extends BaseState<SplashScreen> with BasicState { class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
final SplashScreenViewModel _viewModel = Get.put(SplashScreenViewModel()); final SplashScreenViewModel _viewModel = Get.put(SplashScreenViewModel());
Future<void>? _webSplashCacheFuture;
bool _webLoaderNotified = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
print('🚀 SplashScreen - initState ${DateTime.now().toString()}');
_viewModel.checkUpdateResponse = (data) { _viewModel.checkUpdateResponse = (data) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final updateData = (data?.updateRequest ?? []).firstOrNull; final updateData = (data?.updateRequest ?? []).firstOrNull;
...@@ -40,6 +42,31 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState { ...@@ -40,6 +42,31 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
_viewModel.checkUpdateApp(); _viewModel.checkUpdateApp();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (kIsWeb && _webSplashCacheFuture == null) {
_webSplashCacheFuture = precacheImage(
const AssetImage('assets/images/splash_screen.webp'),
context,
).catchError((error, stackTrace) {
debugPrint('Failed to precache splash background: $error');
debugPrintStack(stackTrace: stackTrace);
}).whenComplete(() {
if (!mounted) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
_notifyWebLoaderReady();
});
});
}
}
void _notifyWebLoaderReady() {
if (!kIsWeb || _webLoaderNotified || !mounted) return;
_webLoaderNotified = true;
webNotifySplashScreenReady();
}
@override @override
Widget createBody() { Widget createBody() {
final path = kIsWeb ? "assets/images/splash_screen.webp" : "assets/images/splash_screen.png"; final path = kIsWeb ? "assets/images/splash_screen.webp" : "assets/images/splash_screen.png";
...@@ -53,7 +80,9 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState { ...@@ -53,7 +80,9 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
height: double.infinity, height: double.infinity,
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
Center(child: CircularProgressIndicator()), Center(
child: kIsWeb ? SizedBox.shrink() : CircularProgressIndicator()
)
], ],
), ),
); );
......
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/networking/restful_api_viewmodel.dart'; import 'package:mypoint_flutter_app/core/network/restful_api_viewmodel.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/core/network/restful_api_client_all_request.dart';
import 'package:mypoint_flutter_app/shared/router_gage.dart'; import 'package:mypoint_flutter_app/shared/router_gage.dart';
import '../../model/auth/login_token_response_model.dart'; import '../login/model/login_token_response_model.dart';
import '../../model/auth/profile_response_model.dart'; import '../personal/model/profile_response_model.dart';
import 'models/update_response_model.dart'; import 'models/update_response_model.dart';
import '../../preference/data_preference.dart'; import '../../shared/preferences/data_preference.dart';
import '../../preference/point/point_manager.dart'; import '../../shared/preferences/point/point_manager.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../web/web_helper.dart'; import '../../core/services/web/web_helper.dart';
import '../popup_manager/popup_manager_viewmodel.dart'; import '../popup_manager/popup_manager_viewmodel.dart';
class SplashScreenViewModel extends RestfulApiViewModel { class SplashScreenViewModel extends RestfulApiViewModel {
......
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
// part 'support_item_model.g.dart';
enum SupportItemType { mail, phone, facebook, question, termsOfUse, privacyPolicy } enum SupportItemType { mail, phone, facebook, question, termsOfUse, privacyPolicy }
@JsonSerializable() @JsonSerializable()
......
import 'package:flutter/foundation.dart'; 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/screen/support/support_item_model.dart'; import 'package:mypoint_flutter_app/features/support/support_item_model.dart';
import 'package:mypoint_flutter_app/screen/support/support_screen_viewmodel.dart'; import 'package:mypoint_flutter_app/features/support/support_screen_viewmodel.dart';
import 'package:mypoint_flutter_app/shared/router_gage.dart'; import 'package:mypoint_flutter_app/shared/router_gage.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:universal_html/js_util.dart' as js_util; import 'package:universal_html/js_util.dart' as js_util;
import '../../widgets/custom_navigation_bar.dart'; import '../../shared/widgets/custom_navigation_bar.dart';
import '../faqs/faqs_screen.dart'; import '../faqs/faqs_screen.dart';
import '../pageDetail/model/detail_page_rule_type.dart'; import '../pageDetail/model/detail_page_rule_type.dart';
import '../../web/web_helper.dart'; import '../../core/services/web/web_helper.dart';
class SupportScreen extends StatefulWidget { class SupportScreen extends StatefulWidget {
const SupportScreen({super.key}); const SupportScreen({super.key});
...@@ -123,9 +123,7 @@ class _SupportScreenState extends State<SupportScreen> { ...@@ -123,9 +123,7 @@ class _SupportScreenState extends State<SupportScreen> {
return Icons.receipt_long; return Icons.receipt_long;
case SupportItemType.privacyPolicy: case SupportItemType.privacyPolicy:
return Icons.lock_outline; return Icons.lock_outline;
default: }
return Icons.info;
}
} }
bool _hasArrow(SupportItemType type) { bool _hasArrow(SupportItemType type) {
......
...@@ -2,7 +2,7 @@ import 'dart:convert'; ...@@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart'; 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/features/support/support_item_model.dart';
class SupportViewModel extends GetxController { class SupportViewModel extends GetxController {
var supportItems = <SupportItemModel>[].obs; var supportItems = <SupportItemModel>[].obs;
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart'; import 'package:mypoint_flutter_app/shared/widgets/image_loader.dart';
import '../voucher/models/product_brand_model.dart'; import '../voucher/models/product_brand_model.dart';
class BrandSelectSheet extends StatelessWidget { class BrandSelectSheet extends StatelessWidget {
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/screen/topup/topup_viewmodel.dart'; import 'package:mypoint_flutter_app/features/topup/topup_viewmodel.dart';
import 'package:mypoint_flutter_app/widgets/custom_navigation_bar.dart'; import 'package:mypoint_flutter_app/shared/widgets/custom_navigation_bar.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart'; import 'package:mypoint_flutter_app/shared/widgets/image_loader.dart';
import '../../base/base_screen.dart'; import '../../shared/widgets/base_view/base_screen.dart';
import '../../base/basic_state.dart'; import '../../shared/widgets/base_view/basic_state.dart';
import '../../extensions/debouncer.dart'; import '../../core/utils/debouncer.dart';
import '../../preference/data_preference.dart'; import '../../shared/preferences/data_preference.dart';
import '../../resources/base_color.dart'; import '../../core/theme/base_color.dart';
import '../../shared/router_gage.dart'; import '../../shared/router_gage.dart';
import '../contacts/contacts_picker.dart'; import '../contacts/contacts_picker.dart';
import 'brand_select_sheet_widget.dart'; import 'brand_select_sheet_widget.dart';
...@@ -110,7 +110,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState ...@@ -110,7 +110,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
selectedBrand: _viewModel.selectedBrand.value, selectedBrand: _viewModel.selectedBrand.value,
onSelected: (brand) { onSelected: (brand) {
Navigator.pop(context); Navigator.pop(context);
if (brand == null && brand.id != _viewModel.selectedBrand.value?.id) return; if (brand.id != _viewModel.selectedBrand.value?.id) return;
_viewModel.selectedProduct.value = null; _viewModel.selectedProduct.value = null;
_viewModel.selectedBrand.value = brand; _viewModel.selectedBrand.value = brand;
_viewModel.getTelcoDetail(); _viewModel.getTelcoDetail();
...@@ -154,7 +154,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState ...@@ -154,7 +154,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
itemCount: histories.length, itemCount: histories.length,
separatorBuilder: (_, __) => const SizedBox(width: 8), separatorBuilder: (_, _) => const SizedBox(width: 8),
itemBuilder: (_, index) { itemBuilder: (_, index) {
final phone = histories[index]; final phone = histories[index];
final myPhone = DataPreference.instance.phone ?? ''; final myPhone = DataPreference.instance.phone ?? '';
......
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/api/product_api.dart' deferred as product_api; import 'package:mypoint_flutter_app/core/network/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/preference/data_preference.dart'; import 'package:mypoint_flutter_app/shared/preferences/data_preference.dart';
import 'package:mypoint_flutter_app/screen/topup/models/brand_network_model.dart'; import 'package:mypoint_flutter_app/features/topup/models/brand_network_model.dart';
import '../../base/base_response_model.dart'; import '../../shared/widgets/base_view/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../core/network/restful_api_viewmodel.dart';
import '../../preference/contact_storage_service.dart'; import '../../core/services/contact_storage_service.dart';
import '../voucher/models/product_brand_model.dart'; import '../voucher/models/product_brand_model.dart';
import '../voucher/models/product_model.dart'; import '../voucher/models/product_model.dart';
import '../voucher/models/product_type.dart'; import '../voucher/models/product_type.dart';
...@@ -50,11 +50,11 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -50,11 +50,11 @@ class TopUpViewModel extends RestfulApiViewModel {
} }
} }
firstLoadTopUpData() async { Future<void> firstLoadTopUpData() async {
_getTopUpBrands(); _getTopUpBrands();
} }
_getTopUpBrands() async { Future<void> _getTopUpBrands() async {
await callApi<List<ProductBrandModel>>( await callApi<List<ProductBrandModel>>(
request: () => _callProductApi((api) => api.getTopUpBrands(ProductType.topupMobile)), request: () => _callProductApi((api) => api.getTopUpBrands(ProductType.topupMobile)),
onSuccess: (data, _) { onSuccess: (data, _) {
...@@ -65,11 +65,11 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -65,11 +65,11 @@ class TopUpViewModel extends RestfulApiViewModel {
); );
} }
checkMobileNetwork() async { Future<void> checkMobileNetwork() async {
await callApi<BrandNameCheckResponse>( await callApi<BrandNameCheckResponse>(
request: () => _callProductApi((api) => api.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
? topUpBrands.firstWhere( ? topUpBrands.firstWhere(
(brand) => brand.code == brandCode, (brand) => brand.code == brandCode,
......
import 'dart:io'; import 'dart:io';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter/webview_flutter.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../base/app_loading.dart'; import '../../shared/widgets/loading/app_loading.dart';
import '../../base/base_screen.dart'; import '../../shared/widgets/base_view/base_screen.dart';
import '../../base/basic_state.dart'; import '../../shared/widgets/base_view/basic_state.dart';
import '../../resources/base_color.dart'; import '../../core/theme/base_color.dart';
import '../../widgets/custom_navigation_bar.dart'; import '../../shared/widgets/custom_navigation_bar.dart';
import 'dart:typed_data' as typed_data; import 'dart:typed_data' as typed_data;
class TrafficServiceCertificateScreen extends BaseScreen { class TrafficServiceCertificateScreen extends BaseScreen {
......
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/screen/traffic_service/traffic_service_certificate_screen.dart'; import 'package:mypoint_flutter_app/features/traffic_service/traffic_service_certificate_screen.dart';
import 'package:mypoint_flutter_app/screen/traffic_service/traffic_service_model.dart'; import 'package:mypoint_flutter_app/features/traffic_service/traffic_service_model.dart';
import 'package:mypoint_flutter_app/screen/traffic_service/traffic_service_viewmodel.dart'; import 'package:mypoint_flutter_app/features/traffic_service/traffic_service_viewmodel.dart';
import 'package:mypoint_flutter_app/widgets/custom_empty_widget.dart'; import 'package:mypoint_flutter_app/shared/widgets/custom_empty_widget.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../resources/base_color.dart'; import '../../core/theme/base_color.dart';
import '../../widgets/custom_navigation_bar.dart'; import '../../shared/widgets/custom_navigation_bar.dart';
class TrafficServiceDetailScreen extends StatefulWidget { class TrafficServiceDetailScreen extends StatefulWidget {
const TrafficServiceDetailScreen({super.key}); const TrafficServiceDetailScreen({super.key});
...@@ -52,7 +52,7 @@ class _TrafficServiceDetailScreenState extends State<TrafficServiceDetailScreen> ...@@ -52,7 +52,7 @@ class _TrafficServiceDetailScreenState extends State<TrafficServiceDetailScreen>
body: Obx(() { body: Obx(() {
final model = _viewModel.trafficServiceDetail.value; final model = _viewModel.trafficServiceDetail.value;
if (model == null) { if (model == null) {
return const Center(child: EmptyWidget()); return Center(child: EmptyWidget(isLoading: _viewModel.isLoading.value));
} }
return Column( return Column(
children: [ children: [
......
import 'package:mypoint_flutter_app/directional/directional_screen.dart'; import 'package:mypoint_flutter_app/shared/navigation/directional_screen.dart';
import 'package:mypoint_flutter_app/extensions/datetime_extensions.dart'; import 'package:mypoint_flutter_app/core/utils/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
enum SortFilter { asc, desc } enum SortFilter { asc, desc }
...@@ -30,12 +30,12 @@ class HeaderFilterOrderModel { ...@@ -30,12 +30,12 @@ class HeaderFilterOrderModel {
String get eventNameTracking { String get eventNameTracking {
if (sort == null) { if (sort == null) {
return 'soskdt_${suffixChecking}'; return 'soskdt_$suffixChecking';
} }
return 'soskdt_${suffixChecking}_${sort!.name}'; return 'soskdt_${suffixChecking}_${sort!.name}';
} }
String get eventNameTrackingDvCar => 'dvcar_${suffixChecking}'; String get eventNameTrackingDvCar => 'dvcar_$suffixChecking';
} }
class TrafficServiceResponseModel { class TrafficServiceResponseModel {
......
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/core/utils/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/screen/traffic_service/traffic_service_detail_screen.dart'; import 'package:mypoint_flutter_app/features/traffic_service/traffic_service_viewmodel.dart';
import 'package:mypoint_flutter_app/screen/traffic_service/traffic_service_viewmodel.dart'; import 'package:mypoint_flutter_app/shared/widgets/custom_empty_widget.dart';
import 'package:mypoint_flutter_app/widgets/custom_empty_widget.dart'; import 'package:mypoint_flutter_app/shared/widgets/image_loader.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart'; import '../../core/utils/extensions/date_format.dart';
import '../../extensions/date_format.dart'; import '../../core/theme/base_color.dart';
import '../../resources/base_color.dart';
import '../../shared/router_gage.dart'; import '../../shared/router_gage.dart';
import '../../widgets/custom_navigation_bar.dart'; import '../../shared/widgets/custom_navigation_bar.dart';
class TrafficServiceScreen extends StatefulWidget { class TrafficServiceScreen extends StatefulWidget {
const TrafficServiceScreen({super.key}); const TrafficServiceScreen({super.key});
...@@ -72,7 +70,7 @@ class _TrafficServiceScreenState extends State<TrafficServiceScreen> { ...@@ -72,7 +70,7 @@ class _TrafficServiceScreenState extends State<TrafficServiceScreen> {
child: Obx(() { child: Obx(() {
final products = _viewModel.trafficData.value?.products ?? []; final products = _viewModel.trafficData.value?.products ?? [];
return products.isEmpty return products.isEmpty
? Center(child: EmptyWidget()) ? Center(child: EmptyWidget(isLoading: _viewModel.isLoading.value))
: ListView.builder( : ListView.builder(
itemCount: products.length, itemCount: products.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
......
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/app/config/constants.dart';
import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api; import 'package:mypoint_flutter_app/core/network/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart'; import 'package:mypoint_flutter_app/core/network/restful_api_client_all_request.dart';
import 'package:mypoint_flutter_app/screen/traffic_service/traffic_service_model.dart'; import 'package:mypoint_flutter_app/features/traffic_service/traffic_service_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../core/network/restful_api_viewmodel.dart';
import '../../base/base_response_model.dart'; import '../../shared/widgets/base_view/base_response_model.dart';
class TrafficServiceViewModel extends RestfulApiViewModel { class TrafficServiceViewModel extends RestfulApiViewModel {
var trafficData = Rxn<TrafficServiceResponseModel>(); var trafficData = Rxn<TrafficServiceResponseModel>();
......
...@@ -2,11 +2,8 @@ class TransactionCategoryModel { ...@@ -2,11 +2,8 @@ class TransactionCategoryModel {
int? id; int? id;
String? code; String? code;
String? name; String? name;
bool _isSelected = false; bool _isSelected = false;
bool get isSelected => _isSelected; bool get isSelected => _isSelected;
set isSelected(bool value) => _isSelected = value;
TransactionCategoryModel({ TransactionCategoryModel({
this.id, this.id,
......
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