Complete refactoring SFM App Source Code
This commit is contained in:
79
lib/feature/home/device_alias_model.dart
Normal file
79
lib/feature/home/device_alias_model.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
import '../devices/device_model.dart';
|
||||
|
||||
class DeviceWithAlias {
|
||||
String? extId;
|
||||
String? thingId;
|
||||
String? thingKey;
|
||||
List<String>? channels;
|
||||
String? areaPath;
|
||||
String? fvers;
|
||||
String? name;
|
||||
HardwareInfo? hardwareInfo;
|
||||
Settings? settings;
|
||||
Status? status;
|
||||
DateTime? connectionTime;
|
||||
int? state;
|
||||
String? visibility;
|
||||
DateTime? createdAt;
|
||||
DateTime? updatedAt;
|
||||
bool? isOwner;
|
||||
String? ownerId;
|
||||
String? ownerName;
|
||||
String? alias;
|
||||
|
||||
DeviceWithAlias({
|
||||
this.extId,
|
||||
this.thingId,
|
||||
this.thingKey,
|
||||
this.channels,
|
||||
this.areaPath,
|
||||
this.fvers,
|
||||
this.name,
|
||||
this.hardwareInfo,
|
||||
this.settings,
|
||||
this.status,
|
||||
this.connectionTime,
|
||||
this.state,
|
||||
this.visibility,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.isOwner,
|
||||
this.ownerId,
|
||||
this.ownerName,
|
||||
this.alias,
|
||||
});
|
||||
|
||||
DeviceWithAlias.fromJson(Map<String, dynamic> json) {
|
||||
extId = json['ext_id'];
|
||||
thingId = json['thing_id'];
|
||||
thingKey = json['thing_key'];
|
||||
if (json['channels'] != null) {
|
||||
channels = [];
|
||||
json['channels'].forEach((v) {
|
||||
channels!.add(v);
|
||||
});
|
||||
}
|
||||
areaPath = json['area_path'];
|
||||
fvers = json['fvers'];
|
||||
name = json['name'];
|
||||
hardwareInfo = json['hardware_info'] != null
|
||||
? HardwareInfo.fromJson(json['hardware_info'])
|
||||
: null;
|
||||
settings =
|
||||
json['settings'] != null ? Settings.fromJson(json['settings']) : null;
|
||||
status = json['status'] != null ? Status.fromJson(json['status']) : null;
|
||||
connectionTime = DateTime.parse(json['connection_time']);
|
||||
state = json['state'];
|
||||
visibility = json['visibility'];
|
||||
createdAt = DateTime.parse(json['created_at']);
|
||||
updatedAt = DateTime.parse(json['updated_at']);
|
||||
isOwner = json['is_owner'];
|
||||
ownerId = json['owner_id'];
|
||||
ownerName = json['owner_name'];
|
||||
alias = json['alias'];
|
||||
}
|
||||
static List<DeviceWithAlias> fromJsonDynamicList(List<dynamic> list) {
|
||||
return list.map((e) => DeviceWithAlias.fromJson(e)).toList();
|
||||
}
|
||||
}
|
||||
92
lib/feature/home/home_bloc.dart
Normal file
92
lib/feature/home/home_bloc.dart
Normal file
@@ -0,0 +1,92 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'device_alias_model.dart';
|
||||
|
||||
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 onlineDevicesAlias =
|
||||
StreamController<List<DeviceWithAlias>>.broadcast();
|
||||
StreamSink<List<DeviceWithAlias>> get sinkOnlineDevicesAlias =>
|
||||
onlineDevicesAlias.sink;
|
||||
Stream<List<DeviceWithAlias>> get streamOnlineDevicesAlias =>
|
||||
onlineDevicesAlias.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 ownerDevicesStatus =
|
||||
StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
|
||||
StreamSink<Map<String, List<DeviceWithAlias>>>
|
||||
get sinkOwnerDevicesStatus => ownerDevicesStatus.sink;
|
||||
Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus =>
|
||||
ownerDevicesStatus.stream;
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {}
|
||||
}
|
||||
411
lib/feature/home/home_screen.dart
Normal file
411
lib/feature/home/home_screen.dart
Normal file
@@ -0,0 +1,411 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'shared/alert_card.dart';
|
||||
import 'shared/warning_card.dart';
|
||||
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/services/api_services.dart';
|
||||
import '../../product/services/language_services.dart';
|
||||
import 'home_bloc.dart';
|
||||
import '../../product/base/bloc/base_bloc.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
late HomeBloc homeBloc;
|
||||
APIServices apiServices = APIServices();
|
||||
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;
|
||||
Map<String, List<DeviceWithAlias>> ownerDevicesStatus = {};
|
||||
List<String> ownerDevicesState = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
homeBloc = BlocProvider.of(context);
|
||||
const duration = Duration(seconds: 20);
|
||||
getOwnerAndJoinedDevices();
|
||||
getAllDevicesTimer =
|
||||
Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices());
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
getAllDevicesTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: context.paddingLow,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
appLocalization(context).notification,
|
||||
style: context.titleMediumTextStyle,
|
||||
),
|
||||
SizedBox(width: context.lowValue),
|
||||
StreamBuilder<int>(
|
||||
stream: homeBloc.streamCountNotitication,
|
||||
builder: (context, countSnapshot) {
|
||||
return Text(
|
||||
"(${countSnapshot.data ?? 0})",
|
||||
style: context.titleMediumTextStyle,
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: StreamBuilder<Map<String, List<DeviceWithAlias>>>(
|
||||
stream: homeBloc.streamOwnerDevicesStatus,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data?['state'] != null ||
|
||||
snapshot.data?['battery'] != null) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (snapshot.data?['state'] != null)
|
||||
...snapshot.data!['state']!
|
||||
.map(
|
||||
(item) => FutureBuilder<Widget>(
|
||||
future: warningCard(
|
||||
context, apiServices, item),
|
||||
builder: (context, warningCardSnapshot) {
|
||||
if (warningCardSnapshot.hasData) {
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 400,
|
||||
maxHeight: 260,
|
||||
),
|
||||
child: warningCardSnapshot.data!,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
if (snapshot.data?['battery'] != null)
|
||||
...snapshot.data!['battery']!
|
||||
.map(
|
||||
(batteryItem) => FutureBuilder<Widget>(
|
||||
future: notificationCard(
|
||||
context,
|
||||
"lowBattery",
|
||||
"Cảnh báo pin yếu",
|
||||
batteryItem.name!,
|
||||
batteryItem.areaPath!,
|
||||
),
|
||||
builder: (context, warningCardSnapshot) {
|
||||
if (warningCardSnapshot.hasData) {
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 400,
|
||||
maxHeight: 260,
|
||||
),
|
||||
child: warningCardSnapshot.data!,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
]);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: context.paddingMedium,
|
||||
child: Center(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.check_circle_outline_rounded,
|
||||
size: 40,
|
||||
color: Colors.green,
|
||||
),
|
||||
SizedBox(width: context.lowValue),
|
||||
Text(
|
||||
appLocalization(context)
|
||||
.notification_description,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
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,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
StreamBuilder<List<DeviceWithAlias>>(
|
||||
stream: homeBloc.streamAllDevicesAliasJoined,
|
||||
initialData: allDevicesAliasJoined,
|
||||
builder: (context, allDeviceSnapshot) {
|
||||
if (allDeviceSnapshot.data?.isEmpty ?? true) {
|
||||
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,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void getOwnerAndJoinedDevices() async {
|
||||
String response = await apiServices.getDashBoardDevices();
|
||||
final data = jsonDecode(response);
|
||||
List<dynamic> result = data["items"];
|
||||
devices = DeviceWithAlias.fromJsonDynamicList(result);
|
||||
getOwnerDeviceState(devices);
|
||||
getDevicesStatusAlias(devices);
|
||||
checkSettingdevice(devices);
|
||||
}
|
||||
|
||||
void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async {
|
||||
List<DeviceWithAlias> ownerDevices = [];
|
||||
for (var device in allDevices) {
|
||||
if (device.isOwner!) {
|
||||
ownerDevices.add(device);
|
||||
}
|
||||
}
|
||||
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 ?? []);
|
||||
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 (double.parse(sensorMap['sensorBattery']) <= 20) {
|
||||
ownerDevicesStatus['battery'] ??= [];
|
||||
ownerDevicesStatus['battery']!.add(device);
|
||||
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
notificationCount = count;
|
||||
homeBloc.sinkCountNotitication.add(notificationCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getDevicesStatusAlias(List<DeviceWithAlias> devices) async {
|
||||
clearAllDeviceStatusAlias();
|
||||
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);
|
||||
}
|
||||
if (device.state! == -1) {
|
||||
offlineDevicesAlias.add(device);
|
||||
homeBloc.sinkOfflineDevicesAlias.add(offlineDevicesAlias);
|
||||
}
|
||||
if (device.state! == 1) {
|
||||
warningDevicesAlias.add(device);
|
||||
homeBloc.sinkWarningDevicesAlias.add(warningDevicesAlias);
|
||||
}
|
||||
if (device.state! == -2) {
|
||||
notUseDevicesAlias.add(device);
|
||||
homeBloc.sinkNotUseDevicesAlias.add(notUseDevicesAlias);
|
||||
}
|
||||
} else {
|
||||
allDevicesAliasJoined.add(device);
|
||||
if (device.state! == 0 || device.state! == 1) {
|
||||
onlineDevicesAliasJoined.add(device);
|
||||
homeBloc.sinkOnlineDevicesAliasJoined.add(onlineDevicesAliasJoined);
|
||||
}
|
||||
if (device.state! == -1) {
|
||||
offlineDevicesAliasJoined.add(device);
|
||||
homeBloc.sinkOfflineDevicesAliasJoined.add(offlineDevicesAliasJoined);
|
||||
}
|
||||
if (device.state! == 1) {
|
||||
warningDevicesAliasJoined.add(device);
|
||||
homeBloc.sinkWarningDevicesAliasJoined.add(warningDevicesAliasJoined);
|
||||
}
|
||||
if (device.state! == -2) {
|
||||
notUseDevicesAliasJoined.add(device);
|
||||
homeBloc.sinkNotUseDevicesAliasJoined.add(notUseDevicesAliasJoined);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkSettingdevice(allDevicesAliasJoined);
|
||||
homeBloc.sinkAllDevicesAlias.add(allDevicesAlias);
|
||||
homeBloc.sinkAllDevicesAliasJoined.add(allDevicesAliasJoined);
|
||||
}
|
||||
|
||||
void checkSettingdevice(List<DeviceWithAlias> devices) async {
|
||||
if (isFunctionCall) {
|
||||
} else {
|
||||
String? response =
|
||||
await apiServices.getAllSettingsNotificationOfDevices();
|
||||
if (response != "") {
|
||||
final data = jsonDecode(response);
|
||||
final result = data['data'];
|
||||
// log("Data ${DeviceNotificationSettings.mapFromJson(jsonDecode(data)).values.toList()}");
|
||||
List<DeviceNotificationSettings> list =
|
||||
DeviceNotificationSettings.mapFromJson(result).values.toList();
|
||||
// log("List: $list");
|
||||
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!);
|
||||
} else {
|
||||
log("All devives are in the notification settings list.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log("apiServices: getAllSettingsNotificationofDevices error!");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
130
lib/feature/home/shared/alert_card.dart
Normal file
130
lib/feature/home/shared/alert_card.dart
Normal file
@@ -0,0 +1,130 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../product/constant/image/image_constants.dart';
|
||||
import '../../../product/extention/context_extention.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
|
||||
Future<Widget> notificationCard(
|
||||
BuildContext context,
|
||||
String notiticationType,
|
||||
String notificationTitle,
|
||||
String notificationDevicename,
|
||||
String notificationLocation) async {
|
||||
String location = await DeviceUtils.instance
|
||||
.getFullDeviceLocation(context, notificationLocation);
|
||||
String path = "";
|
||||
DateTime time = DateTime.now();
|
||||
if (notiticationType == "lowBattery") {
|
||||
path = ImageConstants.instance.getImage("low_battery");
|
||||
}
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Text(
|
||||
notificationTitle,
|
||||
style: const TextStyle(
|
||||
letterSpacing: 1,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color.fromARGB(255, 250, 84, 34),
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
"${appLocalization(context).device_title} $notificationDevicename",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: context.dynamicWidth(0.15),
|
||||
width: context.dynamicWidth(0.15),
|
||||
child: Image.asset(path),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
Row(
|
||||
children: [
|
||||
IconConstants.instance
|
||||
.getMaterialIcon(Icons.location_on_outlined),
|
||||
SizedBox(
|
||||
width: context.lowValue,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
location,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
Row(
|
||||
children: [
|
||||
IconConstants.instance.getMaterialIcon(Icons.schedule),
|
||||
SizedBox(
|
||||
width: context.lowValue,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
time.toString(),
|
||||
style: const TextStyle(fontSize: 15),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: OutlinedButton(
|
||||
style: const ButtonStyle(
|
||||
backgroundColor: MaterialStatePropertyAll(Colors.blueAccent)),
|
||||
onPressed: () {},
|
||||
child: Text(
|
||||
appLocalization(context).detail_message,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
77
lib/feature/home/shared/overview_card.dart
Normal file
77
lib/feature/home/shared/overview_card.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
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';
|
||||
|
||||
class OverviewCard extends StatelessWidget {
|
||||
final bool isOwner;
|
||||
final int total;
|
||||
final int active;
|
||||
final int inactive;
|
||||
final int warning;
|
||||
final int unused;
|
||||
|
||||
const OverviewCard(
|
||||
{super.key,
|
||||
required this.isOwner,
|
||||
required this.total,
|
||||
required this.active,
|
||||
required this.inactive,
|
||||
required this.warning,
|
||||
required this.unused});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
margin: context.paddingLow,
|
||||
elevation: 8,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: context.paddingNormal,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
isOwner
|
||||
? appLocalization(context).overview_message
|
||||
: appLocalization(context).interfamily_page_name,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: context.normalValue),
|
||||
Column(
|
||||
children: [
|
||||
StatusCard(
|
||||
label: appLocalization(context).total_nof_devices_message,
|
||||
count: total,
|
||||
color: Colors.blue,
|
||||
),
|
||||
StatusCard(
|
||||
label: appLocalization(context).active_devices_message,
|
||||
count: active,
|
||||
color: Colors.green,
|
||||
),
|
||||
StatusCard(
|
||||
label: appLocalization(context).inactive_devices_message,
|
||||
count: inactive,
|
||||
color: Colors.grey,
|
||||
),
|
||||
StatusCard(
|
||||
label: appLocalization(context).warning_devices_message,
|
||||
count: warning,
|
||||
color: Colors.orange,
|
||||
),
|
||||
StatusCard(
|
||||
label: appLocalization(context).unused_devices_message,
|
||||
count: unused,
|
||||
color: Colors.yellow,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
42
lib/feature/home/shared/status_card.dart
Normal file
42
lib/feature/home/shared/status_card.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StatusCard extends StatelessWidget {
|
||||
final String label;
|
||||
final int count;
|
||||
final Color color;
|
||||
|
||||
const StatusCard(
|
||||
{super.key,
|
||||
required this.label,
|
||||
required this.count,
|
||||
required this.color});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: color,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(15),
|
||||
margin: const EdgeInsets.symmetric(vertical: 5),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontSize: 18)),
|
||||
Text(
|
||||
count.toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
248
lib/feature/home/shared/warning_card.dart
Normal file
248
lib/feature/home/shared/warning_card.dart
Normal file
@@ -0,0 +1,248 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:maps_launcher/maps_launcher.dart';
|
||||
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/services/api_services.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
import '../../../product/shared/shared_snack_bar.dart';
|
||||
|
||||
Future<Widget> warningCard(
|
||||
BuildContext context, APIServices apiServices, DeviceWithAlias item) async {
|
||||
Color backgroundColor = Colors.blue;
|
||||
Color textColor = Colors.white;
|
||||
String message = "";
|
||||
String fullLocation =
|
||||
await DeviceUtils.instance.getFullDeviceLocation(context, item.areaPath!);
|
||||
String time = "";
|
||||
for (var sensor in item.status!.sensors!) {
|
||||
if (sensor.name! == "11") {
|
||||
DateTime dateTime =
|
||||
DateTime.fromMillisecondsSinceEpoch((sensor.time!) * 1000);
|
||||
time = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
|
||||
}
|
||||
}
|
||||
if (item.state! == 3) {
|
||||
backgroundColor = Colors.grey;
|
||||
textColor = Colors.black;
|
||||
message = appLocalization(context).in_progress_message;
|
||||
} else if (item.state! == 2) {
|
||||
backgroundColor = const Color.fromARGB(255, 6, 138, 72);
|
||||
textColor = const Color.fromARGB(255, 255, 255, 255);
|
||||
message = appLocalization(context).gf_in_firefighting_message;
|
||||
} else if (item.state! == 1) {
|
||||
backgroundColor = const Color.fromARGB(255, 250, 63, 63);
|
||||
textColor = Colors.white;
|
||||
message = appLocalization(context).button_fake_fire_message;
|
||||
} else {
|
||||
backgroundColor = Colors.black;
|
||||
textColor = Colors.white;
|
||||
message = appLocalization(context).disconnect_message_uppercase;
|
||||
}
|
||||
return Card(
|
||||
// color: Color.fromARGB(255, 208, 212, 217),
|
||||
child: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Text(
|
||||
appLocalization(context).smoke_detecting_message,
|
||||
style: const TextStyle(
|
||||
letterSpacing: 1,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
SizedBox(
|
||||
child: Text(
|
||||
"${appLocalization(context).device_title}: ${item.name}",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: context.dynamicWidth(0.15),
|
||||
width: context.dynamicWidth(0.15),
|
||||
child: Image.asset(
|
||||
ImageConstants.instance.getImage("fire_warning")),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
Row(
|
||||
children: [
|
||||
IconConstants.instance
|
||||
.getMaterialIcon(Icons.location_on_outlined),
|
||||
SizedBox(
|
||||
width: context.lowValue,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
fullLocation,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
Row(
|
||||
children: [
|
||||
IconConstants.instance.getMaterialIcon(Icons.schedule),
|
||||
SizedBox(
|
||||
width: context.lowValue,
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
time,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: context.lowValue,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
IconButton.outlined(
|
||||
onPressed: () async => {},
|
||||
// displayListOfFireStationPhoneNumbers(testDevice),
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.call),
|
||||
iconSize: 25,
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all<Color>(Colors.blue[300]!),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
IconButton.outlined(
|
||||
onPressed: () async {
|
||||
String markerLabel = "Destination";
|
||||
MapsLauncher.launchCoordinates(
|
||||
double.parse(item.settings!.latitude!),
|
||||
double.parse(item.settings!.longitude!),
|
||||
markerLabel);
|
||||
},
|
||||
icon: const Icon(Icons.directions),
|
||||
iconSize: 25,
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all<Color>(Colors.blue[300]!),
|
||||
),
|
||||
),
|
||||
SizedBox(width: context.mediumValue),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: OutlinedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStatePropertyAll(backgroundColor)),
|
||||
onPressed: () async {
|
||||
if (message ==
|
||||
appLocalization(context).button_fake_fire_message) {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
icon: const Icon(Icons.warning),
|
||||
iconColor: Colors.red,
|
||||
title: Text(appLocalization(context)
|
||||
.confirm_fake_fire_message),
|
||||
content: Text(appLocalization(context)
|
||||
.confirm_fake_fire_body),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
int statusCode = await apiServices
|
||||
.confirmFakeFireByUser(item.thingId!);
|
||||
if (statusCode == 200) {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
appLocalization(context)
|
||||
.notification_confirm_fake_fire_success,
|
||||
Colors.green,
|
||||
Colors.white);
|
||||
} else {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
appLocalization(context)
|
||||
.notification_confirm_fake_fire_failed,
|
||||
Colors.red,
|
||||
Colors.red);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.confirm_fake_fire_sure_message,
|
||||
style: const TextStyle(color: Colors.red)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(appLocalization(context)
|
||||
.cancel_button_content),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
appLocalization(context).let_PCCC_handle_message,
|
||||
Colors.orange,
|
||||
Colors.white);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
message,
|
||||
style: TextStyle(color: textColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user