Fix bugs in app

This commit is contained in:
anhtunz
2025-03-31 10:42:42 +07:00
parent ba9a3d95f6
commit b830d76d23
37 changed files with 299 additions and 572 deletions

View File

@@ -89,7 +89,7 @@ class DevicesManagerBloc extends BlocBase {
if (state != -2) {
body =
await apiServices.getOwnerDevieByState({"state": state.toString()});
await apiServices.getOwnerDeviceByState({"state": state.toString()});
} else {
body = await apiServices.getOwnerDevices();
}

View File

@@ -6,78 +6,21 @@ import '../product/base/bloc/base_bloc.dart';
class HomeBloc extends BlocBase {
final allDevicesAlias = StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkAllDevicesAlias =>
allDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamAllDevicesAlias =>
allDevicesAlias.stream;
final allDevicesAliasMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast();
StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasMap =>
allDevicesAliasMap.sink;
Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasMap =>
allDevicesAliasMap.stream;
final onlineDevicesAlias =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkOnlineDevicesAlias =>
onlineDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamOnlineDevicesAlias =>
onlineDevicesAlias.stream;
final allDevicesAliasJoinedMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast();
StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasJoinedMap =>
allDevicesAliasJoinedMap.sink;
Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasJoinedMap =>
allDevicesAliasJoinedMap.stream;
final offlineDevicesAlias =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkOfflineDevicesAlias =>
offlineDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamOfflineDevicesAlias =>
offlineDevicesAlias.stream;
final warningDevicesAlias =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkWarningDevicesAlias =>
warningDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamWarningDevicesAlias =>
warningDevicesAlias.stream;
final notUseDevicesAlias =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkNotUseDevicesAlias =>
notUseDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamNotUseDevicesAlias =>
notUseDevicesAlias.stream;
final allDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkAllDevicesAliasJoined =>
allDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamAllDevicesAliasJoined =>
allDevicesAliasJoined.stream;
final onlineDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkOnlineDevicesAliasJoined =>
onlineDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamOnlineDevicesAliasJoined =>
onlineDevicesAliasJoined.stream;
final offlineDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkOfflineDevicesAliasJoined =>
offlineDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamOfflineDevicesAliasJoined =>
offlineDevicesAliasJoined.stream;
final warningDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkWarningDevicesAliasJoined =>
warningDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamWarningDevicesAliasJoined =>
warningDevicesAliasJoined.stream;
final notUseDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkNotUseDevicesAliasJoined =>
notUseDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamNotUseDevicesAliasJoined =>
notUseDevicesAliasJoined.stream;
final countNotitication = StreamController<int>.broadcast();
StreamSink<int> get sinkCountNotitication => countNotitication.sink;
Stream<int> get streamCountNotitication => countNotitication.stream;
final countNotification = StreamController<int>.broadcast();
StreamSink<int> get sinkCountNotification => countNotification.sink;
Stream<int> get streamCountNotification => countNotification.stream;
final ownerDevicesStatus =
StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
@@ -86,7 +29,6 @@ class HomeBloc extends BlocBase {
Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus =>
ownerDevicesStatus.stream;
@override
void dispose() {}
}

View File

@@ -13,7 +13,7 @@ import '../../../../product/constant/enums/local_keys_enums.dart';
import '../../../../product/services/api_services.dart';
import '../../../../product/shared/shared_snack_bar.dart';
import '../../../../product/constant/icon/icon_constants.dart';
import '../../../../product/extention/context_extention.dart';
import '../../../../product/extension/context_extension.dart';
import '../../../../product/constant/image/image_constants.dart';
import '../../../../product/services/language_services.dart';
import '../../../../bloc/login_bloc.dart';

View File

@@ -1,7 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart';
import '../../bloc/bell_bloc.dart';
import '../../product/base/bloc/base_bloc.dart';

View File

@@ -7,7 +7,7 @@ import 'widgets/tag_widget.dart';
import '../devices/device_model.dart';
import '../../bloc/device_logs_bloc.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart';
import '../../product/shared/shared_snack_bar.dart';
import '../../product/utils/date_time_utils.dart';

View File

@@ -7,7 +7,7 @@ import '../../product/constant/enums/role_enums.dart';
import '../../product/services/api_services.dart';
import '../../product/utils/qr_utils.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart';
addNewDevice(BuildContext context, String role) async {

View File

@@ -2,14 +2,14 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:sfm_app/feature/device_log/device_logs_model.dart';
import 'package:sfm_app/product/constant/image/image_constants.dart';
import 'package:sfm_app/product/shared/shared_line_chart.dart';
import 'package:simple_ripple_animation/simple_ripple_animation.dart';
import 'package:sfm_app/feature/device_log/device_logs_model.dart';
import '../../../product/constant/image/image_constants.dart';
import '../../../product/shared/shared_line_chart.dart';
import '../../../product/shared/shared_curve.dart';
import '../device_model.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart';
@@ -18,7 +18,9 @@ import '../../../bloc/device_detail_bloc.dart';
class DetailDeviceScreen extends StatefulWidget {
const DetailDeviceScreen({super.key, required this.thingID});
final String thingID;
@override
State<DetailDeviceScreen> createState() => _DetailDeviceScreenState();
}
@@ -44,18 +46,29 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
late DetailDeviceBloc detailDeviceBloc;
Completer<GoogleMapController> controller = Completer();
CameraPosition initialCamera = const CameraPosition(
target: LatLng(20.966048511844402, 105.74977710843086), zoom: 15);
CameraPosition initialCamera =
const CameraPosition(target: LatLng(20.966048511844402, 105.74977710843086), zoom: 15);
Timer? getDeviceDetailTimer;
@override
void initState() {
super.initState();
detailDeviceBloc = BlocProvider.of(context);
const duration = Duration(seconds: 10);
getDeviceDetailTimer = Timer.periodic(
duration,
(Timer t) => detailDeviceBloc.getDeviceDetail(
context,
widget.thingID,
controller,
),
);
}
TextStyle textstyle = const TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
);
@override
void dispose() {
getDeviceDetailTimer?.cancel();
}
BoxDecoration boxDecoration = BoxDecoration(
borderRadius: BorderRadius.circular(15),
@@ -105,8 +118,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
children: [
Positioned.fill(
child: Image.asset(
ImageConstants.instance
.getImage('smoke-detector'),
ImageConstants.instance.getImage('smoke-detector'),
fit: BoxFit.fill,
),
),
@@ -116,11 +128,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
width: 400,
// color: Colors.blueAccent,
alignment: Alignment.centerRight,
margin: const EdgeInsets.fromLTRB(
0, 0, 0, 50),
margin: const EdgeInsets.fromLTRB(0, 0, 0, 50),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(),
Text(
@@ -146,14 +156,13 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
height: context.dynamicHeight(0.08),
width: context.dynamicWidth(0.5),
decoration: BoxDecoration(
color: DeviceUtils.instance.getTableRowColor(
deviceSnapshot.data?.state ?? 3),
color: DeviceUtils.instance
.getTableRowColor(deviceSnapshot.data?.state ?? 3),
borderRadius: BorderRadius.circular(50),
),
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
height: context.mediumValue,
@@ -161,18 +170,17 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: deviceSnapshot.data?.state == 1
? RippleAnimation(
color: Colors.red,
delay: context
.dynamicMilliSecondDuration(
delay: context.dynamicMilliSecondDuration(
800,
),
repeat: true,
minRadius: 10,
ripplesCount: 5,
duration: context
.dynamicMilliSecondDuration(
duration: context.dynamicMilliSecondDuration(
1800,
),
child: CircleAvatar(
backgroundColor: Colors.transparent,
minRadius: context.mediumValue,
maxRadius: context.mediumValue,
backgroundImage: AssetImage(
@@ -183,9 +191,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
),
)
: CircleAvatar(
backgroundColor: DeviceUtils
.instance
.getTableRowColor(
backgroundColor:
DeviceUtils.instance.getTableRowColor(
deviceSnapshot.data?.state ?? 3,
),
minRadius: context.mediumValue,
@@ -230,12 +237,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Padding(
padding: context.paddingLow,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
appLocalization(context)
@@ -254,8 +259,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
sensorSnapshot.data!['sensorCsq'],
),
size: 30,
color: DeviceUtils.instance
.getSignalIconColor(
color: DeviceUtils.instance.getSignalIconColor(
context,
sensorSnapshot.data!['sensorCsq'],
),
@@ -264,10 +268,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: context.dynamicHeight(0.09),
@@ -275,11 +277,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Text(
sensorSnapshot.data!['sensorCsq'],
style: TextStyle(
color: DeviceUtils.instance
.getSignalIconColor(
color: DeviceUtils.instance.getSignalIconColor(
context,
sensorSnapshot
.data!['sensorCsq'],
sensorSnapshot.data!['sensorCsq'],
),
fontSize: 40,
fontWeight: FontWeight.w900,
@@ -299,12 +299,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Padding(
padding: context.paddingLow,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
appLocalization(context)
@@ -318,18 +316,14 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
height: context.dynamicWidth(0.12),
width: context.dynamicWidth(0.12),
child: Image.asset(
DeviceUtils.instance
.getDeviceBatteryImg(
DeviceUtils.instance.getDeviceBatteryImg(
int.parse(
sensorSnapshot
.data!['sensorBattery'],
sensorSnapshot.data!['sensorBattery'],
),
),
color: DeviceUtils.instance
.getDeviceBatteryColor(
color: DeviceUtils.instance.getDeviceBatteryColor(
int.parse(
sensorSnapshot
.data!['sensorBattery'],
sensorSnapshot.data!['sensorBattery'],
),
),
),
@@ -337,23 +331,18 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: context.dynamicHeight(0.09),
alignment: Alignment.centerLeft,
child: Text(
sensorSnapshot
.data!['sensorBattery'],
sensorSnapshot.data!['sensorBattery'],
style: TextStyle(
color: DeviceUtils.instance
.getDeviceBatteryColor(
color: DeviceUtils.instance.getDeviceBatteryColor(
int.parse(
sensorSnapshot
.data!['sensorBattery'],
sensorSnapshot.data!['sensorBattery'],
),
),
fontSize: 50,
@@ -371,11 +360,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Text(
'%',
style: TextStyle(
color: DeviceUtils.instance
.getDeviceBatteryColor(
color: DeviceUtils.instance.getDeviceBatteryColor(
int.parse(
sensorSnapshot
.data!['sensorBattery'],
sensorSnapshot.data!['sensorBattery'],
),
),
fontSize: 30,
@@ -403,8 +390,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
appLocalization(context)
@@ -419,11 +405,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
width: context.dynamicWidth(0.12),
child: Image.asset(
'assets/icons/temperature.png',
color: DeviceUtils.instance
.getDeviceTempColor(
color: DeviceUtils.instance.getDeviceTempColor(
int.parse(
sensorSnapshot
.data!['sensorTemp'],
sensorSnapshot.data!['sensorTemp'],
),
),
),
@@ -439,28 +423,20 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
width: double.infinity,
height: 20,
decoration: BoxDecoration(
color: Colors.grey
.withValues(alpha: 0.3),
borderRadius:
BorderRadius.circular(10),
color: Colors.grey.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(10),
),
),
LayoutBuilder(
builder: (context, constraints) =>
Container(
builder: (context, constraints) => Container(
width: constraints.maxWidth *
(int.parse(sensorSnapshot
.data!['sensorTemp']) /
75),
(int.parse(sensorSnapshot.data!['sensorTemp']) / 75),
height: 20,
decoration: BoxDecoration(
color: DeviceUtils.instance
.getDeviceTempColor(
int.parse(sensorSnapshot
.data!['sensorTemp']),
color: DeviceUtils.instance.getDeviceTempColor(
int.parse(sensorSnapshot.data!['sensorTemp']),
),
borderRadius:
BorderRadius.circular(10),
borderRadius: BorderRadius.circular(10),
),
),
)
@@ -470,17 +446,14 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
height: 5,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${sensorSnapshot.data!['sensorTemp']} °C",
style: TextStyle(
color: DeviceUtils.instance
.getDeviceTempColor(
color: DeviceUtils.instance.getDeviceTempColor(
int.parse(
sensorSnapshot
.data!['sensorTemp'],
sensorSnapshot.data!['sensorTemp'],
),
),
fontSize: 30,
@@ -507,8 +480,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
appLocalization(context)
.paginated_data_table_column_devicePower,
appLocalization(context).paginated_data_table_column_devicePower,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
@@ -532,8 +504,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
stream: detailDeviceBloc.streamSensorTemps,
builder: (context, sensorTempsSnapshot) {
if (sensorTempsSnapshot.data == null) {
detailDeviceBloc
.getNearerSensorValue(widget.thingID);
detailDeviceBloc.getNearerSensorValue(widget.thingID);
return const AspectRatio(
aspectRatio: 3,
child: Center(
@@ -552,8 +523,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Container(
margin: context.paddingLow,
child: sharedLineChart(
appLocalization(context)
.detail_device_volt_message,
appLocalization(context).detail_device_volt_message,
sensorTempsSnapshot.data ?? [],
),
),
@@ -580,48 +550,33 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
Radius.circular(15),
),
),
child: deviceSnapshot
.data!.settings!.latitude !=
""
child: deviceSnapshot.data!.settings!.latitude != ""
? StreamBuilder<String>(
stream: detailDeviceBloc
.streamDeviceLocation,
stream: detailDeviceBloc.streamDeviceLocation,
builder: (context, locationSnapshot) {
if (locationSnapshot.data == null) {
detailDeviceBloc.findLocation(
context,
deviceSnapshot
.data!.areaPath!);
context, deviceSnapshot.data!.areaPath!);
}
return GoogleMap(
initialCameraPosition:
initialCamera,
initialCameraPosition: initialCamera,
mapType: MapType.normal,
markers: {
Marker(
infoWindow: InfoWindow(
title:
locationSnapshot.data ??
"",
title: locationSnapshot.data ?? "",
),
markerId: MarkerId(
deviceSnapshot
.data!.thingId!),
markerId: MarkerId(deviceSnapshot.data!.thingId!),
position: LatLng(
double.parse(deviceSnapshot
.data!
.settings!
.latitude!),
double.parse(deviceSnapshot
.data!
.settings!
.longitude!),
double.parse(
deviceSnapshot.data!.settings!.latitude!),
double.parse(
deviceSnapshot.data!.settings!.longitude!),
),
),
},
onMapCreated: (mapcontroller) {
controller
.complete(mapcontroller);
controller.complete(mapcontroller);
},
mapToolbarEnabled: false,
zoomControlsEnabled: false,
@@ -636,8 +591,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
),
),
Text(
appLocalization(context)
.device_update_location,
appLocalization(context).device_update_location,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,

View File

@@ -5,7 +5,7 @@ import '../device_model.dart';
import '../../../bloc/device_update_bloc.dart';
import 'map_dialog.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';

View File

@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' ;
import '../../../bloc/device_update_bloc.dart';
import '../../../product/constant/app/app_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import '../../../product/shared/find_location_maps/shared_map_search_location.dart';

View File

@@ -13,7 +13,7 @@ import '../../product/base/bloc/base_bloc.dart';
import '../../product/constant/enums/app_route_enums.dart';
import '../../product/constant/enums/role_enums.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/api_services.dart';
import '../../product/services/language_services.dart';
import '../../product/utils/device_utils.dart';

View File

@@ -9,7 +9,7 @@ import '../../product/utils/device_utils.dart';
import 'device_alias_model.dart';
import 'shared/overview_card.dart';
import '../settings/device_notification_settings/device_notification_settings_model.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/api_services.dart';
import '../../product/services/language_services.dart';
import '../../bloc/home_bloc.dart';
@@ -25,18 +25,9 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> {
late HomeBloc homeBloc;
APIServices apiServices = APIServices();
Map<String, List<DeviceWithAlias>> allDevicesAliasMap = {};
Map<String, List<DeviceWithAlias>> allDevicesAliasJoinedMap = {};
List<DeviceWithAlias> devices = [];
List<DeviceWithAlias> allDevicesAlias = [];
List<DeviceWithAlias> onlineDevicesAlias = [];
List<DeviceWithAlias> offlineDevicesAlias = [];
List<DeviceWithAlias> warningDevicesAlias = [];
List<DeviceWithAlias> notUseDevicesAlias = [];
List<DeviceWithAlias> allDevicesAliasJoined = [];
List<DeviceWithAlias> onlineDevicesAliasJoined = [];
List<DeviceWithAlias> offlineDevicesAliasJoined = [];
List<DeviceWithAlias> warningDevicesAliasJoined = [];
List<DeviceWithAlias> notUseDevicesAliasJoined = [];
bool isFunctionCall = false;
Timer? getAllDevicesTimer;
int notificationCount = 0;
@@ -49,8 +40,7 @@ class _HomeScreenState extends State<HomeScreen> {
homeBloc = BlocProvider.of(context);
getOwnerAndJoinedDevices();
const duration = Duration(seconds: 10);
getAllDevicesTimer =
Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices());
getAllDevicesTimer = Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices());
}
@override
@@ -75,7 +65,7 @@ class _HomeScreenState extends State<HomeScreen> {
),
SizedBox(width: context.lowValue),
StreamBuilder<int>(
stream: homeBloc.streamCountNotitication,
stream: homeBloc.streamCountNotification,
builder: (context, countSnapshot) {
return Text(
"(${countSnapshot.data ?? 0})",
@@ -91,8 +81,7 @@ class _HomeScreenState extends State<HomeScreen> {
child: StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamOwnerDevicesStatus,
builder: (context, snapshot) {
if (snapshot.data?['state'] != null ||
snapshot.data?['battery'] != null) {
if (snapshot.data?['state'] != null || snapshot.data?['battery'] != null) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -101,8 +90,7 @@ class _HomeScreenState extends State<HomeScreen> {
...snapshot.data!['state']!
.map(
(item) => FutureBuilder<Widget>(
future: warningCard(
context, apiServices, item),
future: warningCard(context, apiServices, item),
builder: (context, warningCardSnapshot) {
if (warningCardSnapshot.hasData) {
return ConstrainedBox(
@@ -124,11 +112,7 @@ class _HomeScreenState extends State<HomeScreen> {
.map(
(batteryItem) => FutureBuilder<Widget>(
future: notificationCard(
context,
"lowBattery",
"Cảnh báo pin yếu",
batteryItem
),
context, "lowBattery", appLocalization(context).low_battery_message, batteryItem),
builder: (context, warningCardSnapshot) {
if (warningCardSnapshot.hasData) {
return ConstrainedBox(
@@ -160,8 +144,7 @@ class _HomeScreenState extends State<HomeScreen> {
),
SizedBox(width: context.lowValue),
Text(
appLocalization(context)
.notification_description,
appLocalization(context).notification_description,
maxLines: 2,
overflow: TextOverflow.ellipsis,
softWrap: true,
@@ -176,85 +159,47 @@ class _HomeScreenState extends State<HomeScreen> {
),
),
),
StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamAllDevicesAlias,
initialData: allDevicesAlias,
builder: (context, allDeviceSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamOnlineDevicesAlias,
initialData: onlineDevicesAlias,
builder: (context, onlineDeviceSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamOfflineDevicesAlias,
initialData: offlineDevicesAlias,
builder: (context, deviceDashboardSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamWarningDevicesAlias,
initialData: warningDevicesAlias,
builder: (context, warningDeviceSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamNotUseDevicesAlias,
initialData: notUseDevicesAlias,
builder: (context, notUseSnapshot) {
return OverviewCard(
isOwner: true,
total: allDeviceSnapshot.data!.length,
active: onlineDeviceSnapshot.data!.length,
inactive:
deviceDashboardSnapshot.data!.length,
warning: warningDeviceSnapshot.data!.length,
unused: notUseSnapshot.data!.length,
);
},
);
},
);
},
);
},
);
},
),
StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamAllDevicesAliasMap,
builder: (context, allDevicesAliasMapSnapshot) {
if (!allDevicesAliasMapSnapshot.hasData ||
allDevicesAliasMapSnapshot.data == null) {
return const Center(child: CircularProgressIndicator());
}
final data = allDevicesAliasMapSnapshot.data!;
return OverviewCard(
isOwner: true,
total: data['all']?.length ?? 0,
active: data['online']?.length ?? 0,
inactive: data['offline']?.length ?? 0,
warning: data['warn']?.length ?? 0,
unused: data['not-use']?.length ?? 0);
}),
SizedBox(height: context.lowValue),
StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamAllDevicesAliasJoined,
initialData: allDevicesAliasJoined,
builder: (context, allDeviceSnapshot) {
if (allDeviceSnapshot.data?.isEmpty ?? true) {
StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamAllDevicesAliasJoinedMap,
builder: (context, allDevicesAliasJoinedMapSnapshot) {
if (!allDevicesAliasJoinedMapSnapshot.hasData ||
allDevicesAliasJoinedMapSnapshot.data == null) {
return const Center(child: CircularProgressIndicator());
}
final data = allDevicesAliasJoinedMapSnapshot.data!;
final total = data['all']?.length ?? 0;
final active = data['online']?.length ?? 0;
final inactive = data['offline']?.length ?? 0;
final warning = data['warn']?.length ?? 0;
final unused = data['not-use']?.length ?? 0;
if (total == 0 && active == 0 && inactive == 0 && warning == 0 && unused == 0) {
return const SizedBox.shrink();
}
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamOnlineDevicesAliasJoined,
initialData: onlineDevicesAliasJoined,
builder: (context, onlineDeviceSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamOfflineDevicesAliasJoined,
initialData: offlineDevicesAliasJoined,
builder: (context, deviceDashboardSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamWarningDevicesAliasJoined,
initialData: warningDevicesAliasJoined,
builder: (context, warningDeviceSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamNotUseDevicesAliasJoined,
initialData: notUseDevicesAliasJoined,
builder: (context, notUseSnapshot) {
return OverviewCard(
isOwner: false,
total: allDeviceSnapshot.data!.length,
active: onlineDeviceSnapshot.data!.length,
inactive:
deviceDashboardSnapshot.data!.length,
warning: warningDeviceSnapshot.data!.length,
unused: notUseSnapshot.data!.length,
);
},
);
},
);
},
);
},
return OverviewCard(
isOwner: false,
total: total,
active: active,
inactive: inactive,
warning: warning,
unused: unused,
);
},
),
@@ -271,8 +216,8 @@ class _HomeScreenState extends State<HomeScreen> {
List<dynamic> result = data["items"];
devices = DeviceWithAlias.fromJsonDynamicList(result);
getOwnerDeviceState(devices);
getDevicesStatusAlias(devices);
checkSettingdevice(devices);
checkSettingDevice(devices);
getDeviceStatusAliasMap(devices);
}
void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async {
@@ -282,23 +227,21 @@ class _HomeScreenState extends State<HomeScreen> {
ownerDevices.add(device);
}
}
if (ownerDevicesState.isEmpty ||
ownerDevicesState.length < devices.length) {
if (ownerDevicesState.isEmpty || ownerDevicesState.length < devices.length) {
ownerDevicesState.clear();
ownerDevicesStatus.clear();
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
int count = 0;
for (var device in ownerDevices) {
Map<String, dynamic> sensorMap = DeviceUtils.instance
.getDeviceSensors(context, device.status?.sensors ?? []);
Map<String, dynamic> sensorMap =
DeviceUtils.instance.getDeviceSensors(context, device.status?.sensors ?? []);
if (device.state == 1 || device.state == 3) {
ownerDevicesStatus["state"] ??= [];
ownerDevicesStatus["state"]!.add(device);
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
count++;
}
if (sensorMap['sensorBattery'] !=
appLocalization(context).no_data_message) {
if (sensorMap['sensorBattery'] != appLocalization(context).no_data_message) {
if (double.parse(sensorMap['sensorBattery']) <= 20) {
ownerDevicesStatus['battery'] ??= [];
ownerDevicesStatus['battery']!.add(device);
@@ -307,63 +250,61 @@ class _HomeScreenState extends State<HomeScreen> {
}
}
notificationCount = count;
homeBloc.sinkCountNotitication.add(notificationCount);
homeBloc.sinkCountNotification.add(notificationCount);
}
}
}
void getDevicesStatusAlias(List<DeviceWithAlias> devices) async {
clearAllDeviceStatusAlias();
void getDeviceStatusAliasMap(List<DeviceWithAlias> devices) {
allDevicesAliasMap.clear();
allDevicesAliasJoinedMap.clear();
for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) {
allDevicesAliasMap[key] = [];
allDevicesAliasJoinedMap[key] = [];
}
for (DeviceWithAlias device in devices) {
if (device.isOwner == true) {
allDevicesAlias.add(device);
if (device.state! == 0 || device.state! == 1) {
onlineDevicesAlias.add(device);
homeBloc.sinkOnlineDevicesAlias.add(onlineDevicesAlias);
allDevicesAliasMap['all']!.add(device);
if (device.state == 0 || device.state == 1) {
allDevicesAliasMap['online']!.add(device);
}
if (device.state! == -1) {
offlineDevicesAlias.add(device);
homeBloc.sinkOfflineDevicesAlias.add(offlineDevicesAlias);
if (device.state == -1) {
allDevicesAliasMap['offline']!.add(device);
}
if (device.state! == 1) {
warningDevicesAlias.add(device);
homeBloc.sinkWarningDevicesAlias.add(warningDevicesAlias);
if (device.state == 1) {
allDevicesAliasMap['warning']!.add(device);
}
if (device.state! == -2) {
notUseDevicesAlias.add(device);
homeBloc.sinkNotUseDevicesAlias.add(notUseDevicesAlias);
if (device.state == -2) {
allDevicesAliasMap['not-use']!.add(device);
}
} else {
allDevicesAliasJoined.add(device);
if (device.state! == 0 || device.state! == 1) {
onlineDevicesAliasJoined.add(device);
homeBloc.sinkOnlineDevicesAliasJoined.add(onlineDevicesAliasJoined);
allDevicesAliasJoinedMap['all']!.add(device);
if (device.state == 0 || device.state == 1) {
allDevicesAliasJoinedMap['online']!.add(device);
}
if (device.state! == -1) {
offlineDevicesAliasJoined.add(device);
homeBloc.sinkOfflineDevicesAliasJoined.add(offlineDevicesAliasJoined);
if (device.state == -1) {
allDevicesAliasJoinedMap['offline']!.add(device);
}
if (device.state! == 1) {
warningDevicesAliasJoined.add(device);
homeBloc.sinkWarningDevicesAliasJoined.add(warningDevicesAliasJoined);
if (device.state == 1) {
allDevicesAliasJoinedMap['warning']!.add(device);
}
if (device.state! == -2) {
notUseDevicesAliasJoined.add(device);
homeBloc.sinkNotUseDevicesAliasJoined.add(notUseDevicesAliasJoined);
if (device.state == -2) {
allDevicesAliasJoinedMap['not-use']!.add(device);
}
}
}
// checkSettingdevice(allDevicesAliasJoined);
homeBloc.sinkAllDevicesAlias.add(allDevicesAlias);
homeBloc.sinkAllDevicesAliasJoined.add(allDevicesAliasJoined);
homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap);
homeBloc.sinkAllDevicesAliasJoinedMap.add(allDevicesAliasJoinedMap);
}
void checkSettingdevice(List<DeviceWithAlias> devices) async {
void checkSettingDevice(List<DeviceWithAlias> devices) async {
if (isFunctionCall) {
log("Ham check setting da duoc goi");
} else {
String? response =
await apiServices.getAllSettingsNotificationOfDevices();
String? response = await apiServices.getAllSettingsNotificationOfDevices();
if (response != "") {
final data = jsonDecode(response);
final result = data['data'];
@@ -371,13 +312,11 @@ class _HomeScreenState extends State<HomeScreen> {
List<DeviceNotificationSettings> list =
DeviceNotificationSettings.mapFromJson(result).values.toList();
// log("List: $list");
Set<String> thingIdsInList =
list.map((device) => device.thingId!).toSet();
Set<String> thingIdsInList = list.map((device) => device.thingId!).toSet();
for (var device in devices) {
if (!thingIdsInList.contains(device.thingId)) {
log("Device with Thing ID ${device.thingId} is not in the notification settings list.");
await apiServices.setupDeviceNotification(
device.thingId!, device.name!);
await apiServices.setupDeviceNotification(device.thingId!, device.name!);
} else {
log("All devices are in the notification settings list.");
}
@@ -388,27 +327,4 @@ class _HomeScreenState extends State<HomeScreen> {
}
isFunctionCall = true;
}
void clearAllDeviceStatusAlias() {
allDevicesAlias.clear();
homeBloc.sinkAllDevicesAlias.add(allDevicesAlias);
onlineDevicesAlias.clear();
homeBloc.sinkOnlineDevicesAlias.add(onlineDevicesAlias);
offlineDevicesAlias.clear();
homeBloc.sinkOfflineDevicesAlias.add(offlineDevicesAlias);
warningDevicesAlias.clear();
homeBloc.sinkWarningDevicesAlias.add(warningDevicesAlias);
notUseDevicesAlias.clear();
homeBloc.sinkNotUseDevicesAlias.add(notUseDevicesAlias);
allDevicesAliasJoined.clear();
homeBloc.sinkAllDevicesAliasJoined.add(allDevicesAliasJoined);
onlineDevicesAliasJoined.clear();
homeBloc.sinkOnlineDevicesAliasJoined.add(onlineDevicesAliasJoined);
offlineDevicesAliasJoined.clear();
homeBloc.sinkOfflineDevicesAliasJoined.add(offlineDevicesAliasJoined);
warningDevicesAliasJoined.clear();
homeBloc.sinkWarningDevicesAliasJoined.add(warningDevicesAliasJoined);
notUseDevicesAliasJoined.clear();
homeBloc.sinkNotUseDevicesAliasJoined.add(notUseDevicesAliasJoined);
}
}

View File

@@ -6,7 +6,7 @@ import 'package:intl/intl.dart';
import 'package:sfm_app/feature/home/device_alias_model.dart';
import '../../../product/constant/enums/app_route_enums.dart';
import '../../../product/constant/image/image_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart';

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:sfm_app/feature/home/shared/status_card.dart';
import 'package:sfm_app/product/extention/context_extention.dart';
import 'package:sfm_app/product/services/language_services.dart';
import 'status_card.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
class OverviewCard extends StatelessWidget {
final bool isOwner;

View File

@@ -7,7 +7,7 @@ import 'package:badges/badges.dart' as badges;
import '../device_alias_model.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/constant/image/image_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart';

View File

@@ -1,12 +1,14 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'package:flutter/material.dart';
import '../../../bloc/group_detail_bloc.dart';
import 'group_detail_model.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/constant/app/app_constants.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart';
@@ -25,10 +27,22 @@ class DetailGroupScreen extends StatefulWidget {
class _DetailGroupScreenState extends State<DetailGroupScreen> {
late DetailGroupBloc detailGroupBloc;
final scaffoldKey = GlobalKey<ScaffoldState>();
Timer? getGroupDetailTimer;
@override
void initState() {
super.initState();
detailGroupBloc = BlocProvider.of(context);
const duration = Duration(seconds: 10);
getGroupDetailTimer = Timer.periodic(
duration,
(Timer t) => detailGroupBloc.getGroupDetail(widget.group),
);
}
@override
void dispose() {
getGroupDetailTimer?.cancel();
}
@override

View File

@@ -1,5 +1,7 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
@@ -10,26 +12,38 @@ import '../inter_family_widget.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/constant/app/app_constants.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import 'groups_widget.dart';
class GroupsScreen extends StatefulWidget {
const GroupsScreen({super.key, required this.role});
final String role;
@override
State<GroupsScreen> createState() => _GroupsScreenState();
}
class _GroupsScreenState extends State<GroupsScreen> {
late InterFamilyBloc interFamilyBloc;
Timer? getAllGroupsTimer;
@override
void initState() {
super.initState();
interFamilyBloc = BlocProvider.of(context);
// interFamilyBloc.getAllGroup(widget.role);
const duration = Duration(seconds: 10);
getAllGroupsTimer = Timer.periodic(
duration,
(Timer t) => interFamilyBloc.getAllGroup(widget.role),
);
}
@override
void dispose() {
getAllGroupsTimer?.cancel();
}
@override
@@ -51,56 +65,44 @@ class _GroupsScreenState extends State<GroupsScreen> {
return ListTile(
onTap: () {
context.pushNamed(AppRoutes.GROUP_DETAIL.name,
pathParameters: {
"groupId": groupsSnapshot.data![index].id!
},
pathParameters: {"groupId": groupsSnapshot.data![index].id!},
extra: widget.role);
},
leading: IconConstants.instance
.getMaterialIcon(Icons.diversity_2),
leading: IconConstants.instance.getMaterialIcon(Icons.diversity_2),
title: Text(
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(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0),
),
),
itemBuilder: (ctx) => [
_buildPopupMenuItem(
groupsSnapshot.data![index],
context,
appLocalization(context)
.share_group_title,
Icons.share,
4),
_buildPopupMenuItem(
groupsSnapshot.data![index],
context,
appLocalization(context)
.change_group_infomation_title,
Icons.settings_backup_restore,
2),
_buildPopupMenuItem(
groupsSnapshot.data![index],
context,
appLocalization(context)
.delete_group_title,
Icons.delete_forever_rounded,
3),
],
icon: const Icon(Icons.more_horiz),
)
: const SizedBox.shrink(),
subtitle: Text(groupsSnapshot.data![index].description ?? ""),
trailing: widget.role == ApplicationConstants.OWNER_GROUP
? PopupMenuButton(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0),
),
),
itemBuilder: (ctx) => [
_buildPopupMenuItem(groupsSnapshot.data![index], context,
appLocalization(context).share_group_title, Icons.share, 4),
_buildPopupMenuItem(
groupsSnapshot.data![index],
context,
appLocalization(context).change_group_infomation_title,
Icons.settings_backup_restore,
2),
_buildPopupMenuItem(
groupsSnapshot.data![index],
context,
appLocalization(context).delete_group_title,
Icons.delete_forever_rounded,
3),
],
icon: const Icon(Icons.more_horiz),
)
: const SizedBox.shrink(),
);
},
),
@@ -112,16 +114,15 @@ class _GroupsScreenState extends State<GroupsScreen> {
}
}
PopupMenuItem _buildPopupMenuItem(Group group, BuildContext context,
String title, IconData iconData, int position) {
PopupMenuItem _buildPopupMenuItem(
Group group, BuildContext context, String title, IconData iconData, int position) {
return PopupMenuItem(
onTap: () {
if (title == appLocalization(context).share_group_title) {
Future.delayed(context.lowDuration, () {
shareGroup(context, group);
});
} else if (title ==
appLocalization(context).change_group_infomation_title) {
} else if (title == appLocalization(context).change_group_infomation_title) {
Future.delayed(context.lowDuration, () {
createOrJoinGroupDialog(
context,

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
import '../../../bloc/inter_family_bloc.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import 'groups_model.dart';

View File

@@ -6,7 +6,7 @@ import 'inter_family_widget.dart';
import '../../product/base/bloc/base_bloc.dart';
import '../../product/constant/app/app_constants.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart';
class InterFamilyScreen extends StatefulWidget {

View File

@@ -5,13 +5,11 @@ import 'dart:developer';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
// import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart';
import 'package:badges/badges.dart' as badges;
import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart';
import 'package:sfm_app/feature/sound_notification_test/notification_screen.dart';
import 'package:sfm_app/product/permission/notification_permission.dart';
import '../../product/permission/notification_permission.dart';
import '../settings/profile/profile_model.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../bloc/home_bloc.dart';
import '../../product/constant/app/app_constants.dart';
import '../../product/constant/enums/app_route_enums.dart';
@@ -35,7 +33,6 @@ import '../../product/constant/icon/icon_constants.dart';
import '../../product/constant/lang/language_constants.dart';
import '../../product/services/language_services.dart';
import '../bell/bell_model.dart';
import '../sound_notification_test/notification_bloc.dart';
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
@@ -192,6 +189,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
stream: mainBloc.streamThemeMode,
initialData: isLight,
@@ -344,7 +342,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
controller: controller,
screens: _buildScreens(),
items: _navBarsItems(),
handleAndroidBackButtonPress: false,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
stateManagement: true,
backgroundColor:

View File

@@ -6,7 +6,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'show_direction_widget.dart';
import 'show_nearest_place.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../bloc/map_bloc.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';

View File

@@ -3,9 +3,9 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:maps_launcher/maps_launcher.dart';
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
import 'package:sfm_app/product/extention/context_extention.dart';
import 'package:sfm_app/product/services/language_services.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import '../../../bloc/map_bloc.dart';

View File

@@ -7,7 +7,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../bloc/map_bloc.dart';
import 'show_direction_widget.dart';
import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import '../../../product/services/map_services.dart';
import '../../../product/shared/model/near_by_search_model.dart';

View File

@@ -7,7 +7,7 @@ import '../../../product/shared/shared_snack_bar.dart';
import '../../../bloc/device_notification_settings_bloc.dart';
import 'device_notification_settings_model.dart';
import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';

View File

@@ -6,7 +6,7 @@ import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/services/api_services.dart';
import '../../../bloc/settings_bloc.dart';
import '../../../product/shared/shared_input_decoration.dart';
import '../../../product/extention/context_extention.dart';
import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart';
import 'profile_model.dart';

View File

@@ -5,7 +5,7 @@ import 'package:go_router/go_router.dart';
import '../../product/constant/app/app_constants.dart';
import 'profile/profile_screen.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/api_services.dart';
import 'profile/profile_model.dart';
import '../../bloc/settings_bloc.dart';

View File

@@ -1,11 +0,0 @@
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
class NotificationBloc extends BlocBase{
@override
void dispose() {
// TODO: implement dispose
}
}

View File

@@ -1,77 +0,0 @@
// ignore_for_file: avoid_print
import 'dart:math' as math;
import 'dart:developer' as dev;
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'notification_bloc.dart';
import '../../product/base/bloc/base_bloc.dart';
import '../../product/services/notification_services.dart';
class NotificationScreen extends StatefulWidget {
const NotificationScreen({super.key});
@override
State<NotificationScreen> createState() => _NotificationScreenState();
}
class _NotificationScreenState extends State<NotificationScreen> {
late NotificationBloc notificationBloc;
final notificationPlugin = FlutterLocalNotificationsPlugin();
@override
void initState() {
super.initState();
initNotification();
notificationBloc = BlocProvider.of<NotificationBloc>(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () async {
showNewAlarmSoundNotification("warning_alarm");
dev.log("Da vao day");
},
child: const Text("Show new Alarm Notification"),
),
],
));
}
Future<void> initNotification() async{
const isSettingAndroid = AndroidInitializationSettings('@mipmap/ic_launcher');
const initSetting = InitializationSettings(android: isSettingAndroid);
await notificationPlugin.initialize(initSetting);
}
Future<void> showNewAlarmSoundNotification(String sound) async {
AndroidNotificationChannel androidNotificationChannel =
AndroidNotificationChannel(
math.Random.secure().nextInt(1000000).toString(),
'high Important Notification',
importance: Importance.max);
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
"androidNotificationChannel.id.toString()",
androidNotificationChannel.name.toString(),
sound: RawResourceAndroidNotificationSound(sound),
channelDescription: "Channel description",
importance: androidNotificationChannel.importance,
priority: Priority.high,
ticker: 'ticker',
);
final NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
await FlutterLocalNotificationsPlugin().show(0, 'New Notification',
'Sound Notification Example', notificationDetails);
}
}

View File

@@ -1,7 +1,7 @@
import 'package:app_settings/app_settings.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../../extention/context_extention.dart';
import '../../../extension/context_extension.dart';
import '../../../services/language_services.dart';
class RequestPermissionDialog {

View File

@@ -1,6 +1,4 @@
import 'package:go_router/go_router.dart';
import '../../../feature/sound_notification_test/notification_bloc.dart';
import '../../../feature/sound_notification_test/notification_screen.dart';
import '../../../bloc/device_detail_bloc.dart';
import '../../../feature/devices/device_detail/device_detail_screen.dart';
import '../../../bloc/device_notification_settings_bloc.dart';
@@ -153,14 +151,6 @@ GoRouter goRouter() {
),
transitionsBuilder: transitionsRightToLeft),
),
GoRoute(
path: "/notification",
name: 'notification',
builder: (context, state) => BlocProvider(
child: const NotificationScreen(),
blocBuilder: () => NotificationBloc(),
),
),
],
);
}

View File

@@ -11,6 +11,7 @@
"button_fake_fire_message": "False fire alarm",
"in_progress_message": "In progress",
"smoke_detecting_message": "Smoke detecting!",
"low_battery_message": "Low Battery!",
"smoke_detecting_message_lowercase": "smoke detecting!",
"disconnect_message_uppercase": "Disconnected",
"disconnect_message_lowercase": "disconnected",

View File

@@ -11,6 +11,7 @@
"button_fake_fire_message": "Cháy giả?",
"in_progress_message": "Đang xử lý",
"smoke_detecting_message": "Phát hiện khói!",
"low_battery_message": "Cảnh báo pin yếu!",
"smoke_detecting_message_lowercase": "Phát hiện khói!",
"disconnect_message_uppercase": "Mất kết nối",
"disconnect_message_lowercase": "mất kết nối",

View File

@@ -282,7 +282,7 @@ class APIServices {
return data;
}
Future<String> getOwnerDevieByState(Map<String, dynamic> params) async {
Future<String> getOwnerDeviceByState(Map<String, dynamic> params) async {
String? data = await NetworkManager.instance!
.getDataFromServerWithParams(APIPathConstants.DEVICE_PATH, params);
return data;

View File

@@ -128,8 +128,6 @@ class NotificationServices {
void handleMessage(String? payload) {
dev.log("Handling notification tap with payload: $payload");
// Thêm logic xử lý khi nhấn thông báo ở đây
// Ví dụ: Điều hướng màn hình hoặc xử lý dữ liệu
}
Future<void> setupInteractMessage() async {

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import '../extention/context_extention.dart';
import '../extension/context_extension.dart';
InputDecoration borderRadiusTopLeftAndBottomRight(
BuildContext context, String hintText) =>

View File

@@ -2,10 +2,10 @@ import 'dart:developer';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:sfm_app/bloc/devices_manager_bloc.dart';
import 'package:sfm_app/feature/devices/device_model.dart';
import 'package:sfm_app/product/extention/context_extention.dart';
import 'package:sfm_app/product/services/language_services.dart';
import '../../bloc/devices_manager_bloc.dart';
import '../../feature/devices/device_model.dart';
import '../extension/context_extension.dart';
import '../services/language_services.dart';
import '../constant/app/app_constants.dart';
@@ -54,18 +54,18 @@ class _SharedPieChartState extends State<SharedPieChart> {
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData: PieTouchData(
touchCallback: (FlTouchEvent event, pieTouchResponse) {
if (!event.isInterestedForInteractions ||
pieTouchResponse == null ||
pieTouchResponse.touchedSection == null) {
return;
}
int newTouchedIndex =
pieTouchResponse.touchedSection!.touchedSectionIndex;
updateDevicesOnTapPieChart(newTouchedIndex);
},
),
// pieTouchData: PieTouchData(
// touchCallback: (FlTouchEvent event, pieTouchResponse) {
// if (!event.isInterestedForInteractions ||
// pieTouchResponse == null ||
// pieTouchResponse.touchedSection == null) {
// return;
// }
// int newTouchedIndex =
// pieTouchResponse.touchedSection!.touchedSectionIndex;
// updateDevicesOnTapPieChart(newTouchedIndex);
// },
// ),
sections: [
PieChartSectionData(
color: Colors.grey,
@@ -96,7 +96,7 @@ class _SharedPieChartState extends State<SharedPieChart> {
titleStyle: titleStyle,
),
PieChartSectionData(
color: Colors.black, // Có thể thêm màu cho trạng thái lỗi
color: Colors.black,
value: errorCount.toDouble(),
title: errorCount.toString(),
radius: context.dynamicWidth(0.2),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:sfm_app/product/extention/context_extention.dart';
import 'package:sfm_app/product/extension/context_extension.dart';
import 'package:top_snackbar_flutter/custom_snack_bar.dart';
import 'package:top_snackbar_flutter/top_snack_bar.dart';