Complete refactoring SFM App Source Code

This commit is contained in:
anhtunz
2024-12-15 00:59:02 +07:00
parent caa73ca43c
commit 2e27d59278
247 changed files with 18390 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'device_notification_settings_model.dart';
import '../../../product/base/bloc/base_bloc.dart';
class DeviceNotificationSettingsBloc extends BlocBase {
final listNotifications =
StreamController<List<DeviceNotificationSettings>>.broadcast();
StreamSink<List<DeviceNotificationSettings>> get sinkListNotifications =>
listNotifications.sink;
Stream<List<DeviceNotificationSettings>> get streamListNotifications =>
listNotifications.stream;
final deviceThingID = StreamController<String>.broadcast();
StreamSink<String> get sinkDeviceThingID => deviceThingID.sink;
Stream<String> get streamDeviceThingID => deviceThingID.stream;
final deviceNotificationSettingMap =
StreamController<Map<String, int>>.broadcast();
StreamSink<Map<String, int>> get sinkDeviceNotificationSettingMap =>
deviceNotificationSettingMap.sink;
Stream<Map<String, int>> get streamDeviceNotificationSettingMap =>
deviceNotificationSettingMap.stream;
final isDataChange = StreamController<bool>.broadcast();
StreamSink<bool> get sinkIsDataChange => isDataChange.sink;
Stream<bool> get streamIsDataChange => isDataChange.stream;
final iconChange = StreamController<IconData>.broadcast();
StreamSink<IconData> get sinkIconChange => iconChange.sink;
Stream<IconData> get streamIconChange => iconChange.stream;
final messageChange = StreamController<String>.broadcast();
StreamSink<String> get sinkMessageChange => messageChange.sink;
Stream<String> get streaMmessageChange => messageChange.stream;
@override
void dispose() {}
}

View File

@@ -0,0 +1,56 @@
class DeviceNotificationSettings {
String? id;
String? userId;
String? thingId;
DeviceAliasSettings? settings;
DateTime? updatedAt;
DeviceNotificationSettings({
this.id,
this.userId,
this.thingId,
this.settings,
this.updatedAt,
});
DeviceNotificationSettings.fromJson(Map<String, dynamic> json) {
id = json["id"];
userId = json["user_id"];
thingId = json["thing_id"];
settings = json["settings"] != null
? DeviceAliasSettings.fromJson(json["settings"])
: null;
updatedAt = DateTime.parse(json["updated_at"]);
}
static List<DeviceNotificationSettings> mapToList(
Map<String, DeviceNotificationSettings> map) {
return map.values.toList();
}
static Map<String, DeviceNotificationSettings> mapFromJson(
Map<String, dynamic> json) {
final Map<String, DeviceNotificationSettings> devices = {};
json.forEach((key, value) {
devices[key] = DeviceNotificationSettings.fromJson(value);
});
return devices;
}
}
class DeviceAliasSettings {
String? alias;
Map<String, int>? notifiSettings;
DeviceAliasSettings({
this.alias,
this.notifiSettings,
});
DeviceAliasSettings.fromJson(Map<String, dynamic> json) {
alias = json['alias'];
if (json['notifi_settings'] != null) {
notifiSettings = Map<String, int>.from(json['notifi_settings']);
}
}
}

View File

@@ -0,0 +1,313 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:convert';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import '../../../product/shared/shared_snack_bar.dart';
import '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/services/api_services.dart';
import '../../../product/services/language_services.dart';
class DeviceNotificationSettingsScreen extends StatefulWidget {
const DeviceNotificationSettingsScreen({super.key});
@override
State<DeviceNotificationSettingsScreen> createState() =>
_DeviceNotificationSettingsScreenState();
}
class _DeviceNotificationSettingsScreenState
extends State<DeviceNotificationSettingsScreen> {
late DeviceNotificationSettingsBloc deviceNotificationSettingsBloc;
String thingID = "";
List<DeviceNotificationSettings> deviceNotifications = [];
APIServices apiServices = APIServices();
@override
void initState() {
super.initState();
deviceNotificationSettingsBloc = BlocProvider.of(context);
getNotificationSetting();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<List<DeviceNotificationSettings>>(
stream: deviceNotificationSettingsBloc.streamListNotifications,
initialData: deviceNotifications,
builder: (context, notificationSnapshot) {
return StreamBuilder<String>(
stream: deviceNotificationSettingsBloc.streamDeviceThingID,
initialData: thingID,
builder: (context, deviceThingIdSnapshot) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
appLocalization(context).profile_setting,
style: Theme.of(context).textTheme.titleLarge,
),
),
body: deviceNotifications.isEmpty
? Center(
child: CircularProgressIndicator(
value: context.mediumValue,
),
)
: Padding(
padding: context.paddingLow,
child: Column(
children: [
DropdownButtonFormField2<
DeviceNotificationSettings>(
isExpanded: true,
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(vertical: 10),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
hint: Text(
appLocalization(context)
.choose_device_dropdownButton,
style: const TextStyle(fontSize: 14),
),
iconStyleData: const IconStyleData(
icon: Icon(
Icons.arrow_drop_down,
),
iconSize: 24,
),
menuItemStyleData: const MenuItemStyleData(
padding: EdgeInsets.symmetric(horizontal: 16),
),
items: deviceNotifications
.map((e) => DropdownMenuItem<
DeviceNotificationSettings>(
value: e,
child: Text(e.settings!.alias!),
))
.toList(),
onChanged: (value) {
thingID = value!.thingId ?? "";
deviceNotificationSettingsBloc
.sinkDeviceThingID
.add(thingID);
},
),
if (deviceThingIdSnapshot.data! != "")
listNotificationSetting(
deviceThingIdSnapshot.data ?? thingID,
deviceNotifications)
],
),
),
);
});
});
}
void getNotificationSetting() async {
String? response = await apiServices.getAllSettingsNotificationOfDevices();
final data = jsonDecode(response);
final result = data['data'];
// log("Data ${DeviceNotificationSettings.mapFromJson(jsonDecode(data)).values.toList()}");
deviceNotifications =
DeviceNotificationSettings.mapFromJson(result).values.toList();
deviceNotificationSettingsBloc.sinkListNotifications
.add(deviceNotifications);
}
Widget listNotificationSetting(
String thingID, List<DeviceNotificationSettings> devices) {
DeviceNotificationSettings chooseDevice = DeviceNotificationSettings();
for (var device in devices) {
if (device.thingId == thingID) {
chooseDevice = device;
break;
}
}
IconData selectIcon = Icons.unpublished_outlined;
String selectMessage = appLocalization(context)
.change_profile_device_notification_deselect_all;
bool isChange = false;
bool isDataChange = false;
// Lấy notifiSettings
final notifiSettings = chooseDevice.settings?.notifiSettings ?? {};
deviceNotificationSettingsBloc.sinkDeviceNotificationSettingMap
.add(notifiSettings);
return SingleChildScrollView(
child: StreamBuilder<Map<String, int>>(
stream:
deviceNotificationSettingsBloc.streamDeviceNotificationSettingMap,
initialData: notifiSettings,
builder: (context, deviceNotificationSettingSnapshot) {
return StreamBuilder<bool>(
stream: deviceNotificationSettingsBloc.streamIsDataChange,
initialData: isDataChange,
builder: (context, isDataChangeSnapshot) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton.icon(
onPressed: () {
changeIconAndMessage(
isChange,
selectIcon,
selectMessage,
notifiSettings,
isDataChange);
isChange = !isChange;
},
icon: StreamBuilder<IconData>(
stream: deviceNotificationSettingsBloc
.streamIconChange,
initialData: selectIcon,
builder: (context, iconSnapshot) {
return Icon(
iconSnapshot.data ?? selectIcon);
}),
label: StreamBuilder<String>(
stream: deviceNotificationSettingsBloc
.streaMmessageChange,
builder: (context, messageSnapshot) {
return Text(
messageSnapshot.data ?? selectMessage);
})),
if (isDataChangeSnapshot.data ?? isDataChange)
IconButton(
onPressed: () {
updateDeviceNotification(
thingID, notifiSettings, isDataChange);
},
icon: const Icon(Icons.done))
],
),
ListView.builder(
shrinkWrap: true,
itemCount:
deviceNotificationSettingSnapshot.data?.length ??
notifiSettings.length,
itemBuilder: (context, index) {
final key = deviceNotificationSettingSnapshot
.data!.keys
.elementAt(index);
final value =
deviceNotificationSettingSnapshot.data![key];
return CheckboxListTile(
value: value == 1,
onChanged: (newValue) {
notifiSettings[key] = newValue == true ? 1 : 0;
deviceNotificationSettingsBloc
.sinkDeviceNotificationSettingMap
.add(notifiSettings);
isDataChange = true;
deviceNotificationSettingsBloc.sinkIsDataChange
.add(isDataChange);
},
title: Text(getNotificationEvent(key)),
);
},
),
if (isDataChangeSnapshot.data ?? isDataChange)
Center(
child: TextButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(
Colors.green),
foregroundColor:
MaterialStateProperty.all<Color>(
Colors.white)),
onPressed: () async {
updateDeviceNotification(
thingID, notifiSettings, isDataChange);
},
child: Text(appLocalization(context)
.update_button_content)),
)
],
);
});
}),
);
}
void changeIconAndMessage(bool isChange, IconData icon, String message,
Map<String, int> notifiSettings, bool isDataChange) {
if (isChange == false) {
icon = Icons.published_with_changes_outlined;
message = appLocalization(context)
.change_profile_device_notification_select_all;
notifiSettings.updateAll((key, value) => 0);
} else {
icon = Icons.unpublished_outlined;
message = appLocalization(context)
.change_profile_device_notification_deselect_all;
notifiSettings.updateAll((key, value) => 1);
}
isDataChange = true;
deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange);
deviceNotificationSettingsBloc.sinkDeviceNotificationSettingMap
.add(notifiSettings);
deviceNotificationSettingsBloc.sinkIconChange.add(icon);
deviceNotificationSettingsBloc.sinkMessageChange.add(message);
}
String getNotificationEvent(String eventCode) {
String event = "";
if (eventCode == "001") {
event = "Thiết bị mất kết nối";
} else if (eventCode == "002") {
event = "Hoạt động của thiết bị";
} else if (eventCode == "003") {
event = "Cảnh báo của thiết bị";
} else if (eventCode == "004") {
event = "Thiết bị lỗi";
} else if (eventCode == "005") {
event = "Thiết bị bình thường";
} else if (eventCode == "006") {
event = "Thiết bị yếu pin";
} else if (eventCode == "101") {
event = "Người dùng tham gia nhóm";
} else if (eventCode == "102") {
event = "Người dùng rời nhóm";
} else if (eventCode == "103") {
event = "Thiết bị tham gia nhóm";
} else if (eventCode == "104") {
event = "Thiết bị bị xóa khỏi nhóm";
} else {
event = "Chưa xác định";
}
return event;
}
void updateDeviceNotification(String thingID, Map<String, int> notifiSettings,
bool isDataChange) async {
int statusCode = await apiServices.updateDeviceNotificationSettings(
thingID, notifiSettings);
if (statusCode == 200) {
showNoIconTopSnackBar(
context,
appLocalization(context).notification_update_device_settings_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
context,
appLocalization(context).notification_update_device_settings_failed,
Colors.red,
Colors.white);
}
isDataChange = false;
deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange);
}
}