mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-10-26 20:37:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76793a3c0b | ||
|
|
c330f11206 | ||
|
|
9cb62795a6 | ||
|
|
a034202d76 | ||
|
|
869799f08e | ||
|
|
573e7b42ed | ||
|
|
5bf5120883 | ||
|
|
f307aaff9d | ||
|
|
aea18fb293 | ||
|
|
835dfe8785 | ||
|
|
f670ae78aa | ||
|
|
d3128a9c9c | ||
|
|
b65f172f9d | ||
|
|
dad18b77de | ||
|
|
77a9aa2f19 | ||
|
|
b77dc860cb | ||
|
|
80c43b8046 | ||
|
|
2d3345c1d9 | ||
|
|
de5030d9f0 | ||
|
|
8c15fffd42 | ||
|
|
3750fa8329 |
@@ -2,14 +2,17 @@ import 'package:flutter/foundation.dart';
|
|||||||
|
|
||||||
class FactoryResetModel {
|
class FactoryResetModel {
|
||||||
final List<String> devicesUuid;
|
final List<String> devicesUuid;
|
||||||
|
final String operationType;
|
||||||
|
|
||||||
FactoryResetModel({
|
FactoryResetModel({
|
||||||
required this.devicesUuid,
|
required this.devicesUuid,
|
||||||
|
this.operationType = "RESET",
|
||||||
});
|
});
|
||||||
|
|
||||||
factory FactoryResetModel.fromJson(Map<String, dynamic> json) {
|
factory FactoryResetModel.fromJson(Map<String, dynamic> json) {
|
||||||
return FactoryResetModel(
|
return FactoryResetModel(
|
||||||
devicesUuid: List<String>.from(json['devicesUuid']),
|
devicesUuid: List<String>.from(json['devicesUuid']),
|
||||||
|
operationType: "RESET",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,77 +12,95 @@ class DeviceSearchFilters extends StatefulWidget {
|
|||||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||||
final TextEditingController communityController = TextEditingController();
|
with HelperResponsiveLayout {
|
||||||
final TextEditingController unitNameController = TextEditingController();
|
late final TextEditingController _unitNameController;
|
||||||
final TextEditingController productNameController = TextEditingController();
|
late final TextEditingController _productNameController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_unitNameController = TextEditingController();
|
||||||
|
_productNameController = TextEditingController();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_unitNameController.dispose();
|
||||||
|
_productNameController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> get _widgets => [
|
||||||
|
_buildSearchField(
|
||||||
|
"Space Name",
|
||||||
|
_unitNameController,
|
||||||
|
200,
|
||||||
|
),
|
||||||
|
_buildSearchField(
|
||||||
|
"Device Name / Product Name",
|
||||||
|
_productNameController,
|
||||||
|
300,
|
||||||
|
),
|
||||||
|
_buildSearchResetButtons(),
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return isExtraLargeScreenSize(context)
|
if (isExtraLargeScreenSize(context)) {
|
||||||
? Row(
|
return Row(
|
||||||
children: [
|
children: _widgets.map(
|
||||||
_buildSearchField("Community", communityController, 200),
|
(e) {
|
||||||
const SizedBox(width: 20),
|
return Padding(
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
const SizedBox(width: 20),
|
child: e,
|
||||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
);
|
||||||
const SizedBox(width: 20),
|
},
|
||||||
_buildSearchResetButtons(),
|
).toList(),
|
||||||
],
|
);
|
||||||
)
|
}
|
||||||
: Wrap(
|
|
||||||
spacing: 20,
|
return Wrap(
|
||||||
runSpacing: 10,
|
spacing: 20,
|
||||||
children: [
|
runSpacing: 10,
|
||||||
_buildSearchField(
|
children: _widgets,
|
||||||
"Community",
|
);
|
||||||
communityController,
|
|
||||||
200,
|
|
||||||
),
|
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
|
||||||
_buildSearchField(
|
|
||||||
"Device Name / Product Name",
|
|
||||||
productNameController,
|
|
||||||
300,
|
|
||||||
),
|
|
||||||
_buildSearchResetButtons(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
Widget _buildSearchField(
|
||||||
return Container(
|
String title,
|
||||||
child: StatefulTextField(
|
TextEditingController controller,
|
||||||
title: title,
|
double width,
|
||||||
width: width,
|
) {
|
||||||
elevation: 2,
|
return StatefulTextField(
|
||||||
controller: controller,
|
title: title,
|
||||||
onSubmitted: () {
|
width: width,
|
||||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
elevation: 2,
|
||||||
productName: productNameController.text,
|
controller: controller,
|
||||||
unitName: unitNameController.text,
|
onSubmitted: () {
|
||||||
community: communityController.text,
|
final searchDevicesEvent = SearchDevices(
|
||||||
searchField: true));
|
productName: _productNameController.text,
|
||||||
},
|
unitName: _unitNameController.text,
|
||||||
onChanged: (p0) {},
|
searchField: true,
|
||||||
),
|
);
|
||||||
|
context.read<DeviceManagementBloc>().add(searchDevicesEvent);
|
||||||
|
},
|
||||||
|
onChanged: (p0) {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchResetButtons() {
|
Widget _buildSearchResetButtons() {
|
||||||
return SearchResetButtons(
|
return SearchResetButtons(
|
||||||
onSearch: () {
|
onSearch: () => context.read<DeviceManagementBloc>().add(
|
||||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
SearchDevices(
|
||||||
community: communityController.text,
|
unitName: _unitNameController.text,
|
||||||
unitName: unitNameController.text,
|
productName: _productNameController.text,
|
||||||
productName: productNameController.text,
|
searchField: true,
|
||||||
searchField: true));
|
),
|
||||||
},
|
),
|
||||||
onReset: () {
|
onReset: () {
|
||||||
communityController.clear();
|
_unitNameController.clear();
|
||||||
unitNameController.clear();
|
_productNameController.clear();
|
||||||
productNameController.clear();
|
|
||||||
context.read<DeviceManagementBloc>()
|
context.read<DeviceManagementBloc>()
|
||||||
..add(ResetFilters())
|
..add(ResetFilters())
|
||||||
..add(FetchDevices(context));
|
..add(FetchDevices(context));
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
|
||||||
|
|
||||||
class CommunityDropdown extends StatelessWidget {
|
class CommunityDropdown extends StatelessWidget {
|
||||||
final String? selectedValue;
|
final String? selectedValue;
|
||||||
final Function(String?) onChanged;
|
final Function(String?) onChanged;
|
||||||
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
|
||||||
const CommunityDropdown({
|
CommunityDropdown({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.selectedValue,
|
required this.selectedValue,
|
||||||
required this.onChanged,
|
required this.onChanged,
|
||||||
@@ -34,59 +34,125 @@ class CommunityDropdown extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
BlocBuilder<SpaceTreeBloc, SpaceTreeState>(
|
BlocBuilder<SpaceTreeBloc, SpaceTreeState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
List<CommunityModel> communities = state.isSearching
|
|
||||||
? state.filteredCommunity
|
|
||||||
: state.communityList;
|
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
child: DropdownButtonFormField<String>(
|
child: Container(
|
||||||
dropdownColor: ColorsManager.whiteColors,
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: DropdownButton2<String>(
|
||||||
|
underline: SizedBox(),
|
||||||
value: selectedValue,
|
value: selectedValue,
|
||||||
items: communities.map((community) {
|
items: state.communityList.map((community) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: community.uuid,
|
value: community.uuid,
|
||||||
child: Text(' ${community.name}'),
|
child: Text(
|
||||||
|
' ${community.name}',
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
icon: const SizedBox.shrink(),
|
style: TextStyle(color: Colors.black),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
|
||||||
hint: Padding(
|
hint: Padding(
|
||||||
padding: EdgeInsets.only(left: 10),
|
padding: EdgeInsets.only(left: 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Please Select",
|
" Please Select",
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: inputTextFormDeco().copyWith(
|
customButton: Container(
|
||||||
contentPadding: EdgeInsets.zero,
|
height: 45,
|
||||||
suffixIcon: Container(
|
decoration: BoxDecoration(
|
||||||
padding: EdgeInsets.zero,
|
border:
|
||||||
width: 70,
|
Border.all(color: ColorsManager.textGray, width: 1.0),
|
||||||
height: 45,
|
borderRadius: BorderRadius.circular(10),
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
color: Colors.grey[100],
|
child: Row(
|
||||||
borderRadius: const BorderRadius.only(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
bottomRight: Radius.circular(10),
|
children: [
|
||||||
topRight: Radius.circular(10),
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Text(
|
||||||
|
selectedValue != null
|
||||||
|
? " ${state.communityList.firstWhere((element) => element.uuid == selectedValue).name}"
|
||||||
|
: ' Please Select',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: selectedValue != null
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
border: Border.all(
|
Expanded(
|
||||||
color: ColorsManager.textGray,
|
child: Container(
|
||||||
width: 1.0,
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[100],
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 45,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
child: const Center(
|
),
|
||||||
child: Icon(
|
),
|
||||||
Icons.keyboard_arrow_down,
|
dropdownStyleData: DropdownStyleData(
|
||||||
color: ColorsManager.textGray,
|
maxHeight: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownSearchData: DropdownSearchData(
|
||||||
|
searchController: _searchController,
|
||||||
|
searchInnerWidgetHeight: 50,
|
||||||
|
searchInnerWidget: Container(
|
||||||
|
height: 50,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8, vertical: 4),
|
||||||
|
child: TextFormField(
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
controller: _searchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
hintText: 'Search for community...',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
searchMatchFn: (item, searchValue) {
|
||||||
|
final communityName =
|
||||||
|
(item.child as Text).data?.toLowerCase() ?? '';
|
||||||
|
return communityName
|
||||||
|
.contains(searchValue.toLowerCase().trim());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
onMenuStateChange: (isOpen) {
|
||||||
|
if (!isOpen) {
|
||||||
|
_searchController.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 40,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -62,28 +62,34 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const Divider(),
|
const Divider(),
|
||||||
CommunityDropdown(
|
Padding(
|
||||||
selectedValue: _selectedCommunity,
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
onChanged: (String? newValue) {
|
child: CommunityDropdown(
|
||||||
setState(() {
|
selectedValue: _selectedCommunity,
|
||||||
_selectedCommunity = newValue;
|
onChanged: (String? newValue) {
|
||||||
_selectedSpace = null;
|
setState(() {
|
||||||
});
|
_selectedCommunity = newValue;
|
||||||
if (newValue != null) {
|
_selectedSpace = null;
|
||||||
_fetchSpaces(newValue);
|
});
|
||||||
}
|
if (newValue != null) {
|
||||||
},
|
_fetchSpaces(newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 5),
|
||||||
SpaceDropdown(
|
Padding(
|
||||||
hintMessage: spaceHint,
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
spaces: spaces,
|
child: SpaceDropdown(
|
||||||
selectedValue: _selectedSpace,
|
hintMessage: spaceHint,
|
||||||
onChanged: (String? newValue) {
|
spaces: spaces,
|
||||||
setState(() {
|
selectedValue: _selectedSpace,
|
||||||
_selectedSpace = newValue;
|
onChanged: (String? newValue) {
|
||||||
});
|
setState(() {
|
||||||
},
|
_selectedSpace = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
Row(
|
Row(
|
||||||
@@ -96,7 +102,6 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
|
|||||||
),
|
),
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -139,6 +144,7 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
|
||||||
|
|
||||||
class SpaceDropdown extends StatelessWidget {
|
class SpaceDropdown extends StatelessWidget {
|
||||||
final List<SpaceModel> spaces;
|
final List<SpaceModel> spaces;
|
||||||
@@ -33,62 +34,108 @@ class SpaceDropdown extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
DropdownButtonFormField<String>(
|
SizedBox(
|
||||||
value: selectedValue,
|
child: Container(
|
||||||
items: spaces.map((space) {
|
decoration: BoxDecoration(
|
||||||
return DropdownMenuItem<String>(
|
borderRadius: BorderRadius.circular(10),
|
||||||
value: space.uuid,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
' ${space.name}',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
' ${space.lastThreeParents}',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}).toList(),
|
|
||||||
onChanged: onChanged,
|
|
||||||
icon: const SizedBox.shrink(),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
|
||||||
hint: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
hintMessage,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
child: DropdownButton2<String>(
|
||||||
decoration: inputTextFormDeco().copyWith(
|
underline: const SizedBox(),
|
||||||
contentPadding: EdgeInsets.zero,
|
value: selectedValue,
|
||||||
suffixIcon: Container(
|
items: spaces.map((space) {
|
||||||
width: 70,
|
return DropdownMenuItem<String>(
|
||||||
height: 45,
|
value: space.uuid,
|
||||||
decoration: BoxDecoration(
|
child: Column(
|
||||||
color: Colors.grey[200],
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
borderRadius: const BorderRadius.only(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
bottomRight: Radius.circular(10),
|
children: [
|
||||||
topRight: Radius.circular(10),
|
Text(
|
||||||
),
|
' ${space.name}',
|
||||||
border: Border.all(
|
style:
|
||||||
color: ColorsManager.textGray,
|
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
width: 1.0,
|
fontSize: 12,
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
' ${space.lastThreeParents}',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: onChanged,
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
hint: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
hintMessage,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: const Icon(
|
customButton: Container(
|
||||||
Icons.keyboard_arrow_down,
|
height: 45,
|
||||||
color: ColorsManager.textGray,
|
decoration: BoxDecoration(
|
||||||
|
border:
|
||||||
|
Border.all(color: ColorsManager.textGray, width: 1.0),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
selectedValue != null
|
||||||
|
? spaces
|
||||||
|
.firstWhere((e) => e.uuid == selectedValue)
|
||||||
|
.name
|
||||||
|
: hintMessage,
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: selectedValue != null
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 45,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownStyleData: DropdownStyleData(
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 60,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ class _RoutinesViewState extends State<RoutinesView> {
|
|||||||
communityID: communityId, spaceID: spaceId));
|
communityID: communityId, spaceID: spaceId));
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
|
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
|
||||||
await Future.delayed(const Duration(milliseconds:500));
|
|
||||||
_bloc.add(const ResetSelectedEvent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -28,11 +28,10 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final updatedCommunity = event.updatedCommunity;
|
final updatedCommunity = event.updatedCommunity;
|
||||||
final updatedCommunities =
|
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
||||||
List<CommunityModel>.from(state.communityList);
|
|
||||||
|
|
||||||
final index = updatedCommunities
|
final index =
|
||||||
.indexWhere((community) => community.uuid == updatedCommunity.uuid);
|
updatedCommunities.indexWhere((community) => community.uuid == updatedCommunity.uuid);
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
updatedCommunities[index] = updatedCommunity;
|
updatedCommunities[index] = updatedCommunity;
|
||||||
@@ -51,47 +50,41 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
List<CommunityModel> communities =
|
List<CommunityModel> communities =
|
||||||
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
await CommunitySpaceManagementApi().fetchCommunities(projectUuid, includeSpaces: true);
|
||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
// List<CommunityModel> updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
// communities.map((community) async {
|
||||||
List<SpaceModel> spaces = await CommunitySpaceManagementApi()
|
// List<SpaceModel> spaces =
|
||||||
.getSpaceHierarchy(community.uuid, projectUuid);
|
// await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid, projectUuid);
|
||||||
|
|
||||||
return CommunityModel(
|
// return CommunityModel(
|
||||||
uuid: community.uuid,
|
// uuid: community.uuid,
|
||||||
createdAt: community.createdAt,
|
// createdAt: community.createdAt,
|
||||||
updatedAt: community.updatedAt,
|
// updatedAt: community.updatedAt,
|
||||||
name: community.name,
|
// name: community.name,
|
||||||
description: community.description,
|
// description: community.description,
|
||||||
spaces: spaces,
|
// spaces: spaces,
|
||||||
region: community.region,
|
// region: community.region,
|
||||||
);
|
// );
|
||||||
}).toList(),
|
// }).toList(),
|
||||||
);
|
// );
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(communitiesList: communities, expandedCommunity: [], expandedSpaces: []));
|
||||||
communitiesList: updatedCommunities,
|
|
||||||
expandedCommunity: [],
|
|
||||||
expandedSpaces: []));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onCommunityAdded(
|
void _onCommunityAdded(OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
|
||||||
OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
|
|
||||||
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
||||||
updatedCommunities.add(event.newCommunity);
|
updatedCommunities.add(event.newCommunity);
|
||||||
|
|
||||||
emit(state.copyWith(communitiesList: updatedCommunities));
|
emit(state.copyWith(communitiesList: updatedCommunities));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCommunityExpanded(
|
_onCommunityExpanded(OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||||
OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
List<String> updatedExpandedCommunityList =
|
List<String> updatedExpandedCommunityList = List.from(state.expandedCommunities);
|
||||||
List.from(state.expandedCommunities);
|
|
||||||
|
|
||||||
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
||||||
updatedExpandedCommunityList.remove(event.communityId);
|
updatedExpandedCommunityList.remove(event.communityId);
|
||||||
@@ -123,19 +116,14 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCommunitySelected(
|
_onCommunitySelected(OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
||||||
OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
List<String> updatedSelectedCommunities =
|
List<String> updatedSelectedCommunities =
|
||||||
List.from(state.selectedCommunities.toSet().toList());
|
List.from(state.selectedCommunities.toSet().toList());
|
||||||
List<String> updatedSelectedSpaces =
|
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||||
List.from(state.selectedSpaces.toSet().toList());
|
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||||
List<String> updatedSoldChecks =
|
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||||
List.from(state.soldCheck.toSet().toList());
|
List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityId] ?? [];
|
||||||
Map<String, List<String>> communityAndSpaces =
|
|
||||||
Map.from(state.selectedCommunityAndSpaces);
|
|
||||||
List<String> selectedSpacesInCommunity =
|
|
||||||
communityAndSpaces[event.communityId] ?? [];
|
|
||||||
|
|
||||||
List<String> childrenIds = _getAllChildIds(event.children);
|
List<String> childrenIds = _getAllChildIds(event.children);
|
||||||
|
|
||||||
@@ -168,15 +156,11 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
try {
|
try {
|
||||||
List<String> updatedSelectedCommunities =
|
List<String> updatedSelectedCommunities =
|
||||||
List.from(state.selectedCommunities.toSet().toList());
|
List.from(state.selectedCommunities.toSet().toList());
|
||||||
List<String> updatedSelectedSpaces =
|
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||||
List.from(state.selectedSpaces.toSet().toList());
|
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||||
List<String> updatedSoldChecks =
|
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||||
List.from(state.soldCheck.toSet().toList());
|
|
||||||
Map<String, List<String>> communityAndSpaces =
|
|
||||||
Map.from(state.selectedCommunityAndSpaces);
|
|
||||||
|
|
||||||
List<String> selectedSpacesInCommunity =
|
List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityModel.uuid] ?? [];
|
||||||
communityAndSpaces[event.communityModel.uuid] ?? [];
|
|
||||||
|
|
||||||
List<String> childrenIds = _getAllChildIds(event.children);
|
List<String> childrenIds = _getAllChildIds(event.children);
|
||||||
bool isChildSelected = false;
|
bool isChildSelected = false;
|
||||||
@@ -199,11 +183,9 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
selectedSpacesInCommunity.addAll(childrenIds);
|
selectedSpacesInCommunity.addAll(childrenIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> spaces =
|
List<String> spaces = _getThePathToChild(event.communityModel.uuid, event.spaceId);
|
||||||
_getThePathToChild(event.communityModel.uuid, event.spaceId);
|
|
||||||
for (String space in spaces) {
|
for (String space in spaces) {
|
||||||
if (!updatedSelectedSpaces.contains(space) &&
|
if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) {
|
||||||
!updatedSoldChecks.contains(space)) {
|
|
||||||
updatedSoldChecks.add(space);
|
updatedSoldChecks.add(space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,9 +208,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
updatedSoldChecks.remove(event.spaceId);
|
updatedSoldChecks.remove(event.spaceId);
|
||||||
|
|
||||||
List<String> parents =
|
List<String> parents =
|
||||||
_getThePathToChild(event.communityModel.uuid, event.spaceId)
|
_getThePathToChild(event.communityModel.uuid, event.spaceId).toSet().toList();
|
||||||
.toSet()
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (updatedSelectedSpaces.isEmpty) {
|
if (updatedSelectedSpaces.isEmpty) {
|
||||||
updatedSoldChecks.removeWhere(parents.contains);
|
updatedSoldChecks.removeWhere(parents.contains);
|
||||||
@@ -236,8 +216,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
} else {
|
} else {
|
||||||
// Check if any parent has selected children
|
// Check if any parent has selected children
|
||||||
for (String space in parents) {
|
for (String space in parents) {
|
||||||
if (!_noChildrenSelected(
|
if (!_noChildrenSelected(event.communityModel, space, updatedSelectedSpaces, parents)) {
|
||||||
event.communityModel, space, updatedSelectedSpaces, parents)) {
|
|
||||||
updatedSoldChecks.remove(space);
|
updatedSoldChecks.remove(space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,8 +241,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_noChildrenSelected(CommunityModel community, String spaceId,
|
_noChildrenSelected(
|
||||||
List<String> selectedSpaces, List<String> parents) {
|
CommunityModel community, String spaceId, List<String> selectedSpaces, List<String> parents) {
|
||||||
if (selectedSpaces.contains(spaceId)) {
|
if (selectedSpaces.contains(spaceId)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -290,11 +269,10 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
|
|
||||||
// Filter communities and expand only those that match the query
|
// Filter communities and expand only those that match the query
|
||||||
filteredCommunity = communities.where((community) {
|
filteredCommunity = communities.where((community) {
|
||||||
final containsQueryInCommunity = community.name
|
final containsQueryInCommunity =
|
||||||
.toLowerCase()
|
community.name.toLowerCase().contains(event.searchQuery.toLowerCase());
|
||||||
.contains(event.searchQuery.toLowerCase());
|
final containsQueryInSpaces =
|
||||||
final containsQueryInSpaces = community.spaces.any(
|
community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
||||||
(space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
|
||||||
|
|
||||||
return containsQueryInCommunity || containsQueryInSpaces;
|
return containsQueryInCommunity || containsQueryInSpaces;
|
||||||
}).toList();
|
}).toList();
|
||||||
@@ -347,8 +325,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
// Helper function to determine if any space or its children match the search query
|
// Helper function to determine if any space or its children match the search query
|
||||||
bool _containsQuery(SpaceModel space, String query) {
|
bool _containsQuery(SpaceModel space, String query) {
|
||||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
final matchesSpace = space.name.toLowerCase().contains(query);
|
||||||
final matchesChildren = space.children.any((child) =>
|
final matchesChildren =
|
||||||
_containsQuery(child, query)); // Recursive check for children
|
space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
|
||||||
|
|
||||||
return matchesSpace || matchesChildren;
|
return matchesSpace || matchesChildren;
|
||||||
}
|
}
|
||||||
@@ -371,8 +349,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _anySpacesSelectedInCommunity(CommunityModel community,
|
bool _anySpacesSelectedInCommunity(
|
||||||
List<String> selectedSpaces, List<String> partialCheckedList) {
|
CommunityModel community, List<String> selectedSpaces, List<String> partialCheckedList) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
List<String> ids = _getAllChildIds(community.spaces);
|
List<String> ids = _getAllChildIds(community.spaces);
|
||||||
for (var id in ids) {
|
for (var id in ids) {
|
||||||
@@ -401,8 +379,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> _getAllParentsIds(
|
List<String> _getAllParentsIds(SpaceModel child, String spaceId, List<String> listIds) {
|
||||||
SpaceModel child, String spaceId, List<String> listIds) {
|
|
||||||
List<String> ids = listIds;
|
List<String> ids = listIds;
|
||||||
|
|
||||||
ids.add(child.uuid ?? '');
|
ids.add(child.uuid ?? '');
|
||||||
|
|||||||
@@ -262,27 +262,6 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (communities.isEmpty) {
|
|
||||||
communities = await _api.fetchCommunities(projectUuid);
|
|
||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
|
||||||
communities.map((community) async {
|
|
||||||
List<SpaceModel> spaces = await _fetchSpacesForCommunity(community.uuid);
|
|
||||||
return CommunityModel(
|
|
||||||
uuid: community.uuid,
|
|
||||||
createdAt: community.createdAt,
|
|
||||||
updatedAt: community.updatedAt,
|
|
||||||
name: community.name,
|
|
||||||
description: community.description,
|
|
||||||
spaces: spaces,
|
|
||||||
region: community.region,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
communities = updatedCommunities;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(BlankState(
|
emit(BlankState(
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
communities: communities,
|
communities: communities,
|
||||||
@@ -540,7 +519,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
List<TagModelUpdate> tagUpdates = [];
|
List<TagModelUpdate> tagUpdates = [];
|
||||||
|
|
||||||
List<SpaceModel> matchedSpaces =
|
List<SpaceModel> matchedSpaces =
|
||||||
selectedCommunity.spaces.where((space) => space.uuid == space.uuid).toList();
|
findMatchingSpaces(selectedCommunity.spaces, space.uuid!);
|
||||||
|
|
||||||
if (matchedSpaces.isEmpty) continue;
|
if (matchedSpaces.isEmpty) continue;
|
||||||
|
|
||||||
@@ -696,27 +675,6 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
|
|
||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
if (communities.isEmpty) {
|
|
||||||
communities = await _api.fetchCommunities(projectUuid);
|
|
||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
|
||||||
communities.map((community) async {
|
|
||||||
List<SpaceModel> spaces = await _fetchSpacesForCommunity(community.uuid);
|
|
||||||
return CommunityModel(
|
|
||||||
uuid: community.uuid,
|
|
||||||
createdAt: community.createdAt,
|
|
||||||
updatedAt: community.updatedAt,
|
|
||||||
name: community.name,
|
|
||||||
description: community.description,
|
|
||||||
spaces: spaces,
|
|
||||||
region: community.region,
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
communities = updatedCommunities;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(SpaceModelLoaded(
|
emit(SpaceModelLoaded(
|
||||||
communities: communities,
|
communities: communities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
@@ -799,4 +757,18 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
|
|
||||||
return tagUpdates;
|
return tagUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<SpaceModel> findMatchingSpaces(List<SpaceModel> spaces, String targetUuid) {
|
||||||
|
List<SpaceModel> matched = [];
|
||||||
|
|
||||||
|
for (var space in spaces) {
|
||||||
|
if (space.uuid == targetUuid) {
|
||||||
|
matched.add(space);
|
||||||
|
}
|
||||||
|
matched
|
||||||
|
.addAll(findMatchingSpaces(space.children, targetUuid)); // Recursively search in children
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,11 +301,18 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
||||||
setState(() {
|
setState(() {
|
||||||
// Set the first space in the center or use passed position
|
// Set the first space in the center or use passed position
|
||||||
Offset centerPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
|
Offset newPosition;
|
||||||
|
if (parentIndex != null) {
|
||||||
|
newPosition =
|
||||||
|
getBalancedChildPosition(spaces[parentIndex]); // Ensure balanced position
|
||||||
|
} else {
|
||||||
|
newPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
|
||||||
|
}
|
||||||
|
|
||||||
SpaceModel newSpace = SpaceModel(
|
SpaceModel newSpace = SpaceModel(
|
||||||
name: name,
|
name: name,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
position: centerPosition,
|
position: newPosition,
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
children: [],
|
children: [],
|
||||||
status: SpaceStatus.newSpace,
|
status: SpaceStatus.newSpace,
|
||||||
@@ -425,7 +432,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
Connection(
|
Connection(
|
||||||
startSpace: parent,
|
startSpace: parent,
|
||||||
endSpace: child,
|
endSpace: child,
|
||||||
direction: child.incomingConnection?.direction ?? "down",
|
direction: "down",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -522,6 +529,38 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Offset getBalancedChildPosition(SpaceModel parent) {
|
||||||
|
int totalSiblings = parent.children.length + 1;
|
||||||
|
double totalWidth = (totalSiblings - 1) * 250; // Horizontal spacing
|
||||||
|
double startX = parent.position.dx - (totalWidth / 2);
|
||||||
|
|
||||||
|
Offset position = Offset(startX + (parent.children.length * 250), parent.position.dy + 180);
|
||||||
|
|
||||||
|
// Check for overlaps & adjust
|
||||||
|
while (spaces.any((s) => (s.position - position).distance < 250)) {
|
||||||
|
position = Offset(position.dx + 250, position.dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void realignTree() {
|
||||||
|
void updatePositions(SpaceModel node, double x, double y) {
|
||||||
|
node.position = Offset(x, y);
|
||||||
|
|
||||||
|
int numChildren = node.children.length;
|
||||||
|
double childStartX = x - ((numChildren - 1) * 250) / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < numChildren; i++) {
|
||||||
|
updatePositions(node.children[i], childStartX + (i * 250), y + 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spaces.isNotEmpty) {
|
||||||
|
updatePositions(spaces.first, spaces.first.position.dx, spaces.first.position.dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onDuplicate(BuildContext parentContext) {
|
void _onDuplicate(BuildContext parentContext) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
@@ -604,29 +643,57 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
void _duplicateSpace(SpaceModel space) {
|
void _duplicateSpace(SpaceModel space) {
|
||||||
final Map<SpaceModel, SpaceModel> originalToDuplicate = {};
|
final Map<SpaceModel, SpaceModel> originalToDuplicate = {};
|
||||||
const double horizontalGap = 200.0;
|
double horizontalGap = 250.0; // Increased spacing
|
||||||
const double verticalGap = 100.0;
|
double verticalGap = 180.0; // Adjusted for better visualization
|
||||||
|
|
||||||
SpaceModel duplicateRecursive(
|
print("🟢 Duplicating: ${space.name}");
|
||||||
SpaceModel original, Offset parentPosition, SpaceModel? duplicatedParent) {
|
|
||||||
Offset newPosition = Offset(parentPosition.dx + horizontalGap, original.position.dy);
|
|
||||||
|
|
||||||
while (spaces.any((s) =>
|
/// **Find a new position ensuring no overlap**
|
||||||
(s.position - newPosition).distance < horizontalGap && s.status != SpaceStatus.deleted)) {
|
Offset getBalancedChildPosition(SpaceModel parent) {
|
||||||
newPosition += Offset(horizontalGap, 0);
|
int totalSiblings = parent.children.length + 1;
|
||||||
|
double totalWidth = (totalSiblings - 1) * horizontalGap;
|
||||||
|
double startX = parent.position.dx - (totalWidth / 2);
|
||||||
|
Offset position = Offset(
|
||||||
|
startX + (parent.children.length * horizontalGap), parent.position.dy + verticalGap);
|
||||||
|
|
||||||
|
// **Check for overlaps & adjust**
|
||||||
|
while (spaces.any((s) => (s.position - position).distance < horizontalGap)) {
|
||||||
|
position = Offset(position.dx + horizontalGap, position.dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("🔹 New position for ${parent.name}: (${position.dx}, ${position.dy})");
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// **Realign the entire tree after duplication**
|
||||||
|
void realignTree() {
|
||||||
|
void updatePositions(SpaceModel node, double x, double y) {
|
||||||
|
node.position = Offset(x, y);
|
||||||
|
print("✅ Adjusted ${node.name} to (${x}, ${y})");
|
||||||
|
|
||||||
|
int numChildren = node.children.length;
|
||||||
|
double childStartX = x - ((numChildren - 1) * horizontalGap) / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < numChildren; i++) {
|
||||||
|
updatePositions(node.children[i], childStartX + (i * horizontalGap), y + verticalGap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spaces.isNotEmpty) {
|
||||||
|
print("🔄 Realigning tree...");
|
||||||
|
updatePositions(spaces.first, spaces.first.position.dx, spaces.first.position.dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// **Recursive duplication logic**
|
||||||
|
SpaceModel duplicateRecursive(SpaceModel original, SpaceModel? duplicatedParent) {
|
||||||
|
Offset newPosition = duplicatedParent == null
|
||||||
|
? Offset(original.position.dx + horizontalGap, original.position.dy)
|
||||||
|
: getBalancedChildPosition(duplicatedParent);
|
||||||
|
|
||||||
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
||||||
|
print(
|
||||||
final List<SubspaceModel>? duplicatedSubspaces;
|
"🟡 Duplicating ${original.name} → ${duplicatedName} at (${newPosition.dx}, ${newPosition.dy})");
|
||||||
final List<Tag>? duplicatedTags;
|
|
||||||
if (original.spaceModel != null) {
|
|
||||||
duplicatedTags = [];
|
|
||||||
duplicatedSubspaces = [];
|
|
||||||
} else {
|
|
||||||
duplicatedTags = original.tags;
|
|
||||||
duplicatedSubspaces = original.subspaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
final duplicated = SpaceModel(
|
final duplicated = SpaceModel(
|
||||||
name: duplicatedName,
|
name: duplicatedName,
|
||||||
@@ -637,12 +704,10 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
status: SpaceStatus.newSpace,
|
status: SpaceStatus.newSpace,
|
||||||
parent: duplicatedParent,
|
parent: duplicatedParent,
|
||||||
spaceModel: original.spaceModel,
|
spaceModel: original.spaceModel,
|
||||||
subspaces: duplicatedSubspaces,
|
subspaces: original.subspaces,
|
||||||
tags: duplicatedTags,
|
tags: original.tags,
|
||||||
);
|
);
|
||||||
|
|
||||||
originalToDuplicate[original] = duplicated;
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
spaces.add(duplicated);
|
spaces.add(duplicated);
|
||||||
_updateNodePosition(duplicated, duplicated.position);
|
_updateNodePosition(duplicated, duplicated.position);
|
||||||
@@ -651,60 +716,42 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
final newConnection = Connection(
|
final newConnection = Connection(
|
||||||
startSpace: duplicatedParent,
|
startSpace: duplicatedParent,
|
||||||
endSpace: duplicated,
|
endSpace: duplicated,
|
||||||
direction: original.incomingConnection?.direction ?? 'down',
|
direction: "down",
|
||||||
);
|
);
|
||||||
connections.add(newConnection);
|
connections.add(newConnection);
|
||||||
duplicated.incomingConnection = newConnection;
|
duplicated.incomingConnection = newConnection;
|
||||||
duplicatedParent.addOutgoingConnection(newConnection);
|
duplicatedParent.addOutgoingConnection(newConnection);
|
||||||
|
duplicatedParent.children.add(duplicated);
|
||||||
|
print("🔗 Created connection: ${duplicatedParent.name} → ${duplicated.name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (original.parent != null && duplicatedParent == null) {
|
// **Recalculate the whole tree to avoid overlaps**
|
||||||
final originalParent = original.parent!;
|
realignTree();
|
||||||
final duplicatedParent = originalToDuplicate[originalParent] ?? originalParent;
|
|
||||||
|
|
||||||
final parentConnection = Connection(
|
|
||||||
startSpace: duplicatedParent,
|
|
||||||
endSpace: duplicated,
|
|
||||||
direction: original.incomingConnection?.direction ?? "down",
|
|
||||||
);
|
|
||||||
|
|
||||||
connections.add(parentConnection);
|
|
||||||
duplicated.incomingConnection = parentConnection;
|
|
||||||
duplicatedParent.addOutgoingConnection(parentConnection);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final childrenWithDownDirection = original.children
|
// Recursively duplicate children
|
||||||
.where((child) =>
|
for (var child in original.children) {
|
||||||
child.incomingConnection?.direction == "down" && child.status != SpaceStatus.deleted)
|
duplicateRecursive(child, duplicated);
|
||||||
.toList();
|
|
||||||
|
|
||||||
Offset childStartPosition = childrenWithDownDirection.length == 1
|
|
||||||
? duplicated.position
|
|
||||||
: newPosition + Offset(0, verticalGap);
|
|
||||||
|
|
||||||
for (final child in original.children) {
|
|
||||||
final isDownDirection = child.incomingConnection?.direction == "down" ?? false;
|
|
||||||
|
|
||||||
if (isDownDirection && childrenWithDownDirection.length == 1) {
|
|
||||||
childStartPosition = duplicated.position + Offset(0, verticalGap);
|
|
||||||
} else if (!isDownDirection) {
|
|
||||||
childStartPosition = duplicated.position + Offset(horizontalGap, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
final duplicatedChild = duplicateRecursive(child, childStartPosition, duplicated);
|
|
||||||
duplicated.children.add(duplicatedChild);
|
|
||||||
childStartPosition += Offset(0, verticalGap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return duplicated;
|
return duplicated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// **Handle root duplication**
|
||||||
if (space.parent == null) {
|
if (space.parent == null) {
|
||||||
duplicateRecursive(space, space.position, null);
|
print("🟠 Duplicating root node: ${space.name}");
|
||||||
|
SpaceModel duplicatedRoot = duplicateRecursive(space, null);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
spaces.add(duplicatedRoot);
|
||||||
|
realignTree();
|
||||||
|
});
|
||||||
|
|
||||||
|
print("✅ Root duplication successful: ${duplicatedRoot.name}");
|
||||||
} else {
|
} else {
|
||||||
final duplicatedParent = originalToDuplicate[space.parent!] ?? space.parent!;
|
duplicateRecursive(space, space.parent);
|
||||||
duplicateRecursive(space, space.position, duplicatedParent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("🟢 Finished duplication process for: ${space.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,18 +47,6 @@ class SpaceCardWidget extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
buildSpaceContainer(index), // Build the space container
|
buildSpaceContainer(index), // Build the space container
|
||||||
if (isHovered) ...[
|
if (isHovered) ...[
|
||||||
PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'left',
|
|
||||||
offset: const Offset(-21, 20),
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
|
||||||
PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'right',
|
|
||||||
offset: const Offset(140, 20),
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
|
||||||
PlusButtonWidget(
|
PlusButtonWidget(
|
||||||
index: index,
|
index: index,
|
||||||
direction: 'down',
|
direction: 'down',
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_m
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
|
||||||
class SpaceHelper {
|
class SpaceHelper {
|
||||||
static SpaceModel? findSpaceByUuid(
|
static SpaceModel? findSpaceByUuid(String? uuid, List<CommunityModel> communities) {
|
||||||
String? uuid, List<CommunityModel> communities) {
|
|
||||||
for (var community in communities) {
|
for (var community in communities) {
|
||||||
for (var space in community.spaces) {
|
for (var space in community.spaces) {
|
||||||
if (space.uuid == uuid) return space;
|
if (space.uuid == uuid) return space;
|
||||||
@@ -12,8 +11,7 @@ class SpaceHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SpaceModel? findSpaceByInternalId(
|
static SpaceModel? findSpaceByInternalId(String? internalId, List<SpaceModel> spaces) {
|
||||||
String? internalId, List<SpaceModel> spaces) {
|
|
||||||
if (internalId != null) {
|
if (internalId != null) {
|
||||||
for (var space in spaces) {
|
for (var space in spaces) {
|
||||||
if (space.internalId == internalId) return space;
|
if (space.internalId == internalId) return space;
|
||||||
@@ -23,8 +21,7 @@ class SpaceHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String generateUniqueSpaceName(
|
static String generateUniqueSpaceName(String originalName, List<SpaceModel> spaces) {
|
||||||
String originalName, List<SpaceModel> spaces) {
|
|
||||||
final baseName = originalName.replaceAll(RegExp(r'\(\d+\)$'), '').trim();
|
final baseName = originalName.replaceAll(RegExp(r'\(\d+\)$'), '').trim();
|
||||||
int maxNumber = 0;
|
int maxNumber = 0;
|
||||||
|
|
||||||
@@ -54,13 +51,10 @@ class SpaceHelper {
|
|||||||
|
|
||||||
return space == selectedSpace ||
|
return space == selectedSpace ||
|
||||||
selectedSpace.parent?.internalId == space.internalId ||
|
selectedSpace.parent?.internalId == space.internalId ||
|
||||||
selectedSpace.children
|
selectedSpace.children?.any((child) => child.internalId == space.internalId) == true;
|
||||||
?.any((child) => child.internalId == space.internalId) ==
|
|
||||||
true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isNameConflict(
|
static bool isNameConflict(String value, SpaceModel? parentSpace, SpaceModel? editSpace) {
|
||||||
String value, SpaceModel? parentSpace, SpaceModel? editSpace) {
|
|
||||||
final siblings = parentSpace?.children
|
final siblings = parentSpace?.children
|
||||||
.where((child) => child.internalId != editSpace?.internalId)
|
.where((child) => child.internalId != editSpace?.internalId)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
@@ -71,19 +65,17 @@ class SpaceHelper {
|
|||||||
.toList() ??
|
.toList() ??
|
||||||
[];
|
[];
|
||||||
|
|
||||||
final editSiblingConflict =
|
final editSiblingConflict = editSiblings.any((child) => child.name == value);
|
||||||
editSiblings.any((child) => child.name == value);
|
|
||||||
|
|
||||||
final siblingConflict = siblings.any((child) => child.name == value);
|
final siblingConflict = siblings.any((child) => child.name == value);
|
||||||
|
|
||||||
final parentConflict = parentSpace?.name == value &&
|
final parentConflict =
|
||||||
parentSpace?.internalId != editSpace?.internalId;
|
parentSpace?.name == value && parentSpace?.internalId != editSpace?.internalId;
|
||||||
|
|
||||||
final parentOfEditSpaceConflict = editSpace?.parent?.name == value &&
|
final parentOfEditSpaceConflict =
|
||||||
editSpace?.parent?.internalId != editSpace?.internalId;
|
editSpace?.parent?.name == value && editSpace?.parent?.internalId != editSpace?.internalId;
|
||||||
|
|
||||||
final childConflict =
|
final childConflict = editSpace?.children.any((child) => child.name == value) ?? false;
|
||||||
editSpace?.children.any((child) => child.name == value) ?? false;
|
|
||||||
|
|
||||||
return siblingConflict ||
|
return siblingConflict ||
|
||||||
parentConflict ||
|
parentConflict ||
|
||||||
|
|||||||
@@ -194,9 +194,10 @@ class VisitorPasswordBloc
|
|||||||
emit(DeviceLoaded());
|
emit(DeviceLoaded());
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
data = await AccessMangApi().fetchDevices(projectUuid);
|
data = await AccessMangApi().fetchDoorLockDeviceList(projectUuid);
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print("error: $e");
|
||||||
emit(FailedState(e.toString()));
|
emit(FailedState(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,23 @@ import 'package:syncrow_web/services/api/http_service.dart';
|
|||||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||||
|
|
||||||
class AccessMangApi {
|
class AccessMangApi {
|
||||||
|
AccessMangApi() {
|
||||||
|
_validateEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _validateEndpoints() {
|
||||||
|
if (!ApiEndpoints.getDevices.contains('{projectId}')) {
|
||||||
|
throw Exception("Endpoint 'getDevices' must contain '{projectId}' placeholder.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<PasswordModel>> fetchVisitorPassword(String projectId) async {
|
Future<List<PasswordModel>> fetchVisitorPassword(String projectId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.visitorPassword.replaceAll('{projectId}', projectId),
|
path: ApiEndpoints.visitorPassword,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = json;
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
List<PasswordModel> passwordList = jsonData.map((jsonItem) {
|
List<PasswordModel> passwordList = jsonData.map((jsonItem) {
|
||||||
return PasswordModel.fromJson(jsonItem);
|
return PasswordModel.fromJson(jsonItem);
|
||||||
}).toList();
|
}).toList();
|
||||||
@@ -25,17 +35,22 @@ class AccessMangApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future fetchDevices(String projectId) async {
|
Future fetchDoorLockDeviceList(String projectId) async {
|
||||||
try {
|
try {
|
||||||
|
// The endpoint structure is already validated during initialization.
|
||||||
|
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getDevices.replaceAll('{projectId}', projectId),
|
path: ApiEndpoints.getDevices.replaceAll('{projectId}', projectId),
|
||||||
|
queryParameters: {
|
||||||
|
'deviceType': 'DOOR_LOCK',
|
||||||
|
},
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = json;
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
List<DeviceModel> passwordList = jsonData.map((jsonItem) {
|
List<DeviceModel> deviceList = jsonData.map((jsonItem) {
|
||||||
return DeviceModel.fromJson(jsonItem);
|
return DeviceModel.fromJson(jsonItem);
|
||||||
}).toList();
|
}).toList();
|
||||||
return passwordList;
|
return deviceList;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@@ -52,14 +67,15 @@ class AccessMangApi {
|
|||||||
String? invalidTime,
|
String? invalidTime,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOnlineOneTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
"email": email,
|
"email": email,
|
||||||
"passwordName": passwordName,
|
"passwordName": passwordName,
|
||||||
"password": password,
|
"password": password,
|
||||||
"devicesUuid": devicesUuid,
|
"devicesUuid": devicesUuid,
|
||||||
"effectiveTime": effectiveTime,
|
"effectiveTime": effectiveTime,
|
||||||
"invalidTime": invalidTime
|
"invalidTime": invalidTime,
|
||||||
|
"operationType": "ONLINE_ONE_TIME",
|
||||||
}),
|
}),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
@@ -84,13 +100,13 @@ class AccessMangApi {
|
|||||||
"password": password,
|
"password": password,
|
||||||
"effectiveTime": effectiveTime,
|
"effectiveTime": effectiveTime,
|
||||||
"invalidTime": invalidTime,
|
"invalidTime": invalidTime,
|
||||||
|
"operationType": "ONLINE_MULTIPLE_TIME",
|
||||||
};
|
};
|
||||||
if (scheduleList != null) {
|
if (scheduleList != null) {
|
||||||
body["scheduleList"] =
|
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||||
scheduleList.map((schedule) => schedule.toJson()).toList();
|
|
||||||
}
|
}
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOnlineMultipleTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode(body),
|
body: jsonEncode(body),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
@@ -105,8 +121,9 @@ class AccessMangApi {
|
|||||||
Future postOffLineOneTime(
|
Future postOffLineOneTime(
|
||||||
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOffLineOneTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
|
"operationType": "OFFLINE_ONE_TIME",
|
||||||
"email": email,
|
"email": email,
|
||||||
"passwordName": passwordName,
|
"passwordName": passwordName,
|
||||||
"devicesUuid": devicesUuid
|
"devicesUuid": devicesUuid
|
||||||
@@ -126,13 +143,14 @@ class AccessMangApi {
|
|||||||
String? invalidTime,
|
String? invalidTime,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOffLineMultipleTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
"email": email,
|
"email": email,
|
||||||
"devicesUuid": devicesUuid,
|
"devicesUuid": devicesUuid,
|
||||||
"passwordName": passwordName,
|
"passwordName": passwordName,
|
||||||
"effectiveTime": effectiveTime,
|
"effectiveTime": effectiveTime,
|
||||||
"invalidTime": invalidTime,
|
"invalidTime": invalidTime,
|
||||||
|
"operationType": "OFFLINE_MULTIPLE_TIME",
|
||||||
}),
|
}),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
|
|||||||
@@ -23,9 +23,8 @@ class DevicesManagementApi {
|
|||||||
: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = communityId.isNotEmpty && spaceId.isNotEmpty
|
List<dynamic> jsonData =
|
||||||
? json['data']
|
communityId.isNotEmpty && spaceId.isNotEmpty ? json['data'] : json['data'];
|
||||||
: json;
|
|
||||||
List<AllDevicesModel> devicesList = jsonData.map((jsonItem) {
|
List<AllDevicesModel> devicesList = jsonData.map((jsonItem) {
|
||||||
return AllDevicesModel.fromJson(jsonItem);
|
return AllDevicesModel.fromJson(jsonItem);
|
||||||
}).toList();
|
}).toList();
|
||||||
@@ -34,7 +33,7 @@ class DevicesManagementApi {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('fetchDevices Error fetching $e');
|
debugPrint('Error fetching device $e');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +44,7 @@ class DevicesManagementApi {
|
|||||||
path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', uuid),
|
path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', uuid),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceStatus.fromJson(json);
|
return DeviceStatus.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@@ -62,7 +61,7 @@ class DevicesManagementApi {
|
|||||||
Future getPowerClampInfo(String deviceId) async {
|
Future getPowerClampInfo(String deviceId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.powerClamp.replaceAll('{powerClampUuid}', deviceId),
|
path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', deviceId),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return json;
|
return json;
|
||||||
@@ -100,6 +99,7 @@ class DevicesManagementApi {
|
|||||||
'devicesUuid': uuids,
|
'devicesUuid': uuids,
|
||||||
'code': code,
|
'code': code,
|
||||||
'value': value,
|
'value': value,
|
||||||
|
'operationType': 'COMMAND',
|
||||||
};
|
};
|
||||||
|
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
@@ -107,7 +107,7 @@ class DevicesManagementApi {
|
|||||||
body: body,
|
body: body,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return (json['successResults'] as List).isNotEmpty;
|
return json['success'] ?? false;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ class DevicesManagementApi {
|
|||||||
if (json == null || json.isEmpty || json == []) {
|
if (json == null || json.isEmpty || json == []) {
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
for (var device in json['devices']) {
|
for (var device in json['data']['devices']) {
|
||||||
devices.add(DeviceModel.fromJson(device));
|
devices.add(DeviceModel.fromJson(device));
|
||||||
}
|
}
|
||||||
return devices;
|
return devices;
|
||||||
@@ -158,7 +158,7 @@ class DevicesManagementApi {
|
|||||||
.replaceAll('{code}', code),
|
.replaceAll('{code}', code),
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceReport.fromJson(json);
|
return DeviceReport.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@@ -174,7 +174,7 @@ class DevicesManagementApi {
|
|||||||
.replaceAll('{endTime}', to ?? ''),
|
.replaceAll('{endTime}', to ?? ''),
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceReport.fromJson(json);
|
return DeviceReport.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@@ -190,7 +190,7 @@ class DevicesManagementApi {
|
|||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceStatus.fromJson(json['status']);
|
return DeviceStatus.fromJson(json['data']['status']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@@ -3,27 +3,24 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_m
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subspace_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subspace_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
|
||||||
|
|
||||||
class CommunitySpaceManagementApi {
|
class CommunitySpaceManagementApi {
|
||||||
// Community Management APIs
|
// Community Management APIs
|
||||||
Future<List<CommunityModel>> fetchCommunities(String projectId,
|
Future<List<CommunityModel>> fetchCommunities(String projectId,
|
||||||
{int page = 1}) async {
|
{int page = 1, bool includeSpaces = false}) async {
|
||||||
try {
|
try {
|
||||||
List<CommunityModel> allCommunities = [];
|
List<CommunityModel> allCommunities = [];
|
||||||
bool hasNext = true;
|
bool hasNext = true;
|
||||||
|
|
||||||
while (hasNext) {
|
while (hasNext) {
|
||||||
await HTTPService().get(
|
await HTTPService().get(
|
||||||
path: ApiEndpoints.getCommunityList
|
path: ApiEndpoints.getCommunityList.replaceAll('{projectId}', projectId),
|
||||||
.replaceAll('{projectId}', projectId),
|
queryParameters: {'page': page, 'includeSpaces': includeSpaces},
|
||||||
queryParameters: {'page': page},
|
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
try {
|
try {
|
||||||
List<dynamic> jsonData = json['data'] ?? [];
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
@@ -52,8 +49,7 @@ class CommunitySpaceManagementApi {
|
|||||||
Future<CommunityModel?> getCommunityById(String communityId) async {
|
Future<CommunityModel?> getCommunityById(String communityId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getCommunityById
|
path: ApiEndpoints.getCommunityById.replaceAll('{communityId}', communityId),
|
||||||
.replaceAll('{communityId}', communityId),
|
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return CommunityModel.fromJson(json['data']);
|
return CommunityModel.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
@@ -65,8 +61,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<CommunityModel?> createCommunity(
|
Future<CommunityModel?> createCommunity(String name, String description, String projectId) async {
|
||||||
String name, String description, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId),
|
path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId),
|
||||||
@@ -85,8 +80,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateCommunity(
|
Future<bool> updateCommunity(String communityId, String name, String projectId) async {
|
||||||
String communityId, String name, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().put(
|
final response = await HTTPService().put(
|
||||||
path: ApiEndpoints.updateCommunity
|
path: ApiEndpoints.updateCommunity
|
||||||
@@ -123,8 +117,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpacesResponse> fetchSpaces(
|
Future<SpacesResponse> fetchSpaces(String communityId, String projectId) async {
|
||||||
String communityId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.listSpaces
|
path: ApiEndpoints.listSpaces
|
||||||
@@ -150,8 +143,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpaceModel?> getSpace(
|
Future<SpaceModel?> getSpace(String communityId, String spaceId, String projectId) async {
|
||||||
String communityId, String spaceId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getSpace
|
path: ApiEndpoints.getSpace
|
||||||
@@ -262,8 +254,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deleteSpace(
|
Future<bool> deleteSpace(String communityId, String spaceId, String projectId) async {
|
||||||
String communityId, String spaceId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().delete(
|
final response = await HTTPService().delete(
|
||||||
path: ApiEndpoints.deleteSpace
|
path: ApiEndpoints.deleteSpace
|
||||||
@@ -281,17 +272,15 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<SpaceModel>> getSpaceHierarchy(
|
Future<List<SpaceModel>> getSpaceHierarchy(String communityId, String projectId) async {
|
||||||
String communityId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getSpaceHierarchy
|
path: ApiEndpoints.getSpaceHierarchy
|
||||||
.replaceAll('{communityId}', communityId)
|
.replaceAll('{communityId}', communityId)
|
||||||
.replaceAll('{projectId}', projectId),
|
.replaceAll('{projectId}', projectId),
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final spaceModels = (json['data'] as List)
|
final spaceModels =
|
||||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
(json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
return spaceModels;
|
return spaceModels;
|
||||||
},
|
},
|
||||||
@@ -302,17 +291,16 @@ class CommunitySpaceManagementApi {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Future<List<SpaceModel>> getSpaceOnlyWithDevices(
|
|
||||||
{String? communityId, String? projectId}) async {
|
Future<List<SpaceModel>> getSpaceOnlyWithDevices({String? communityId, String? projectId}) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.spaceOnlyWithDevices
|
path: ApiEndpoints.spaceOnlyWithDevices
|
||||||
.replaceAll('{communityId}', communityId!)
|
.replaceAll('{communityId}', communityId!)
|
||||||
.replaceAll('{projectId}', projectId!),
|
.replaceAll('{projectId}', projectId!),
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final spaceModels = (json['data'] as List)
|
final spaceModels =
|
||||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
(json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList();
|
||||||
.toList();
|
|
||||||
return spaceModels;
|
return spaceModels;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,21 +9,8 @@ abstract class ApiEndpoints {
|
|||||||
static const String sendOtp = '/authentication/user/send-otp';
|
static const String sendOtp = '/authentication/user/send-otp';
|
||||||
static const String verifyOtp = '/authentication/user/verify-otp';
|
static const String verifyOtp = '/authentication/user/verify-otp';
|
||||||
static const String getRegion = '/region';
|
static const String getRegion = '/region';
|
||||||
static const String visitorPassword =
|
static const String visitorPassword = '/visitor-passwords';
|
||||||
'/projects/{projectId}/visitor-password';
|
static const String getDevices = '/projects/{projectId}/devices';
|
||||||
static const String getDevices =
|
|
||||||
'/projects/{projectId}/visitor-password/devices';
|
|
||||||
|
|
||||||
static const String sendOnlineOneTime =
|
|
||||||
'/visitor-password/temporary-password/online/one-time';
|
|
||||||
static const String sendOnlineMultipleTime =
|
|
||||||
'/visitor-password/temporary-password/online/multiple-time';
|
|
||||||
|
|
||||||
//offline Password
|
|
||||||
static const String sendOffLineOneTime =
|
|
||||||
'/visitor-password/temporary-password/offline/one-time';
|
|
||||||
static const String sendOffLineMultipleTime =
|
|
||||||
'/visitor-password/temporary-password/offline/multiple-time';
|
|
||||||
|
|
||||||
static const String getUser = '/user/{userUuid}';
|
static const String getUser = '/user/{userUuid}';
|
||||||
|
|
||||||
@@ -32,15 +19,15 @@ abstract class ApiEndpoints {
|
|||||||
static const String getAllDevices = '/projects/{projectId}/devices';
|
static const String getAllDevices = '/projects/{projectId}/devices';
|
||||||
static const String getSpaceDevices =
|
static const String getSpaceDevices =
|
||||||
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
||||||
static const String getDeviceStatus = '/device/{uuid}/functions/status';
|
static const String getDeviceStatus = '/devices/{uuid}/functions/status';
|
||||||
static const String getBatchStatus = '/device/status/batch';
|
static const String getBatchStatus = '/devices/batch';
|
||||||
|
|
||||||
static const String deviceControl = '/device/{uuid}/control';
|
static const String deviceControl = '/devices/{uuid}/command';
|
||||||
static const String deviceBatchControl = '/device/control/batch';
|
static const String deviceBatchControl = '/devices/batch';
|
||||||
static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices';
|
static const String gatewayApi = '/devices/gateway/{gatewayUuid}/devices';
|
||||||
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
|
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
|
||||||
|
|
||||||
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
|
static const String getDeviceLogs = '/devices/{uuid}/report-logs?code={code}';
|
||||||
|
|
||||||
// Space Module
|
// Space Module
|
||||||
static const String createSpace =
|
static const String createSpace =
|
||||||
@@ -70,18 +57,13 @@ abstract class ApiEndpoints {
|
|||||||
static const String createUserCommunity =
|
static const String createUserCommunity =
|
||||||
'/projects/{projectId}/communities/user';
|
'/projects/{projectId}/communities/user';
|
||||||
static const String getDeviceLogsByDate =
|
static const String getDeviceLogsByDate =
|
||||||
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
'/devices/{uuid}/report-logs?code={code}&startTime={startTime}&endTime={endTime}';
|
||||||
|
|
||||||
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
||||||
static const String getScheduleByDeviceId =
|
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}';
|
||||||
'/schedule/{deviceUuid}?category={category}';
|
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}';
|
||||||
static const String deleteScheduleByDeviceId =
|
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}';
|
||||||
'/schedule/{deviceUuid}/{scheduleUuid}';
|
static const String factoryReset = '/devices/batch';
|
||||||
static const String updateScheduleByDeviceId =
|
|
||||||
'/schedule/enable/{deviceUuid}';
|
|
||||||
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
|
|
||||||
static const String powerClamp =
|
|
||||||
'/device/{powerClampUuid}/power-clamp/status';
|
|
||||||
|
|
||||||
//product
|
//product
|
||||||
static const String listProducts = '/products';
|
static const String listProducts = '/products';
|
||||||
|
|||||||
Reference in New Issue
Block a user