Complete refactoring SFM App Source Code
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'group_detail_bloc.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import '../../devices/device_model.dart';
|
||||
import 'group_detail_model.dart';
|
||||
|
||||
addDeviceDialog(BuildContext context, DetailGroupBloc detailGroupBloc,
|
||||
String groupID, List<DeviceOfGroup> devices) async {
|
||||
List<Device> ownerDevices = await detailGroupBloc.getOwnerDevices();
|
||||
List<String> selectedItems = [];
|
||||
List<String> selectedDevices = [];
|
||||
if (devices.isNotEmpty) {
|
||||
ownerDevices.removeWhere((element) =>
|
||||
devices.any((device) => device.thingId == element.thingId));
|
||||
}
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertDialog(
|
||||
title: Center(child: Text(appLocalization(context).add_device_title)),
|
||||
content: DropdownButtonFormField2<String>(
|
||||
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),
|
||||
),
|
||||
items: ownerDevices
|
||||
.map((item) => DropdownMenuItem<String>(
|
||||
value: item.thingId,
|
||||
child: StatefulBuilder(builder: (context, menuSetState) {
|
||||
final isSelected = selectedItems.contains(item.thingId);
|
||||
final isNameSelected = selectedItems.contains(item.name);
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
isSelected
|
||||
? selectedItems.remove(item.thingId)
|
||||
: selectedItems.add(item.thingId!);
|
||||
isNameSelected
|
||||
? selectedDevices.remove(item.name)
|
||||
: selectedDevices.add(item.name!);
|
||||
menuSetState(() {});
|
||||
},
|
||||
child: SizedBox(
|
||||
height: double.infinity,
|
||||
child: Row(
|
||||
children: [
|
||||
if (isSelected)
|
||||
const Icon(Icons.check_box_outlined)
|
||||
else
|
||||
const Icon(Icons.check_box_outline_blank),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.name!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
})))
|
||||
.toList(),
|
||||
buttonStyleData: const ButtonStyleData(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
),
|
||||
onChanged: (value) {
|
||||
// thingID = value!;
|
||||
// setState(() {});
|
||||
},
|
||||
onSaved: (value) {},
|
||||
selectedItemBuilder: (context) {
|
||||
return selectedDevices.map(
|
||||
(item) {
|
||||
return Container(
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Text(
|
||||
item,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
maxLines: 1,
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
},
|
||||
iconStyleData: IconStyleData(
|
||||
icon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.arrow_drop_down)),
|
||||
dropdownStyleData: DropdownStyleData(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
),
|
||||
menuItemStyleData: const MenuItemStyleData(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context).cancel_button_content,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
for (var device in selectedItems) {
|
||||
await detailGroupBloc.addDeviceToGroup(
|
||||
context, groupID, device);
|
||||
await detailGroupBloc.getGroupDetail(groupID);
|
||||
}
|
||||
},
|
||||
child: Text(appLocalization(context).add_device_title))
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
118
lib/feature/inter_family/group_detail/group_detail_bloc.dart
Normal file
118
lib/feature/inter_family/group_detail/group_detail_bloc.dart
Normal file
@@ -0,0 +1,118 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../../devices/device_model.dart';
|
||||
import '../../../product/base/bloc/base_bloc.dart';
|
||||
import '../../../product/services/api_services.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/response_status_utils.dart';
|
||||
|
||||
import 'group_detail_model.dart';
|
||||
|
||||
class DetailGroupBloc extends BlocBase {
|
||||
APIServices apiServices = APIServices();
|
||||
final detailGroup = StreamController<GroupDetail>.broadcast();
|
||||
StreamSink<GroupDetail> get sinkDetailGroup => detailGroup.sink;
|
||||
Stream<GroupDetail> get streamDetailGroup => detailGroup.stream;
|
||||
|
||||
final warningDevice = StreamController<List<DeviceOfGroup>>.broadcast();
|
||||
StreamSink<List<DeviceOfGroup>> get sinkWarningDevice => warningDevice.sink;
|
||||
Stream<List<DeviceOfGroup>> get streamWarningDevice => warningDevice.stream;
|
||||
|
||||
final message = StreamController<String>.broadcast();
|
||||
StreamSink<String> get sinkMessage => message.sink;
|
||||
Stream<String> get streamMessage => message.stream;
|
||||
|
||||
@override
|
||||
void dispose() {}
|
||||
|
||||
Future<void> getGroupDetail(String groupID) async {
|
||||
final body = await apiServices.getGroupDetail(groupID);
|
||||
final data = jsonDecode(body);
|
||||
List<DeviceOfGroup> warningDevices = [];
|
||||
if (data != null) {
|
||||
GroupDetail group = GroupDetail.fromJson(data);
|
||||
sinkDetailGroup.add(group);
|
||||
if (group.devices != null) {
|
||||
for (var device in group.devices!) {
|
||||
if (device.state == 1) {
|
||||
warningDevices.add(device);
|
||||
}
|
||||
}
|
||||
sinkWarningDevice.add(warningDevices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> approveUserToGroup(BuildContext context, String groupID,
|
||||
String userID, String userName) async {
|
||||
Map<String, dynamic> body = {"group_id": groupID, "user_id": userID};
|
||||
int statusCode = await apiServices.approveGroup(body);
|
||||
showSnackBarResponseByStatusCode(context, statusCode,
|
||||
"Đã duyệt $userName vào nhóm!", "Duyệt $userName thất bại!");
|
||||
}
|
||||
|
||||
Future<void> deleteOrUnapproveUser(BuildContext context, String groupID,
|
||||
String userID, String userName) async {
|
||||
int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
|
||||
showSnackBarResponseByStatusCode(context, statusCode,
|
||||
"Đã xóa người dùng $userName", "Xóa người dùng $userName thất bại");
|
||||
}
|
||||
|
||||
Future<void> deleteDevice(BuildContext context, String groupID,
|
||||
String thingID, String deviceName) async {
|
||||
int statusCode = await apiServices.deleteDeviceInGroup(groupID, thingID);
|
||||
showSnackBarResponseByStatusCode(context, statusCode,
|
||||
"Đã xóa thiết bị $deviceName", "Xóa thiết bị $deviceName thất bại");
|
||||
}
|
||||
|
||||
Future<void> leaveGroup(
|
||||
BuildContext context, String groupID, String userID) async {
|
||||
int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_leave_group_success,
|
||||
appLocalization(context).notification_leave_group_failed);
|
||||
}
|
||||
|
||||
Future<void> updateDeviceNameInGroup(
|
||||
BuildContext context, String thingID, String newAlias) async {
|
||||
Map<String, dynamic> body = {"thing_id": thingID, "alias": newAlias};
|
||||
int statusCode = await apiServices.updateDeviceAlias(body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_update_device_success,
|
||||
appLocalization(context).notification_update_device_failed,
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Device>> getOwnerDevices() async {
|
||||
List<Device> allDevices = [];
|
||||
String body = await apiServices.getOwnerDevices();
|
||||
if (body != "") {
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data['items'];
|
||||
allDevices = Device.fromJsonDynamicList(items);
|
||||
}
|
||||
return allDevices;
|
||||
}
|
||||
|
||||
Future<void> addDeviceToGroup(
|
||||
BuildContext context, String groupID, String thingID) async {
|
||||
Map<String, dynamic> body = {
|
||||
"thing_id": thingID,
|
||||
};
|
||||
int statusCode = await apiServices.addDeviceToGroup(groupID, body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_add_device_success,
|
||||
appLocalization(context).notification_add_device_failed,
|
||||
);
|
||||
}
|
||||
}
|
||||
133
lib/feature/inter_family/group_detail/group_detail_model.dart
Normal file
133
lib/feature/inter_family/group_detail/group_detail_model.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
class GroupDetail {
|
||||
String? id;
|
||||
String? type;
|
||||
String? name;
|
||||
String? description;
|
||||
String? ownerId;
|
||||
String? status;
|
||||
String? visibility;
|
||||
DateTime? createdAt;
|
||||
DateTime? updatedAt;
|
||||
List<GroupUser>? users;
|
||||
List<DeviceOfGroup>? devices;
|
||||
|
||||
GroupDetail({
|
||||
required this.id,
|
||||
this.type,
|
||||
this.name,
|
||||
this.description,
|
||||
this.ownerId,
|
||||
this.status,
|
||||
this.visibility,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
this.users,
|
||||
this.devices,
|
||||
});
|
||||
|
||||
GroupDetail.fromJson(Map<String, dynamic> json) {
|
||||
id = json["id"];
|
||||
type = json["type"];
|
||||
name = json["name"];
|
||||
description = json["description"];
|
||||
ownerId = json["ownerId"];
|
||||
status = json["status"];
|
||||
visibility = json["visibility"];
|
||||
createdAt = DateTime.parse(json["created_at"]);
|
||||
updatedAt = DateTime.parse(json['updated_at']);
|
||||
if (json['users'] != null) {
|
||||
users = [];
|
||||
json["users"].forEach((v) {
|
||||
final user = GroupUser.fromJson(v);
|
||||
users!.add(user);
|
||||
});
|
||||
}
|
||||
if (json['devices'] != null) {
|
||||
devices = [];
|
||||
json["devices"].forEach((v) {
|
||||
final device = DeviceOfGroup.fromJson(v);
|
||||
devices!.add(device);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// static List<GroupDetail> fromJsonDynamicList(List<dynamic> list) {
|
||||
// return list.map((e) => GroupDetail.fromJson(e)).toList();
|
||||
// }
|
||||
}
|
||||
|
||||
class GroupUser {
|
||||
String? id;
|
||||
String? username;
|
||||
String? role;
|
||||
String? name;
|
||||
String? email;
|
||||
String? phone;
|
||||
bool? isOwner;
|
||||
String? status;
|
||||
String? address;
|
||||
String? latitude;
|
||||
String? longitude;
|
||||
|
||||
GroupUser({
|
||||
required this.id,
|
||||
this.username,
|
||||
this.role,
|
||||
this.name,
|
||||
this.email,
|
||||
this.phone,
|
||||
this.isOwner,
|
||||
this.status,
|
||||
this.address,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
});
|
||||
|
||||
GroupUser.fromJson(Map<String, dynamic> json) {
|
||||
id = json["id"];
|
||||
username = json["username"];
|
||||
role = json["role"];
|
||||
name = json["name"];
|
||||
email = json['email'];
|
||||
phone = json['phone'];
|
||||
isOwner = json['is_owner'];
|
||||
status = json['status'];
|
||||
address = json['address'];
|
||||
latitude = json['latitude'];
|
||||
longitude = json['longitude'];
|
||||
}
|
||||
|
||||
static List<GroupUser> fromJsonList(List list) {
|
||||
return list.map((e) => GroupUser.fromJson(e)).toList();
|
||||
}
|
||||
|
||||
static List<GroupUser> fromJsonDynamicList(List<dynamic> list) {
|
||||
return list.map((e) => GroupUser.fromJson(e)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceOfGroup {
|
||||
String? thingId;
|
||||
String? name;
|
||||
String? alias;
|
||||
DateTime? connectionTime;
|
||||
int? state;
|
||||
String? visibility;
|
||||
|
||||
DeviceOfGroup({
|
||||
required this.thingId,
|
||||
this.name,
|
||||
this.alias,
|
||||
this.connectionTime,
|
||||
this.state,
|
||||
this.visibility,
|
||||
});
|
||||
DeviceOfGroup.fromJson(Map<String, dynamic> json) {
|
||||
thingId = json['thing_id'];
|
||||
name = json['name'];
|
||||
alias = json['alias'];
|
||||
connectionTime = DateTime.parse(json['connection_time']);
|
||||
state = json['state'];
|
||||
visibility = json['visibility'];
|
||||
}
|
||||
}
|
||||
552
lib/feature/inter_family/group_detail/group_detail_screen.dart
Normal file
552
lib/feature/inter_family/group_detail/group_detail_screen.dart
Normal file
@@ -0,0 +1,552 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '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/services/api_services.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
import '../../../product/utils/response_status_utils.dart';
|
||||
|
||||
import 'add_device_to_group_dialog.dart';
|
||||
|
||||
class DetailGroupScreen extends StatefulWidget {
|
||||
const DetailGroupScreen({super.key, required this.group, required this.role});
|
||||
final String group;
|
||||
final String role;
|
||||
@override
|
||||
State<DetailGroupScreen> createState() => _DetailGroupScreenState();
|
||||
}
|
||||
|
||||
class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
late DetailGroupBloc detailGroupBloc;
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
detailGroupBloc = BlocProvider.of(context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StreamBuilder<GroupDetail>(
|
||||
stream: detailGroupBloc.streamDetailGroup,
|
||||
builder: (context, detailGroupSnapshot) {
|
||||
if (detailGroupSnapshot.data?.id == null) {
|
||||
detailGroupBloc.getGroupDetail(widget.group);
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
appBar: AppBar(
|
||||
title: Center(
|
||||
child: Text(
|
||||
detailGroupSnapshot.data?.name ??
|
||||
appLocalization(context).loading_message,
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
if (scaffoldKey.currentState != null) {
|
||||
scaffoldKey.currentState?.openEndDrawer();
|
||||
} else {
|
||||
// log("_scaffoldKey.currentState is null");
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.info_outline_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
endDrawer: endDrawer(detailGroupSnapshot.data!),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
addDeviceDialog(context, detailGroupBloc, widget.group,
|
||||
detailGroupSnapshot.data?.devices ?? []);
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
// backgroundColor: const Color.fromARGB(255, 109, 244, 96),
|
||||
label: Text(appLocalization(context).add_device_title),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: groupBody(
|
||||
detailGroupSnapshot.data?.devices ?? [],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget endDrawer(GroupDetail groupDetail) {
|
||||
APIServices apiServices = APIServices();
|
||||
return Drawer(
|
||||
width: context.dynamicWidth(0.75),
|
||||
child: ListView(
|
||||
children: [
|
||||
Center(
|
||||
child: Text(groupDetail.name ?? "",
|
||||
style: Theme.of(context).textTheme.titleLarge)),
|
||||
Center(
|
||||
child: Text(groupDetail.description ?? "",
|
||||
style: Theme.of(context).textTheme.bodyMedium)),
|
||||
Visibility(
|
||||
visible: widget.role == "owner",
|
||||
child: Theme(
|
||||
data:
|
||||
Theme.of(context).copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
title: Text(
|
||||
"${appLocalization(context).approve_user} (${getNumberInGroup(groupDetail, "PENDING")})",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
children: <Widget>[
|
||||
if (groupDetail.users != null &&
|
||||
groupDetail.users!.isNotEmpty)
|
||||
for (var user in groupDetail.users!)
|
||||
if (user.status == "PENDING")
|
||||
ListTile(
|
||||
title: Text(user.name!),
|
||||
subtitle: Text(user.email!),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 48,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
await detailGroupBloc.approveUserToGroup(
|
||||
context,
|
||||
widget.group,
|
||||
user.id!,
|
||||
user.name!);
|
||||
detailGroupBloc
|
||||
.getGroupDetail(widget.group);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.check,
|
||||
color: Colors.green,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 48,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
await detailGroupBloc.deleteOrUnapproveUser(
|
||||
context,
|
||||
widget.group,
|
||||
user.id!,
|
||||
user.name!);
|
||||
await detailGroupBloc
|
||||
.getGroupDetail(widget.group);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Theme(
|
||||
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
title: Text(
|
||||
"${appLocalization(context).member_title} (${getNumberInGroup(groupDetail, "JOINED")})",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
children: <Widget>[
|
||||
if (groupDetail.users != null && groupDetail.users!.isNotEmpty)
|
||||
for (var user in groupDetail.users!)
|
||||
if (user.status == "JOINED")
|
||||
ListTile(
|
||||
title: Text(user.name ?? 'Error'),
|
||||
subtitle: Text(user.email ?? 'Error'),
|
||||
trailing: widget.role == "owner"
|
||||
? PopupMenuButton(
|
||||
icon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.more_horiz),
|
||||
itemBuilder: (contex) => [
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
child: Text(appLocalization(context)
|
||||
.change_button_content)),
|
||||
PopupMenuItem(
|
||||
onTap: () async {
|
||||
await detailGroupBloc
|
||||
.deleteOrUnapproveUser(
|
||||
context,
|
||||
widget.group,
|
||||
user.id!,
|
||||
user.name!);
|
||||
await detailGroupBloc
|
||||
.getGroupDetail(widget.group);
|
||||
},
|
||||
value: 2,
|
||||
child: Text(appLocalization(context)
|
||||
.delete_button_content)),
|
||||
],
|
||||
)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Theme(
|
||||
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
title: Text(
|
||||
"${appLocalization(context).devices_title} (${getNumberInGroup(groupDetail, "DEVICES")})",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
children: <Widget>[
|
||||
if (groupDetail.devices != null &&
|
||||
groupDetail.devices!.isNotEmpty)
|
||||
for (var device in groupDetail.devices!)
|
||||
if (device.visibility == "PUBLIC")
|
||||
ListTile(
|
||||
title: Text(
|
||||
device.alias != "" ? device.alias! : device.name!),
|
||||
// subtitle: Text(device.thingId ?? 'Error'),
|
||||
trailing: widget.role ==
|
||||
ApplicationConstants.OWNER_GROUP
|
||||
? PopupMenuButton(
|
||||
icon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.more_horiz),
|
||||
itemBuilder: (contex) => [
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
showChangeAlias(device);
|
||||
},
|
||||
value: 1,
|
||||
child: Text(appLocalization(context)
|
||||
.change_button_content)),
|
||||
PopupMenuItem(
|
||||
onTap: () async {
|
||||
await detailGroupBloc.deleteDevice(
|
||||
context,
|
||||
widget.group,
|
||||
device.thingId!,
|
||||
device.name!,
|
||||
);
|
||||
},
|
||||
value: 2,
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.delete_button_content,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: PopupMenuButton(
|
||||
icon: IconConstants.instance.getMaterialIcon(
|
||||
Icons.more_horiz,
|
||||
),
|
||||
itemBuilder: ((itemContext) => [
|
||||
PopupMenuItem(
|
||||
onTap: () async {
|
||||
Navigator.pop(itemContext);
|
||||
Future.delayed(
|
||||
context.normalDuration,
|
||||
() => showChangeAlias(device),
|
||||
);
|
||||
},
|
||||
value: 1,
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.change_button_content,
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: context.dynamicHeight(0.3)),
|
||||
if (widget.role == "owner")
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Future.delayed(context.normalDuration)
|
||||
.then((value) => Navigator.pop(context))
|
||||
.then(
|
||||
(value) => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertDialog(
|
||||
title: Center(
|
||||
child: Text(appLocalization(context)
|
||||
.delete_group_title)),
|
||||
content: Text(
|
||||
appLocalization(context)
|
||||
.delete_device_dialog_content,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.cancel_button_content,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(dialogContext).pop();
|
||||
Future.delayed(context.lowDuration).then(
|
||||
(value) => Navigator.pop(context),
|
||||
);
|
||||
int statusCode = await apiServices
|
||||
.deleteGroup(widget.group);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context)
|
||||
.notification_delete_group_success,
|
||||
appLocalization(context)
|
||||
.notification_delete_group_failed);
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.confirm_button_content,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
},
|
||||
);
|
||||
},
|
||||
style: const ButtonStyle(
|
||||
backgroundColor: MaterialStatePropertyAll(Colors.red),
|
||||
foregroundColor: MaterialStatePropertyAll(Colors.white),
|
||||
),
|
||||
child: Text(
|
||||
appLocalization(context).delete_group_title,
|
||||
),
|
||||
)
|
||||
else
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
String uid = await apiServices.getUID();
|
||||
Future.delayed(context.lowDuration)
|
||||
.then((value) => Navigator.pop(context))
|
||||
.then((value) => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertDialog(
|
||||
title: Center(
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.leave_group_title,
|
||||
),
|
||||
),
|
||||
content: Text(appLocalization(context)
|
||||
.leave_group_content),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.cancel_button_content,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(dialogContext).pop();
|
||||
Future.delayed(context.normalDuration)
|
||||
.then((value) =>
|
||||
Navigator.pop(context));
|
||||
await detailGroupBloc.leaveGroup(
|
||||
context, widget.group, uid);
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.confirm_button_content,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
))
|
||||
],
|
||||
);
|
||||
})
|
||||
});
|
||||
},
|
||||
style: const ButtonStyle(
|
||||
backgroundColor: MaterialStatePropertyAll(Colors.red),
|
||||
foregroundColor: MaterialStatePropertyAll(Colors.white),
|
||||
),
|
||||
child: Text(
|
||||
appLocalization(context).leave_group_title,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget groupBody(List<DeviceOfGroup> devices) {
|
||||
devices = softDeviceByState(devices);
|
||||
List<String> deviceState = [];
|
||||
if (devices.isNotEmpty) {
|
||||
for (var device in devices) {
|
||||
String state =
|
||||
DeviceUtils.instance.checkStateDevice(context, device.state!);
|
||||
deviceState.add(state);
|
||||
}
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Center(
|
||||
child: devices.isEmpty
|
||||
? Center(
|
||||
child: Text(appLocalization(context).dont_have_device),
|
||||
)
|
||||
: StreamBuilder<List<DeviceOfGroup>>(
|
||||
stream: detailGroupBloc.streamWarningDevice,
|
||||
builder: (context, warningDeviceSnapshot) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
"${appLocalization(context).warning_message} ${warningDeviceSnapshot.data?.length ?? '0'}",
|
||||
style: const TextStyle(
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: devices.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return ListTile(
|
||||
title: Text(devices[index].alias != ""
|
||||
? devices[index].alias!
|
||||
: devices[index].name!,),
|
||||
trailing: Text(
|
||||
DeviceUtils.instance.checkStateDevice(
|
||||
context, devices[index].state!),
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance
|
||||
.getTableRowColor(
|
||||
devices[index].state!,),),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
showChangeAlias(DeviceOfGroup device) async {
|
||||
TextEditingController aliasController =
|
||||
TextEditingController(text: device.alias);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
backgroundColor: Colors.white,
|
||||
dismissDirection: DismissDirection.none,
|
||||
duration: const Duration(minutes: 1),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('${appLocalization(context).map_result}: ',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black)),
|
||||
Container(
|
||||
alignment: Alignment.centerRight,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
)
|
||||
],
|
||||
),
|
||||
TextField(
|
||||
controller: aliasController,
|
||||
decoration: InputDecoration(
|
||||
label:
|
||||
Text(appLocalization(context).input_name_device_device),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16.0)))),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Center(
|
||||
child: TextButton(
|
||||
style: const ButtonStyle(
|
||||
foregroundColor: MaterialStatePropertyAll(Colors.white),
|
||||
backgroundColor: MaterialStatePropertyAll(Colors.green)),
|
||||
onPressed: () async {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
String alias = aliasController.text;
|
||||
await detailGroupBloc.updateDeviceNameInGroup(
|
||||
context, device.thingId!, alias);
|
||||
await detailGroupBloc.getGroupDetail(widget.group);
|
||||
},
|
||||
child: Text(appLocalization(context).confirm_button_content)),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<DeviceOfGroup> softDeviceByState(List<DeviceOfGroup> devices) {
|
||||
List<DeviceOfGroup> sortedDevices = List.from(devices);
|
||||
sortedDevices.sort((a, b) {
|
||||
int stateOrder = [2, 1, 3, 0, -1, 3].indexOf(a.state!) -
|
||||
[2, 1, 3, 0, -1, 3].indexOf(b.state!);
|
||||
return stateOrder;
|
||||
});
|
||||
|
||||
return sortedDevices;
|
||||
}
|
||||
|
||||
int getNumberInGroup(GroupDetail group, String name) {
|
||||
int number = 0;
|
||||
|
||||
if (group.id != "") {
|
||||
if (name == "PENDING" || name == "JOINED") {
|
||||
for (var user in group.users ?? []) {
|
||||
if (user.status == name) {
|
||||
number++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var device in group.devices ?? []) {
|
||||
if (device.visibility == "PUBLIC") {
|
||||
number++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
Reference in New Issue
Block a user