mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-11 15:47:44 +00:00
Compare commits
57 Commits
SP-1594-de
...
space_mana
Author | SHA1 | Date | |
---|---|---|---|
f415aa1676 | |||
08f8c3c79a | |||
329a4ef027 | |||
940b179686 | |||
5ddfb47977 | |||
2a5d602e94 | |||
5d6747056e | |||
8a274af7be | |||
316c3bd8a7 | |||
aa3b79bdaf | |||
0e31a3ea96 | |||
fd192894cd | |||
692c9e7792 | |||
08a9a5c71f | |||
7eb1d5b0b0 | |||
0d5734a236 | |||
e22bab00d9 | |||
d2a2d391e0 | |||
1d30c753f5 | |||
ca02de2093 | |||
8f7bfa984b | |||
8e9278c93c | |||
15d3a05553 | |||
c6b55cb28b | |||
bfd8e964f7 | |||
08725201d5 | |||
7fe34c61b2 | |||
0c6e4fed80 | |||
69c23525ba | |||
3e32968209 | |||
beb5239c4f | |||
3a98f71ff3 | |||
ad8e06ac40 | |||
5f8eb9de06 | |||
8e8fdf0fc6 | |||
a1d7457065 | |||
c99b32fb81 | |||
321df401fd | |||
ee244fa5ed | |||
1db069e9a5 | |||
cf9bafef4d | |||
2c73dd6c31 | |||
6ec20e2d72 | |||
4feae9ad87 | |||
52046909d5 | |||
fc81555be3 | |||
8967852ca8 | |||
a87e79878b | |||
056e7372e0 | |||
d69d867120 | |||
644fe56478 | |||
766a39f161 | |||
c97dd40b05 | |||
0b65c58947 | |||
e0951aa13d | |||
9e8ebf3768 | |||
b593e75c67 |
6
.github/pull_request_template.md
vendored
6
.github/pull_request_template.md
vendored
@ -7,11 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
## Jira Ticket
|
## Jira Ticket
|
||||||
<!-- Add your Jira ticket number as a link (e.g., [PROJ-123](https://jira.company.com/browse/PROJ-123)) -->
|
[SP-0000](https://syncrow.atlassian.net/browse/SP-0000)
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
**READY/IN DEVELOPMENT/HOLD**
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
@ -4,10 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened, closed]
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_deploy_job:
|
build_and_deploy_job:
|
||||||
|
@ -4,18 +4,12 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened, closed]
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_deploy_job:
|
build_and_deploy_job:
|
||||||
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Build and Deploy Job
|
name: Build and Deploy Job
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
29
.github/workflows/pr-check.yml
vendored
Normal file
29
.github/workflows/pr-check.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: Pull Request Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup_flutter:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Setup Flutter and Dependencies
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
lfs: false
|
||||||
|
|
||||||
|
- name: Set up Flutter
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
flutter-version: '3.27.3'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: flutter pub get
|
||||||
|
|
||||||
|
- name: Run Flutter Build
|
||||||
|
run: flutter build web --web-renderer canvaskit -t lib/main_dev.dart
|
24
assets/icons/settings_button.svg
Normal file
24
assets/icons/settings_button.svg
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<svg width="40" height="26" viewBox="0 0 40 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_9292_1537)">
|
||||||
|
<rect x="3" y="3" width="34" height="20" rx="10" fill="#F5F6F7"/>
|
||||||
|
<g clip-path="url(#clip0_9292_1537)">
|
||||||
|
<path d="M20.4393 20H19.5607C18.85 20 18.2718 19.4218 18.2718 18.7112V18.414C17.9697 18.3174 17.6762 18.1956 17.3942 18.0497L17.1835 18.2603C16.6733 18.7711 15.8561 18.7562 15.3607 18.2601L14.7397 17.6391C14.2434 17.1434 14.2291 16.3264 14.7398 15.8163L14.9503 15.6058C14.8044 15.3238 14.6826 15.0303 14.586 14.7281H14.2888C13.5782 14.7281 13 14.15 13 13.4393V12.5607C13 11.85 13.5782 11.2719 14.2888 11.2719H14.586C14.6826 10.9697 14.8044 10.6762 14.9503 10.3942L14.7397 10.1836C14.2293 9.67374 14.2434 8.85666 14.7399 8.36072L15.3609 7.73969C15.8574 7.24247 16.6745 7.23006 17.1838 7.73986L17.3942 7.95032C17.6762 7.80441 17.9698 7.68257 18.2719 7.58602V7.28879C18.2719 6.57816 18.85 6 19.5607 6H20.4393C21.15 6 21.7281 6.57816 21.7281 7.28879V7.58605C22.0302 7.68257 22.3238 7.80441 22.6058 7.95035L22.8164 7.73969C23.3266 7.22886 24.1439 7.24384 24.6393 7.73988L25.2603 8.36086C25.7566 8.85657 25.7708 9.67358 25.2601 10.1837L25.0497 10.3942C25.1956 10.6762 25.3174 10.9697 25.414 11.2719H25.7112C26.4218 11.2719 27 11.85 27 12.5607V13.4393C27 14.15 26.4218 14.7281 25.7112 14.7281H25.414C25.3174 15.0303 25.1956 15.3238 25.0497 15.6058L25.2603 15.8164C25.7707 16.3263 25.7566 17.1434 25.2601 17.6393L24.6391 18.2603C24.1426 18.7576 23.3255 18.77 22.8162 18.2602L22.6058 18.0497C22.3238 18.1956 22.0302 18.3175 21.7281 18.414V18.7113C21.7281 19.4218 21.15 20 20.4393 20ZM17.5313 17.1882C17.9231 17.4199 18.3447 17.595 18.7845 17.7085C18.9656 17.7552 19.0922 17.9185 19.0922 18.1056V18.7112C19.0922 18.9695 19.3024 19.1797 19.5607 19.1797H20.4393C20.6976 19.1797 20.9078 18.9695 20.9078 18.7112V18.1056C20.9078 17.9185 21.0344 17.7552 21.2155 17.7085C21.6553 17.595 22.0769 17.4199 22.4687 17.1882C22.6299 17.0929 22.8351 17.1188 22.9675 17.2513L23.3965 17.6803C23.5815 17.8654 23.8785 17.8611 24.0589 17.6805L24.6803 17.059C24.8603 16.8793 24.8663 16.5822 24.6805 16.3966L24.2513 15.9675C24.1189 15.8351 24.093 15.6298 24.1883 15.4687C24.42 15.0769 24.595 14.6553 24.7085 14.2155C24.7552 14.0344 24.9186 13.9078 25.1056 13.9078H25.7112C25.9695 13.9078 26.1797 13.6977 26.1797 13.4394V12.5607C26.1797 12.3024 25.9695 12.0922 25.7112 12.0922H25.1056C24.9186 12.0922 24.7552 11.9657 24.7085 11.7846C24.595 11.3447 24.42 10.9231 24.1883 10.5314C24.093 10.3702 24.1189 10.165 24.2513 10.0326L24.6803 9.60358C24.8658 9.41835 24.8609 9.1214 24.6805 8.94118L24.0591 8.31979C23.879 8.13943 23.5819 8.13415 23.3967 8.31962L22.9676 8.74879C22.8352 8.88121 22.6299 8.90713 22.4687 8.81181C22.077 8.58013 21.6553 8.4051 21.2155 8.2916C21.0344 8.24487 20.9079 8.08152 20.9079 7.89446V7.28879C20.9079 7.03048 20.6977 6.82031 20.4394 6.82031H19.5607C19.3024 6.82031 19.0922 7.03048 19.0922 7.28879V7.8944C19.0922 8.08146 18.9657 8.24481 18.7845 8.29154C18.3447 8.40505 17.9231 8.58007 17.5314 8.81176C17.3701 8.90705 17.1649 8.88113 17.0325 8.74873L16.6036 8.31973C16.4186 8.13456 16.1216 8.13886 15.9412 8.31954L15.3197 8.94096C15.1398 9.12071 15.1337 9.41775 15.3196 9.60336L15.7487 10.0325C15.8811 10.1649 15.9071 10.3702 15.8118 10.5313C15.5801 10.9231 15.4051 11.3447 15.2916 11.7845C15.2448 11.9656 15.0815 12.0922 14.8944 12.0922H14.2888C14.0305 12.0922 13.8203 12.3024 13.8203 12.5607V13.4393C13.8203 13.6976 14.0305 13.9078 14.2888 13.9078H14.8944C15.0815 13.9078 15.2448 14.0344 15.2915 14.2155C15.405 14.6553 15.5801 15.0769 15.8117 15.4686C15.907 15.6298 15.8811 15.8351 15.7487 15.9675L15.3197 16.3965C15.1343 16.5817 15.1391 16.8786 15.3195 17.0589L15.9409 17.6802C16.121 17.8606 16.4181 17.8659 16.6033 17.6804L17.0325 17.2512C17.13 17.1537 17.333 17.0709 17.5313 17.1882Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
<path d="M19.9992 16.0461C18.3196 16.0461 16.9531 14.6796 16.9531 13C16.9531 11.3204 18.3196 9.95391 19.9992 9.95391C21.6789 9.95391 23.0453 11.3204 23.0453 13C23.0453 14.6796 21.6789 16.0461 19.9992 16.0461ZM19.9992 10.7742C18.7719 10.7742 17.7734 11.7727 17.7734 13C17.7734 14.2273 18.7719 15.2258 19.9992 15.2258C21.2265 15.2258 22.225 14.2273 22.225 13C22.225 11.7727 21.2265 10.7742 19.9992 10.7742Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_9292_1537" x="0" y="0" width="40" height="26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="1.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_9292_1537"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_9292_1537" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="clip0_9292_1537">
|
||||||
|
<rect width="14" height="14" fill="white" transform="translate(13 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
@ -17,7 +17,8 @@ class TagDialogTextfieldDropdown extends StatefulWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_DialogTextfieldDropdownState createState() => _DialogTextfieldDropdownState();
|
_DialogTextfieldDropdownState createState() =>
|
||||||
|
_DialogTextfieldDropdownState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
||||||
@ -36,6 +37,12 @@ class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
|||||||
|
|
||||||
_focusNode.addListener(() {
|
_focusNode.addListener(() {
|
||||||
if (!_focusNode.hasFocus) {
|
if (!_focusNode.hasFocus) {
|
||||||
|
// Call onSelected when focus is lost
|
||||||
|
final selectedTag = _filteredItems.firstWhere(
|
||||||
|
(tag) => tag.tag == _controller.text,
|
||||||
|
orElse: () => Tag(tag: _controller.text),
|
||||||
|
);
|
||||||
|
widget.onSelected(selectedTag);
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -43,7 +50,9 @@ class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
|||||||
|
|
||||||
void _filterItems() {
|
void _filterItems() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_filteredItems = widget.items.where((tag) => tag.product?.uuid == widget.product).toList();
|
_filteredItems = widget.items;
|
||||||
|
// .where((tag) => tag.product?.uuid == widget.product)
|
||||||
|
// .toList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +121,9 @@ class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
|||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium
|
.bodyMedium
|
||||||
?.copyWith(color: ColorsManager.textPrimaryColor)),
|
?.copyWith(
|
||||||
|
color: ColorsManager
|
||||||
|
.textPrimaryColor)),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_controller.text = tag.tag ?? '';
|
_controller.text = tag.tag ?? '';
|
||||||
widget.onSelected(tag);
|
widget.onSelected(tag);
|
||||||
@ -156,13 +167,15 @@ class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
|||||||
controller: _controller,
|
controller: _controller,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
onFieldSubmitted: (value) {
|
onFieldSubmitted: (value) {
|
||||||
final selectedTag = _filteredItems.firstWhere((tag) => tag.tag == value,
|
final selectedTag = _filteredItems.firstWhere(
|
||||||
|
(tag) => tag.tag == value,
|
||||||
orElse: () => Tag(tag: value));
|
orElse: () => Tag(tag: value));
|
||||||
widget.onSelected(selectedTag);
|
widget.onSelected(selectedTag);
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
},
|
},
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
widget.onSelected(_filteredItems.firstWhere((tag) => tag.tag == _controller.text,
|
widget.onSelected(_filteredItems.firstWhere(
|
||||||
|
(tag) => tag.tag == _controller.text,
|
||||||
orElse: () => Tag(tag: _controller.text)));
|
orElse: () => Tag(tag: _controller.text)));
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
},
|
},
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'analytics_devices_event.dart';
|
part 'analytics_devices_event.dart';
|
||||||
part 'analytics_devices_state.dart';
|
part 'analytics_devices_state.dart';
|
||||||
@ -36,6 +37,13 @@ class AnalyticsDevicesBloc
|
|||||||
if (devices.isNotEmpty) {
|
if (devices.isNotEmpty) {
|
||||||
event.onSuccess(devices.first);
|
event.onSuccess(devices.first);
|
||||||
}
|
}
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
AnalyticsDevicesState(
|
||||||
|
status: AnalyticsDevicesStatus.failure,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
AnalyticsDevicesState(
|
AnalyticsDevicesState(
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/energy_consumption_by_phases_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/energy_consumption_by_phases_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'energy_consumption_by_phases_event.dart';
|
part 'energy_consumption_by_phases_event.dart';
|
||||||
part 'energy_consumption_by_phases_state.dart';
|
part 'energy_consumption_by_phases_state.dart';
|
||||||
@ -31,6 +32,13 @@ class EnergyConsumptionByPhasesBloc
|
|||||||
chartData: chartData,
|
chartData: chartData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: EnergyConsumptionByPhasesStatus.failure,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/energy_consumption_per_device_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/energy_consumption_per_device_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'energy_consumption_per_device_event.dart';
|
part 'energy_consumption_per_device_event.dart';
|
||||||
part 'energy_consumption_per_device_state.dart';
|
part 'energy_consumption_per_device_state.dart';
|
||||||
@ -13,7 +14,8 @@ class EnergyConsumptionPerDeviceBloc
|
|||||||
this._energyConsumptionPerDeviceService,
|
this._energyConsumptionPerDeviceService,
|
||||||
) : super(const EnergyConsumptionPerDeviceState()) {
|
) : super(const EnergyConsumptionPerDeviceState()) {
|
||||||
on<LoadEnergyConsumptionPerDeviceEvent>(_onLoadEnergyConsumptionPerDeviceEvent);
|
on<LoadEnergyConsumptionPerDeviceEvent>(_onLoadEnergyConsumptionPerDeviceEvent);
|
||||||
on<ClearEnergyConsumptionPerDeviceEvent>(_onClearEnergyConsumptionPerDeviceEvent);
|
on<ClearEnergyConsumptionPerDeviceEvent>(
|
||||||
|
_onClearEnergyConsumptionPerDeviceEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
final EnergyConsumptionPerDeviceService _energyConsumptionPerDeviceService;
|
final EnergyConsumptionPerDeviceService _energyConsumptionPerDeviceService;
|
||||||
@ -31,6 +33,13 @@ class EnergyConsumptionPerDeviceBloc
|
|||||||
chartData: chartData,
|
chartData: chartData,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: EnergyConsumptionPerDeviceStatus.failure,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/services/power_clamp_info/power_clamp_info_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/power_clamp_info/power_clamp_info_service.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
|
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'power_clamp_info_event.dart';
|
part 'power_clamp_info_event.dart';
|
||||||
part 'power_clamp_info_state.dart';
|
part 'power_clamp_info_state.dart';
|
||||||
@ -31,6 +32,13 @@ class PowerClampInfoBloc extends Bloc<PowerClampInfoEvent, PowerClampInfoState>
|
|||||||
powerClampModel: powerClampModel,
|
powerClampModel: powerClampModel,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: PowerClampInfoStatus.error,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/total_energy_consumption/total_energy_consumption_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/total_energy_consumption/total_energy_consumption_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'total_energy_consumption_event.dart';
|
part 'total_energy_consumption_event.dart';
|
||||||
part 'total_energy_consumption_state.dart';
|
part 'total_energy_consumption_state.dart';
|
||||||
@ -31,6 +32,13 @@ class TotalEnergyConsumptionBloc
|
|||||||
status: TotalEnergyConsumptionStatus.loaded,
|
status: TotalEnergyConsumptionStatus.loaded,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
errorMessage: e.message,
|
||||||
|
status: TotalEnergyConsumptionStatus.failure,
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
|
@ -1,34 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
|
||||||
|
|
||||||
class AnalyticsEnergyManagementView extends StatefulWidget {
|
class AnalyticsEnergyManagementView extends StatelessWidget {
|
||||||
const AnalyticsEnergyManagementView({super.key});
|
const AnalyticsEnergyManagementView({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<AnalyticsEnergyManagementView> createState() =>
|
|
||||||
_AnalyticsEnergyManagementViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AnalyticsEnergyManagementViewState
|
|
||||||
extends State<AnalyticsEnergyManagementView> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
final spaceTreeBloc = context.read<SpaceTreeBloc>();
|
|
||||||
final communityId = spaceTreeBloc.state.selectedCommunities.firstOrNull;
|
|
||||||
final spaceId = spaceTreeBloc.state.selectedSpaces.firstOrNull;
|
|
||||||
FetchEnergyManagementDataHelper.loadEnergyManagementData(
|
|
||||||
context,
|
|
||||||
communityId: communityId ?? '',
|
|
||||||
spaceId: spaceId ?? '',
|
|
||||||
);
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const _padding = EdgeInsetsDirectional.all(32);
|
static const _padding = EdgeInsetsDirectional.all(32);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/models/occupacy.dart';
|
import 'package:syncrow_web/pages/analytics/models/occupacy.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupacy/occupacy_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/occupacy/occupacy_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'occupancy_event.dart';
|
part 'occupancy_event.dart';
|
||||||
part 'occupancy_state.dart';
|
part 'occupancy_state.dart';
|
||||||
@ -23,6 +24,8 @@ class OccupancyBloc extends Bloc<OccupancyEvent, OccupancyState> {
|
|||||||
try {
|
try {
|
||||||
final chartData = await _occupacyService.load(event.param);
|
final chartData = await _occupacyService.load(event.param);
|
||||||
emit(state.copyWith(chartData: chartData, status: OccupancyStatus.loaded));
|
emit(state.copyWith(chartData: chartData, status: OccupancyStatus.loaded));
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(state.copyWith(status: OccupancyStatus.failure, errorMessage: e.message));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(state.copyWith(status: OccupancyStatus.failure, errorMessage: '$e'));
|
emit(state.copyWith(status: OccupancyStatus.failure, errorMessage: '$e'));
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/models/occupancy_heat_map_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/occupancy_heat_map_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/occupancy_heat_map_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/occupancy_heat_map_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
part 'occupancy_heat_map_event.dart';
|
part 'occupancy_heat_map_event.dart';
|
||||||
part 'occupancy_heat_map_state.dart';
|
part 'occupancy_heat_map_state.dart';
|
||||||
@ -30,6 +31,13 @@ class OccupancyHeatMapBloc
|
|||||||
heatMapData: occupancyHeatMap,
|
heatMapData: occupancyHeatMap,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: OccupancyHeatMapStatus.failure,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
|
@ -10,7 +10,7 @@ class GetEnergyConsumptionPerDeviceParam {
|
|||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'monthDate':
|
'monthDate':
|
||||||
'${monthDate?.year}-${monthDate?.month.toString().padLeft(2, '0')}',
|
'${monthDate?.year}-${monthDate?.month.toString().padLeft(2, '0')}',
|
||||||
if (spaceId == null || spaceId == null) 'spaceUuid': spaceId,
|
if (spaceId != null) 'spaceUuid': spaceId,
|
||||||
'groupByDevice': true,
|
'groupByDevice': true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ class GetTotalEnergyConsumptionParam {
|
|||||||
return {
|
return {
|
||||||
'monthDate':
|
'monthDate':
|
||||||
'${monthDate?.year}-${monthDate?.month.toString().padLeft(2, '0')}',
|
'${monthDate?.year}-${monthDate?.month.toString().padLeft(2, '0')}',
|
||||||
if (spaceId == null || spaceId == null) 'spaceUuid': spaceId,
|
if (spaceId != null) 'spaceUuid': spaceId,
|
||||||
'groupByDevice': false,
|
'groupByDevice': false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
final class RemoteEnergyManagementAnalyticsDevicesService
|
final class RemoteEnergyManagementAnalyticsDevicesService
|
||||||
@ -9,6 +11,8 @@ final class RemoteEnergyManagementAnalyticsDevicesService
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load analytics devices';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param) async {
|
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param) async {
|
||||||
try {
|
try {
|
||||||
@ -29,8 +33,14 @@ final class RemoteEnergyManagementAnalyticsDevicesService
|
|||||||
);
|
);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load total energy consumption: $e');
|
throw APIException('$_defaultErrorMessage: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
import 'package:syncrow_web/pages/analytics/models/analytics_device.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_analytics_devices_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService {
|
class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService {
|
||||||
@ -9,6 +11,8 @@ class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load analytics devices';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param) async {
|
Future<List<AnalyticsDevice>> getDevices(GetAnalyticsDevicesParam param) async {
|
||||||
try {
|
try {
|
||||||
@ -26,8 +30,15 @@ class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService
|
|||||||
|
|
||||||
final result = requests.map((e) => e.first).toList();
|
final result = requests.map((e) => e.first).toList();
|
||||||
return result;
|
return result;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load total energy consumption: $e');
|
final formattedErrorMessage = [_defaultErrorMessage, e.toString()].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,8 +65,14 @@ class RemoteOccupancyAnalyticsDevicesService implements AnalyticsDevicesService
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
rethrow;
|
throw APIException('$_defaultErrorMessage: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
import 'package:syncrow_web/pages/analytics/models/phases_energy_consumption.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/energy_consumption_by_phases_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/energy_consumption_by_phases_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
final class RemoteEnergyConsumptionByPhasesService
|
final class RemoteEnergyConsumptionByPhasesService
|
||||||
@ -9,6 +11,8 @@ final class RemoteEnergyConsumptionByPhasesService
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load energy consumption per phase';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<PhasesEnergyConsumption>> load(
|
Future<List<PhasesEnergyConsumption>> load(
|
||||||
GetEnergyConsumptionByPhasesParam param,
|
GetEnergyConsumptionByPhasesParam param,
|
||||||
@ -28,8 +32,15 @@ final class RemoteEnergyConsumptionByPhasesService
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load energy consumption per phase: $e');
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/device_energy_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/energy_consumption_per_device_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/energy_consumption_per_device_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
class RemoteEnergyConsumptionPerDeviceService
|
class RemoteEnergyConsumptionPerDeviceService
|
||||||
@ -11,6 +13,8 @@ class RemoteEnergyConsumptionPerDeviceService
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load energy consumption per device';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<DeviceEnergyDataModel>> load(
|
Future<List<DeviceEnergyDataModel>> load(
|
||||||
GetEnergyConsumptionPerDeviceParam param,
|
GetEnergyConsumptionPerDeviceParam param,
|
||||||
@ -23,8 +27,15 @@ class RemoteEnergyConsumptionPerDeviceService
|
|||||||
expectedResponseModel: _EnergyConsumptionPerDeviceMapper.map,
|
expectedResponseModel: _EnergyConsumptionPerDeviceMapper.map,
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load energy consumption per device: $e');
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/occupacy.dart';
|
import 'package:syncrow_web/pages/analytics/models/occupacy.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupacy/occupacy_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/occupacy/occupacy_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
final class RemoteOccupancyService implements OccupacyService {
|
final class RemoteOccupancyService implements OccupacyService {
|
||||||
@ -8,6 +10,8 @@ final class RemoteOccupancyService implements OccupacyService {
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load occupancy';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Occupacy>> load(GetOccupancyParam param) async {
|
Future<List<Occupacy>> load(GetOccupancyParam param) async {
|
||||||
try {
|
try {
|
||||||
@ -25,8 +29,15 @@ final class RemoteOccupancyService implements OccupacyService {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load energy consumption per phase: $e');
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/occupancy_heat_map_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/occupancy_heat_map_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_occupancy_heat_map_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/occupancy_heat_map_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/occupancy_heat_map/occupancy_heat_map_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
final class RemoteOccupancyHeatMapService implements OccupancyHeatMapService {
|
final class RemoteOccupancyHeatMapService implements OccupancyHeatMapService {
|
||||||
@ -8,6 +10,8 @@ final class RemoteOccupancyHeatMapService implements OccupancyHeatMapService {
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load occupancy heat map';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<OccupancyHeatMapModel>> load(GetOccupancyHeatMapParam param) async {
|
Future<List<OccupancyHeatMapModel>> load(GetOccupancyHeatMapParam param) async {
|
||||||
try {
|
try {
|
||||||
@ -28,8 +32,15 @@ final class RemoteOccupancyHeatMapService implements OccupancyHeatMapService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load total energy consumption:');
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/power_clamp_info/power_clamp_info_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/power_clamp_info/power_clamp_info_service.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
|
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
final class RemotePowerClampInfoService implements PowerClampInfoService {
|
final class RemotePowerClampInfoService implements PowerClampInfoService {
|
||||||
@ -7,6 +9,8 @@ final class RemotePowerClampInfoService implements PowerClampInfoService {
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to fetch power clamp info';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PowerClampModel> getInfo(String deviceId) async {
|
Future<PowerClampModel> getInfo(String deviceId) async {
|
||||||
try {
|
try {
|
||||||
@ -20,8 +24,15 @@ final class RemotePowerClampInfoService implements PowerClampInfoService {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to fetch power clamp info: $e');
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
import 'package:syncrow_web/pages/analytics/models/energy_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart';
|
import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/services/total_energy_consumption/total_energy_consumption_service.dart';
|
import 'package:syncrow_web/pages/analytics/services/total_energy_consumption/total_energy_consumption_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
class RemoteTotalEnergyConsumptionService implements TotalEnergyConsumptionService {
|
class RemoteTotalEnergyConsumptionService implements TotalEnergyConsumptionService {
|
||||||
@ -8,6 +10,8 @@ class RemoteTotalEnergyConsumptionService implements TotalEnergyConsumptionServi
|
|||||||
|
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to load total energy consumption';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<EnergyDataModel>> load(
|
Future<List<EnergyDataModel>> load(
|
||||||
GetTotalEnergyConsumptionParam param,
|
GetTotalEnergyConsumptionParam param,
|
||||||
@ -21,8 +25,15 @@ class RemoteTotalEnergyConsumptionService implements TotalEnergyConsumptionServi
|
|||||||
);
|
);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, errorMessage].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw Exception('Failed to load total energy consumption: $e');
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,19 +162,21 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
controller: _horizontalBodyScrollController,
|
controller: _horizontalBodyScrollController,
|
||||||
|
child: Container(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: widget.size.width,
|
width: widget.size.width,
|
||||||
child: widget.isEmpty
|
child: widget.isEmpty
|
||||||
? _buildEmptyState()
|
? _buildEmptyState()
|
||||||
: Column(
|
: Column(
|
||||||
children:
|
children: List.generate(widget.data.length,
|
||||||
List.generate(widget.data.length, (rowIndex) {
|
(rowIndex) {
|
||||||
final row = widget.data[rowIndex];
|
final row = widget.data[rowIndex];
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (widget.withCheckBox)
|
if (widget.withCheckBox)
|
||||||
_buildRowCheckbox(
|
_buildRowCheckbox(rowIndex,
|
||||||
rowIndex, widget.size.height * 0.08),
|
widget.size.height * 0.08),
|
||||||
...row.asMap().entries.map((entry) {
|
...row.asMap().entries.map((entry) {
|
||||||
return _buildTableCell(
|
return _buildTableCell(
|
||||||
entry.value.toString(),
|
entry.value.toString(),
|
||||||
@ -193,6 +195,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -211,7 +214,6 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
onChanged: widget.withSelectAll && widget.data.isNotEmpty
|
onChanged: widget.withSelectAll && widget.data.isNotEmpty
|
||||||
? _toggleSelectAll
|
? _toggleSelectAll
|
||||||
: null,
|
: null,
|
||||||
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -282,7 +284,6 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: index == widget.headers.length - 1 ? 12 : 8.0,
|
horizontal: index == widget.headers.length - 1 ? 12 : 8.0,
|
||||||
vertical: 4),
|
vertical: 4),
|
||||||
|
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: context.textTheme.titleSmall!.copyWith(
|
style: context.textTheme.titleSmall!.copyWith(
|
||||||
@ -303,7 +304,6 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
required int rowIndex,
|
required int rowIndex,
|
||||||
required int columnIndex,
|
required int columnIndex,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
bool isBatteryLevel = content.endsWith('%');
|
bool isBatteryLevel = content.endsWith('%');
|
||||||
double? batteryLevel;
|
double? batteryLevel;
|
||||||
|
|
||||||
@ -313,10 +313,14 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
bool isSettingsColumn = widget.headers[columnIndex] == 'Settings';
|
bool isSettingsColumn = widget.headers[columnIndex] == 'Settings';
|
||||||
|
|
||||||
if (isSettingsColumn) {
|
if (isSettingsColumn) {
|
||||||
return _buildSettingsIcon(rowIndex, size);
|
return buildSettingsIcon(
|
||||||
|
width: 120,
|
||||||
|
height: 60,
|
||||||
|
iconSize: 40,
|
||||||
|
onTap: () => widget.onSettingsPressed?.call(rowIndex),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Color? statusColor;
|
Color? statusColor;
|
||||||
switch (content) {
|
switch (content) {
|
||||||
case 'Effective':
|
case 'Effective':
|
||||||
@ -368,22 +372,63 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSettingsIcon(int rowIndex, double size) {
|
Widget buildSettingsIcon(
|
||||||
return Container(
|
{double width = 120,
|
||||||
height: size,
|
double height = 60,
|
||||||
width: 120,
|
double iconSize = 40,
|
||||||
padding: const EdgeInsets.all(5.0),
|
VoidCallback? onTap}) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.only(top: 10, bottom: 15, left: 10),
|
||||||
|
margin: const EdgeInsets.only(right: 15),
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(color: ColorsManager.boxDivider, width: 1.0),
|
bottom: BorderSide(
|
||||||
|
color: ColorsManager.boxDivider,
|
||||||
|
width: 1.0,
|
||||||
),
|
),
|
||||||
color: Colors.white,
|
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
|
||||||
child: IconButton(
|
|
||||||
icon: SvgPicture.asset(Assets.settings),
|
|
||||||
onPressed: () => widget.onSettingsPressed?.call(rowIndex),
|
|
||||||
),
|
),
|
||||||
|
width: width,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
right: 16.0,
|
||||||
|
left: 17.0,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFF7F8FA),
|
||||||
|
borderRadius: BorderRadius.circular(height / 2),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.17),
|
||||||
|
blurRadius: 14,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Center(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.settings, // ضع المسار الصحيح هنا
|
||||||
|
width: 40,
|
||||||
|
height: 22,
|
||||||
|
color: ColorsManager
|
||||||
|
.primaryColor, // نفس لون الأيقونة في الصورة
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,13 +40,14 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: !state.routineTab
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
BlocProvider.of<CreateRoutineBloc>(context)
|
BlocProvider.of<CreateRoutineBloc>(context)
|
||||||
.add(const ResetSelectedEvent());
|
.add(const ResetSelectedEvent());
|
||||||
|
|
||||||
context
|
context.read<RoutineBloc>().add(
|
||||||
.read<RoutineBloc>()
|
const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
|
||||||
context
|
context
|
||||||
.read<DeviceManagementBloc>()
|
.read<DeviceManagementBloc>()
|
||||||
.add(FetchDevices(context));
|
.add(FetchDevices(context));
|
||||||
@ -66,13 +67,14 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: state.routineTab
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
BlocProvider.of<CreateRoutineBloc>(context)
|
BlocProvider.of<CreateRoutineBloc>(context)
|
||||||
.add(const ResetSelectedEvent());
|
.add(const ResetSelectedEvent());
|
||||||
|
|
||||||
context
|
context.read<RoutineBloc>().add(
|
||||||
.read<RoutineBloc>()
|
const TriggerSwitchTabsEvent(isRoutineTab: true));
|
||||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: true));
|
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Routines',
|
'Routines',
|
||||||
|
@ -30,12 +30,13 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
|
|
||||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||||
try {
|
try {
|
||||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
var uuid =
|
||||||
|
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
user = await HomeApi().fetchUserInfo(uuid);
|
user = await HomeApi().fetchUserInfo(uuid);
|
||||||
|
|
||||||
if (user != null && user!.project != null) {
|
if (user != null && user!.project != null) {
|
||||||
await ProjectManager.setProjectUUID(user!.project!.uuid);
|
await ProjectManager.setProjectUUID(user!.project!.uuid);
|
||||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
|
// NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
|
||||||
}
|
}
|
||||||
add(FetchTermEvent());
|
add(FetchTermEvent());
|
||||||
add(FetchPolicyEvent());
|
add(FetchPolicyEvent());
|
||||||
@ -67,10 +68,12 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _confirmUserAgreement(ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
Future _confirmUserAgreement(
|
||||||
|
ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(LoadingHome());
|
emit(LoadingHome());
|
||||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
var uuid =
|
||||||
|
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||||
policy = await HomeApi().confirmUserAgreements(uuid);
|
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||||
emit(PolicyAgreement());
|
emit(PolicyAgreement());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -123,5 +126,41 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
},
|
},
|
||||||
color: const Color(0xFF023DFE),
|
color: const Color(0xFF023DFE),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// HomeItemModel(
|
||||||
|
// title: 'Move in',
|
||||||
|
// icon: Assets.moveinIcon,
|
||||||
|
// active: false,
|
||||||
|
// onPress: (context) {},
|
||||||
|
// color: ColorsManager.primaryColor,
|
||||||
|
// ),
|
||||||
|
// HomeItemModel(
|
||||||
|
// title: 'Construction',
|
||||||
|
// icon: Assets.constructionIcon,
|
||||||
|
// active: false,
|
||||||
|
// onPress: (context) {},
|
||||||
|
// color: ColorsManager.primaryColor,
|
||||||
|
// ),
|
||||||
|
// HomeItemModel(
|
||||||
|
// title: 'Energy',
|
||||||
|
// icon: Assets.energyIcon,
|
||||||
|
// active: false,
|
||||||
|
// onPress: (context) {},
|
||||||
|
// color: ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
|
// ),
|
||||||
|
// HomeItemModel(
|
||||||
|
// title: 'Integrations',
|
||||||
|
// icon: Assets.integrationsIcon,
|
||||||
|
// active: false,
|
||||||
|
// onPress: (context) {},
|
||||||
|
// color: ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
|
// ),
|
||||||
|
// HomeItemModel(
|
||||||
|
// title: 'Asset',
|
||||||
|
// icon: Assets.assetIcon,
|
||||||
|
// active: false,
|
||||||
|
// onPress: (context) {},
|
||||||
|
// color: ColorsManager.slidingBlueColor.withOpacity(0.2),
|
||||||
|
// ),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class _HomeWebPageState extends State<HomeWebPage> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||||
homeBloc.add(const FetchUserInfo());
|
// homeBloc.add(const FetchUserInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -38,8 +38,10 @@ class _HomeWebPageState extends State<HomeWebPage> {
|
|||||||
child: BlocConsumer<HomeBloc, HomeState>(
|
child: BlocConsumer<HomeBloc, HomeState>(
|
||||||
listener: (BuildContext context, state) {
|
listener: (BuildContext context, state) {
|
||||||
if (state is HomeInitial) {
|
if (state is HomeInitial) {
|
||||||
if (homeBloc.user!.hasAcceptedWebAgreement == false && !_dialogShown) {
|
if (homeBloc.user!.hasAcceptedWebAgreement == false &&
|
||||||
_dialogShown = true; // Set the flag to true to indicate the dialog is showing.
|
!_dialogShown) {
|
||||||
|
_dialogShown =
|
||||||
|
true; // Set the flag to true to indicate the dialog is showing.
|
||||||
Future.delayed(const Duration(seconds: 1), () {
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -54,7 +56,7 @@ class _HomeWebPageState extends State<HomeWebPage> {
|
|||||||
_dialogShown = false;
|
_dialogShown = false;
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
homeBloc.add(ConfirmUserAgreementEvent());
|
homeBloc.add(ConfirmUserAgreementEvent());
|
||||||
homeBloc.add(const FetchUserInfo());
|
// homeBloc.add(const FetchUserInfo());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -98,7 +100,8 @@ class _HomeWebPageState extends State<HomeWebPage> {
|
|||||||
width: size.width * 0.68,
|
width: size.width * 0.68,
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
itemCount: homeBloc.homeItems.length,
|
itemCount: homeBloc.homeItems.length,
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate:
|
||||||
|
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 3, // Adjust as needed.
|
crossAxisCount: 3, // Adjust as needed.
|
||||||
crossAxisSpacing: 20.0,
|
crossAxisSpacing: 20.0,
|
||||||
mainAxisSpacing: 20.0,
|
mainAxisSpacing: 20.0,
|
||||||
@ -111,7 +114,8 @@ class _HomeWebPageState extends State<HomeWebPage> {
|
|||||||
active: homeBloc.homeItems[index].active!,
|
active: homeBloc.homeItems[index].active!,
|
||||||
name: homeBloc.homeItems[index].title!,
|
name: homeBloc.homeItems[index].title!,
|
||||||
img: homeBloc.homeItems[index].icon!,
|
img: homeBloc.homeItems[index].icon!,
|
||||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
onTap: () =>
|
||||||
|
homeBloc.homeItems[index].onPress(context),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -110,11 +110,11 @@ class SaveRoutineHelper {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
DialogFooterButton(
|
DialogFooterButton(
|
||||||
text: 'Cancel',
|
text: 'Back',
|
||||||
onTap: () => Navigator.pop(context),
|
onTap: () => Navigator.pop(context),
|
||||||
),
|
),
|
||||||
DialogFooterButton(
|
DialogFooterButton(
|
||||||
text: 'Confirm',
|
text: 'Save',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (state.isAutomation) {
|
if (state.isAutomation) {
|
||||||
if (state.isUpdate ?? false) {
|
if (state.isUpdate ?? false) {
|
||||||
|
@ -21,7 +21,8 @@ import 'package:syncrow_web/services/space_mana_api.dart';
|
|||||||
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/action_enum.dart' as custom_action;
|
import 'package:syncrow_web/utils/constants/action_enum.dart' as custom_action;
|
||||||
|
|
||||||
class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
class SpaceManagementBloc
|
||||||
|
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
||||||
final CommunitySpaceManagementApi _api;
|
final CommunitySpaceManagementApi _api;
|
||||||
final ProductApi _productApi;
|
final ProductApi _productApi;
|
||||||
final SpaceModelManagementApi _spaceModelApi;
|
final SpaceModelManagementApi _spaceModelApi;
|
||||||
@ -62,7 +63,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
int page = 1;
|
int page = 1;
|
||||||
|
|
||||||
while (hasNext) {
|
while (hasNext) {
|
||||||
final spaceModels = await _spaceModelApi.listSpaceModels(page: page, projectId: projectUuid);
|
final spaceModels = await _spaceModelApi.listSpaceModels(
|
||||||
|
page: page, projectId: projectUuid);
|
||||||
if (spaceModels.isNotEmpty) {
|
if (spaceModels.isNotEmpty) {
|
||||||
allSpaceModels.addAll(spaceModels);
|
allSpaceModels.addAll(spaceModels);
|
||||||
page++;
|
page++;
|
||||||
@ -75,26 +77,29 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
await fetchTags();
|
await fetchTags();
|
||||||
|
|
||||||
emit(SpaceModelLoaded(
|
emit(SpaceModelLoaded(
|
||||||
communities:
|
communities: state is SpaceManagementLoaded
|
||||||
state is SpaceManagementLoaded ? (state as SpaceManagementLoaded).communities : [],
|
? (state as SpaceManagementLoaded).communities
|
||||||
|
: [],
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
spaceModels: List.from(_cachedSpaceModels ?? []),
|
spaceModels: List.from(_cachedSpaceModels ?? []),
|
||||||
allTags: _cachedTags ?? []));
|
allTags: _cachedTags ?? []));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deleteSpaceModelFromCache(
|
void _deleteSpaceModelFromCache(DeleteSpaceModelFromCache event,
|
||||||
DeleteSpaceModelFromCache event, Emitter<SpaceManagementState> emit) async {
|
Emitter<SpaceManagementState> emit) async {
|
||||||
if (_cachedSpaceModels != null) {
|
if (_cachedSpaceModels != null) {
|
||||||
_cachedSpaceModels =
|
_cachedSpaceModels = _cachedSpaceModels!
|
||||||
_cachedSpaceModels!.where((model) => model.uuid != event.deletedUuid).toList();
|
.where((model) => model.uuid != event.deletedUuid)
|
||||||
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
_cachedSpaceModels = await fetchSpaceModels();
|
_cachedSpaceModels = await fetchSpaceModels();
|
||||||
}
|
}
|
||||||
await fetchTags();
|
await fetchTags();
|
||||||
|
|
||||||
emit(SpaceModelLoaded(
|
emit(SpaceModelLoaded(
|
||||||
communities:
|
communities: state is SpaceManagementLoaded
|
||||||
state is SpaceManagementLoaded ? (state as SpaceManagementLoaded).communities : [],
|
? (state as SpaceManagementLoaded).communities
|
||||||
|
: [],
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
spaceModels: List.from(_cachedSpaceModels ?? []),
|
spaceModels: List.from(_cachedSpaceModels ?? []),
|
||||||
allTags: _cachedTags ?? []));
|
allTags: _cachedTags ?? []));
|
||||||
@ -122,8 +127,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
int page = 1;
|
int page = 1;
|
||||||
|
|
||||||
while (hasNext) {
|
while (hasNext) {
|
||||||
final spaceModels =
|
final spaceModels = await _spaceModelApi.listSpaceModels(
|
||||||
await _spaceModelApi.listSpaceModels(page: page, projectId: projectUuid);
|
page: page, projectId: projectUuid);
|
||||||
if (spaceModels.isNotEmpty) {
|
if (spaceModels.isNotEmpty) {
|
||||||
allSpaceModels.addAll(spaceModels);
|
allSpaceModels.addAll(spaceModels);
|
||||||
page++;
|
page++;
|
||||||
@ -164,10 +169,12 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
await fetchTags();
|
await fetchTags();
|
||||||
|
|
||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
final success = await _api.updateCommunity(event.communityUuid, event.name, projectUuid);
|
final success = await _api.updateCommunity(
|
||||||
|
event.communityUuid, event.name, projectUuid);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (previousState is SpaceManagementLoaded) {
|
if (previousState is SpaceManagementLoaded) {
|
||||||
final updatedCommunities = List<CommunityModel>.from(previousState.communities);
|
final updatedCommunities =
|
||||||
|
List<CommunityModel>.from(previousState.communities);
|
||||||
for (var community in updatedCommunities) {
|
for (var community in updatedCommunities) {
|
||||||
if (community.uuid == event.communityUuid) {
|
if (community.uuid == event.communityUuid) {
|
||||||
community.name = event.name;
|
community.name = event.name;
|
||||||
@ -212,7 +219,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(String communityUuid) async {
|
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||||
|
String communityUuid) async {
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
return await _api.getSpaceHierarchy(communityUuid, projectUuid);
|
return await _api.getSpaceHierarchy(communityUuid, projectUuid);
|
||||||
@ -242,20 +250,23 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBlankState(BlankStateEvent event, Emitter<SpaceManagementState> emit) async {
|
Future<void> _onBlankState(
|
||||||
|
BlankStateEvent event, Emitter<SpaceManagementState> emit) async {
|
||||||
try {
|
try {
|
||||||
final previousState = state;
|
final previousState = state;
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
var spaceTreeState = event.context.read<SpaceTreeBloc>().state;
|
var spaceTreeState = event.context.read<SpaceTreeBloc>().state;
|
||||||
|
|
||||||
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc, spaceTreeState);
|
List<CommunityModel> communities =
|
||||||
|
await _waitForCommunityList(spaceBloc, spaceTreeState);
|
||||||
await fetchSpaceModels();
|
await fetchSpaceModels();
|
||||||
await fetchTags();
|
// await fetchTags();
|
||||||
|
|
||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
if (previousState is SpaceManagementLoaded || previousState is BlankState) {
|
if (previousState is SpaceManagementLoaded ||
|
||||||
|
previousState is BlankState) {
|
||||||
final prevCommunities = (previousState as dynamic).communities ?? [];
|
final prevCommunities = (previousState as dynamic).communities ?? [];
|
||||||
emit(BlankState(
|
emit(BlankState(
|
||||||
communities: List<CommunityModel>.from(prevCommunities),
|
communities: List<CommunityModel>.from(prevCommunities),
|
||||||
@ -286,7 +297,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
_onloadProducts();
|
_onloadProducts();
|
||||||
await fetchTags();
|
await fetchTags();
|
||||||
// Wait until `communityList` is loaded
|
// Wait until `communityList` is loaded
|
||||||
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc, spaceTreeState);
|
List<CommunityModel> communities =
|
||||||
|
await _waitForCommunityList(spaceBloc, spaceTreeState);
|
||||||
|
|
||||||
// Fetch space models after communities are available
|
// Fetch space models after communities are available
|
||||||
final prevSpaceModels = await fetchSpaceModels();
|
final prevSpaceModels = await fetchSpaceModels();
|
||||||
@ -310,8 +322,9 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
final completer = Completer<List<CommunityModel>>();
|
final completer = Completer<List<CommunityModel>>();
|
||||||
final subscription = spaceBloc.stream.listen((state) {
|
final subscription = spaceBloc.stream.listen((state) {
|
||||||
if (!completer.isCompleted && state.communityList.isNotEmpty) {
|
if (!completer.isCompleted && state.communityList.isNotEmpty) {
|
||||||
completer
|
completer.complete(state.searchQuery.isNotEmpty
|
||||||
.complete(state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList);
|
? state.filteredCommunity
|
||||||
|
: state.communityList);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@ -339,7 +352,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
final success = await _api.deleteCommunity(event.communityUuid, projectUuid);
|
final success =
|
||||||
|
await _api.deleteCommunity(event.communityUuid, projectUuid);
|
||||||
if (success) {
|
if (success) {
|
||||||
// add(LoadCommunityAndSpacesEvent());
|
// add(LoadCommunityAndSpacesEvent());
|
||||||
} else {
|
} else {
|
||||||
@ -361,12 +375,13 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
try {
|
try {
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
await fetchTags();
|
await fetchTags();
|
||||||
CommunityModel? newCommunity =
|
CommunityModel? newCommunity = await _api.createCommunity(
|
||||||
await _api.createCommunity(event.name, event.description, projectUuid);
|
event.name, event.description, projectUuid);
|
||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
if (newCommunity != null) {
|
if (newCommunity != null) {
|
||||||
if (previousState is SpaceManagementLoaded || previousState is BlankState) {
|
if (previousState is SpaceManagementLoaded ||
|
||||||
|
previousState is BlankState) {
|
||||||
final prevCommunities = List<CommunityModel>.from(
|
final prevCommunities = List<CommunityModel>.from(
|
||||||
(previousState as dynamic).communities,
|
(previousState as dynamic).communities,
|
||||||
);
|
);
|
||||||
@ -459,12 +474,15 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
try {
|
try {
|
||||||
final spaceTreeState = event.context.read<SpaceTreeBloc>().state;
|
final spaceTreeState = event.context.read<SpaceTreeBloc>().state;
|
||||||
|
|
||||||
final updatedSpaces =
|
final updatedSpaces = await saveSpacesHierarchically(
|
||||||
await saveSpacesHierarchically(event.context, event.spaces, event.communityUuid);
|
event.context, event.spaces, event.communityUuid);
|
||||||
final allSpaces = await _fetchSpacesForCommunity(event.communityUuid);
|
final allSpaces = await _fetchSpacesForCommunity(event.communityUuid);
|
||||||
|
|
||||||
emit(SpaceCreationSuccess(spaces: updatedSpaces));
|
// emit(SpaceCreationSuccess(spaces: updatedSpaces));
|
||||||
|
// updatedSpaces.forEach(
|
||||||
|
// (element) => element.uuid,
|
||||||
|
// );
|
||||||
|
// final lastUpdatedSpaced = updatedSpaces..addAll(allSpaces);
|
||||||
if (previousState is SpaceManagementLoaded) {
|
if (previousState is SpaceManagementLoaded) {
|
||||||
await _updateLoadedState(
|
await _updateLoadedState(
|
||||||
spaceTreeState,
|
spaceTreeState,
|
||||||
@ -475,7 +493,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceManagementError('Error saving spaces: $e'));
|
// emit(SpaceManagementError('Error saving spaces: $e'));
|
||||||
|
|
||||||
if (previousState is SpaceManagementLoaded) {
|
if (previousState is SpaceManagementLoaded) {
|
||||||
emit(previousState);
|
emit(previousState);
|
||||||
@ -515,13 +533,15 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
emit(previousState);
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
rethrow;
|
emit(previousState);
|
||||||
|
// rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<SpaceModel>> saveSpacesHierarchically(
|
Future<List<SpaceModel>> saveSpacesHierarchically(BuildContext context,
|
||||||
BuildContext context, List<SpaceModel> spaces, String communityUuid) async {
|
List<SpaceModel> spaces, String communityUuid) async {
|
||||||
final orderedSpaces = flattenHierarchy(spaces);
|
final orderedSpaces = flattenHierarchy(spaces);
|
||||||
|
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
@ -534,6 +554,14 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
|
|
||||||
selectedCommunity = filteredCommunities.firstWhere(
|
selectedCommunity = filteredCommunities.firstWhere(
|
||||||
(community) => community.uuid == communityUuid,
|
(community) => community.uuid == communityUuid,
|
||||||
|
orElse: () => CommunityModel(
|
||||||
|
uuid: '',
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
spaces: spaces,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
@ -548,9 +576,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
if (parent.uuid != null) {
|
if (parent.uuid != null) {
|
||||||
await _api.deleteSpace(communityUuid, parent.uuid!, projectUuid);
|
await _api.deleteSpace(communityUuid, parent.uuid!, projectUuid);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
orderedSpaces.removeWhere((space) => parentsToDelete.contains(space));
|
orderedSpaces.removeWhere((space) => parentsToDelete.contains(space));
|
||||||
|
|
||||||
@ -564,7 +590,7 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
|
|
||||||
if (matchedSpaces.isEmpty) continue;
|
if (matchedSpaces.isEmpty) continue;
|
||||||
|
|
||||||
final prevSpace = matchedSpaces[0];
|
final prevSpace = matchedSpaces.elementAtOrNull(0);
|
||||||
|
|
||||||
final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
|
final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
|
||||||
final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
|
final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
|
||||||
@ -575,17 +601,19 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
if (prevSubspaces != null || newSubspaces != null) {
|
if (prevSubspaces != null || newSubspaces != null) {
|
||||||
if (prevSubspaces != null && newSubspaces != null) {
|
if (prevSubspaces != null && newSubspaces != null) {
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
final existsInNew =
|
final existsInNew = newSubspaces
|
||||||
newSubspaces.any((subspace) => subspace.uuid == prevSubspace.uuid);
|
.any((subspace) => subspace.uuid == prevSubspace.uuid);
|
||||||
if (!existsInNew) {
|
if (!existsInNew) {
|
||||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||||
action: custom_action.Action.delete, uuid: prevSubspace.uuid));
|
action: custom_action.Action.delete,
|
||||||
|
uuid: prevSubspace.uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (prevSubspaces != null && newSubspaces == null) {
|
} else if (prevSubspaces != null && newSubspaces == null) {
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||||
action: custom_action.Action.delete, uuid: prevSubspace.uuid));
|
action: custom_action.Action.delete,
|
||||||
|
uuid: prevSubspace.uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,7 +641,9 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prevSubspaces != null && newSubspaces != null) {
|
if (prevSubspaces != null && newSubspaces != null) {
|
||||||
final newSubspaceMap = {for (var subspace in newSubspaces) subspace.uuid: subspace};
|
final newSubspaceMap = {
|
||||||
|
for (var subspace in newSubspaces) subspace.uuid: subspace
|
||||||
|
};
|
||||||
|
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
final newSubspace = newSubspaceMap[prevSubspace.uuid];
|
final newSubspace = newSubspaceMap[prevSubspace.uuid];
|
||||||
@ -639,9 +669,10 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
isPrivate: space.isPrivate,
|
isPrivate: space.isPrivate,
|
||||||
position: space.position,
|
position: space.position,
|
||||||
icon: space.icon,
|
icon: space.icon,
|
||||||
subspaces: subspaceUpdates,
|
subspaces: space.subspaces,
|
||||||
tags: tagUpdates,
|
// subspaceUpdates,
|
||||||
direction: space.incomingConnection?.direction,
|
tags: space.tags,
|
||||||
|
// tagUpdates,
|
||||||
spaceModelUuid: space.spaceModel?.uuid,
|
spaceModelUuid: space.spaceModel?.uuid,
|
||||||
projectId: projectUuid);
|
projectId: projectUuid);
|
||||||
} else {
|
} else {
|
||||||
@ -651,8 +682,10 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
var createSubspaceBodyModels = space.subspaces?.map((subspace) {
|
var createSubspaceBodyModels = space.subspaces?.map((subspace) {
|
||||||
final tagBodyModels =
|
final tagBodyModels = subspace.tags
|
||||||
subspace.tags?.map((tag) => tag.toCreateTagBodyModel()).toList() ?? [];
|
?.map((tag) => tag.toCreateTagBodyModel())
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
return CreateSubspaceModel()
|
return CreateSubspaceModel()
|
||||||
..subspaceName = subspace.subspaceName
|
..subspaceName = subspace.subspaceName
|
||||||
..tags = tagBodyModels;
|
..tags = tagBodyModels;
|
||||||
@ -671,7 +704,6 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
isPrivate: space.isPrivate,
|
isPrivate: space.isPrivate,
|
||||||
position: space.position,
|
position: space.position,
|
||||||
icon: space.icon,
|
icon: space.icon,
|
||||||
direction: space.incomingConnection?.direction,
|
|
||||||
spaceModelUuid: space.spaceModel?.uuid,
|
spaceModelUuid: space.spaceModel?.uuid,
|
||||||
tags: tagBodyModels,
|
tags: tagBodyModels,
|
||||||
subspaces: createSubspaceBodyModels,
|
subspaces: createSubspaceBodyModels,
|
||||||
@ -679,7 +711,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
space.uuid = response?.uuid;
|
space.uuid = response?.uuid;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
rethrow; // Stop further execution on failure
|
return [];
|
||||||
|
// Stop further execution on failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return spaces;
|
return spaces;
|
||||||
@ -710,7 +743,8 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
return result.toList(); // Convert back to a list
|
return result.toList(); // Convert back to a list
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onLoadSpaceModel(SpaceModelLoadEvent event, Emitter<SpaceManagementState> emit) async {
|
void _onLoadSpaceModel(
|
||||||
|
SpaceModelLoadEvent event, Emitter<SpaceManagementState> emit) async {
|
||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -757,14 +791,17 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
// Case 1: Tags deleted
|
// Case 1: Tags deleted
|
||||||
if (prevTags != null && newTags != null) {
|
if (prevTags != null && newTags != null) {
|
||||||
for (var prevTag in prevTags) {
|
for (var prevTag in prevTags) {
|
||||||
final existsInNew = newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
final existsInNew =
|
||||||
|
newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
||||||
if (!existsInNew) {
|
if (!existsInNew) {
|
||||||
tagUpdates.add(TagModelUpdate(action: custom_action.Action.delete, uuid: prevTag.uuid));
|
tagUpdates.add(TagModelUpdate(
|
||||||
|
action: custom_action.Action.delete, uuid: prevTag.uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (prevTags != null && newTags == null) {
|
} else if (prevTags != null && newTags == null) {
|
||||||
for (var prevTag in prevTags) {
|
for (var prevTag in prevTags) {
|
||||||
tagUpdates.add(TagModelUpdate(action: custom_action.Action.delete, uuid: prevTag.uuid));
|
tagUpdates.add(TagModelUpdate(
|
||||||
|
action: custom_action.Action.delete, uuid: prevTag.uuid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,15 +844,16 @@ class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementStat
|
|||||||
return tagUpdates;
|
return tagUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SpaceModel> findMatchingSpaces(List<SpaceModel> spaces, String targetUuid) {
|
List<SpaceModel> findMatchingSpaces(
|
||||||
|
List<SpaceModel> spaces, String targetUuid) {
|
||||||
List<SpaceModel> matched = [];
|
List<SpaceModel> matched = [];
|
||||||
|
|
||||||
for (var space in spaces) {
|
for (var space in spaces) {
|
||||||
if (space.uuid == targetUuid) {
|
if (space.uuid == targetUuid) {
|
||||||
matched.add(space);
|
matched.add(space);
|
||||||
}
|
}
|
||||||
matched
|
matched.addAll(findMatchingSpaces(
|
||||||
.addAll(findMatchingSpaces(space.children, targetUuid)); // Recursively search in children
|
space.children, targetUuid)); // Recursively search in children
|
||||||
}
|
}
|
||||||
|
|
||||||
return matched;
|
return matched;
|
||||||
|
@ -3,23 +3,26 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model
|
|||||||
class Connection {
|
class Connection {
|
||||||
final SpaceModel startSpace;
|
final SpaceModel startSpace;
|
||||||
final SpaceModel endSpace;
|
final SpaceModel endSpace;
|
||||||
final String direction;
|
|
||||||
|
|
||||||
Connection({required this.startSpace, required this.endSpace, required this.direction});
|
Connection({
|
||||||
|
required this.startSpace,
|
||||||
|
required this.endSpace,
|
||||||
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return {
|
||||||
'startUuid': startSpace.uuid ?? 'unsaved-start-space-${startSpace.name}', // Fallback for unsaved spaces
|
'startUuid': startSpace.uuid ??
|
||||||
'endUuid': endSpace.uuid ?? 'unsaved-end-space-${endSpace.name}', // Fallback for unsaved spaces
|
'unsaved-start-space-${startSpace.name}', // Fallback for unsaved spaces
|
||||||
'direction': direction,
|
'endUuid': endSpace.uuid ??
|
||||||
|
'unsaved-end-space-${endSpace.name}', // Fallback for unsaved spaces
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Connection fromMap(Map<String, dynamic> map, Map<String, SpaceModel> spaces) {
|
static Connection fromMap(
|
||||||
|
Map<String, dynamic> map, Map<String, SpaceModel> spaces) {
|
||||||
return Connection(
|
return Connection(
|
||||||
startSpace: spaces[map['startUuid']]!,
|
startSpace: spaces[map['startUuid']]!,
|
||||||
endSpace: spaces[map['endUuid']]!,
|
endSpace: spaces[map['endUuid']]!,
|
||||||
direction: map['direction'],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
|
import 'selected_product_model.dart';
|
||||||
|
|
||||||
class ProductModel {
|
class ProductModel {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
final String catName;
|
final String catName;
|
||||||
@ -38,6 +40,15 @@ class ProductModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SelectedProduct toSelectedProduct(int count) {
|
||||||
|
return SelectedProduct(
|
||||||
|
productId: uuid,
|
||||||
|
count: count,
|
||||||
|
productName: name!,
|
||||||
|
product: this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static String _mapIconToProduct(String prodType) {
|
static String _mapIconToProduct(String prodType) {
|
||||||
const iconMapping = {
|
const iconMapping = {
|
||||||
'1G': Assets.Gang1SwitchIcon,
|
'1G': Assets.Gang1SwitchIcon,
|
||||||
|
@ -101,7 +101,7 @@ class SpaceModel {
|
|||||||
spaceModel: json['spaceModel'] != null
|
spaceModel: json['spaceModel'] != null
|
||||||
? SpaceTemplateModel.fromJson(json['spaceModel'])
|
? SpaceTemplateModel.fromJson(json['spaceModel'])
|
||||||
: null,
|
: null,
|
||||||
tags: (json['tags'] as List<dynamic>?)
|
tags: (json['productAllocations'] as List<dynamic>?)
|
||||||
?.where((item) => item is Map<String, dynamic>) // Validate type
|
?.where((item) => item is Map<String, dynamic>) // Validate type
|
||||||
.map((item) => Tag.fromJson(item as Map<String, dynamic>))
|
.map((item) => Tag.fromJson(item as Map<String, dynamic>))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
@ -116,7 +116,6 @@ class SpaceModel {
|
|||||||
instance.incomingConnection = Connection(
|
instance.incomingConnection = Connection(
|
||||||
startSpace: instance.parent ?? instance, // Parent space
|
startSpace: instance.parent ?? instance, // Parent space
|
||||||
endSpace: instance, // This space instance
|
endSpace: instance, // This space instance
|
||||||
direction: conn['direction'],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class SubspaceModel {
|
|||||||
subspaceName: json['subspaceName'] ?? '',
|
subspaceName: json['subspaceName'] ?? '',
|
||||||
disabled: json['disabled'] ?? false,
|
disabled: json['disabled'] ?? false,
|
||||||
internalId: internalId,
|
internalId: internalId,
|
||||||
tags: (json['tags'] as List<dynamic>?)
|
tags: (json['productAllocations'] as List<dynamic>?)
|
||||||
?.map((item) => Tag.fromJson(item))
|
?.map((item) => Tag.fromJson(item))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
@ -36,7 +36,7 @@ class SubspaceModel {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'uuid': uuid,
|
if (uuid != null) 'uuid': uuid,
|
||||||
'subspaceName': subspaceName,
|
'subspaceName': subspaceName,
|
||||||
'disabled': disabled,
|
'disabled': disabled,
|
||||||
'tags': tags?.map((e) => e.toJson()).toList() ?? [],
|
'tags': tags?.map((e) => e.toJson()).toList() ?? [],
|
||||||
|
@ -23,10 +23,13 @@ class Tag extends BaseTag {
|
|||||||
final String internalId = json['internalId'] ?? const Uuid().v4();
|
final String internalId = json['internalId'] ?? const Uuid().v4();
|
||||||
|
|
||||||
return Tag(
|
return Tag(
|
||||||
uuid: json['uuid'] ?? '',
|
//TODO:insure UUId for tag or prodAlloc
|
||||||
|
uuid: json['name'] != null ? json['uuid'] : json['tag']?['uuid'] ?? '',
|
||||||
internalId: internalId,
|
internalId: internalId,
|
||||||
tag: json['name'] ?? '',
|
tag: json['name'] ?? json['tag']?['name'] ?? '',
|
||||||
product: json['product'] != null ? ProductModel.fromMap(json['product']) : null,
|
product: json['product'] != null
|
||||||
|
? ProductModel.fromMap(json['product'])
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,9 +52,10 @@ class Tag extends BaseTag {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'uuid': uuid,
|
if (uuid != null) 'uuid': uuid,
|
||||||
'tag': tag,
|
'name': tag,
|
||||||
'product': product?.toMap(),
|
'productUuid': product?.uuid,
|
||||||
|
// .toMap(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
||||||
connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
connections =
|
||||||
|
widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
||||||
_adjustCanvasSizeForSpaces();
|
_adjustCanvasSizeForSpaces();
|
||||||
_nameController = TextEditingController(
|
_nameController = TextEditingController(
|
||||||
text: widget.selectedCommunity?.name ?? '',
|
text: widget.selectedCommunity?.name ?? '',
|
||||||
@ -96,13 +97,15 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
if (oldWidget.spaces != widget.spaces) {
|
if (oldWidget.spaces != widget.spaces) {
|
||||||
setState(() {
|
setState(() {
|
||||||
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
||||||
connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
connections =
|
||||||
|
widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
||||||
_adjustCanvasSizeForSpaces();
|
_adjustCanvasSizeForSpaces();
|
||||||
realignTree();
|
realignTree();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget.selectedSpace != oldWidget.selectedSpace && widget.selectedSpace != null) {
|
if (widget.selectedSpace != oldWidget.selectedSpace &&
|
||||||
|
widget.selectedSpace != null) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_moveToSpace(widget.selectedSpace!);
|
_moveToSpace(widget.selectedSpace!);
|
||||||
});
|
});
|
||||||
@ -185,7 +188,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
connection, widget.selectedSpace)
|
connection, widget.selectedSpace)
|
||||||
? 1.0
|
? 1.0
|
||||||
: 0.3, // Adjust opacity
|
: 0.3, // Adjust opacity
|
||||||
child: CustomPaint(painter: CurvedLinePainter([connection])),
|
child: CustomPaint(
|
||||||
|
painter: CurvedLinePainter([connection])),
|
||||||
),
|
),
|
||||||
for (var entry in spaces.asMap().entries)
|
for (var entry in spaces.asMap().entries)
|
||||||
if (entry.value.status != SpaceStatus.deleted &&
|
if (entry.value.status != SpaceStatus.deleted &&
|
||||||
@ -195,11 +199,11 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
top: entry.value.position.dy,
|
top: entry.value.position.dy,
|
||||||
child: SpaceCardWidget(
|
child: SpaceCardWidget(
|
||||||
index: entry.key,
|
index: entry.key,
|
||||||
onButtonTap: (int index, Offset newPosition, String direction) {
|
onButtonTap: (int index, Offset newPosition) {
|
||||||
_showCreateSpaceDialog(screenSize,
|
_showCreateSpaceDialog(screenSize,
|
||||||
position: spaces[index].position + newPosition,
|
position:
|
||||||
|
spaces[index].position + newPosition,
|
||||||
parentIndex: index,
|
parentIndex: index,
|
||||||
direction: direction,
|
|
||||||
projectTags: widget.projectTags);
|
projectTags: widget.projectTags);
|
||||||
},
|
},
|
||||||
position: entry.value.position,
|
position: entry.value.position,
|
||||||
@ -210,7 +214,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
_updateNodePosition(entry.value, newPosition);
|
_updateNodePosition(entry.value, newPosition);
|
||||||
},
|
},
|
||||||
buildSpaceContainer: (int index) {
|
buildSpaceContainer: (int index) {
|
||||||
final bool isHighlighted = SpaceHelper.isHighlightedSpace(
|
final bool isHighlighted =
|
||||||
|
SpaceHelper.isHighlightedSpace(
|
||||||
spaces[index], widget.selectedSpace);
|
spaces[index], widget.selectedSpace);
|
||||||
|
|
||||||
return Opacity(
|
return Opacity(
|
||||||
@ -289,7 +294,6 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
void _showCreateSpaceDialog(Size screenSize,
|
void _showCreateSpaceDialog(Size screenSize,
|
||||||
{Offset? position,
|
{Offset? position,
|
||||||
int? parentIndex,
|
int? parentIndex,
|
||||||
String? direction,
|
|
||||||
double? canvasWidth,
|
double? canvasWidth,
|
||||||
double? canvasHeight,
|
double? canvasHeight,
|
||||||
required List<Tag> projectTags}) {
|
required List<Tag> projectTags}) {
|
||||||
@ -299,19 +303,25 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
return CreateSpaceDialog(
|
return CreateSpaceDialog(
|
||||||
products: widget.products,
|
products: widget.products,
|
||||||
spaceModels: widget.spaceModels,
|
spaceModels: widget.spaceModels,
|
||||||
allTags: TagHelper.getAllTagValues(widget.communities, widget.spaceModels),
|
allTags:
|
||||||
|
TagHelper.getAllTagValues(widget.communities, widget.spaceModels),
|
||||||
parentSpace: parentIndex != null ? spaces[parentIndex] : null,
|
parentSpace: parentIndex != null ? spaces[parentIndex] : null,
|
||||||
projectTags: projectTags,
|
projectTags: projectTags,
|
||||||
onCreateSpace: (String name, String icon, List<SelectedProduct> selectedProducts,
|
onCreateSpace: (String name,
|
||||||
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
String icon,
|
||||||
|
List<SelectedProduct> selectedProducts,
|
||||||
|
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 newPosition;
|
Offset newPosition;
|
||||||
if (parentIndex != null) {
|
if (parentIndex != null) {
|
||||||
newPosition =
|
newPosition = getBalancedChildPosition(
|
||||||
getBalancedChildPosition(spaces[parentIndex]); // Ensure balanced position
|
spaces[parentIndex]); // Ensure balanced position
|
||||||
} else {
|
} else {
|
||||||
newPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
|
newPosition =
|
||||||
|
position ?? ConnectionHelper.getCenterPosition(screenSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceModel newSpace = SpaceModel(
|
SpaceModel newSpace = SpaceModel(
|
||||||
@ -325,14 +335,13 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
tags: tags);
|
tags: tags);
|
||||||
|
|
||||||
if (parentIndex != null && direction != null) {
|
if (parentIndex != null) {
|
||||||
SpaceModel parentSpace = spaces[parentIndex];
|
SpaceModel parentSpace = spaces[parentIndex];
|
||||||
parentSpace.internalId = spaces[parentIndex].internalId;
|
parentSpace.internalId = spaces[parentIndex].internalId;
|
||||||
newSpace.parent = parentSpace;
|
newSpace.parent = parentSpace;
|
||||||
final newConnection = Connection(
|
final newConnection = Connection(
|
||||||
startSpace: parentSpace,
|
startSpace: parentSpace,
|
||||||
endSpace: newSpace,
|
endSpace: newSpace,
|
||||||
direction: direction,
|
|
||||||
);
|
);
|
||||||
connections.add(newConnection);
|
connections.add(newConnection);
|
||||||
newSpace.incomingConnection = newConnection;
|
newSpace.incomingConnection = newConnection;
|
||||||
@ -360,16 +369,21 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
name: widget.selectedSpace!.name,
|
name: widget.selectedSpace!.name,
|
||||||
icon: widget.selectedSpace!.icon,
|
icon: widget.selectedSpace!.icon,
|
||||||
projectTags: widget.projectTags,
|
projectTags: widget.projectTags,
|
||||||
parentSpace:
|
parentSpace: SpaceHelper.findSpaceByInternalId(
|
||||||
SpaceHelper.findSpaceByInternalId(widget.selectedSpace?.parent?.internalId, spaces),
|
widget.selectedSpace?.parent?.internalId, spaces),
|
||||||
editSpace: widget.selectedSpace,
|
editSpace: widget.selectedSpace,
|
||||||
currentSpaceModel: widget.selectedSpace?.spaceModel,
|
currentSpaceModel: widget.selectedSpace?.spaceModel,
|
||||||
tags: widget.selectedSpace?.tags,
|
tags: widget.selectedSpace?.tags,
|
||||||
subspaces: widget.selectedSpace?.subspaces,
|
subspaces: widget.selectedSpace?.subspaces,
|
||||||
isEdit: true,
|
isEdit: true,
|
||||||
allTags: TagHelper.getAllTagValues(widget.communities, widget.spaceModels),
|
allTags: TagHelper.getAllTagValues(
|
||||||
onCreateSpace: (String name, String icon, List<SelectedProduct> selectedProducts,
|
widget.communities, widget.spaceModels),
|
||||||
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
onCreateSpace: (String name,
|
||||||
|
String icon,
|
||||||
|
List<SelectedProduct> selectedProducts,
|
||||||
|
SpaceTemplateModel? spaceModel,
|
||||||
|
List<SubspaceModel>? subspaces,
|
||||||
|
List<Tag>? tags) {
|
||||||
setState(() {
|
setState(() {
|
||||||
// Update the space's properties
|
// Update the space's properties
|
||||||
widget.selectedSpace!.name = name;
|
widget.selectedSpace!.name = name;
|
||||||
@ -379,7 +393,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
widget.selectedSpace!.tags = tags;
|
widget.selectedSpace!.tags = tags;
|
||||||
|
|
||||||
if (widget.selectedSpace!.status != SpaceStatus.newSpace) {
|
if (widget.selectedSpace!.status != SpaceStatus.newSpace) {
|
||||||
widget.selectedSpace!.status = SpaceStatus.modified; // Mark as modified
|
widget.selectedSpace!.status =
|
||||||
|
SpaceStatus.modified; // Mark as modified
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var space in spaces) {
|
for (var space in spaces) {
|
||||||
@ -410,7 +425,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
Map<String, SpaceModel> idToSpace = {};
|
Map<String, SpaceModel> idToSpace = {};
|
||||||
|
|
||||||
void flatten(SpaceModel space) {
|
void flatten(SpaceModel space) {
|
||||||
if (space.status == SpaceStatus.deleted || space.status == SpaceStatus.parentDeleted) {
|
if (space.status == SpaceStatus.deleted ||
|
||||||
|
space.status == SpaceStatus.parentDeleted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
result.add(space);
|
result.add(space);
|
||||||
@ -447,7 +463,6 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
Connection(
|
Connection(
|
||||||
startSpace: parent,
|
startSpace: parent,
|
||||||
endSpace: child,
|
endSpace: child,
|
||||||
direction: "down",
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -532,13 +547,16 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
void _selectSpace(BuildContext context, SpaceModel space) {
|
void _selectSpace(BuildContext context, SpaceModel space) {
|
||||||
context.read<SpaceManagementBloc>().add(
|
context.read<SpaceManagementBloc>().add(
|
||||||
SelectSpaceEvent(selectedCommunity: widget.selectedCommunity, selectedSpace: space),
|
SelectSpaceEvent(
|
||||||
|
selectedCommunity: widget.selectedCommunity,
|
||||||
|
selectedSpace: space),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deselectSpace(BuildContext context) {
|
void _deselectSpace(BuildContext context) {
|
||||||
context.read<SpaceManagementBloc>().add(
|
context.read<SpaceManagementBloc>().add(
|
||||||
SelectSpaceEvent(selectedCommunity: widget.selectedCommunity, selectedSpace: null),
|
SelectSpaceEvent(
|
||||||
|
selectedCommunity: widget.selectedCommunity, selectedSpace: null),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,7 +726,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
SpaceModel duplicated = _deepCloneSpaceTree(space, parent: parent);
|
SpaceModel duplicated = _deepCloneSpaceTree(space, parent: parent);
|
||||||
|
|
||||||
duplicated.position = Offset(space.position.dx + 300, space.position.dy + 100);
|
duplicated.position =
|
||||||
|
Offset(space.position.dx + 300, space.position.dy + 100);
|
||||||
List<SpaceModel> duplicatedSubtree = [];
|
List<SpaceModel> duplicatedSubtree = [];
|
||||||
void collectSubtree(SpaceModel node) {
|
void collectSubtree(SpaceModel node) {
|
||||||
duplicatedSubtree.add(node);
|
duplicatedSubtree.add(node);
|
||||||
@ -726,7 +745,6 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
final newConnection = Connection(
|
final newConnection = Connection(
|
||||||
startSpace: parent,
|
startSpace: parent,
|
||||||
endSpace: duplicated,
|
endSpace: duplicated,
|
||||||
direction: "down",
|
|
||||||
);
|
);
|
||||||
connections.add(newConnection);
|
connections.add(newConnection);
|
||||||
duplicated.incomingConnection = newConnection;
|
duplicated.incomingConnection = newConnection;
|
||||||
@ -739,7 +757,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SpaceModel _deepCloneSpaceTree(SpaceModel original, {SpaceModel? parent}) {
|
SpaceModel _deepCloneSpaceTree(SpaceModel original, {SpaceModel? parent}) {
|
||||||
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
final duplicatedName =
|
||||||
|
SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
||||||
|
|
||||||
final newSpace = SpaceModel(
|
final newSpace = SpaceModel(
|
||||||
name: duplicatedName,
|
name: duplicatedName,
|
||||||
@ -761,7 +780,6 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
final newConnection = Connection(
|
final newConnection = Connection(
|
||||||
startSpace: newSpace,
|
startSpace: newSpace,
|
||||||
endSpace: duplicatedChild,
|
endSpace: duplicatedChild,
|
||||||
direction: "down",
|
|
||||||
);
|
);
|
||||||
connections.add(newConnection);
|
connections.add(newConnection);
|
||||||
|
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
|
import '../../../../../common/edit_chip.dart';
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
import '../../../helper/tag_helper.dart';
|
||||||
|
import '../../../space_model/widgets/button_content_widget.dart';
|
||||||
|
import '../../model/subspace_model.dart';
|
||||||
|
import '../../model/tag.dart';
|
||||||
|
|
||||||
|
class DevicesPartWidget extends StatelessWidget {
|
||||||
|
const DevicesPartWidget({
|
||||||
|
super.key,
|
||||||
|
required this.tags,
|
||||||
|
required this.subspaces,
|
||||||
|
required this.screenWidth,
|
||||||
|
required this.onEditChip,
|
||||||
|
required this.onTextButtonPressed,
|
||||||
|
required this.isTagsAndSubspaceModelDisabled,
|
||||||
|
});
|
||||||
|
final bool isTagsAndSubspaceModelDisabled;
|
||||||
|
final void Function() onEditChip;
|
||||||
|
final void Function() onTextButtonPressed;
|
||||||
|
final double screenWidth;
|
||||||
|
final List<Tag>? tags;
|
||||||
|
final List<SubspaceModel>? subspaces;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
(tags?.isNotEmpty == true ||
|
||||||
|
subspaces?.any(
|
||||||
|
(subspace) => subspace.tags?.isNotEmpty == true) ==
|
||||||
|
true)
|
||||||
|
? SizedBox(
|
||||||
|
width: screenWidth * 0.25,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.textFieldGreyColor,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.textFieldGreyColor,
|
||||||
|
width: 3.0, // Border width
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8.0,
|
||||||
|
runSpacing: 8.0,
|
||||||
|
children: [
|
||||||
|
// Combine tags from spaceModel and subspaces
|
||||||
|
...TagHelper.groupTags([
|
||||||
|
...?tags,
|
||||||
|
...?subspaces?.expand((subspace) => subspace.tags ?? [])
|
||||||
|
]).entries.map(
|
||||||
|
(entry) => Chip(
|
||||||
|
avatar: SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
entry.key.icon ?? 'assets/icons/gateway.svg',
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
label: Text(
|
||||||
|
'x${entry.value}', // Show count
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall
|
||||||
|
?.copyWith(color: ColorsManager.spaceColor),
|
||||||
|
),
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: ColorsManager.spaceColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
EditChip(onTap: onEditChip)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: TextButton(
|
||||||
|
onPressed: onTextButtonPressed,
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
child: ButtonContentWidget(
|
||||||
|
icon: Icons.add,
|
||||||
|
label: 'Add Devices',
|
||||||
|
disabled: isTagsAndSubspaceModelDisabled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
import '../../../../../utils/constants/assets.dart';
|
||||||
|
|
||||||
|
class IconChoosePartWidget extends StatelessWidget {
|
||||||
|
const IconChoosePartWidget({
|
||||||
|
super.key,
|
||||||
|
required this.selectedIcon,
|
||||||
|
required this.showIconSelection,
|
||||||
|
required this.screenWidth,
|
||||||
|
});
|
||||||
|
final double screenWidth;
|
||||||
|
final String selectedIcon;
|
||||||
|
final void Function() showIconSelection;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 50),
|
||||||
|
Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: screenWidth * 0.1,
|
||||||
|
height: screenWidth * 0.1,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: ColorsManager.boxColor,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SvgPicture.asset(
|
||||||
|
selectedIcon,
|
||||||
|
width: screenWidth * 0.04,
|
||||||
|
height: screenWidth * 0.04,
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 20,
|
||||||
|
right: 20,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: showIconSelection,
|
||||||
|
child: Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.iconEdit,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
import '../../../../../utils/constants/assets.dart';
|
||||||
|
import '../../../space_model/models/space_template_model.dart';
|
||||||
|
import '../../../space_model/widgets/button_content_widget.dart';
|
||||||
|
|
||||||
|
class SpaceModelLinkingWidget extends StatelessWidget {
|
||||||
|
const SpaceModelLinkingWidget({
|
||||||
|
super.key,
|
||||||
|
required this.onDeleted,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.screenWidth,
|
||||||
|
required this.selectedSpaceModel,
|
||||||
|
required this.isSpaceModelDisabled,
|
||||||
|
});
|
||||||
|
final bool isSpaceModelDisabled;
|
||||||
|
final void Function()? onDeleted;
|
||||||
|
final void Function()? onPressed;
|
||||||
|
final double screenWidth;
|
||||||
|
final SpaceTemplateModel? selectedSpaceModel;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
selectedSpaceModel == null
|
||||||
|
? TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: ButtonContentWidget(
|
||||||
|
svgAssets: Assets.link,
|
||||||
|
label: 'Link a space model',
|
||||||
|
disabled: isSpaceModelDisabled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
width: screenWidth * 0.25,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10.0, horizontal: 16.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.boxColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8.0,
|
||||||
|
runSpacing: 8.0,
|
||||||
|
children: [
|
||||||
|
Chip(
|
||||||
|
label: Text(
|
||||||
|
selectedSpaceModel?.modelName ?? '',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium!
|
||||||
|
.copyWith(color: ColorsManager.spaceColor),
|
||||||
|
),
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: ColorsManager.transparentColor,
|
||||||
|
width: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
deleteIcon: Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 16,
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onDeleted: onDeleted),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
|
||||||
|
class SpaceNameTextfieldWidget extends StatelessWidget {
|
||||||
|
SpaceNameTextfieldWidget({
|
||||||
|
super.key,
|
||||||
|
required this.isNameFieldExist,
|
||||||
|
required this.isNameFieldInvalid,
|
||||||
|
required this.onChange,
|
||||||
|
required this.screenWidth,
|
||||||
|
required this.nameController,
|
||||||
|
});
|
||||||
|
TextEditingController nameController;
|
||||||
|
final void Function(String value) onChange;
|
||||||
|
final double screenWidth;
|
||||||
|
bool isNameFieldExist;
|
||||||
|
bool isNameFieldInvalid;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: screenWidth * 0.25,
|
||||||
|
child: TextField(
|
||||||
|
controller: nameController,
|
||||||
|
onChanged: onChange,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Please enter the name',
|
||||||
|
hintStyle: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium!
|
||||||
|
.copyWith(color: ColorsManager.lightGrayColor),
|
||||||
|
filled: true,
|
||||||
|
fillColor: ColorsManager.boxColor,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: isNameFieldInvalid || isNameFieldExist
|
||||||
|
? ColorsManager.red
|
||||||
|
: ColorsManager.boxColor,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: ColorsManager.boxColor,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isNameFieldInvalid)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Text(
|
||||||
|
'*Space name should not be empty.',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall
|
||||||
|
?.copyWith(color: ColorsManager.red),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (isNameFieldExist)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: Text(
|
||||||
|
'*Name already exist',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall
|
||||||
|
?.copyWith(color: ColorsManager.red),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../../common/edit_chip.dart';
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
import '../../../space_model/widgets/button_content_widget.dart';
|
||||||
|
import '../../../space_model/widgets/subspace_name_label_widget.dart';
|
||||||
|
import '../../model/subspace_model.dart';
|
||||||
|
|
||||||
|
class SubSpacePartWidget extends StatefulWidget {
|
||||||
|
SubSpacePartWidget({
|
||||||
|
super.key,
|
||||||
|
required this.subspaces,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.isTagsAndSubspaceModelDisabled,
|
||||||
|
required this.screenWidth,
|
||||||
|
required this.editChipOnTap,
|
||||||
|
});
|
||||||
|
double screenWidth;
|
||||||
|
bool isTagsAndSubspaceModelDisabled;
|
||||||
|
final void Function() editChipOnTap;
|
||||||
|
List<SubspaceModel>? subspaces;
|
||||||
|
final void Function() onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SubSpacePartWidget> createState() => _SubSpacePartWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SubSpacePartWidgetState extends State<SubSpacePartWidget> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
widget.subspaces == null || widget.subspaces!.isEmpty
|
||||||
|
? TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
overlayColor: ColorsManager.transparentColor,
|
||||||
|
),
|
||||||
|
onPressed: widget.onPressed,
|
||||||
|
child: ButtonContentWidget(
|
||||||
|
icon: Icons.add,
|
||||||
|
label: 'Create Sub Spaces',
|
||||||
|
disabled: widget.isTagsAndSubspaceModelDisabled,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SizedBox(
|
||||||
|
width: widget.screenWidth * 0.25,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.textFieldGreyColor,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.textFieldGreyColor,
|
||||||
|
width: 3.0, // Border width
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8.0,
|
||||||
|
runSpacing: 8.0,
|
||||||
|
children: [
|
||||||
|
if (widget.subspaces != null)
|
||||||
|
...widget.subspaces!.map((subspace) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SubspaceNameDisplayWidget(
|
||||||
|
text: subspace.subspaceName,
|
||||||
|
validateName: (updatedName) {
|
||||||
|
bool nameExists = widget.subspaces!.any((s) {
|
||||||
|
bool isSameId =
|
||||||
|
s.internalId == subspace.internalId;
|
||||||
|
bool isSameName =
|
||||||
|
s.subspaceName.trim().toLowerCase() ==
|
||||||
|
updatedName.trim().toLowerCase();
|
||||||
|
|
||||||
|
return !isSameId && isSameName;
|
||||||
|
});
|
||||||
|
|
||||||
|
return !nameExists;
|
||||||
|
},
|
||||||
|
onNameChanged: (updatedName) {
|
||||||
|
setState(() {
|
||||||
|
subspace.subspaceName = updatedName;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
EditChip(
|
||||||
|
onTap: widget.editChipOnTap,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -30,27 +30,12 @@ class CurvedLinePainter extends CustomPainter {
|
|||||||
Offset end = connection.endSpace.position +
|
Offset end = connection.endSpace.position +
|
||||||
const Offset(75, 0); // Center top of end space
|
const Offset(75, 0); // Center top of end space
|
||||||
|
|
||||||
if (connection.direction == 'down') {
|
|
||||||
// Curved line for down connections
|
// Curved line for down connections
|
||||||
final controlPoint = Offset((start.dx + end.dx) / 2, start.dy + 50);
|
final controlPoint = Offset((start.dx + end.dx) / 2, start.dy + 50);
|
||||||
final path = Path()
|
final path = Path()
|
||||||
..moveTo(start.dx, start.dy)
|
..moveTo(start.dx, start.dy)
|
||||||
..quadraticBezierTo(controlPoint.dx, controlPoint.dy, end.dx, end.dy);
|
..quadraticBezierTo(controlPoint.dx, controlPoint.dy, end.dx, end.dy);
|
||||||
canvas.drawPath(path, paint);
|
canvas.drawPath(path, paint);
|
||||||
} else if (connection.direction == 'right') {
|
|
||||||
start = connection.startSpace.position +
|
|
||||||
const Offset(150, 30); // Right center
|
|
||||||
end = connection.endSpace.position + const Offset(0, 30); // Left center
|
|
||||||
|
|
||||||
canvas.drawLine(start, end, paint);
|
|
||||||
} else if (connection.direction == 'left') {
|
|
||||||
start =
|
|
||||||
connection.startSpace.position + const Offset(0, 30); // Left center
|
|
||||||
end = connection.endSpace.position +
|
|
||||||
const Offset(150, 30); // Right center
|
|
||||||
|
|
||||||
canvas.drawLine(start, end, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
final dotPaint = Paint()..color = ColorsManager.blackColor;
|
final dotPaint = Paint()..color = ColorsManager.blackColor;
|
||||||
canvas.drawCircle(start, 5, dotPaint); // Start dot
|
canvas.drawCircle(start, 5, dotPaint); // Start dot
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:syncrow_web/common/edit_chip.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/views/add_device_type_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/add_device_type/views/add_device_type_widget.dart';
|
||||||
@ -9,6 +7,11 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_pr
|
|||||||
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/subspace_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/devices_part_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/icon_choose_part_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_model_linking_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_name_textfield_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/sub_space_part_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/dialogs/icon_selection_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/dialogs/icon_selection_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart';
|
||||||
@ -16,8 +19,6 @@ import 'package:syncrow_web/pages/spaces_management/helper/space_helper.dart';
|
|||||||
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/view/link_space_model_dialog.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/widgets/button_content_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/constants/space_icon_const.dart';
|
import 'package:syncrow_web/utils/constants/space_icon_const.dart';
|
||||||
@ -82,8 +83,10 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
selectedIcon = widget.icon ?? Assets.location;
|
selectedIcon = widget.icon ?? Assets.location;
|
||||||
nameController = TextEditingController(text: widget.name ?? '');
|
nameController = TextEditingController(text: widget.name ?? '');
|
||||||
selectedProducts = widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
|
selectedProducts =
|
||||||
isOkButtonEnabled = enteredName.isNotEmpty || nameController.text.isNotEmpty;
|
widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
|
||||||
|
isOkButtonEnabled =
|
||||||
|
enteredName.isNotEmpty || nameController.text.isNotEmpty;
|
||||||
if (widget.currentSpaceModel != null) {
|
if (widget.currentSpaceModel != null) {
|
||||||
subspaces = [];
|
subspaces = [];
|
||||||
tags = [];
|
tags = [];
|
||||||
@ -96,13 +99,15 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool isSpaceModelDisabled =
|
bool isSpaceModelDisabled = (tags != null && tags!.isNotEmpty ||
|
||||||
(tags != null && tags!.isNotEmpty || subspaces != null && subspaces!.isNotEmpty);
|
subspaces != null && subspaces!.isNotEmpty);
|
||||||
bool isTagsAndSubspaceModelDisabled = (selectedSpaceModel != null);
|
bool isTagsAndSubspaceModelDisabled = (selectedSpaceModel != null);
|
||||||
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: widget.isEdit ? const Text('Edit Space') : const Text('Create New Space'),
|
title: widget.isEdit
|
||||||
|
? const Text('Edit Space')
|
||||||
|
: const Text('Create New Space'),
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: screenWidth * 0.5,
|
width: screenWidth * 0.5,
|
||||||
@ -112,50 +117,10 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Column(
|
child: IconChoosePartWidget(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
selectedIcon: selectedIcon,
|
||||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
showIconSelection: _showIconSelectionDialog,
|
||||||
children: [
|
screenWidth: screenWidth,
|
||||||
const SizedBox(height: 50),
|
|
||||||
Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: screenWidth * 0.1,
|
|
||||||
height: screenWidth * 0.1,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SvgPicture.asset(
|
|
||||||
selectedIcon,
|
|
||||||
width: screenWidth * 0.04,
|
|
||||||
height: screenWidth * 0.04,
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
top: 20,
|
|
||||||
right: 20,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: _showIconSelectionDialog,
|
|
||||||
child: Container(
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.iconEdit,
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
@ -164,11 +129,12 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SpaceNameTextfieldWidget(
|
||||||
width: screenWidth * 0.25,
|
isNameFieldExist: isNameFieldExist,
|
||||||
child: TextField(
|
isNameFieldInvalid: isNameFieldInvalid,
|
||||||
controller: nameController,
|
nameController: nameController,
|
||||||
onChanged: (value) {
|
screenWidth: screenWidth,
|
||||||
|
onChange: (value) {
|
||||||
enteredName = value.trim();
|
enteredName = value.trim();
|
||||||
setState(() {
|
setState(() {
|
||||||
isNameFieldExist = false;
|
isNameFieldExist = false;
|
||||||
@ -187,273 +153,88 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Please enter the name',
|
|
||||||
hintStyle: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyMedium!
|
|
||||||
.copyWith(color: ColorsManager.lightGrayColor),
|
|
||||||
filled: true,
|
|
||||||
fillColor: ColorsManager.boxColor,
|
|
||||||
enabledBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
borderSide: BorderSide(
|
|
||||||
color: isNameFieldInvalid || isNameFieldExist
|
|
||||||
? ColorsManager.red
|
|
||||||
: ColorsManager.boxColor,
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
borderSide: const BorderSide(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (isNameFieldInvalid)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Text(
|
|
||||||
'*Space name should not be empty.',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall
|
|
||||||
?.copyWith(color: ColorsManager.red),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (isNameFieldExist)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
|
||||||
child: Text(
|
|
||||||
'*Name already exist',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall
|
|
||||||
?.copyWith(color: ColorsManager.red),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
selectedSpaceModel == null
|
// SpaceModelLinkingWidget(
|
||||||
? TextButton(
|
// isSpaceModelDisabled: true,
|
||||||
style: TextButton.styleFrom(
|
// // isSpaceModelDisabled,
|
||||||
padding: EdgeInsets.zero,
|
// onPressed: () {
|
||||||
),
|
// isSpaceModelDisabled
|
||||||
|
// ? null
|
||||||
|
// : _showLinkSpaceModelDialog(context);
|
||||||
|
// },
|
||||||
|
// onDeleted: () => setState(() {
|
||||||
|
// selectedSpaceModel = null;
|
||||||
|
// subspaces = widget.subspaces ?? [];
|
||||||
|
// tags = widget.tags ?? [];
|
||||||
|
// }),
|
||||||
|
// screenWidth: screenWidth,
|
||||||
|
// selectedSpaceModel: selectedSpaceModel,
|
||||||
|
// ),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
// Row(
|
||||||
|
// children: [
|
||||||
|
// const Expanded(
|
||||||
|
// child: Divider(
|
||||||
|
// color: ColorsManager.neutralGray,
|
||||||
|
// thickness: 1.0,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
|
// child: Text(
|
||||||
|
// 'OR',
|
||||||
|
// style: Theme.of(context)
|
||||||
|
// .textTheme
|
||||||
|
// .bodyMedium
|
||||||
|
// ?.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// const Expanded(
|
||||||
|
// child: Divider(
|
||||||
|
// color: ColorsManager.neutralGray,
|
||||||
|
// thickness: 1.0,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
SubSpacePartWidget(
|
||||||
|
subspaces: subspaces,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
isSpaceModelDisabled ? null : _showLinkSpaceModelDialog(context);
|
|
||||||
},
|
|
||||||
child: ButtonContentWidget(
|
|
||||||
svgAssets: Assets.link,
|
|
||||||
label: 'Link a space model',
|
|
||||||
disabled: isSpaceModelDisabled,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Container(
|
|
||||||
width: screenWidth * 0.25,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8.0,
|
|
||||||
runSpacing: 8.0,
|
|
||||||
children: [
|
|
||||||
Chip(
|
|
||||||
label: Text(
|
|
||||||
selectedSpaceModel?.modelName ?? '',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyMedium!
|
|
||||||
.copyWith(color: ColorsManager.spaceColor),
|
|
||||||
),
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
side: const BorderSide(
|
|
||||||
color: ColorsManager.transparentColor,
|
|
||||||
width: 0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
deleteIcon: Container(
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Icon(
|
|
||||||
Icons.close,
|
|
||||||
size: 16,
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onDeleted: () => setState(() {
|
|
||||||
this.selectedSpaceModel = null;
|
|
||||||
subspaces = widget.subspaces ?? [];
|
|
||||||
tags = widget.tags ?? [];
|
|
||||||
})),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 25),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Expanded(
|
|
||||||
child: Divider(
|
|
||||||
color: ColorsManager.neutralGray,
|
|
||||||
thickness: 1.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
|
||||||
child: Text(
|
|
||||||
'OR',
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyMedium
|
|
||||||
?.copyWith(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Expanded(
|
|
||||||
child: Divider(
|
|
||||||
color: ColorsManager.neutralGray,
|
|
||||||
thickness: 1.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 25),
|
|
||||||
subspaces == null || subspaces!.isEmpty
|
|
||||||
? TextButton(
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
overlayColor: ColorsManager.transparentColor,
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
isTagsAndSubspaceModelDisabled
|
isTagsAndSubspaceModelDisabled
|
||||||
? null
|
? null
|
||||||
: _showSubSpaceDialog(
|
: _showSubSpaceDialog(
|
||||||
context, enteredName, [], false, widget.products, subspaces);
|
context,
|
||||||
},
|
enteredName,
|
||||||
child: ButtonContentWidget(
|
[],
|
||||||
icon: Icons.add,
|
false,
|
||||||
label: 'Create Sub Space',
|
widget.products,
|
||||||
disabled: isTagsAndSubspaceModelDisabled,
|
subspaces,
|
||||||
),
|
);
|
||||||
)
|
},
|
||||||
: SizedBox(
|
isTagsAndSubspaceModelDisabled:
|
||||||
width: screenWidth * 0.25,
|
isTagsAndSubspaceModelDisabled,
|
||||||
child: Container(
|
screenWidth: screenWidth,
|
||||||
padding: const EdgeInsets.all(8.0),
|
editChipOnTap: () async {
|
||||||
decoration: BoxDecoration(
|
_showSubSpaceDialog(
|
||||||
color: ColorsManager.textFieldGreyColor,
|
context,
|
||||||
borderRadius: BorderRadius.circular(15),
|
enteredName,
|
||||||
border: Border.all(
|
[],
|
||||||
color: ColorsManager.textFieldGreyColor,
|
true,
|
||||||
width: 3.0, // Border width
|
widget.products,
|
||||||
),
|
subspaces,
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8.0,
|
|
||||||
runSpacing: 8.0,
|
|
||||||
children: [
|
|
||||||
if (subspaces != null)
|
|
||||||
...subspaces!.map((subspace) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SubspaceNameDisplayWidget(
|
|
||||||
text: subspace.subspaceName,
|
|
||||||
validateName: (updatedName) {
|
|
||||||
bool nameExists = subspaces!.any((s) {
|
|
||||||
bool isSameId = s.internalId == subspace.internalId;
|
|
||||||
bool isSameName =
|
|
||||||
s.subspaceName.trim().toLowerCase() ==
|
|
||||||
updatedName.trim().toLowerCase();
|
|
||||||
|
|
||||||
return !isSameId && isSameName;
|
|
||||||
});
|
|
||||||
|
|
||||||
return !nameExists;
|
|
||||||
},
|
|
||||||
onNameChanged: (updatedName) {
|
|
||||||
setState(() {
|
|
||||||
subspace.subspaceName = updatedName;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}),
|
|
||||||
EditChip(
|
|
||||||
onTap: () async {
|
|
||||||
_showSubSpaceDialog(context, enteredName, [], true,
|
|
||||||
widget.products, subspaces);
|
|
||||||
},
|
},
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
(tags?.isNotEmpty == true ||
|
DevicesPartWidget(
|
||||||
subspaces?.any((subspace) => subspace.tags?.isNotEmpty == true) == true)
|
tags: tags,
|
||||||
? SizedBox(
|
subspaces: subspaces,
|
||||||
width: screenWidth * 0.25,
|
screenWidth: screenWidth,
|
||||||
child: Container(
|
isTagsAndSubspaceModelDisabled:
|
||||||
padding: const EdgeInsets.all(8.0),
|
isTagsAndSubspaceModelDisabled,
|
||||||
decoration: BoxDecoration(
|
onEditChip: () async {
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.textFieldGreyColor,
|
|
||||||
width: 3.0, // Border width
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8.0,
|
|
||||||
runSpacing: 8.0,
|
|
||||||
children: [
|
|
||||||
// Combine tags from spaceModel and subspaces
|
|
||||||
...TagHelper.groupTags([
|
|
||||||
...?tags,
|
|
||||||
...?subspaces?.expand((subspace) => subspace.tags ?? [])
|
|
||||||
]).entries.map(
|
|
||||||
(entry) => Chip(
|
|
||||||
avatar: SizedBox(
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
entry.key.icon ?? 'assets/icons/gateway.svg',
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
label: Text(
|
|
||||||
'x${entry.value}', // Show count
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall
|
|
||||||
?.copyWith(color: ColorsManager.spaceColor),
|
|
||||||
),
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(16),
|
|
||||||
side: const BorderSide(
|
|
||||||
color: ColorsManager.spaceColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
EditChip(onTap: () async {
|
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AssignTagDialog(
|
builder: (context) => AssignTagDialog(
|
||||||
@ -476,13 +257,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
})
|
},
|
||||||
],
|
onTextButtonPressed: () {
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
isTagsAndSubspaceModelDisabled
|
isTagsAndSubspaceModelDisabled
|
||||||
? null
|
? null
|
||||||
: _showTagCreateDialog(
|
: _showTagCreateDialog(
|
||||||
@ -492,14 +268,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
widget.products,
|
widget.products,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
)
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
),
|
|
||||||
child: ButtonContentWidget(
|
|
||||||
icon: Icons.add,
|
|
||||||
label: 'Add Devices',
|
|
||||||
disabled: isTagsAndSubspaceModelDisabled,
|
|
||||||
))
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -529,17 +298,32 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
} else if (isNameFieldExist) {
|
} else if (isNameFieldExist) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
String newName = enteredName.isNotEmpty ? enteredName : (widget.name ?? '');
|
String newName = enteredName.isNotEmpty
|
||||||
|
? enteredName
|
||||||
|
: (widget.name ?? '');
|
||||||
if (newName.isNotEmpty) {
|
if (newName.isNotEmpty) {
|
||||||
widget.onCreateSpace(newName, selectedIcon, selectedProducts,
|
if (tags != null && tags!.isNotEmpty) {
|
||||||
selectedSpaceModel, subspaces, tags);
|
if (tags!.any(
|
||||||
|
(tag) => tag.uuid == null || tag.uuid!.isEmpty,
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
widget.onCreateSpace(
|
||||||
|
newName,
|
||||||
|
selectedIcon,
|
||||||
|
selectedProducts,
|
||||||
|
selectedSpaceModel,
|
||||||
|
subspaces,
|
||||||
|
tags);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
backgroundColor:
|
backgroundColor: isOkButtonEnabled
|
||||||
isOkButtonEnabled ? ColorsManager.secondaryColor : ColorsManager.grayColor,
|
? ColorsManager.secondaryColor
|
||||||
|
: ColorsManager.grayColor,
|
||||||
foregroundColor: ColorsManager.whiteColors,
|
foregroundColor: ColorsManager.whiteColors,
|
||||||
child: const Text('OK'),
|
child: const Text('OK'),
|
||||||
),
|
),
|
||||||
@ -550,6 +334,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//dialooogggs
|
||||||
void _showIconSelectionDialog() {
|
void _showIconSelectionDialog() {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -586,26 +371,50 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showSubSpaceDialog(BuildContext context, String name, final List<Tag>? spaceTags,
|
void _showSubSpaceDialog(
|
||||||
bool isEdit, List<ProductModel>? products, final List<SubspaceModel>? existingSubSpaces) {
|
BuildContext context,
|
||||||
|
String name,
|
||||||
|
final List<Tag>? spaceTags,
|
||||||
|
bool isEdit,
|
||||||
|
List<ProductModel>? products,
|
||||||
|
final List<SubspaceModel>? existingSubSpaces,
|
||||||
|
) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return CreateSubSpaceDialog(
|
return CreateSubSpaceDialog(
|
||||||
spaceName: name,
|
spaceName: name,
|
||||||
dialogTitle: isEdit ? 'Edit Sub-space' : 'Create Sub-space',
|
dialogTitle: isEdit ? 'Edit Sub-spaces' : 'Create Sub-spaces',
|
||||||
products: products,
|
products: products,
|
||||||
existingSubSpaces: existingSubSpaces,
|
existingSubSpaces: existingSubSpaces,
|
||||||
onSave: (slectedSubspaces) {
|
onSave: (slectedSubspaces, updatedSubSpaces) {
|
||||||
final List<Tag> tagsToAppendToSpace = [];
|
final List<Tag> tagsToAppendToSpace = [];
|
||||||
|
|
||||||
if (slectedSubspaces != null) {
|
if (slectedSubspaces != null && slectedSubspaces.isNotEmpty) {
|
||||||
final updatedIds = slectedSubspaces.map((s) => s.internalId).toSet();
|
final updatedIds =
|
||||||
|
slectedSubspaces.map((s) => s.internalId).toSet();
|
||||||
if (existingSubSpaces != null) {
|
if (existingSubSpaces != null) {
|
||||||
final deletedSubspaces =
|
final deletedSubspaces = existingSubSpaces
|
||||||
existingSubSpaces.where((s) => !updatedIds.contains(s.internalId)).toList();
|
.where((s) => !updatedIds.contains(s.internalId))
|
||||||
|
.toList();
|
||||||
for (var s in deletedSubspaces) {
|
for (var s in deletedSubspaces) {
|
||||||
if (s.tags != null) {
|
if (s.tags != null) {
|
||||||
|
s.tags!.forEach(
|
||||||
|
(tag) => tag.location = null,
|
||||||
|
);
|
||||||
|
tagsToAppendToSpace.addAll(s.tags!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (existingSubSpaces != null) {
|
||||||
|
final deletedSubspaces = existingSubSpaces;
|
||||||
|
|
||||||
|
for (var s in deletedSubspaces) {
|
||||||
|
if (s.tags != null) {
|
||||||
|
s.tags!.forEach(
|
||||||
|
(tag) => tag.location = null,
|
||||||
|
);
|
||||||
tagsToAppendToSpace.addAll(s.tags!);
|
tagsToAppendToSpace.addAll(s.tags!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,15 +432,16 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showTagCreateDialog(
|
void _showTagCreateDialog(BuildContext context, String name, bool isEdit,
|
||||||
BuildContext context, String name, bool isEdit, List<ProductModel>? products) {
|
List<ProductModel>? products) {
|
||||||
isEdit
|
isEdit
|
||||||
? showDialog(
|
? showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AssignTagDialog(
|
return AssignTagDialog(
|
||||||
title: 'Edit Device',
|
title: 'Edit Device',
|
||||||
addedProducts: TagHelper.createInitialSelectedProductsForTags(tags, subspaces),
|
addedProducts: TagHelper.createInitialSelectedProductsForTags(
|
||||||
|
tags, subspaces),
|
||||||
spaceName: name,
|
spaceName: name,
|
||||||
products: products,
|
products: products,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
@ -646,7 +456,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
if (subspaces != null) {
|
if (subspaces != null) {
|
||||||
for (final subspace in subspaces!) {
|
for (final subspace in subspaces!) {
|
||||||
for (final selectedSubspace in selectedSubspaces) {
|
for (final selectedSubspace in selectedSubspaces) {
|
||||||
if (subspace.subspaceName == selectedSubspace.subspaceName) {
|
if (subspace.subspaceName ==
|
||||||
|
selectedSubspace.subspaceName) {
|
||||||
subspace.tags = selectedSubspace.tags;
|
subspace.tags = selectedSubspace.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,7 +481,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
allTags: widget.allTags,
|
allTags: widget.allTags,
|
||||||
projectTags: widget.projectTags,
|
projectTags: widget.projectTags,
|
||||||
initialSelectedProducts:
|
initialSelectedProducts:
|
||||||
TagHelper.createInitialSelectedProductsForTags(tags, subspaces),
|
TagHelper.createInitialSelectedProductsForTags(
|
||||||
|
tags, subspaces),
|
||||||
onSave: (selectedSpaceTags, selectedSubspaces) {
|
onSave: (selectedSpaceTags, selectedSubspaces) {
|
||||||
setState(() {
|
setState(() {
|
||||||
tags = selectedSpaceTags;
|
tags = selectedSpaceTags;
|
||||||
@ -680,7 +492,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
if (subspaces != null) {
|
if (subspaces != null) {
|
||||||
for (final subspace in subspaces!) {
|
for (final subspace in subspaces!) {
|
||||||
for (final selectedSubspace in selectedSubspaces) {
|
for (final selectedSubspace in selectedSubspaces) {
|
||||||
if (subspace.subspaceName == selectedSubspace.subspaceName) {
|
if (subspace.subspaceName ==
|
||||||
|
selectedSubspace.subspaceName) {
|
||||||
subspace.tags = selectedSubspace.tags;
|
subspace.tags = selectedSubspace.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ class PlusButtonWidget extends StatelessWidget {
|
|||||||
final int index;
|
final int index;
|
||||||
final String direction;
|
final String direction;
|
||||||
final Offset offset;
|
final Offset offset;
|
||||||
final Function(int index, Offset newPosition, String direction) onButtonTap;
|
final Function(int index, Offset newPosition) onButtonTap;
|
||||||
|
|
||||||
const PlusButtonWidget({
|
const PlusButtonWidget({
|
||||||
super.key,
|
super.key,
|
||||||
@ -17,26 +17,9 @@ class PlusButtonWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Positioned(
|
return GestureDetector(
|
||||||
left: offset.dx,
|
|
||||||
top: offset.dy,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Offset newPosition;
|
onButtonTap(index, const Offset(0, 150));
|
||||||
switch (direction) {
|
|
||||||
case 'left':
|
|
||||||
newPosition = const Offset(-200, 0);
|
|
||||||
break;
|
|
||||||
case 'right':
|
|
||||||
newPosition = const Offset(200, 0);
|
|
||||||
break;
|
|
||||||
case 'down':
|
|
||||||
newPosition = const Offset(0, 150);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
newPosition = Offset.zero;
|
|
||||||
}
|
|
||||||
onButtonTap(index, newPosition, direction);
|
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 30,
|
width: 30,
|
||||||
@ -45,7 +28,10 @@ class PlusButtonWidget extends StatelessWidget {
|
|||||||
color: ColorsManager.spaceColor,
|
color: ColorsManager.spaceColor,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: const Icon(Icons.add, color: ColorsManager.whiteColors, size: 20),
|
child: const Icon(
|
||||||
|
Icons.add,
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
size: 20,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -7,7 +7,7 @@ class SpaceCardWidget extends StatelessWidget {
|
|||||||
final Offset position;
|
final Offset position;
|
||||||
final bool isHovered;
|
final bool isHovered;
|
||||||
final Function(int index, bool isHovered) onHoverChanged;
|
final Function(int index, bool isHovered) onHoverChanged;
|
||||||
final Function(int index, Offset newPosition, String direction) onButtonTap;
|
final Function(int index, Offset newPosition) onButtonTap;
|
||||||
final Widget Function(int index) buildSpaceContainer;
|
final Widget Function(int index) buildSpaceContainer;
|
||||||
final ValueChanged<Offset> onPositionChanged;
|
final ValueChanged<Offset> onPositionChanged;
|
||||||
|
|
||||||
@ -25,35 +25,34 @@ class SpaceCardWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return MouseRegion(
|
||||||
behavior: HitTestBehavior.opaque,
|
onEnter: (_) => onHoverChanged(index, true),
|
||||||
onPanUpdate: (details) {
|
onExit: (_) => onHoverChanged(index, false),
|
||||||
// Call the provided callback to update the position
|
child: SizedBox(
|
||||||
final newPosition = position + details.delta;
|
width: 140, // Make sure this covers both card and plus button
|
||||||
onPositionChanged(newPosition);
|
height: 90,
|
||||||
},
|
|
||||||
child: MouseRegion(
|
|
||||||
onEnter: (_) {
|
|
||||||
// Call the provided callback to handle hover state
|
|
||||||
onHoverChanged(index, true);
|
|
||||||
},
|
|
||||||
onExit: (_) {
|
|
||||||
// Call the provided callback to handle hover state
|
|
||||||
onHoverChanged(index, false);
|
|
||||||
},
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip
|
clipBehavior: Clip.none,
|
||||||
.none, // Allow hovering elements to be displayed outside the boundary
|
|
||||||
children: [
|
children: [
|
||||||
buildSpaceContainer(index), // Build the space container
|
// Main card
|
||||||
if (isHovered) ...[
|
Container(
|
||||||
PlusButtonWidget(
|
width: 140,
|
||||||
|
height: 80,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: buildSpaceContainer(index),
|
||||||
|
),
|
||||||
|
// Plus button (NO inner Positioned!)
|
||||||
|
if (isHovered)
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: PlusButtonWidget(
|
||||||
index: index,
|
index: index,
|
||||||
direction: 'down',
|
direction: 'down',
|
||||||
offset: const Offset(63, 50),
|
offset: Offset.zero,
|
||||||
onButtonTap: onButtonTap,
|
onButtonTap: onButtonTap,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -13,7 +13,8 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
final existingTagCounts = <String, int>{};
|
final existingTagCounts = <String, int>{};
|
||||||
for (var tag in initialTags) {
|
for (var tag in initialTags) {
|
||||||
if (tag.product != null) {
|
if (tag.product != null) {
|
||||||
existingTagCounts[tag.product!.uuid] = (existingTagCounts[tag.product!.uuid] ?? 0) + 1;
|
existingTagCounts[tag.product!.uuid] =
|
||||||
|
(existingTagCounts[tag.product!.uuid] ?? 0) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,14 +23,17 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
for (var selectedProduct in event.addedProducts) {
|
for (var selectedProduct in event.addedProducts) {
|
||||||
final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;
|
final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;
|
||||||
|
|
||||||
if (selectedProduct.count == 0 || selectedProduct.count <= existingCount) {
|
if (selectedProduct.count == 0 ||
|
||||||
tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
selectedProduct.count <= existingCount) {
|
||||||
|
tags.addAll(initialTags
|
||||||
|
.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final missingCount = selectedProduct.count - existingCount;
|
final missingCount = selectedProduct.count - existingCount;
|
||||||
|
|
||||||
tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
tags.addAll(initialTags
|
||||||
|
.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
||||||
|
|
||||||
if (missingCount > 0) {
|
if (missingCount > 0) {
|
||||||
tags.addAll(List.generate(
|
tags.addAll(List.generate(
|
||||||
@ -85,7 +89,8 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
final tags = List<Tag>.from(currentState.tags);
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
|
|
||||||
// Update the location
|
// Update the location
|
||||||
tags[event.index] = tags[event.index].copyWith(location: event.location);
|
tags[event.index] =
|
||||||
|
tags[event.index].copyWith(location: event.location);
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
@ -117,7 +122,8 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
final tags = List<Tag>.from(currentState.tags)..remove(event.tagToDelete);
|
final tags = List<Tag>.from(currentState.tags)
|
||||||
|
..remove(event.tagToDelete);
|
||||||
|
|
||||||
// Recalculate available tags
|
// Recalculate available tags
|
||||||
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
@ -141,8 +147,10 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
|
|
||||||
// Get validation error for duplicate tags
|
// Get validation error for duplicate tags
|
||||||
String? _getValidationError(List<Tag> tags) {
|
String? _getValidationError(List<Tag> tags) {
|
||||||
final nonEmptyTags =
|
final nonEmptyTags = tags
|
||||||
tags.map((tag) => tag.tag?.trim() ?? '').where((tag) => tag.isNotEmpty).toList();
|
.map((tag) => tag.tag?.trim() ?? '')
|
||||||
|
.where((tag) => tag.isNotEmpty)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final duplicateTags = nonEmptyTags
|
final duplicateTags = nonEmptyTags
|
||||||
.fold<Map<String, int>>({}, (map, tag) {
|
.fold<Map<String, int>>({}, (map, tag) {
|
||||||
@ -168,9 +176,11 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
.toSet();
|
.toSet();
|
||||||
|
|
||||||
final availableTags = allTags
|
final availableTags = allTags
|
||||||
.where((tag) => tag.tag != null && !selectedTagSet.contains(tag.tag!.trim()))
|
.where((tag) =>
|
||||||
|
tag.tag != null && !selectedTagSet.contains(tag.tag!.trim()))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return availableTags;
|
return projectTags;
|
||||||
|
// availableTags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
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/common/dialog_dropdown.dart';
|
|
||||||
import 'package:syncrow_web/common/tag_dialog_textfield_dropdown.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/views/add_device_type_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||||
@ -12,9 +7,10 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
|||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/widgets/assign_tags_tables_widget.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
import 'widgets/save_add_device_row_widget.dart';
|
||||||
|
|
||||||
class AssignTagDialog extends StatelessWidget {
|
class AssignTagDialog extends StatelessWidget {
|
||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
@ -29,7 +25,7 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
final List<Tag> projectTags;
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const AssignTagDialog(
|
const AssignTagDialog(
|
||||||
{Key? key,
|
{super.key,
|
||||||
required this.products,
|
required this.products,
|
||||||
required this.subspaces,
|
required this.subspaces,
|
||||||
required this.addedProducts,
|
required this.addedProducts,
|
||||||
@ -39,13 +35,14 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
required this.spaceName,
|
required this.spaceName,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.onSave,
|
this.onSave,
|
||||||
required this.projectTags})
|
required this.projectTags});
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<String> locations =
|
final List<String> locations = (subspaces ?? [])
|
||||||
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space');
|
.map((subspace) => subspace.subspaceName)
|
||||||
|
.toList()
|
||||||
|
..add('Main Space');
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => AssignTagBloc(projectTags)
|
create: (_) => AssignTagBloc(projectTags)
|
||||||
@ -67,131 +64,31 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
AssignTagsTable(
|
||||||
borderRadius: BorderRadius.circular(20),
|
controllers: controllers,
|
||||||
child: DataTable(
|
locations: locations,
|
||||||
headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey),
|
tags: state.tags,
|
||||||
key: ValueKey(state.tags.length),
|
updatedTags: state.updatedTags,
|
||||||
border: TableBorder.all(
|
onDeleteDevice: ({required index, required tag}) {
|
||||||
color: ColorsManager.dataHeaderGrey,
|
context
|
||||||
width: 1,
|
.read<AssignTagBloc>()
|
||||||
borderRadius: BorderRadius.circular(20),
|
.add(DeleteTag(tagToDelete: tag, tags: state.tags));
|
||||||
),
|
|
||||||
columns: [
|
|
||||||
DataColumn(
|
|
||||||
label: Text('#', style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
|
||||||
label: Text('Device', style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
|
||||||
numeric: false,
|
|
||||||
label: Text('Tag', style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
|
||||||
label:
|
|
||||||
Text('Location', style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
],
|
|
||||||
rows: state.tags.isEmpty
|
|
||||||
? [
|
|
||||||
DataRow(cells: [
|
|
||||||
DataCell(
|
|
||||||
Center(
|
|
||||||
child: Text('No Data Available',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const DataCell(SizedBox()),
|
|
||||||
const DataCell(SizedBox()),
|
|
||||||
const DataCell(SizedBox()),
|
|
||||||
])
|
|
||||||
]
|
|
||||||
: List.generate(state.tags.length, (index) {
|
|
||||||
final tag = state.tags[index];
|
|
||||||
final controller = controllers[index];
|
|
||||||
|
|
||||||
return DataRow(
|
|
||||||
cells: [
|
|
||||||
DataCell(Text((index + 1).toString())),
|
|
||||||
DataCell(
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
tag.product?.name ?? 'Unknown',
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
)),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Container(
|
|
||||||
width: 20.0,
|
|
||||||
height: 20.0,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
width: 1.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: IconButton(
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.close,
|
|
||||||
color: ColorsManager.lightGreyColor,
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
context.read<AssignTagBloc>().add(
|
|
||||||
DeleteTag(tagToDelete: tag, tags: state.tags));
|
|
||||||
|
|
||||||
controllers.removeAt(index);
|
controllers.removeAt(index);
|
||||||
},
|
},
|
||||||
tooltip: 'Delete Tag',
|
onTagDropDownSelected: ({required index, required tag}) {
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: const BoxConstraints(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DataCell(
|
|
||||||
Container(
|
|
||||||
alignment:
|
|
||||||
Alignment.centerLeft, // Align cell content to the left
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: TagDialogTextfieldDropdown(
|
|
||||||
key: ValueKey('dropdown_${const Uuid().v4()}_$index'),
|
|
||||||
items: state.updatedTags,
|
|
||||||
product: tag.product?.uuid ?? 'Unknown',
|
|
||||||
initialValue: tag,
|
|
||||||
onSelected: (value) {
|
|
||||||
controller.text = value.tag ?? '';
|
|
||||||
context.read<AssignTagBloc>().add(UpdateTagEvent(
|
context.read<AssignTagBloc>().add(UpdateTagEvent(
|
||||||
index: index,
|
index: index,
|
||||||
tag: value,
|
tag: tag,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
onLocationDropDownSelected: (
|
||||||
),
|
{required index, required location}) {
|
||||||
),
|
|
||||||
),
|
|
||||||
DataCell(
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: DialogDropdown(
|
|
||||||
items: locations,
|
|
||||||
selectedValue: tag.location ?? 'Main Space',
|
|
||||||
onSelected: (value) {
|
|
||||||
context.read<AssignTagBloc>().add(UpdateLocation(
|
context.read<AssignTagBloc>().add(UpdateLocation(
|
||||||
index: index,
|
index: index,
|
||||||
location: value,
|
location: location,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (state.errorMessage != null)
|
if (state.errorMessage != null)
|
||||||
Text(state.errorMessage!,
|
Text(state.errorMessage!,
|
||||||
@ -203,69 +100,15 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
Row(
|
SaveAddDeviceRowWidget(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
subspaces: subspaces,
|
||||||
children: [
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Builder(
|
|
||||||
builder: (buttonContext) => CancelButton(
|
|
||||||
label: 'Add New Device',
|
|
||||||
onPressed: () async {
|
|
||||||
final updatedTags = List<Tag>.from(state.tags);
|
|
||||||
final result = TagHelper.processTags(updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags = result['updatedTags'] as List<Tag>;
|
|
||||||
final processedSubspaces =
|
|
||||||
List<SubspaceModel>.from(result['subspaces'] as List<dynamic>);
|
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AddDeviceTypeWidget(
|
|
||||||
products: products,
|
products: products,
|
||||||
subspaces: processedSubspaces,
|
|
||||||
projectTags: projectTags,
|
projectTags: projectTags,
|
||||||
initialSelectedProducts:
|
|
||||||
TagHelper.createInitialSelectedProductsForTags(
|
|
||||||
processedTags, processedSubspaces),
|
|
||||||
spaceName: spaceName,
|
spaceName: spaceName,
|
||||||
spaceTags: processedTags,
|
|
||||||
isCreate: false,
|
|
||||||
onSave: onSave,
|
onSave: onSave,
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
),
|
tags: state.tags,
|
||||||
);
|
isSaveEnabled: state.isSaveEnabled,
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: DefaultButton(
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: ColorsManager.secondaryColor,
|
|
||||||
foregroundColor: state.isSaveEnabled
|
|
||||||
? ColorsManager.whiteColors
|
|
||||||
: ColorsManager.whiteColorsWithOpacity,
|
|
||||||
onPressed: state.isSaveEnabled
|
|
||||||
? () async {
|
|
||||||
final updatedTags = List<Tag>.from(state.tags);
|
|
||||||
final result = TagHelper.processTags(updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags = result['updatedTags'] as List<Tag>;
|
|
||||||
final processedSubspaces =
|
|
||||||
List<SubspaceModel>.from(result['subspaces'] as List<dynamic>);
|
|
||||||
onSave?.call(processedTags, processedSubspaces);
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: const Text('Save'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
import '../../../add_device_type/views/add_device_type_widget.dart';
|
||||||
|
import '../../../helper/tag_helper.dart';
|
||||||
|
|
||||||
|
class SaveAddDeviceRowWidget extends StatelessWidget {
|
||||||
|
const SaveAddDeviceRowWidget({
|
||||||
|
super.key,
|
||||||
|
required this.subspaces,
|
||||||
|
required this.products,
|
||||||
|
required this.projectTags,
|
||||||
|
required this.spaceName,
|
||||||
|
required this.onSave,
|
||||||
|
required this.allTags,
|
||||||
|
required this.tags,
|
||||||
|
required this.isSaveEnabled,
|
||||||
|
});
|
||||||
|
final List<Tag> tags;
|
||||||
|
final List<SubspaceModel>? subspaces;
|
||||||
|
final List<ProductModel>? products;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
final String spaceName;
|
||||||
|
final Function(List<Tag> p1, List<SubspaceModel>? p2)? onSave;
|
||||||
|
final List<String>? allTags;
|
||||||
|
final bool isSaveEnabled;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Builder(
|
||||||
|
builder: (buttonContext) => CancelButton(
|
||||||
|
label: 'Add New Device',
|
||||||
|
onPressed: () async {
|
||||||
|
final updatedTags = List<Tag>.from(tags);
|
||||||
|
final result = TagHelper.processTags(updatedTags, subspaces);
|
||||||
|
|
||||||
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
|
final processedSubspaces = List<SubspaceModel>.from(
|
||||||
|
result['subspaces'] as List<dynamic>);
|
||||||
|
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AddDeviceTypeWidget(
|
||||||
|
products: products,
|
||||||
|
subspaces: processedSubspaces,
|
||||||
|
projectTags: projectTags,
|
||||||
|
initialSelectedProducts:
|
||||||
|
TagHelper.createInitialSelectedProductsForTags(
|
||||||
|
processedTags, processedSubspaces),
|
||||||
|
spaceName: spaceName,
|
||||||
|
spaceTags: processedTags,
|
||||||
|
isCreate: false,
|
||||||
|
onSave: onSave,
|
||||||
|
allTags: allTags,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: DefaultButton(
|
||||||
|
borderRadius: 10,
|
||||||
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
|
foregroundColor: isSaveEnabled
|
||||||
|
? ColorsManager.whiteColors
|
||||||
|
: ColorsManager.whiteColorsWithOpacity,
|
||||||
|
onPressed: isSaveEnabled
|
||||||
|
? () async {
|
||||||
|
final updatedTags = List<Tag>.from(tags);
|
||||||
|
final result =
|
||||||
|
TagHelper.processTags(updatedTags, subspaces);
|
||||||
|
|
||||||
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
|
final processedSubspaces = List<SubspaceModel>.from(
|
||||||
|
result['subspaces'] as List<dynamic>);
|
||||||
|
onSave?.call(processedTags, processedSubspaces);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Text('Save'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,5 @@
|
|||||||
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/common/dialog_dropdown.dart';
|
|
||||||
import 'package:syncrow_web/common/tag_dialog_textfield_dropdown.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
@ -12,11 +8,10 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assig
|
|||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.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/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
import 'widgets/RowOfCancelSaveWidget.dart';
|
||||||
|
import 'widgets/assign_tags_tables_widget.dart';
|
||||||
|
|
||||||
class AssignTagModelsDialog extends StatelessWidget {
|
class AssignTagModelsDialog extends StatelessWidget {
|
||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
@ -53,8 +48,10 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<String> locations =
|
final List<String> locations = (subspaces ?? [])
|
||||||
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space');
|
.map((subspace) => subspace.subspaceName)
|
||||||
|
.toList()
|
||||||
|
..add('Main Space');
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => AssignTagModelBloc(projectTags)
|
create: (_) => AssignTagModelBloc(projectTags)
|
||||||
@ -78,137 +75,38 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
AssignTagsTable(
|
||||||
borderRadius: BorderRadius.circular(20),
|
controllers: controllers,
|
||||||
child: DataTable(
|
locations: locations,
|
||||||
headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey),
|
tags: state.tags,
|
||||||
key: ValueKey(state.tags.length),
|
updatedTags: state.updatedTags,
|
||||||
border: TableBorder.all(
|
onDeleteDevice: ({required index, required tag}) {
|
||||||
color: ColorsManager.dataHeaderGrey,
|
|
||||||
width: 1,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
columns: [
|
|
||||||
DataColumn(
|
|
||||||
label: Text('#', style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
|
||||||
label: Text('Device',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
|
||||||
numeric: false,
|
|
||||||
label:
|
|
||||||
Text('Tag', style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
|
||||||
label: Text('Location',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
],
|
|
||||||
rows: state.tags.isEmpty
|
|
||||||
? [
|
|
||||||
DataRow(cells: [
|
|
||||||
DataCell(
|
|
||||||
Center(
|
|
||||||
child: Text('No Devices Available',
|
|
||||||
style:
|
|
||||||
Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const DataCell(SizedBox()),
|
|
||||||
const DataCell(SizedBox()),
|
|
||||||
const DataCell(SizedBox()),
|
|
||||||
])
|
|
||||||
]
|
|
||||||
: List.generate(state.tags.length, (index) {
|
|
||||||
final tag = state.tags[index];
|
|
||||||
final controller = controllers[index];
|
|
||||||
|
|
||||||
return DataRow(
|
|
||||||
cells: [
|
|
||||||
DataCell(Text((index + 1).toString())),
|
|
||||||
DataCell(
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
tag.product?.name ?? 'Unknown',
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
)),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Container(
|
|
||||||
width: 20.0,
|
|
||||||
height: 20.0,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
width: 1.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: IconButton(
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.close,
|
|
||||||
color: ColorsManager.lightGreyColor,
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
context.read<AssignTagModelBloc>().add(
|
|
||||||
DeleteTagModel(
|
|
||||||
tagToDelete: tag, tags: state.tags));
|
|
||||||
controllers.removeAt(index);
|
|
||||||
},
|
|
||||||
tooltip: 'Delete Tag',
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
constraints: const BoxConstraints(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DataCell(
|
|
||||||
Container(
|
|
||||||
alignment: Alignment
|
|
||||||
.centerLeft, // Align cell content to the left
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: TagDialogTextfieldDropdown(
|
|
||||||
key: ValueKey(
|
|
||||||
'dropdown_${const Uuid().v4()}_$index'),
|
|
||||||
product: tag.product?.uuid ?? 'Unknown',
|
|
||||||
items: state.updatedTags,
|
|
||||||
initialValue: tag,
|
|
||||||
onSelected: (value) {
|
|
||||||
controller.text = value.tag ?? '';
|
|
||||||
context.read<AssignTagModelBloc>().add(UpdateTag(
|
|
||||||
index: index,
|
|
||||||
tag: value,
|
|
||||||
));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DataCell(
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: DialogDropdown(
|
|
||||||
items: locations,
|
|
||||||
selectedValue: tag.location ?? 'Main Space',
|
|
||||||
onSelected: (value) {
|
|
||||||
context
|
context
|
||||||
.read<AssignTagModelBloc>()
|
.read<AssignTagModelBloc>()
|
||||||
.add(UpdateLocation(
|
.add(DeleteTagModel(
|
||||||
index: index,
|
tagToDelete: tag,
|
||||||
location: value,
|
tags: state.tags,
|
||||||
));
|
));
|
||||||
|
controllers.removeAt(index);
|
||||||
},
|
},
|
||||||
)),
|
onTagDropDownSelected: (
|
||||||
|
{required index, required tag}) {
|
||||||
|
context.read<AssignTagModelBloc>().add(
|
||||||
|
UpdateTag(
|
||||||
|
index: index,
|
||||||
|
tag: tag,
|
||||||
),
|
),
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
onLocationDropDownSelected: (
|
||||||
|
{required index, required location}) {
|
||||||
|
context.read<AssignTagModelBloc>().add(
|
||||||
|
UpdateLocation(
|
||||||
|
index: index,
|
||||||
|
location: location,
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
if (state.errorMessage != null)
|
if (state.errorMessage != null)
|
||||||
Text(state.errorMessage!,
|
Text(state.errorMessage!,
|
||||||
@ -220,101 +118,16 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
Row(
|
RowOfSaveCancelWidget(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
subspaces: subspaces,
|
||||||
children: [
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Builder(
|
|
||||||
builder: (buttonContext) => CancelButton(
|
|
||||||
label: 'Add New Device',
|
|
||||||
onPressed: () async {
|
|
||||||
final updatedTags = List<Tag>.from(state.tags);
|
|
||||||
final result =
|
|
||||||
TagHelper.updateSubspaceTagModels(updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags = result['updatedTags'] as List<Tag>;
|
|
||||||
final processedSubspaces = List<SubspaceTemplateModel>.from(
|
|
||||||
result['subspaces'] as List<dynamic>);
|
|
||||||
|
|
||||||
if (context.mounted) {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
|
|
||||||
await showDialog<bool>(
|
|
||||||
barrierDismissible: false,
|
|
||||||
context: context,
|
|
||||||
builder: (dialogContext) => AddDeviceTypeModelWidget(
|
|
||||||
products: products,
|
products: products,
|
||||||
subspaces: processedSubspaces,
|
|
||||||
isCreate: false,
|
|
||||||
initialSelectedProducts:
|
|
||||||
TagHelper.createInitialSelectedProducts(
|
|
||||||
processedTags, processedSubspaces),
|
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
spaceName: spaceName,
|
spaceName: spaceName,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
spaceTagModels: processedTags,
|
|
||||||
pageContext: pageContext,
|
pageContext: pageContext,
|
||||||
projectTags: projectTags,
|
projectTags: projectTags,
|
||||||
spaceModel: SpaceTemplateModel(
|
spaceModel: spaceModel,
|
||||||
modelName: spaceName,
|
|
||||||
tags: updatedTags,
|
|
||||||
uuid: spaceModel?.uuid,
|
|
||||||
internalId: spaceModel?.internalId,
|
|
||||||
subspaceModels: processedSubspaces)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: DefaultButton(
|
|
||||||
borderRadius: 10,
|
|
||||||
backgroundColor: ColorsManager.secondaryColor,
|
|
||||||
foregroundColor: state.isSaveEnabled
|
|
||||||
? ColorsManager.whiteColors
|
|
||||||
: ColorsManager.whiteColorsWithOpacity,
|
|
||||||
onPressed: state.isSaveEnabled
|
|
||||||
? () async {
|
|
||||||
final updatedTags = List<Tag>.from(state.tags);
|
|
||||||
|
|
||||||
final result =
|
|
||||||
TagHelper.updateSubspaceTagModels(updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags = result['updatedTags'] as List<Tag>;
|
|
||||||
final processedSubspaces = List<SubspaceTemplateModel>.from(
|
|
||||||
result['subspaces'] as List<dynamic>);
|
|
||||||
|
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
|
||||||
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext dialogContext) {
|
|
||||||
return CreateSpaceModelDialog(
|
|
||||||
products: products,
|
|
||||||
allSpaceModels: allSpaceModels,
|
allSpaceModels: allSpaceModels,
|
||||||
allTags: allTags,
|
|
||||||
projectTags: projectTags,
|
|
||||||
pageContext: pageContext,
|
|
||||||
otherSpaceModels: otherSpaceModels,
|
|
||||||
spaceModel: SpaceTemplateModel(
|
|
||||||
modelName: spaceName,
|
|
||||||
tags: processedTags,
|
|
||||||
uuid: spaceModel?.uuid,
|
|
||||||
internalId: spaceModel?.internalId,
|
|
||||||
subspaceModels: processedSubspaces),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: const Text('Save'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,152 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
import '../../../../common/buttons/cancel_button.dart';
|
||||||
|
import '../../../../common/buttons/default_button.dart';
|
||||||
|
import '../../../all_spaces/model/product_model.dart';
|
||||||
|
import '../../../all_spaces/model/tag.dart';
|
||||||
|
import '../../../helper/tag_helper.dart';
|
||||||
|
import '../../../space_model/models/space_template_model.dart';
|
||||||
|
import '../../../space_model/models/subspace_template_model.dart';
|
||||||
|
import '../../../space_model/widgets/dialog/create_space_model_dialog.dart';
|
||||||
|
import '../../../tag_model/views/add_device_type_model_widget.dart';
|
||||||
|
import '../../bloc/assign_tag_model_bloc.dart';
|
||||||
|
import '../../bloc/assign_tag_model_state.dart';
|
||||||
|
|
||||||
|
class RowOfSaveCancelWidget extends StatelessWidget {
|
||||||
|
const RowOfSaveCancelWidget({
|
||||||
|
super.key,
|
||||||
|
required this.subspaces,
|
||||||
|
required this.products,
|
||||||
|
required this.allTags,
|
||||||
|
required this.spaceName,
|
||||||
|
required this.otherSpaceModels,
|
||||||
|
required this.pageContext,
|
||||||
|
required this.projectTags,
|
||||||
|
required this.spaceModel,
|
||||||
|
required this.allSpaceModels,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<SubspaceTemplateModel>? subspaces;
|
||||||
|
final List<ProductModel>? products;
|
||||||
|
final List<String>? allTags;
|
||||||
|
final String spaceName;
|
||||||
|
final List<String>? otherSpaceModels;
|
||||||
|
final BuildContext? pageContext;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
final SpaceTemplateModel? spaceModel;
|
||||||
|
final List<SpaceTemplateModel>? allSpaceModels;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<AssignTagModelBloc, AssignTagModelState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is AssignTagModelLoaded) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Builder(
|
||||||
|
builder: (buttonContext) => CancelButton(
|
||||||
|
label: 'Add New Device',
|
||||||
|
onPressed: () async {
|
||||||
|
final updatedTags = List<Tag>.from(state.tags);
|
||||||
|
final result = TagHelper.updateSubspaceTagModels(
|
||||||
|
updatedTags, subspaces);
|
||||||
|
|
||||||
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
|
final processedSubspaces =
|
||||||
|
List<SubspaceTemplateModel>.from(
|
||||||
|
result['subspaces'] as List<dynamic>);
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
await showDialog<bool>(
|
||||||
|
barrierDismissible: false,
|
||||||
|
context: context,
|
||||||
|
builder: (dialogContext) => AddDeviceTypeModelWidget(
|
||||||
|
products: products,
|
||||||
|
subspaces: processedSubspaces,
|
||||||
|
isCreate: false,
|
||||||
|
initialSelectedProducts:
|
||||||
|
TagHelper.createInitialSelectedProducts(
|
||||||
|
processedTags, processedSubspaces),
|
||||||
|
allTags: allTags,
|
||||||
|
spaceName: spaceName,
|
||||||
|
otherSpaceModels: otherSpaceModels,
|
||||||
|
spaceTagModels: processedTags,
|
||||||
|
pageContext: pageContext,
|
||||||
|
projectTags: projectTags,
|
||||||
|
spaceModel: SpaceTemplateModel(
|
||||||
|
modelName: spaceName,
|
||||||
|
tags: updatedTags,
|
||||||
|
uuid: spaceModel?.uuid,
|
||||||
|
internalId: spaceModel?.internalId,
|
||||||
|
subspaceModels: processedSubspaces)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: DefaultButton(
|
||||||
|
borderRadius: 10,
|
||||||
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
|
foregroundColor: state.isSaveEnabled
|
||||||
|
? ColorsManager.whiteColors
|
||||||
|
: ColorsManager.whiteColorsWithOpacity,
|
||||||
|
onPressed: state.isSaveEnabled
|
||||||
|
? () async {
|
||||||
|
final updatedTags = List<Tag>.from(state.tags);
|
||||||
|
|
||||||
|
final result = TagHelper.updateSubspaceTagModels(
|
||||||
|
updatedTags, subspaces);
|
||||||
|
|
||||||
|
final processedTags =
|
||||||
|
result['updatedTags'] as List<Tag>;
|
||||||
|
final processedSubspaces =
|
||||||
|
List<SubspaceTemplateModel>.from(
|
||||||
|
result['subspaces'] as List<dynamic>);
|
||||||
|
|
||||||
|
Navigator.of(context)
|
||||||
|
.popUntil((route) => route.isFirst);
|
||||||
|
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return CreateSpaceModelDialog(
|
||||||
|
products: products,
|
||||||
|
allSpaceModels: allSpaceModels,
|
||||||
|
allTags: allTags,
|
||||||
|
projectTags: projectTags,
|
||||||
|
pageContext: pageContext,
|
||||||
|
otherSpaceModels: otherSpaceModels,
|
||||||
|
spaceModel: SpaceTemplateModel(
|
||||||
|
modelName: spaceName,
|
||||||
|
tags: processedTags,
|
||||||
|
uuid: spaceModel?.uuid,
|
||||||
|
internalId: spaceModel?.internalId,
|
||||||
|
subspaceModels: processedSubspaces),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Text('Save'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
import '../../../../../common/dialog_dropdown.dart';
|
||||||
|
import '../../../../../common/tag_dialog_textfield_dropdown.dart';
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
|
||||||
|
class AssignTagsTable extends StatelessWidget {
|
||||||
|
const AssignTagsTable({
|
||||||
|
super.key,
|
||||||
|
required this.controllers,
|
||||||
|
required this.locations,
|
||||||
|
required this.tags,
|
||||||
|
required this.updatedTags,
|
||||||
|
required this.onDeleteDevice,
|
||||||
|
required this.onLocationDropDownSelected,
|
||||||
|
required this.onTagDropDownSelected,
|
||||||
|
});
|
||||||
|
final void Function({required Tag tag, required int index})
|
||||||
|
onTagDropDownSelected;
|
||||||
|
final void Function({required String location, required int index})
|
||||||
|
onLocationDropDownSelected;
|
||||||
|
final void Function({required Tag tag, required int index}) onDeleteDevice;
|
||||||
|
final List<Tag> tags;
|
||||||
|
final List<Tag> updatedTags;
|
||||||
|
final List<TextEditingController> controllers;
|
||||||
|
final List<String> locations;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
child: DataTable(
|
||||||
|
headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey),
|
||||||
|
key: ValueKey(tags.length),
|
||||||
|
border: TableBorder.all(
|
||||||
|
color: ColorsManager.dataHeaderGrey,
|
||||||
|
width: 1,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
columns: [
|
||||||
|
DataColumn(
|
||||||
|
label: Text('#', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Device',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
|
DataColumn(
|
||||||
|
numeric: false,
|
||||||
|
label:
|
||||||
|
Text('Tag', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
|
DataColumn(
|
||||||
|
label: Text('Location',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
|
],
|
||||||
|
rows: tags.isEmpty
|
||||||
|
? [
|
||||||
|
DataRow(cells: [
|
||||||
|
DataCell(
|
||||||
|
Center(
|
||||||
|
child: Text('No Devices Available',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const DataCell(SizedBox()),
|
||||||
|
const DataCell(SizedBox()),
|
||||||
|
const DataCell(SizedBox()),
|
||||||
|
])
|
||||||
|
]
|
||||||
|
: List.generate(tags.length, (index) {
|
||||||
|
final tag = tags[index];
|
||||||
|
final controller = controllers[index];
|
||||||
|
|
||||||
|
return DataRow(
|
||||||
|
cells: [
|
||||||
|
DataCell(Text((index + 1).toString())),
|
||||||
|
DataCell(
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
tag.product?.name ?? 'Unknown',
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
)),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Container(
|
||||||
|
width: 20.0,
|
||||||
|
height: 20.0,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.close,
|
||||||
|
color: ColorsManager.lightGreyColor,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
onDeleteDevice(tag: tag, index: index);
|
||||||
|
},
|
||||||
|
tooltip: 'Delete Tag',
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Container(
|
||||||
|
alignment: Alignment
|
||||||
|
.centerLeft, // Align cell content to the left
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: TagDialogTextfieldDropdown(
|
||||||
|
key: ValueKey(
|
||||||
|
'dropdown_${const Uuid().v4()}_$index'),
|
||||||
|
product: tag.product?.uuid ?? 'Unknown',
|
||||||
|
items: updatedTags,
|
||||||
|
initialValue: tag,
|
||||||
|
onSelected: (value) {
|
||||||
|
controller.text = value.tag ?? '';
|
||||||
|
onTagDropDownSelected(tag: value, index: index);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: DialogDropdown(
|
||||||
|
items: locations,
|
||||||
|
selectedValue: tag.location ?? 'Main Space',
|
||||||
|
onSelected: (value) {
|
||||||
|
onLocationDropDownSelected(
|
||||||
|
location: value, index: index);
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,23 @@
|
|||||||
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/common/buttons/cancel_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
import 'widgets/ok_cancel_sub_space_widget.dart';
|
||||||
|
import 'widgets/textfield_sub_space_dialog_widget.dart';
|
||||||
|
|
||||||
class CreateSubSpaceDialog extends StatefulWidget {
|
class CreateSubSpaceDialog extends StatefulWidget {
|
||||||
final String dialogTitle;
|
final String dialogTitle;
|
||||||
final List<SubspaceModel>? existingSubSpaces;
|
final List<SubspaceModel>? existingSubSpaces;
|
||||||
final String? spaceName;
|
final String? spaceName;
|
||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
final void Function(List<SubspaceModel>?)? onSave;
|
final void Function(
|
||||||
|
List<SubspaceModel>?, List<UpdateSubspaceModel> updatedSubSpaces)? onSave;
|
||||||
|
|
||||||
const CreateSubSpaceDialog({
|
const CreateSubSpaceDialog({
|
||||||
required this.dialogTitle,
|
required this.dialogTitle,
|
||||||
@ -33,14 +33,7 @@ class CreateSubSpaceDialog extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _CreateSubSpaceDialogState extends State<CreateSubSpaceDialog> {
|
class _CreateSubSpaceDialogState extends State<CreateSubSpaceDialog> {
|
||||||
late final TextEditingController _subspaceNameController;
|
final TextEditingController _subspaceNameController = TextEditingController();
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
_subspaceNameController = TextEditingController();
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_subspaceNameController.dispose();
|
_subspaceNameController.dispose();
|
||||||
@ -79,83 +72,26 @@ class _CreateSubSpaceDialogState extends State<CreateSubSpaceDialog> {
|
|||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
Row(
|
||||||
Container(
|
|
||||||
width: context.screenWidth * 0.35,
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 10,
|
|
||||||
horizontal: 16,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.boxColor,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 8,
|
|
||||||
alignment: WrapAlignment.start,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
...state.subSpaces.asMap().entries.map(
|
Text(
|
||||||
(entry) {
|
'press Enter to Save',
|
||||||
final index = entry.key;
|
style: context.textTheme.headlineLarge?.copyWith(
|
||||||
final subSpace = entry.value;
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 10,
|
||||||
final lowerName = subSpace.subspaceName.toLowerCase();
|
color: ColorsManager.grayColor,
|
||||||
|
|
||||||
final duplicateIndices = state.subSpaces
|
|
||||||
.asMap()
|
|
||||||
.entries
|
|
||||||
.where((e) =>
|
|
||||||
e.value.subspaceName.toLowerCase() == lowerName)
|
|
||||||
.map((e) => e.key)
|
|
||||||
.toList();
|
|
||||||
final isDuplicate = duplicateIndices.length > 1 &&
|
|
||||||
duplicateIndices.indexOf(index) != 0;
|
|
||||||
return SubspaceChip(
|
|
||||||
subSpace: SubspaceTemplateModel(
|
|
||||||
subspaceName: entry.value.subspaceName,
|
|
||||||
disabled: entry.value.disabled,
|
|
||||||
),
|
|
||||||
isDuplicate: isDuplicate,
|
|
||||||
onDeleted: () => context.read<SubSpaceBloc>().add(
|
|
||||||
RemoveSubSpace(subSpace),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 200,
|
|
||||||
child: TextField(
|
|
||||||
controller: _subspaceNameController,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
border: InputBorder.none,
|
|
||||||
hintText: state.subSpaces.isEmpty
|
|
||||||
? 'Please enter the name'
|
|
||||||
: null,
|
|
||||||
hintStyle: context.textTheme.bodySmall?.copyWith(
|
|
||||||
color: ColorsManager.lightGrayColor,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onSubmitted: (value) {
|
const SizedBox(
|
||||||
final trimmedValue = value.trim();
|
width: 5,
|
||||||
if (trimmedValue.isNotEmpty) {
|
|
||||||
context.read<SubSpaceBloc>().add(
|
|
||||||
AddSubSpace(
|
|
||||||
SubspaceModel(
|
|
||||||
subspaceName: trimmedValue,
|
|
||||||
disabled: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
_subspaceNameController.clear();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: context.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
const Icon(Icons.save_as_sharp, size: 10),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
TextFieldSubSpaceDialogWidget(
|
||||||
|
subspaceNameController: _subspaceNameController,
|
||||||
|
subSpaces: state.subSpaces,
|
||||||
),
|
),
|
||||||
if (state.errorMessage.isNotEmpty)
|
if (state.errorMessage.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
@ -168,36 +104,10 @@ class _CreateSubSpaceDialogState extends State<CreateSubSpaceDialog> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Row(
|
OkCancelSubSpaceWidget(
|
||||||
children: [
|
subspaceNameController: _subspaceNameController,
|
||||||
Expanded(
|
errorMessage: state.errorMessage,
|
||||||
child: CancelButton(
|
onSave: widget.onSave,
|
||||||
label: 'Cancel',
|
|
||||||
onPressed: () async {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: DefaultButton(
|
|
||||||
onPressed: state.errorMessage.isEmpty
|
|
||||||
? () {
|
|
||||||
final subSpacesBloc = context.read<SubSpaceBloc>();
|
|
||||||
final subSpaces = subSpacesBloc.state.subSpaces;
|
|
||||||
widget.onSave?.call(subSpaces);
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
backgroundColor: ColorsManager.secondaryColor,
|
|
||||||
borderRadius: 10,
|
|
||||||
foregroundColor: state.errorMessage.isNotEmpty
|
|
||||||
? ColorsManager.whiteColorsWithOpacity
|
|
||||||
: ColorsManager.whiteColors,
|
|
||||||
child: const Text('OK'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
|
|
||||||
|
import '../../bloc/subspace_bloc.dart';
|
||||||
|
import '../../bloc/subspace_event.dart';
|
||||||
|
|
||||||
|
class OkCancelSubSpaceWidget extends StatelessWidget {
|
||||||
|
const OkCancelSubSpaceWidget({
|
||||||
|
super.key,
|
||||||
|
required this.subspaceNameController,
|
||||||
|
required this.onSave,
|
||||||
|
required this.errorMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
final TextEditingController subspaceNameController;
|
||||||
|
final void Function(
|
||||||
|
List<SubspaceModel>?, List<UpdateSubspaceModel> updatedSubSpaces)? onSave;
|
||||||
|
final String errorMessage;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CancelButton(
|
||||||
|
label: 'Cancel',
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: DefaultButton(
|
||||||
|
onPressed: errorMessage.isEmpty
|
||||||
|
? () async {
|
||||||
|
final trimmedValue = subspaceNameController.text.trim();
|
||||||
|
|
||||||
|
final subSpacesBloc = context.read<SubSpaceBloc>();
|
||||||
|
if (trimmedValue.isNotEmpty) {
|
||||||
|
subSpacesBloc.add(
|
||||||
|
AddSubSpace(
|
||||||
|
SubspaceModel(
|
||||||
|
subspaceName: trimmedValue,
|
||||||
|
disabled: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
subspaceNameController.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(milliseconds: 10));
|
||||||
|
final subSpaces = subSpacesBloc.state.subSpaces;
|
||||||
|
|
||||||
|
onSave?.call(
|
||||||
|
subSpaces, subSpacesBloc.state.updatedSubSpaceModels);
|
||||||
|
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
|
borderRadius: 10,
|
||||||
|
foregroundColor: errorMessage.isNotEmpty
|
||||||
|
? ColorsManager.whiteColorsWithOpacity
|
||||||
|
: ColorsManager.whiteColors,
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
import '../../../../../utils/color_manager.dart';
|
||||||
|
import '../../../all_spaces/model/subspace_model.dart';
|
||||||
|
import '../../../create_subspace_model/widgets/subspace_chip.dart';
|
||||||
|
import '../../../space_model/models/subspace_template_model.dart';
|
||||||
|
import '../../bloc/subspace_bloc.dart';
|
||||||
|
import '../../bloc/subspace_event.dart';
|
||||||
|
|
||||||
|
class TextFieldSubSpaceDialogWidget extends StatelessWidget {
|
||||||
|
const TextFieldSubSpaceDialogWidget({
|
||||||
|
super.key,
|
||||||
|
required TextEditingController subspaceNameController,
|
||||||
|
required this.subSpaces,
|
||||||
|
}) : _subspaceNameController = subspaceNameController;
|
||||||
|
|
||||||
|
final TextEditingController _subspaceNameController;
|
||||||
|
final List<SubspaceModel> subSpaces;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: context.screenWidth * 0.35,
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 16,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.boxColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
alignment: WrapAlignment.start,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
children: [
|
||||||
|
...subSpaces.asMap().entries.map(
|
||||||
|
(entry) {
|
||||||
|
final index = entry.key;
|
||||||
|
final subSpace = entry.value;
|
||||||
|
|
||||||
|
final lowerName = subSpace.subspaceName.toLowerCase();
|
||||||
|
|
||||||
|
final duplicateIndices = subSpaces
|
||||||
|
.asMap()
|
||||||
|
.entries
|
||||||
|
.where((e) => e.value.subspaceName.toLowerCase() == lowerName)
|
||||||
|
.map((e) => e.key)
|
||||||
|
.toList();
|
||||||
|
final isDuplicate = duplicateIndices.length > 1 &&
|
||||||
|
duplicateIndices.indexOf(index) != 0;
|
||||||
|
return SubspaceChip(
|
||||||
|
subSpace: SubspaceTemplateModel(
|
||||||
|
subspaceName: entry.value.subspaceName,
|
||||||
|
disabled: entry.value.disabled,
|
||||||
|
),
|
||||||
|
isDuplicate: isDuplicate,
|
||||||
|
onDeleted: () => context.read<SubSpaceBloc>().add(
|
||||||
|
RemoveSubSpace(subSpace),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 200,
|
||||||
|
child: TextField(
|
||||||
|
controller: _subspaceNameController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
hintText: subSpaces.isEmpty ? 'Please enter the name' : null,
|
||||||
|
hintStyle: context.textTheme.bodySmall?.copyWith(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
final trimmedValue = value.trim();
|
||||||
|
if (trimmedValue.isNotEmpty) {
|
||||||
|
context.read<SubSpaceBloc>().add(
|
||||||
|
AddSubSpace(
|
||||||
|
SubspaceModel(
|
||||||
|
subspaceName: trimmedValue,
|
||||||
|
disabled: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
_subspaceNameController.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -31,15 +31,19 @@ class CenterBodyWidget extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<CenterBodyBloc>().add(CommunityStructureSelectedEvent());
|
context
|
||||||
|
.read<CenterBodyBloc>()
|
||||||
|
.add(CommunityStructureSelectedEvent());
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Community Structure',
|
'Community Structure',
|
||||||
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
fontWeight: state is CommunityStructureState || state is CommunitySelectedState
|
fontWeight: state is CommunityStructureState ||
|
||||||
|
state is CommunitySelectedState
|
||||||
? FontWeight.bold
|
? FontWeight.bold
|
||||||
: FontWeight.normal,
|
: FontWeight.normal,
|
||||||
color: state is CommunityStructureState || state is CommunitySelectedState
|
color: state is CommunityStructureState ||
|
||||||
|
state is CommunitySelectedState
|
||||||
? Theme.of(context).textTheme.bodyLarge!.color
|
? Theme.of(context).textTheme.bodyLarge!.color
|
||||||
: Theme.of(context)
|
: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
@ -50,26 +54,26 @@ class CenterBodyWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
GestureDetector(
|
// GestureDetector(
|
||||||
onTap: () {
|
// onTap: () {
|
||||||
context.read<CenterBodyBloc>().add(SpaceModelSelectedEvent());
|
// context.read<CenterBodyBloc>().add(SpaceModelSelectedEvent());
|
||||||
},
|
// },
|
||||||
child: Text(
|
// child: Text(
|
||||||
'Space Model',
|
// 'Space Model',
|
||||||
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
// style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
fontWeight: state is SpaceModelState
|
// fontWeight: state is SpaceModelState
|
||||||
? FontWeight.bold
|
// ? FontWeight.bold
|
||||||
: FontWeight.normal,
|
// : FontWeight.normal,
|
||||||
color: state is SpaceModelState
|
// color: state is SpaceModelState
|
||||||
? Theme.of(context).textTheme.bodyLarge!.color
|
// ? Theme.of(context).textTheme.bodyLarge!.color
|
||||||
: Theme.of(context)
|
// : Theme.of(context)
|
||||||
.textTheme
|
// .textTheme
|
||||||
.bodyLarge!
|
// .bodyLarge!
|
||||||
.color!
|
// .color!
|
||||||
.withOpacity(0.5),
|
// .withOpacity(0.5),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -24,37 +24,22 @@ class AddDeviceTypeModelBloc
|
|||||||
|
|
||||||
if (currentState is AddDeviceModelLoaded) {
|
if (currentState is AddDeviceModelLoaded) {
|
||||||
final existingProduct = currentState.selectedProducts.firstWhere(
|
final existingProduct = currentState.selectedProducts.firstWhere(
|
||||||
(p) => p.productId == event.productId,
|
(p) => p.productId == event.selectedProduct.productId,
|
||||||
orElse: () => SelectedProduct(
|
orElse: () => event.selectedProduct,
|
||||||
productId: event.productId,
|
|
||||||
count: 0,
|
|
||||||
productName: event.productName,
|
|
||||||
product: event.product,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<SelectedProduct> updatedProducts;
|
List<SelectedProduct> updatedProducts;
|
||||||
|
|
||||||
if (event.count > 0) {
|
if (event.selectedProduct.count > 0) {
|
||||||
if (!currentState.selectedProducts.contains(existingProduct)) {
|
if (!currentState.selectedProducts.contains(existingProduct)) {
|
||||||
updatedProducts = [
|
updatedProducts = [
|
||||||
...currentState.selectedProducts,
|
...currentState.selectedProducts,
|
||||||
SelectedProduct(
|
event.selectedProduct,
|
||||||
productId: event.productId,
|
|
||||||
count: event.count,
|
|
||||||
productName: event.productName,
|
|
||||||
product: event.product,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
updatedProducts = currentState.selectedProducts.map((p) {
|
updatedProducts = currentState.selectedProducts.map((p) {
|
||||||
if (p.productId == event.productId) {
|
if (p.productId == event.selectedProduct.productId) {
|
||||||
return SelectedProduct(
|
return event.selectedProduct;
|
||||||
productId: p.productId,
|
|
||||||
count: event.count,
|
|
||||||
productName: p.productName,
|
|
||||||
product: p.product,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}).toList();
|
}).toList();
|
||||||
@ -62,7 +47,7 @@ class AddDeviceTypeModelBloc
|
|||||||
} else {
|
} else {
|
||||||
// Remove the product if the count is 0
|
// Remove the product if the count is 0
|
||||||
updatedProducts = currentState.selectedProducts
|
updatedProducts = currentState.selectedProducts
|
||||||
.where((p) => p.productId != event.productId)
|
.where((p) => p.productId != event.selectedProduct.productId)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,20 +10,15 @@ abstract class AddDeviceTypeModelEvent extends Equatable {
|
|||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
|
class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
|
||||||
final String productId;
|
final SelectedProduct selectedProduct;
|
||||||
final int count;
|
|
||||||
final String productName;
|
|
||||||
final ProductModel product;
|
|
||||||
|
|
||||||
UpdateProductCountEvent({required this.productId, required this.count, required this.productName, required this.product});
|
UpdateProductCountEvent({required this.selectedProduct});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [productId, count];
|
List<Object> get props => [selectedProduct];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class InitializeDeviceTypeModel extends AddDeviceTypeModelEvent {
|
class InitializeDeviceTypeModel extends AddDeviceTypeModelEvent {
|
||||||
final List<Tag> initialTags;
|
final List<Tag> initialTags;
|
||||||
final List<SelectedProduct> addedProducts;
|
final List<SelectedProduct> addedProducts;
|
||||||
|
@ -54,10 +54,10 @@ class DeviceTypeTileWidget extends StatelessWidget {
|
|||||||
onCountChanged: (newCount) {
|
onCountChanged: (newCount) {
|
||||||
context.read<AddDeviceTypeModelBloc>().add(
|
context.read<AddDeviceTypeModelBloc>().add(
|
||||||
UpdateProductCountEvent(
|
UpdateProductCountEvent(
|
||||||
productId: product.uuid,
|
selectedProduct: product.toSelectedProduct(
|
||||||
count: newCount,
|
newCount,
|
||||||
productName: product.catName,
|
),
|
||||||
product: product),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -22,6 +22,18 @@ class HTTPService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
client.interceptors.add(serviceLocator.get<HTTPInterceptor>());
|
client.interceptors.add(serviceLocator.get<HTTPInterceptor>());
|
||||||
|
// Add this interceptor for logging requests and responses
|
||||||
|
// client.interceptors.add(
|
||||||
|
// LogInterceptor(
|
||||||
|
// request: true,
|
||||||
|
// requestHeader: true,
|
||||||
|
// requestBody: true,
|
||||||
|
// responseHeader: false,
|
||||||
|
// responseBody: true,
|
||||||
|
// error: true,
|
||||||
|
// logPrint: (object) => print(object),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,15 @@ 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/all_spaces/model/tag.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 '../pages/spaces_management/all_spaces/model/subspace_model.dart';
|
||||||
|
|
||||||
class CommunitySpaceManagementApi {
|
class CommunitySpaceManagementApi {
|
||||||
// Community Management APIs
|
// Community Management APIs
|
||||||
Future<List<CommunityModel>> fetchCommunities(String projectId,
|
Future<List<CommunityModel>> fetchCommunities(String projectId,
|
||||||
@ -216,7 +219,6 @@ class CommunitySpaceManagementApi {
|
|||||||
{required String communityId,
|
{required String communityId,
|
||||||
required String name,
|
required String name,
|
||||||
String? parentId,
|
String? parentId,
|
||||||
String? direction,
|
|
||||||
bool isPrivate = false,
|
bool isPrivate = false,
|
||||||
required Offset position,
|
required Offset position,
|
||||||
String? spaceModelUuid,
|
String? spaceModelUuid,
|
||||||
@ -230,7 +232,6 @@ class CommunitySpaceManagementApi {
|
|||||||
'isPrivate': isPrivate,
|
'isPrivate': isPrivate,
|
||||||
'x': position.dx,
|
'x': position.dx,
|
||||||
'y': position.dy,
|
'y': position.dy,
|
||||||
'direction': direction,
|
|
||||||
'icon': icon,
|
'icon': icon,
|
||||||
};
|
};
|
||||||
if (parentId != null) {
|
if (parentId != null) {
|
||||||
@ -265,11 +266,10 @@ class CommunitySpaceManagementApi {
|
|||||||
required String name,
|
required String name,
|
||||||
String? parentId,
|
String? parentId,
|
||||||
String? icon,
|
String? icon,
|
||||||
String? direction,
|
|
||||||
bool isPrivate = false,
|
bool isPrivate = false,
|
||||||
required Offset position,
|
required Offset position,
|
||||||
List<TagModelUpdate>? tags,
|
List<Tag>? tags,
|
||||||
List<UpdateSubspaceTemplateModel>? subspaces,
|
List<SubspaceModel>? subspaces,
|
||||||
String? spaceModelUuid,
|
String? spaceModelUuid,
|
||||||
required String projectId}) async {
|
required String projectId}) async {
|
||||||
try {
|
try {
|
||||||
@ -278,9 +278,8 @@ class CommunitySpaceManagementApi {
|
|||||||
'isPrivate': isPrivate,
|
'isPrivate': isPrivate,
|
||||||
'x': position.dx,
|
'x': position.dx,
|
||||||
'y': position.dy,
|
'y': position.dy,
|
||||||
'direction': direction,
|
|
||||||
'icon': icon,
|
'icon': icon,
|
||||||
'subspace': subspaces,
|
'subspaces': subspaces,
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'spaceModelUuid': spaceModelUuid,
|
'spaceModelUuid': spaceModelUuid,
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.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/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';
|
||||||
@ -7,17 +9,23 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
|
|||||||
class SpaceModelManagementApi {
|
class SpaceModelManagementApi {
|
||||||
Future<List<SpaceTemplateModel>> listSpaceModels(
|
Future<List<SpaceTemplateModel>> listSpaceModels(
|
||||||
{required String projectId, int page = 1}) async {
|
{required String projectId, int page = 1}) async {
|
||||||
final response = await HTTPService().get(
|
try {
|
||||||
path: ApiEndpoints.listSpaceModels.replaceAll('{projectId}', projectId),
|
// final response = await HTTPService().get(
|
||||||
queryParameters: {'page': page},
|
// path: ApiEndpoints.listSpaceModels.replaceAll('{projectId}', projectId),
|
||||||
expectedResponseModel: (json) {
|
// queryParameters: {'page': page},
|
||||||
List<dynamic> jsonData = json['data'];
|
// expectedResponseModel: (json) {
|
||||||
return jsonData.map((jsonItem) {
|
// List<dynamic> jsonData = json['data'];
|
||||||
return SpaceTemplateModel.fromJson(jsonItem);
|
// return jsonData.map((jsonItem) {
|
||||||
}).toList();
|
// return SpaceTemplateModel.fromJson(jsonItem);
|
||||||
},
|
// }).toList();
|
||||||
);
|
// },
|
||||||
return response;
|
// );
|
||||||
|
return [];
|
||||||
|
// response;
|
||||||
|
} catch (e) {
|
||||||
|
log(e.toString());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpaceTemplateModel?> createSpaceModel(
|
Future<SpaceTemplateModel?> createSpaceModel(
|
||||||
@ -33,8 +41,8 @@ class SpaceModelManagementApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> updateSpaceModel(
|
Future<String?> updateSpaceModel(CreateSpaceTemplateBodyModel spaceModel,
|
||||||
CreateSpaceTemplateBodyModel spaceModel, String spaceModelUuid, String projectId) async {
|
String spaceModelUuid, String projectId) async {
|
||||||
final response = await HTTPService().put(
|
final response = await HTTPService().put(
|
||||||
path: ApiEndpoints.updateSpaceModel
|
path: ApiEndpoints.updateSpaceModel
|
||||||
.replaceAll('{projectId}', projectId)
|
.replaceAll('{projectId}', projectId)
|
||||||
@ -47,7 +55,8 @@ class SpaceModelManagementApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpaceTemplateModel?> getSpaceModel(String spaceModelUuid, String projectId) async {
|
Future<SpaceTemplateModel?> getSpaceModel(
|
||||||
|
String spaceModelUuid, String projectId) async {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getSpaceModel
|
path: ApiEndpoints.getSpaceModel
|
||||||
.replaceAll('{projectId}', projectId)
|
.replaceAll('{projectId}', projectId)
|
||||||
|
@ -14,7 +14,8 @@ class Assets {
|
|||||||
static const String rightLine = "assets/images/right_line.png";
|
static const String rightLine = "assets/images/right_line.png";
|
||||||
static const String google = "assets/images/google.svg";
|
static const String google = "assets/images/google.svg";
|
||||||
static const String facebook = "assets/images/facebook.svg";
|
static const String facebook = "assets/images/facebook.svg";
|
||||||
static const String invisiblePassword = "assets/images/Password_invisible.svg";
|
static const String invisiblePassword =
|
||||||
|
"assets/images/Password_invisible.svg";
|
||||||
static const String visiblePassword = "assets/images/password_visible.svg";
|
static const String visiblePassword = "assets/images/password_visible.svg";
|
||||||
static const String accessIcon = "assets/images/access_icon.svg";
|
static const String accessIcon = "assets/images/access_icon.svg";
|
||||||
static const String spaseManagementIcon =
|
static const String spaseManagementIcon =
|
||||||
@ -33,7 +34,8 @@ class Assets {
|
|||||||
static const String emptyTable = "assets/images/empty_table.svg";
|
static const String emptyTable = "assets/images/empty_table.svg";
|
||||||
|
|
||||||
// General assets
|
// General assets
|
||||||
static const String motionlessDetection = "assets/icons/motionless_detection.svg";
|
static const String motionlessDetection =
|
||||||
|
"assets/icons/motionless_detection.svg";
|
||||||
static const String acHeating = "assets/icons/ac_heating.svg";
|
static const String acHeating = "assets/icons/ac_heating.svg";
|
||||||
static const String acPowerOff = "assets/icons/ac_power_off.svg";
|
static const String acPowerOff = "assets/icons/ac_power_off.svg";
|
||||||
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
|
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
|
||||||
@ -70,19 +72,22 @@ class Assets {
|
|||||||
"assets/icons/automation_functions/temp_password_unlock.svg";
|
"assets/icons/automation_functions/temp_password_unlock.svg";
|
||||||
static const String doorlockNormalOpen =
|
static const String doorlockNormalOpen =
|
||||||
"assets/icons/automation_functions/doorlock_normal_open.svg";
|
"assets/icons/automation_functions/doorlock_normal_open.svg";
|
||||||
static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
|
static const String doorbell =
|
||||||
|
"assets/icons/automation_functions/doorbell.svg";
|
||||||
static const String remoteUnlockViaApp =
|
static const String remoteUnlockViaApp =
|
||||||
"assets/icons/automation_functions/remote_unlock_via_app.svg";
|
"assets/icons/automation_functions/remote_unlock_via_app.svg";
|
||||||
static const String doubleLock =
|
static const String doubleLock =
|
||||||
"assets/icons/automation_functions/double_lock.svg";
|
"assets/icons/automation_functions/double_lock.svg";
|
||||||
static const String selfTestResult =
|
static const String selfTestResult =
|
||||||
"assets/icons/automation_functions/self_test_result.svg";
|
"assets/icons/automation_functions/self_test_result.svg";
|
||||||
static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
|
static const String lockAlarm =
|
||||||
|
"assets/icons/automation_functions/lock_alarm.svg";
|
||||||
static const String presenceState =
|
static const String presenceState =
|
||||||
"assets/icons/automation_functions/presence_state.svg";
|
"assets/icons/automation_functions/presence_state.svg";
|
||||||
static const String currentTemp =
|
static const String currentTemp =
|
||||||
"assets/icons/automation_functions/current_temp.svg";
|
"assets/icons/automation_functions/current_temp.svg";
|
||||||
static const String presence = "assets/icons/automation_functions/presence.svg";
|
static const String presence =
|
||||||
|
"assets/icons/automation_functions/presence.svg";
|
||||||
static const String residualElectricity =
|
static const String residualElectricity =
|
||||||
"assets/icons/automation_functions/residual_electricity.svg";
|
"assets/icons/automation_functions/residual_electricity.svg";
|
||||||
static const String hijackAlarm =
|
static const String hijackAlarm =
|
||||||
@ -99,12 +104,15 @@ class Assets {
|
|||||||
|
|
||||||
// Presence Sensor Assets
|
// Presence Sensor Assets
|
||||||
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
|
||||||
static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
|
static const String sensorPresenceIcon =
|
||||||
|
"assets/icons/sensor_presence_ic.svg";
|
||||||
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
|
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
|
||||||
static const String illuminanceRecordIcon =
|
static const String illuminanceRecordIcon =
|
||||||
"assets/icons/illuminance_record_ic.svg";
|
"assets/icons/illuminance_record_ic.svg";
|
||||||
static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
|
static const String presenceRecordIcon =
|
||||||
static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
|
"assets/icons/presence_record_ic.svg";
|
||||||
|
static const String helpDescriptionIcon =
|
||||||
|
"assets/icons/help_description_ic.svg";
|
||||||
|
|
||||||
static const String lightPulp = "assets/icons/light_pulb.svg";
|
static const String lightPulp = "assets/icons/light_pulb.svg";
|
||||||
static const String acDevice = "assets/icons/ac_device.svg";
|
static const String acDevice = "assets/icons/ac_device.svg";
|
||||||
@ -154,10 +162,12 @@ class Assets {
|
|||||||
static const String unit = 'assets/icons/unit_icon.svg';
|
static const String unit = 'assets/icons/unit_icon.svg';
|
||||||
static const String villa = 'assets/icons/villa_icon.svg';
|
static const String villa = 'assets/icons/villa_icon.svg';
|
||||||
static const String iconEdit = 'assets/icons/icon_edit_icon.svg';
|
static const String iconEdit = 'assets/icons/icon_edit_icon.svg';
|
||||||
static const String textFieldSearch = 'assets/icons/textfield_search_icon.svg';
|
static const String textFieldSearch =
|
||||||
|
'assets/icons/textfield_search_icon.svg';
|
||||||
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg';
|
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg';
|
||||||
static const String addIcon = 'assets/icons/add_icon.svg';
|
static const String addIcon = 'assets/icons/add_icon.svg';
|
||||||
static const String smartThermostatIcon = 'assets/icons/smart_thermostat_icon.svg';
|
static const String smartThermostatIcon =
|
||||||
|
'assets/icons/smart_thermostat_icon.svg';
|
||||||
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg';
|
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg';
|
||||||
static const String presenceSensor = 'assets/icons/presence_sensor.svg';
|
static const String presenceSensor = 'assets/icons/presence_sensor.svg';
|
||||||
static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg';
|
static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg';
|
||||||
@ -205,7 +215,8 @@ class Assets {
|
|||||||
//assets/icons/water_leak_normal.svg
|
//assets/icons/water_leak_normal.svg
|
||||||
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
|
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
|
||||||
//assets/icons/water_leak_detected.svg
|
//assets/icons/water_leak_detected.svg
|
||||||
static const String waterLeakDetected = 'assets/icons/water_leak_detected.svg';
|
static const String waterLeakDetected =
|
||||||
|
'assets/icons/water_leak_detected.svg';
|
||||||
|
|
||||||
//assets/icons/automation_records.svg
|
//assets/icons/automation_records.svg
|
||||||
static const String automationRecords = 'assets/icons/automation_records.svg';
|
static const String automationRecords = 'assets/icons/automation_records.svg';
|
||||||
@ -276,13 +287,16 @@ class Assets {
|
|||||||
"assets/icons/functions_icons/sensitivity.svg";
|
"assets/icons/functions_icons/sensitivity.svg";
|
||||||
static const String assetsSensitivityOperationIcon =
|
static const String assetsSensitivityOperationIcon =
|
||||||
"assets/icons/functions_icons/sesitivity_operation_icon.svg";
|
"assets/icons/functions_icons/sesitivity_operation_icon.svg";
|
||||||
static const String assetsAcPower = "assets/icons/functions_icons/ac_power.svg";
|
static const String assetsAcPower =
|
||||||
|
"assets/icons/functions_icons/ac_power.svg";
|
||||||
static const String assetsAcPowerOFF =
|
static const String assetsAcPowerOFF =
|
||||||
"assets/icons/functions_icons/ac_power_off.svg";
|
"assets/icons/functions_icons/ac_power_off.svg";
|
||||||
static const String assetsChildLock =
|
static const String assetsChildLock =
|
||||||
"assets/icons/functions_icons/child_lock.svg";
|
"assets/icons/functions_icons/child_lock.svg";
|
||||||
static const String assetsFreezing = "assets/icons/functions_icons/freezing.svg";
|
static const String assetsFreezing =
|
||||||
static const String assetsFanSpeed = "assets/icons/functions_icons/fan_speed.svg";
|
"assets/icons/functions_icons/freezing.svg";
|
||||||
|
static const String assetsFanSpeed =
|
||||||
|
"assets/icons/functions_icons/fan_speed.svg";
|
||||||
static const String assetsAcCooling =
|
static const String assetsAcCooling =
|
||||||
"assets/icons/functions_icons/ac_cooling.svg";
|
"assets/icons/functions_icons/ac_cooling.svg";
|
||||||
static const String assetsAcHeating =
|
static const String assetsAcHeating =
|
||||||
@ -291,7 +305,8 @@ class Assets {
|
|||||||
"assets/icons/functions_icons/celsius_degrees.svg";
|
"assets/icons/functions_icons/celsius_degrees.svg";
|
||||||
static const String assetsTempreture =
|
static const String assetsTempreture =
|
||||||
"assets/icons/functions_icons/tempreture.svg";
|
"assets/icons/functions_icons/tempreture.svg";
|
||||||
static const String assetsAcFanLow = "assets/icons/functions_icons/ac_fan_low.svg";
|
static const String assetsAcFanLow =
|
||||||
|
"assets/icons/functions_icons/ac_fan_low.svg";
|
||||||
static const String assetsAcFanMiddle =
|
static const String assetsAcFanMiddle =
|
||||||
"assets/icons/functions_icons/ac_fan_middle.svg";
|
"assets/icons/functions_icons/ac_fan_middle.svg";
|
||||||
static const String assetsAcFanHigh =
|
static const String assetsAcFanHigh =
|
||||||
@ -310,7 +325,8 @@ class Assets {
|
|||||||
"assets/icons/functions_icons/far_detection.svg";
|
"assets/icons/functions_icons/far_detection.svg";
|
||||||
static const String assetsFarDetectionFunction =
|
static const String assetsFarDetectionFunction =
|
||||||
"assets/icons/functions_icons/far_detection_function.svg";
|
"assets/icons/functions_icons/far_detection_function.svg";
|
||||||
static const String assetsIndicator = "assets/icons/functions_icons/indicator.svg";
|
static const String assetsIndicator =
|
||||||
|
"assets/icons/functions_icons/indicator.svg";
|
||||||
static const String assetsMotionDetection =
|
static const String assetsMotionDetection =
|
||||||
"assets/icons/functions_icons/motion_detection.svg";
|
"assets/icons/functions_icons/motion_detection.svg";
|
||||||
static const String assetsMotionlessDetection =
|
static const String assetsMotionlessDetection =
|
||||||
@ -323,7 +339,8 @@ class Assets {
|
|||||||
"assets/icons/functions_icons/master_state.svg";
|
"assets/icons/functions_icons/master_state.svg";
|
||||||
static const String assetsSwitchAlarmSound =
|
static const String assetsSwitchAlarmSound =
|
||||||
"assets/icons/functions_icons/switch_alarm_sound.svg";
|
"assets/icons/functions_icons/switch_alarm_sound.svg";
|
||||||
static const String assetsResetOff = "assets/icons/functions_icons/reset_off.svg";
|
static const String assetsResetOff =
|
||||||
|
"assets/icons/functions_icons/reset_off.svg";
|
||||||
|
|
||||||
// Assets for automation_functions
|
// Assets for automation_functions
|
||||||
static const String assetsCardUnlock =
|
static const String assetsCardUnlock =
|
||||||
@ -367,12 +384,14 @@ class Assets {
|
|||||||
static const String activeUser = 'assets/icons/active_user.svg';
|
static const String activeUser = 'assets/icons/active_user.svg';
|
||||||
static const String deActiveUser = 'assets/icons/deactive_user.svg';
|
static const String deActiveUser = 'assets/icons/deactive_user.svg';
|
||||||
static const String invitedIcon = 'assets/icons/invited_icon.svg';
|
static const String invitedIcon = 'assets/icons/invited_icon.svg';
|
||||||
static const String rectangleCheckBox = 'assets/icons/rectangle_check_box.png';
|
static const String rectangleCheckBox =
|
||||||
|
'assets/icons/rectangle_check_box.png';
|
||||||
static const String CheckBoxChecked = 'assets/icons/box_checked.png';
|
static const String CheckBoxChecked = 'assets/icons/box_checked.png';
|
||||||
static const String emptyBox = 'assets/icons/empty_box.png';
|
static const String emptyBox = 'assets/icons/empty_box.png';
|
||||||
static const String completeProcessIcon =
|
static const String completeProcessIcon =
|
||||||
'assets/icons/compleate_process_icon.svg';
|
'assets/icons/compleate_process_icon.svg';
|
||||||
static const String currentProcessIcon = 'assets/icons/current_process_icon.svg';
|
static const String currentProcessIcon =
|
||||||
|
'assets/icons/current_process_icon.svg';
|
||||||
static const String uncomplete_ProcessIcon =
|
static const String uncomplete_ProcessIcon =
|
||||||
'assets/icons/uncompleate_process_icon.svg';
|
'assets/icons/uncompleate_process_icon.svg';
|
||||||
static const String wrongProcessIcon = 'assets/icons/wrong_process_icon.svg';
|
static const String wrongProcessIcon = 'assets/icons/wrong_process_icon.svg';
|
||||||
@ -393,9 +412,11 @@ class Assets {
|
|||||||
static const String successIcon = 'assets/icons/success_icon.svg';
|
static const String successIcon = 'assets/icons/success_icon.svg';
|
||||||
static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg';
|
static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg';
|
||||||
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
|
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
|
||||||
static const String scenesPlayIconCheck = 'assets/icons/scenesPlayIconCheck.png';
|
static const String scenesPlayIconCheck =
|
||||||
|
'assets/icons/scenesPlayIconCheck.png';
|
||||||
static const String presenceStateIcon = 'assets/icons/presence_state.svg';
|
static const String presenceStateIcon = 'assets/icons/presence_state.svg';
|
||||||
static const String currentDistanceIcon = 'assets/icons/current_distance_icon.svg';
|
static const String currentDistanceIcon =
|
||||||
|
'assets/icons/current_distance_icon.svg';
|
||||||
|
|
||||||
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
|
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
|
||||||
static const String motionDetectionSensitivityIcon =
|
static const String motionDetectionSensitivityIcon =
|
||||||
@ -418,29 +439,44 @@ class Assets {
|
|||||||
static const String cpsMode4 = 'assets/icons/cps_mode4.svg';
|
static const String cpsMode4 = 'assets/icons/cps_mode4.svg';
|
||||||
static const String closeToMotion = 'assets/icons/close_to_motion.svg';
|
static const String closeToMotion = 'assets/icons/close_to_motion.svg';
|
||||||
static const String farAwayMotion = 'assets/icons/far_away_motion.svg';
|
static const String farAwayMotion = 'assets/icons/far_away_motion.svg';
|
||||||
static const String communicationFault = 'assets/icons/communication_fault.svg';
|
static const String communicationFault =
|
||||||
|
'assets/icons/communication_fault.svg';
|
||||||
static const String radarFault = 'assets/icons/radar_fault.svg';
|
static const String radarFault = 'assets/icons/radar_fault.svg';
|
||||||
static const String selfTestingSuccess = 'assets/icons/self_testing_success.svg';
|
static const String selfTestingSuccess =
|
||||||
static const String selfTestingFailure = 'assets/icons/self_testing_failure.svg';
|
'assets/icons/self_testing_success.svg';
|
||||||
static const String selfTestingTimeout = 'assets/icons/self_testing_timeout.svg';
|
static const String selfTestingFailure =
|
||||||
|
'assets/icons/self_testing_failure.svg';
|
||||||
|
static const String selfTestingTimeout =
|
||||||
|
'assets/icons/self_testing_timeout.svg';
|
||||||
static const String movingSpeed = 'assets/icons/moving_speed.svg';
|
static const String movingSpeed = 'assets/icons/moving_speed.svg';
|
||||||
static const String boundary = 'assets/icons/boundary.svg';
|
static const String boundary = 'assets/icons/boundary.svg';
|
||||||
static const String motionMeter = 'assets/icons/motion_meter.svg';
|
static const String motionMeter = 'assets/icons/motion_meter.svg';
|
||||||
static const String spatialStaticValue = 'assets/icons/spatial_static_value.svg';
|
static const String spatialStaticValue =
|
||||||
static const String spatialMotionValue = 'assets/icons/spatial_motion_value.svg';
|
'assets/icons/spatial_static_value.svg';
|
||||||
|
static const String spatialMotionValue =
|
||||||
|
'assets/icons/spatial_motion_value.svg';
|
||||||
static const String presenceJudgementThrshold =
|
static const String presenceJudgementThrshold =
|
||||||
'assets/icons/presence_judgement_threshold.svg';
|
'assets/icons/presence_judgement_threshold.svg';
|
||||||
static const String spaceType = 'assets/icons/space_type.svg';
|
static const String spaceType = 'assets/icons/space_type.svg';
|
||||||
static const String sportsPara = 'assets/icons/sports_para.svg';
|
static const String sportsPara = 'assets/icons/sports_para.svg';
|
||||||
static const String sensitivityFeature1 = 'assets/icons/sensitivity_feature_1.svg';
|
static const String sensitivityFeature1 =
|
||||||
static const String sensitivityFeature2 = 'assets/icons/sensitivity_feature_2.svg';
|
'assets/icons/sensitivity_feature_1.svg';
|
||||||
static const String sensitivityFeature3 = 'assets/icons/sensitivity_feature_3.svg';
|
static const String sensitivityFeature2 =
|
||||||
static const String sensitivityFeature4 = 'assets/icons/sensitivity_feature_4.svg';
|
'assets/icons/sensitivity_feature_2.svg';
|
||||||
static const String sensitivityFeature5 = 'assets/icons/sensitivity_feature_5.svg';
|
static const String sensitivityFeature3 =
|
||||||
static const String sensitivityFeature6 = 'assets/icons/sensitivity_feature_6.svg';
|
'assets/icons/sensitivity_feature_3.svg';
|
||||||
static const String sensitivityFeature7 = 'assets/icons/sensitivity_feature_7.svg';
|
static const String sensitivityFeature4 =
|
||||||
static const String sensitivityFeature8 = 'assets/icons/sensitivity_feature_8.svg';
|
'assets/icons/sensitivity_feature_4.svg';
|
||||||
static const String sensitivityFeature9 = 'assets/icons/sensitivity_feature_9.svg';
|
static const String sensitivityFeature5 =
|
||||||
|
'assets/icons/sensitivity_feature_5.svg';
|
||||||
|
static const String sensitivityFeature6 =
|
||||||
|
'assets/icons/sensitivity_feature_6.svg';
|
||||||
|
static const String sensitivityFeature7 =
|
||||||
|
'assets/icons/sensitivity_feature_7.svg';
|
||||||
|
static const String sensitivityFeature8 =
|
||||||
|
'assets/icons/sensitivity_feature_8.svg';
|
||||||
|
static const String sensitivityFeature9 =
|
||||||
|
'assets/icons/sensitivity_feature_9.svg';
|
||||||
static const String deviceTagIcon = 'assets/icons/device_tag_ic.svg';
|
static const String deviceTagIcon = 'assets/icons/device_tag_ic.svg';
|
||||||
static const String targetConfirmTimeIcon =
|
static const String targetConfirmTimeIcon =
|
||||||
'assets/icons/target_confirm_time_icon.svg';
|
'assets/icons/target_confirm_time_icon.svg';
|
||||||
|
Reference in New Issue
Block a user