chore(group): fix delay show group when switch and convert to relative import
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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") {
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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});
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.');
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -59,6 +59,5 @@ class MapServices {
|
|||||||
log("Lỗi khi tìm đường");
|
log("Lỗi khi tìm đường");
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 đó");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
@@ -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{
|
||||||
|
|||||||
Reference in New Issue
Block a user