chore(group): fix delay show group when switch and convert to relative import

This commit is contained in:
Tran Anh Tuan
2025-10-23 11:08:03 +07:00
parent cfebf74515
commit 9bff11a0b1
44 changed files with 357 additions and 380 deletions

View File

@@ -7,6 +7,10 @@
# The following line activates a set of recommended lints for Flutter apps, # The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices. # packages, and plugins designed to encourage good coding practices.
analyzer:
errors:
use_build_context_synchronously: ignore
avoid_print: ignore
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
linter: linter:

View File

@@ -1,5 +1,4 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -9,7 +8,6 @@ import '../product/services/api_services.dart';
import '../product/utils/date_time_utils.dart'; import '../product/utils/date_time_utils.dart';
import '../feature/device_log/device_logs_model.dart'; import '../feature/device_log/device_logs_model.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/utils/device_utils.dart'; import '../product/utils/device_utils.dart';

View File

@@ -6,7 +6,6 @@ import '../product/base/bloc/base_bloc.dart';
import '../product/constant/app/app_constants.dart'; import '../product/constant/app/app_constants.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../product/utils/date_time_utils.dart'; import '../product/utils/date_time_utils.dart';
import '../product/utils/device_utils.dart'; import '../product/utils/device_utils.dart';
import '../feature/device_log/device_logs_model.dart'; import '../feature/device_log/device_logs_model.dart';

View File

@@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../feature/settings/device_notification_settings/device_notification_settings_model.dart'; import '../feature/settings/device_notification_settings/device_notification_settings_model.dart';

View File

@@ -2,7 +2,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';

View File

@@ -1,8 +1,8 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';

View File

@@ -1,8 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/extension/context_extension.dart';
import '../product/extension/context_extension.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../feature/home/device_alias_model.dart'; import '../feature/home/device_alias_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
@@ -65,7 +64,6 @@ class HomeBloc extends BlocBase {
void getOwnerDeviceState(BuildContext context,List<DeviceWithAlias> allDevices) async { void getOwnerDeviceState(BuildContext context,List<DeviceWithAlias> allDevices) async {
// int notificationCount = 0; // int notificationCount = 0;
Map<String, List<DeviceWithAlias>> ownerDevicesStatus = {}; Map<String, List<DeviceWithAlias>> ownerDevicesStatus = {};
List<String> ownerDevicesState = [];
if (!context.mounted) return; if (!context.mounted) return;
sinkOwnerDevicesStatus.add(ownerDevicesStatus); sinkOwnerDevicesStatus.add(ownerDevicesStatus);

View File

@@ -1,7 +1,6 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../product/constant/app/app_constants.dart'; import '../product/constant/app/app_constants.dart';

View File

@@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';

View File

@@ -1,6 +1,7 @@
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../../product/shared/shared_component_loading_animation.dart'; import '../../product/shared/shared_component_loading_animation.dart';
import '../../product/shared/shared_loading_animation.dart'; import '../../product/shared/shared_loading_animation.dart';
@@ -14,7 +15,6 @@ import '../../product/services/language_services.dart';
import '../../product/shared/shared_snack_bar.dart'; import '../../product/shared/shared_snack_bar.dart';
import '../../product/utils/date_time_utils.dart'; import '../../product/utils/date_time_utils.dart';
import '../../product/utils/device_utils.dart'; import '../../product/utils/device_utils.dart';
import '../../product/base/bloc/base_bloc.dart'; import '../../product/base/bloc/base_bloc.dart';
import 'device_logs_model.dart'; import 'device_logs_model.dart';

View File

@@ -1,6 +1,7 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../bloc/devices_manager_bloc.dart'; import '../../bloc/devices_manager_bloc.dart';
import '../../product/constant/enums/role_enums.dart'; import '../../product/constant/enums/role_enums.dart';
import '../../product/services/api_services.dart'; import '../../product/services/api_services.dart';

View File

@@ -1,10 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:sfm_app/product/shared/shared_component_loading_animation.dart';
import 'package:simple_ripple_animation/simple_ripple_animation.dart'; import 'package:simple_ripple_animation/simple_ripple_animation.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../product/shared/shared_component_loading_animation.dart';
import '../../../product/constant/image/image_constants.dart'; import '../../../product/constant/image/image_constants.dart';
import '../../../product/shared/shared_line_chart.dart'; import '../../../product/shared/shared_line_chart.dart';
import '../../../product/shared/shared_curve.dart'; import '../../../product/shared/shared_curve.dart';
@@ -15,7 +14,6 @@ import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../bloc/device_detail_bloc.dart'; import '../../../bloc/device_detail_bloc.dart';

View File

@@ -9,7 +9,6 @@ import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/api_services.dart'; import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/shared/model/district_model.dart'; import '../../../product/shared/model/district_model.dart';
import '../../../product/shared/model/province_model.dart'; import '../../../product/shared/model/province_model.dart';
import '../../../product/shared/model/ward_model.dart'; import '../../../product/shared/model/ward_model.dart';

View File

@@ -2,15 +2,14 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../bloc/device_update_bloc.dart'; import '../../../bloc/device_update_bloc.dart';
import '../../../product/constant/app/app_constants.dart'; import '../../../product/constant/app/app_constants.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/shared/find_location_maps/shared_map_search_location.dart'; import '../../../product/shared/find_location_maps/shared_map_search_location.dart';
import '../../../product/shared/find_location_maps/model/prediction_model.dart'; import '../../../product/shared/find_location_maps/model/prediction_model.dart';
import '../../../product/shared/shared_transition.dart'; import '../../../product/shared/shared_transition.dart';
import 'geocode_model.dart'; import 'geocode_model.dart';
@@ -64,7 +63,8 @@ showMapDialog(
String latitude = mapDialogLatitudeController.text; String latitude = mapDialogLatitudeController.text;
String longitude = mapDialogLongitudeController.text; String longitude = mapDialogLongitudeController.text;
log("Finish -- Latitude: $latitude, longitude: $longitude --"); log("Finish -- Latitude: $latitude, longitude: $longitude --");
getDataFromApi(context,latitude, longitude, deviceUpdateBloc); getDataFromApi(
context, latitude, longitude, deviceUpdateBloc);
latitudeController.text = latitudeController.text =
mapDialogLatitudeController.text; mapDialogLatitudeController.text;
longitudeController.text = longitudeController.text =
@@ -255,15 +255,15 @@ Future<void> _processLocations(BuildContext context,
.add({"code": province.code!, "name": province.fullName!}); .add({"code": province.code!, "name": province.fullName!});
deviceUpdateBloc.getAllProvinces(context); deviceUpdateBloc.getAllProvinces(context);
final district = await deviceUpdateBloc.getDistrictByName(context, final district = await deviceUpdateBloc.getDistrictByName(
districtNameFromAPI, province.code!); context, districtNameFromAPI, province.code!);
log("Districtname: ${district.fullName}, districtCode: ${district.code}"); log("Districtname: ${district.fullName}, districtCode: ${district.code}");
deviceUpdateBloc.getAllDistricts(context, province.code!); deviceUpdateBloc.getAllDistricts(context, province.code!);
if (district.name != "null") { if (district.name != "null") {
deviceUpdateBloc.sinkDistrictData deviceUpdateBloc.sinkDistrictData
.add({"code": district.code!, "name": district.fullName!}); .add({"code": district.code!, "name": district.fullName!});
final ward = final ward = await deviceUpdateBloc.getWardByName(
await deviceUpdateBloc.getWardByName(context,wardNameFromAPI, district.code!); context, wardNameFromAPI, district.code!);
log("Wardname: ${ward.fullName}, WardCode: ${ward.code}"); log("Wardname: ${ward.fullName}, WardCode: ${ward.code}");
deviceUpdateBloc.getAllWards(context, district.code!); deviceUpdateBloc.getAllWards(context, district.code!);
if (ward.name != "null") { if (ward.name != "null") {

View File

@@ -1,9 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:data_table_2/data_table_2.dart'; import 'package:data_table_2/data_table_2.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../product/shared/shared_component_loading_animation.dart'; import '../../product/shared/shared_component_loading_animation.dart';
import '../../product/shared/shared_loading_animation.dart'; import '../../product/shared/shared_loading_animation.dart';
import 'add_new_device_widget.dart'; import 'add_new_device_widget.dart';

View File

@@ -1,7 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:sfm_app/product/constant/enums/app_route_enums.dart';
import 'package:sfm_app/product/constant/image/image_constants.dart'; import '../../product/constant/enums/app_route_enums.dart';
import '../../product/constant/image/image_constants.dart';
class NotFoundScreen extends StatelessWidget { class NotFoundScreen extends StatelessWidget {
const NotFoundScreen({super.key}); const NotFoundScreen({super.key});

View File

@@ -3,13 +3,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../../../product/shared/shared_rocket_container.dart'; import '../../../product/shared/shared_rocket_container.dart';
import '../../../product/constant/enums/app_route_enums.dart'; import '../../../product/constant/enums/app_route_enums.dart';
import '../../../product/constant/image/image_constants.dart'; import '../../../product/constant/image/image_constants.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../device_alias_model.dart'; import '../device_alias_model.dart';

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'status_card.dart'; import 'status_card.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
class StatusCard extends StatelessWidget { class StatusCard extends StatelessWidget {

View File

@@ -2,11 +2,11 @@
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../bloc/group_detail_bloc.dart'; import '../../../bloc/group_detail_bloc.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../devices/device_model.dart'; import '../../devices/device_model.dart';
import 'group_detail_model.dart'; import 'group_detail_model.dart';

View File

@@ -1,8 +1,8 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../bloc/group_detail_bloc.dart'; import '../../../bloc/group_detail_bloc.dart';
import '../../../product/shared/shared_loading_animation.dart'; import '../../../product/shared/shared_loading_animation.dart';
import 'group_detail_model.dart'; import 'group_detail_model.dart';
@@ -14,7 +14,6 @@ import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
import '../../../product/utils/response_status_utils.dart'; import '../../../product/utils/response_status_utils.dart';
import 'add_device_to_group_dialog.dart'; import 'add_device_to_group_dialog.dart';
class DetailGroupScreen extends StatefulWidget { class DetailGroupScreen extends StatefulWidget {

View File

@@ -1,187 +1,125 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../../product/constant/enums/app_route_enums.dart'; import '../../../product/constant/enums/app_route_enums.dart';
import '../../../product/shared/shared_component_loading_animation.dart';
import '../../../product/shared/shared_loading_animation.dart';
import 'groups_model.dart'; import 'groups_model.dart';
import 'groups_widget.dart';
import '../../../bloc/inter_family_bloc.dart'; import '../../../bloc/inter_family_bloc.dart';
import '../inter_family_widget.dart'; import '../inter_family_widget.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/constant/app/app_constants.dart'; import '../../../product/constant/app/app_constants.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import 'groups_widget.dart'; /// Stateless widget that renders a provided list of groups. The parent
/// screen owns fetching/updating the list; this widget only displays it and
class GroupsScreen extends StatefulWidget { /// forwards actions to the provided [InterFamilyBloc].
const GroupsScreen({super.key, required this.role}); class GroupsScreen extends StatelessWidget {
const GroupsScreen(
{super.key,
required this.role,
required this.groups,
required this.interFamilyBloc});
final String role; final String role;
final List<Group> groups;
@override final InterFamilyBloc interFamilyBloc;
State<GroupsScreen> createState() => _GroupsScreenState();
}
class _GroupsScreenState extends State<GroupsScreen> {
late InterFamilyBloc interFamilyBloc;
Timer? getAllGroupsTimer;
@override
void initState() {
super.initState();
interFamilyBloc = BlocProvider.of(context);
const duration = Duration(seconds: 5);
getAllGroupsTimer = Timer.periodic(
duration,
(Timer t) => interFamilyBloc.getAllGroup(context, widget.role),
);
}
@override
void dispose() {
getAllGroupsTimer?.cancel();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.role == ApplicationConstants.OWNER_GROUP || if (role != ApplicationConstants.OWNER_GROUP &&
widget.role == ApplicationConstants.PARTICIPANT_GROUP) { role != ApplicationConstants.PARTICIPANT_GROUP) {
return StreamBuilder<List<Group>>( return const SizedBox.shrink();
stream: interFamilyBloc.streamCurrentGroups, }
builder: (context, groupsSnapshot) {
if (groupsSnapshot.data == null) { if (groups.isEmpty) {
interFamilyBloc.getAllGroup(context,widget.role); return Center(child: Text(appLocalization(context).dont_have_group));
return const SharedLoadingAnimation(); }
} else if (groupsSnapshot.data!.isEmpty) {
return Center( return ListView.builder(
child: Text(appLocalization(context).dont_have_group), itemCount: groups.length,
);
} else {
return Scaffold(
body: groupsSnapshot.data?.isEmpty ?? true
? const SharedComponentLoadingAnimation()
: ListView.builder(
itemCount: groupsSnapshot.data!.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final group = groups[index];
return ListTile( return ListTile(
onTap: () { onTap: () => context.pushNamed(AppRoutes.GROUP_DETAIL.name,
context.pushNamed(AppRoutes.GROUP_DETAIL.name, pathParameters: {"groupId": group.id!}, extra: role),
pathParameters: { leading: IconConstants.instance.getMaterialIcon(Icons.diversity_2),
"groupId": groupsSnapshot.data![index].id! title: Text(group.name ?? '',
style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(group.description ?? ''),
trailing: role == ApplicationConstants.OWNER_GROUP
? _ownerPopupMenu(group, context)
: null,
);
}, },
extra: widget.role); );
}, }
leading: IconConstants.instance
.getMaterialIcon(Icons.diversity_2), Widget _ownerPopupMenu(Group group, BuildContext context) {
title: Text( return PopupMenuButton<int>(
groupsSnapshot.data![index].name ?? '',
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(
groupsSnapshot.data![index].description ?? ""),
trailing:
widget.role == ApplicationConstants.OWNER_GROUP
? PopupMenuButton(
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.all(Radius.circular(8.0))),
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0),
),
),
itemBuilder: (ctx) => [ itemBuilder: (ctx) => [
_buildPopupMenuItem(group, context,
appLocalization(context).share_group_title, Icons.share, 4),
_buildPopupMenuItem( _buildPopupMenuItem(
groupsSnapshot.data![index], group,
context, context,
appLocalization(context) appLocalization(context).change_group_infomation_title,
.share_group_title,
Icons.share,
4),
_buildPopupMenuItem(
groupsSnapshot.data![index],
context,
appLocalization(context)
.change_group_infomation_title,
Icons.settings_backup_restore, Icons.settings_backup_restore,
2), 2),
_buildPopupMenuItem( _buildPopupMenuItem(
groupsSnapshot.data![index], group,
context, context,
appLocalization(context) appLocalization(context).delete_group_title,
.delete_group_title,
Icons.delete_forever_rounded, Icons.delete_forever_rounded,
3), 3),
], ],
icon: const Icon(Icons.more_horiz), icon: const Icon(Icons.more_horiz),
)
: const SizedBox.shrink(),
); );
},
),
);
}
},
);
} else {
return const SizedBox.shrink();
}
} }
PopupMenuItem _buildPopupMenuItem(Group group, BuildContext context, PopupMenuItem<int> _buildPopupMenuItem(Group group, BuildContext context,
String title, IconData iconData, int position) { String title, IconData iconData, int value) {
return PopupMenuItem( return PopupMenuItem<int>(
value: value,
child: Row(children: [
Icon(iconData, color: Colors.black),
const SizedBox(width: 10),
Text(title)
]),
onTap: () { onTap: () {
if (title == appLocalization(context).share_group_title) {
Future.delayed(context.lowDuration, () { Future.delayed(context.lowDuration, () {
if (title == appLocalization(context).share_group_title) {
shareGroup(context, group); shareGroup(context, group);
});
} else if (title == } else if (title ==
appLocalization(context).change_group_infomation_title) { appLocalization(context).change_group_infomation_title) {
Future.delayed(context.lowDuration, () {
createOrJoinGroupDialog( createOrJoinGroupDialog(
context, context,
interFamilyBloc, interFamilyBloc,
widget.role, role,
appLocalization(context).change_group_infomation_content, appLocalization(context).change_group_infomation_content,
appLocalization(context).group_name_title, appLocalization(context).group_name_title,
group.name!, group.name ?? '',
false, false,
group.id!, group.id ?? '',
appLocalization(context).description_group, appLocalization(context).description_group,
group.description ?? ""); group.description ?? '',
}); );
} else if (title == appLocalization(context).delete_group_title) { } else if (title == appLocalization(context).delete_group_title) {
Future.delayed(context.lowDuration, () {
showActionDialog( showActionDialog(
context, context,
widget.role, role,
interFamilyBloc, interFamilyBloc,
appLocalization(context).delete_group_title, appLocalization(context).delete_group_title,
appLocalization(context).delete_group_content, appLocalization(context).delete_group_content,
group); group,
);
}
}); });
} else {}
}, },
value: position,
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
iconData,
color: Colors.black,
),
const SizedBox(width: 10),
Text(title),
],
),
); );
} }
} }

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'groups/groups_screen.dart'; import 'groups/groups_screen.dart';
import 'groups/groups_model.dart';
import '../../bloc/inter_family_bloc.dart'; import '../../bloc/inter_family_bloc.dart';
import 'inter_family_widget.dart'; import 'inter_family_widget.dart';
import '../../product/base/bloc/base_bloc.dart'; import '../../product/base/bloc/base_bloc.dart';
@@ -25,20 +26,29 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
void initState() { void initState() {
super.initState(); super.initState();
interFamilyBloc = BlocProvider.of(context); interFamilyBloc = BlocProvider.of(context);
// fetch initial groups for the default selected tab
WidgetsBinding.instance.addPostFrameCallback((_) {
interFamilyBloc.getAllGroup(
context,
_selectedIndex == 0
? ApplicationConstants.OWNER_GROUP
: ApplicationConstants.PARTICIPANT_GROUP);
});
} }
final _widgetOptions = <Widget>[ List<Group> ownerGroups = [];
BlocProvider( List<Group> participantGroups = [];
blocBuilder: () => InterFamilyBloc(),
child: const GroupsScreen( List<Widget> get _widgetOptions => [
GroupsScreen(
role: ApplicationConstants.OWNER_GROUP, role: ApplicationConstants.OWNER_GROUP,
groups: ownerGroups,
interFamilyBloc: interFamilyBloc,
), ),
), GroupsScreen(
BlocProvider(
blocBuilder: () => InterFamilyBloc(),
child: const GroupsScreen(
role: ApplicationConstants.PARTICIPANT_GROUP, role: ApplicationConstants.PARTICIPANT_GROUP,
), groups: participantGroups,
interFamilyBloc: interFamilyBloc,
), ),
]; ];
@@ -49,6 +59,20 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
stream: interFamilyBloc.streamSelectedScreen, stream: interFamilyBloc.streamSelectedScreen,
initialData: _selectedIndex, initialData: _selectedIndex,
builder: (context, selectSnapshot) { builder: (context, selectSnapshot) {
// subscribe to groups stream and update local lists so child widgets render instantly
return StreamBuilder<List<Group>>(
stream: interFamilyBloc.streamCurrentGroups,
builder: (context, groupsSnapshot) {
if (groupsSnapshot.hasData) {
final all = groupsSnapshot.data!;
ownerGroups = all
.where((g) => g.isOwner == true && g.visibility == 'PUBLIC')
.toList();
participantGroups = all
.where((g) => g.isOwner == null && g.visibility == 'PUBLIC')
.toList();
}
// build UI below
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
actions: [ actions: [
@@ -58,35 +82,32 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
createOrJoinGroupDialog( createOrJoinGroupDialog(
context, context,
interFamilyBloc, interFamilyBloc,
selectSnapshot.data! == 0 ApplicationConstants.OWNER_GROUP,
? ApplicationConstants.OWNER_GROUP
: ApplicationConstants.PARTICIPANT_GROUP,
appLocalization(context).add_new_group, appLocalization(context).add_new_group,
appLocalization(context).group_name_title, appLocalization(context).group_name_title,
"", "",
false, false,
"", "",
"", "",
""); "",
);
} else { } else {
createOrJoinGroupDialog( createOrJoinGroupDialog(
context, context,
interFamilyBloc, interFamilyBloc,
selectSnapshot.data! == 0 ApplicationConstants.PARTICIPANT_GROUP,
? ApplicationConstants.OWNER_GROUP
: ApplicationConstants.PARTICIPANT_GROUP,
appLocalization(context).join_group, appLocalization(context).join_group,
appLocalization(context).group_id_title, appLocalization(context).group_id_title,
'', '',
true, true,
"", "",
appLocalization(context).group_name_title, appLocalization(context).group_name_title,
""); "",
);
} }
}, },
style: ElevatedButton.styleFrom( style:
shape: const CircleBorder(), ElevatedButton.styleFrom(shape: const CircleBorder()),
),
child: IconConstants.instance.getMaterialIcon(Icons.add), child: IconConstants.instance.getMaterialIcon(Icons.add),
), ),
], ],
@@ -142,6 +163,8 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
); );
}, },
); );
},
);
} }
void checkTitle(int index) { void checkTitle(int index) {
@@ -159,5 +182,11 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
interFamilyBloc.sinkSelectedScreen.add(_selectedIndex); interFamilyBloc.sinkSelectedScreen.add(_selectedIndex);
isLoading = false; isLoading = false;
interFamilyBloc.sinkIsLoading.add(isLoading); interFamilyBloc.sinkIsLoading.add(isLoading);
// fetch groups for the selected tab immediately
interFamilyBloc.getAllGroup(
context,
_selectedIndex == 0
? ApplicationConstants.OWNER_GROUP
: ApplicationConstants.PARTICIPANT_GROUP);
} }
} }

View File

@@ -7,8 +7,8 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
import 'package:sfm_app/product/shared/shared_snack_bar.dart';
import '../../product/shared/shared_snack_bar.dart';
import '../../product/services/notification_services.dart'; import '../../product/services/notification_services.dart';
import '../../product/utils/permission_handler.dart'; import '../../product/utils/permission_handler.dart';
import '../../product/permission/notification_permission.dart'; import '../../product/permission/notification_permission.dart';

View File

@@ -3,6 +3,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'show_direction_widget.dart'; import 'show_direction_widget.dart';
import 'show_nearest_place.dart'; import 'show_nearest_place.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
@@ -11,7 +12,6 @@ import '../../../bloc/map_bloc.dart';
import '../../../product/services/api_services.dart'; import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
import '../../devices/device_model.dart'; import '../../devices/device_model.dart';
onTapMarker( onTapMarker(

View File

@@ -1,12 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:maps_launcher/maps_launcher.dart'; import 'package:maps_launcher/maps_launcher.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../bloc/map_bloc.dart'; import '../../../bloc/map_bloc.dart';
showDirections( showDirections(

View File

@@ -1,9 +1,9 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../bloc/map_bloc.dart'; import '../../../bloc/map_bloc.dart';
import 'show_direction_widget.dart'; import 'show_direction_widget.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/feature/settings/sim_data/shared_sim_component.dart';
import 'shared_sim_component.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/shared/shared_loading_animation.dart'; import '../../../product/shared/shared_loading_animation.dart';
import '../../../bloc/sim_data_bloc.dart'; import '../../../bloc/sim_data_bloc.dart';

View File

@@ -1,4 +1,4 @@
// ignore_for_file: constant_identifier_names // ignore_for_file: constant_identifier_names, non_constant_identifier_names
class ApplicationConstants { class ApplicationConstants {
static const APP_NAME = "Smatec SFM"; static const APP_NAME = "Smatec SFM";

View File

@@ -1,9 +1,8 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/utils/app_logger_utils.dart';
import 'package:sfm_app/product/utils/responsive_text_utils.dart';
import '../utils/app_logger_utils.dart';
import '../utils/responsive_text_utils.dart';
import '../theme/app_theme_light.dart'; import '../theme/app_theme_light.dart';
// MEDIA // MEDIA

View File

@@ -95,7 +95,7 @@ abstract class AppLocalizations {
/// A list of this localizations delegate's supported locales. /// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[ static const List<Locale> supportedLocales = <Locale>[
Locale('en'), Locale('en'),
Locale('vi'), Locale('vi')
]; ];
/// No description provided for @description_NOTUSE. /// No description provided for @description_NOTUSE.
@@ -1623,6 +1623,5 @@ AppLocalizations lookupAppLocalizations(Locale locale) {
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue ' 'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration ' 'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.', 'that was used.');
);
} }

View File

@@ -1,5 +1,5 @@
import 'package:sfm_app/product/constant/icon/icon_constants.dart'; import '../constant/icon/icon_constants.dart';
import 'package:sfm_app/product/constant/lang/language_constants.dart'; import '../constant/lang/language_constants.dart';
class Language { class Language {
final int id; final int id;

View File

@@ -1,10 +1,10 @@
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:app_settings/app_settings.dart'; import 'package:app_settings/app_settings.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:sfm_app/product/base/widget/dialog/request_permission_dialog.dart';
import '../base/widget/dialog/request_permission_dialog.dart';
class LocationPermissionRequest { class LocationPermissionRequest {
LocationPermissionRequest._init(); LocationPermissionRequest._init();

View File

@@ -59,6 +59,5 @@ class MapServices {
log("Lỗi khi tìm đường"); log("Lỗi khi tìm đường");
return []; return [];
} }
return [];
} }
} }

View File

@@ -3,18 +3,20 @@ import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:alarm/alarm.dart'; import 'package:alarm/alarm.dart';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart' hide NotificationSettings; import 'package:firebase_messaging/firebase_messaging.dart'
hide NotificationSettings;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
import 'package:sfm_app/product/utils/app_logger_utils.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import '../utils/app_logger_utils.dart';
import '../../firebase_options.dart'; import '../../firebase_options.dart';
import '../../main.dart'; import '../../main.dart';
import 'alarm_services.dart'; import 'alarm_services.dart';
class NotificationServices { class NotificationServices {
static final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); static final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();
final FirebaseMessaging _messaging = FirebaseMessaging.instance; final FirebaseMessaging _messaging = FirebaseMessaging.instance;
AlarmServices alarmServices = AlarmServices(); AlarmServices alarmServices = AlarmServices();
@@ -25,9 +27,12 @@ class NotificationServices {
Future<void> initializeLocalNotifications() async { Future<void> initializeLocalNotifications() async {
try { try {
const AndroidInitializationSettings androidInitializationSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const AndroidInitializationSettings androidInitializationSettings =
const DarwinInitializationSettings iosInitializationSettings = DarwinInitializationSettings(); AndroidInitializationSettings('@mipmap/ic_launcher');
const InitializationSettings initializationSettings = InitializationSettings( const DarwinInitializationSettings iosInitializationSettings =
DarwinInitializationSettings();
const InitializationSettings initializationSettings =
InitializationSettings(
android: androidInitializationSettings, android: androidInitializationSettings,
iOS: iosInitializationSettings, iOS: iosInitializationSettings,
); );
@@ -35,7 +40,8 @@ class NotificationServices {
await _notificationsPlugin.initialize( await _notificationsPlugin.initialize(
initializationSettings, initializationSettings,
onDidReceiveNotificationResponse: (NotificationResponse response) { onDidReceiveNotificationResponse: (NotificationResponse response) {
dev.log("Người dùng click thông báo ở foreground với payload: ${response.payload}"); dev.log(
"Người dùng click thông báo ở foreground với payload: ${response.payload}");
handleMessage(response.payload, controller); handleMessage(response.payload, controller);
}, },
); );
@@ -62,11 +68,13 @@ class NotificationServices {
try { try {
if (Platform.isAndroid) { if (Platform.isAndroid) {
return await _notificationsPlugin return await _notificationsPlugin
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>() .resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission(); ?.requestNotificationsPermission();
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
return await _notificationsPlugin return await _notificationsPlugin
.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>() .resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(alert: true, sound: true, badge: true); ?.requestPermissions(alert: true, sound: true, badge: true);
} }
return null; return null;
@@ -84,7 +92,8 @@ class NotificationServices {
final type = message.data['type'] as String? ?? 'normal'; final type = message.data['type'] as String? ?? 'normal';
if (title == null || body == null) { if (title == null || body == null) {
dev.log('Skipping notification: missing title or body', name: 'Notification'); dev.log('Skipping notification: missing title or body',
name: 'Notification');
return; return;
} }
@@ -100,15 +109,16 @@ class NotificationServices {
const channelName = 'High Importance Notification'; const channelName = 'High Importance Notification';
const channelDescription = 'Channel description'; const channelDescription = 'Channel description';
final androidChannel = AndroidNotificationChannel( // final androidChannel = AndroidNotificationChannel(
channelId, // channelId,
channelName, // channelName,
importance: Importance.max, // importance: Importance.max,
description: channelDescription, // description: channelDescription,
); // );
final androidPlugin = _notificationsPlugin final androidPlugin =
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>(); _notificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
// Delete existing channel to prevent conflicts // Delete existing channel to prevent conflicts
await androidPlugin?.deleteNotificationChannel(channelId); await androidPlugin?.deleteNotificationChannel(channelId);
@@ -180,7 +190,8 @@ class NotificationServices {
Future<void> setupInteractMessage(PersistentTabController controller) async { Future<void> setupInteractMessage(PersistentTabController controller) async {
// Khi app terminated // Khi app terminated
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage(); RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) { if (initialMessage != null) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -201,7 +212,8 @@ class NotificationServices {
}); });
} }
Future<void> showBackgroundOrTerminateNotification(RemoteMessage message) async { Future<void> showBackgroundOrTerminateNotification(
RemoteMessage message) async {
try { try {
// Early validation of notification data // Early validation of notification data
final title = message.data['title'] as String?; final title = message.data['title'] as String?;
@@ -209,7 +221,8 @@ class NotificationServices {
final type = message.data['type'] as String? ?? 'normal'; final type = message.data['type'] as String? ?? 'normal';
if (title == null || body == null) { if (title == null || body == null) {
dev.log('Skipping notification: missing title or body', name: 'Notification'); dev.log('Skipping notification: missing title or body',
name: 'Notification');
return; return;
} }
@@ -218,7 +231,6 @@ class NotificationServices {
const channelName = 'High Importance Notification'; const channelName = 'High Importance Notification';
const channelDescription = 'Channel description'; const channelDescription = 'Channel description';
// Configure notification details // Configure notification details
final androidDetails = AndroidNotificationDetails( final androidDetails = AndroidNotificationDetails(
channelId, channelId,
@@ -274,9 +286,9 @@ Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
if (Firebase.apps.isEmpty) { if (Firebase.apps.isEmpty) {
await Firebase.initializeApp( await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform, options: DefaultFirebaseOptions.currentPlatform,
name: "sfm-notification" name: "sfm-notification");
); AppLoggerUtils.warning(
AppLoggerUtils.warning("Firebase đã được khởi tạo trong background handler"); "Firebase đã được khởi tạo trong background handler");
} else { } else {
AppLoggerUtils.warning("Firebase đã được khởi tạo trước đó"); AppLoggerUtils.warning("Firebase đã được khởi tạo trước đó");
} }

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/constant/image/image_constants.dart';
import '../constant/image/image_constants.dart';
class SharedBackground extends StatelessWidget { class SharedBackground extends StatelessWidget {
final Widget child; final Widget child;

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
import '../constant/icon/icon_constants.dart';
const int _kDuration = 300; const int _kDuration = 300;
const double _kWidth = 60; const double _kWidth = 60;

View File

@@ -1,8 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/extension/context_extension.dart';
import 'package:top_snackbar_flutter/custom_snack_bar.dart'; import 'package:top_snackbar_flutter/custom_snack_bar.dart';
import 'package:top_snackbar_flutter/top_snack_bar.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart';
import '../extension/context_extension.dart';
void showNoIconTopSnackBar(BuildContext context, String message, void showNoIconTopSnackBar(BuildContext context, String message,
Color backgroundColor, Color textColor) { Color backgroundColor, Color textColor) {
if (!context.mounted) return; if (!context.mounted) return;

View File

@@ -1,7 +1,7 @@
import 'package:flex_color_scheme/flex_color_scheme.dart'; import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/theme/app_theme.dart';
import 'app_theme.dart';
class AppThemeDark extends AppTheme { class AppThemeDark extends AppTheme {
static AppThemeDark? _instance; static AppThemeDark? _instance;
static AppThemeDark get instance { static AppThemeDark get instance {

View File

@@ -1,11 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/feature/device_log/device_logs_model.dart';
import 'package:sfm_app/product/services/api_services.dart';
import 'package:sfm_app/product/services/language_services.dart';
import 'package:sfm_app/product/shared/model/district_model.dart';
import 'package:sfm_app/product/shared/model/province_model.dart';
import '../../feature/device_log/device_logs_model.dart';
import '../services/api_services.dart';
import '../services/language_services.dart';
import '../shared/model/district_model.dart';
import '../shared/model/province_model.dart';
import '../../feature/devices/device_model.dart'; import '../../feature/devices/device_model.dart';
import '../constant/icon/icon_constants.dart'; import '../constant/icon/icon_constants.dart';
import '../shared/model/ward_model.dart'; import '../shared/model/ward_model.dart';

View File

@@ -23,7 +23,8 @@ Future<LocationPermission> checkAndRequestPermission() async {
} }
if (permission == LocationPermission.deniedForever) { if (permission == LocationPermission.deniedForever) {
print('Quyền truy cập vị trí bị từ chối vĩnh viễn. Vui lòng cấp quyền trong cài đặt.'); print(
'Quyền truy cập vị trí bị từ chối vĩnh viễn. Vui lòng cấp quyền trong cài đặt.');
return permission; return permission;
} }
@@ -56,7 +57,8 @@ Future<void> requestLocationPermission() async {
LocationPermission permission = await checkAndRequestPermission(); LocationPermission permission = await checkAndRequestPermission();
// Bước 3: Nếu quyền được cấp, lấy vị trí // Bước 3: Nếu quyền được cấp, lấy vị trí
if (permission == LocationPermission.whileInUse || permission == LocationPermission.always) { if (permission == LocationPermission.whileInUse ||
permission == LocationPermission.always) {
await getCurrentPosition(); await getCurrentPosition();
} }
} }

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_barcode_scanner_plus/flutter_barcode_scanner_plus.dart'; import 'package:flutter_barcode_scanner_plus/flutter_barcode_scanner_plus.dart';
import '../services/language_services.dart'; import '../services/language_services.dart';
class QRScanUtils { class QRScanUtils {

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../constant/status_code/status_code_constants.dart'; import '../constant/status_code/status_code_constants.dart';
import '../shared/shared_snack_bar.dart'; import '../shared/shared_snack_bar.dart';

View File

@@ -1,4 +1,5 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import '../extension/context_extension.dart'; import '../extension/context_extension.dart';
class ResponsiveText{ class ResponsiveText{