mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-11 15:47:44 +00:00
Compare commits
79 Commits
SP-1279
...
fix-timer-
Author | SHA1 | Date | |
---|---|---|---|
db84a9aa5e | |||
140f4ff5e2 | |||
cbaeecc968 | |||
2a95720cb0 | |||
4fae2d6be0 | |||
5b84076572 | |||
9bf37243a6 | |||
acad0e8c9c | |||
79f5ef7871 | |||
6493f02bcc | |||
c7c8898763 | |||
62ee9a72d6 | |||
55695ca5db | |||
c2f5a8df10 | |||
cd9821679e | |||
bfd3d4542e | |||
35a99ccda7 | |||
978934399e | |||
bc32fe7941 | |||
cb6d50d367 | |||
97eb1c152b | |||
c23176706f | |||
387ef99728 | |||
694a5a7dda | |||
c90b9a1912 | |||
7860292276 | |||
550acc4953 | |||
fd6b737556 | |||
3d5825adca | |||
9c97e2879a | |||
fda96025e9 | |||
92aa574944 | |||
d08ab8caac | |||
774f21a55b | |||
9b69ec31e9 | |||
a242377ea6 | |||
3a0c8edf86 | |||
970f7ed16f | |||
006bd4c8ae | |||
b6752683fd | |||
b0846b2fef | |||
8a244dcd23 | |||
9d4395e204 | |||
46f318734a | |||
7accf1d4c8 | |||
c2476b9719 | |||
a56f4e488e | |||
6bd9fb7e4e | |||
d264409d29 | |||
ca44f3bf55 | |||
9949a0a0bf | |||
8dc4081a89 | |||
52498f4e6b | |||
37440f288c | |||
973ae82bec | |||
8c4dec4483 | |||
ad922577da | |||
64f61a6c3d | |||
ab3f268f29 | |||
b345822366 | |||
76793a3c0b | |||
c330f11206 | |||
9cb62795a6 | |||
a034202d76 | |||
869799f08e | |||
573e7b42ed | |||
22935f7007 | |||
5bf5120883 | |||
f307aaff9d | |||
aea18fb293 | |||
835dfe8785 | |||
f670ae78aa | |||
d3128a9c9c | |||
b65f172f9d | |||
dad18b77de | |||
77a9aa2f19 | |||
de5030d9f0 | |||
8c15fffd42 | |||
3750fa8329 |
21
assets/icons/active_bell.svg
Normal file
21
assets/icons/active_bell.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_7572_5102)">
|
||||||
|
<path d="M11.255 22.5148H11.2389C9.82071 22.5148 8.66699 21.361 8.66699 19.9429V19.3419C8.66699 18.9913 8.95123 18.707 9.30183 18.707H13.1921C13.5427 18.707 13.8269 18.9913 13.8269 19.3419V19.9429C13.8269 21.3611 12.6731 22.5148 11.255 22.5148Z" fill="#FFA81C"/>
|
||||||
|
<path d="M13.1912 18.707H11.2461V22.5148H11.2542C12.6723 22.5148 13.826 21.361 13.826 19.9429V19.3419C13.826 18.9912 13.5418 18.707 13.1912 18.707Z" fill="#FF9300"/>
|
||||||
|
<path d="M12.5157 4.81334H9.97762C9.62701 4.81334 9.34277 4.5291 9.34277 4.1785V2.74955C9.34277 1.69974 10.1968 0.845703 11.2466 0.845703C12.2964 0.845703 13.1505 1.69978 13.1505 2.74955V4.1785C13.1505 4.5291 12.8663 4.81334 12.5157 4.81334Z" fill="#FFA81C"/>
|
||||||
|
<path d="M12.5151 4.81334C12.8657 4.81334 13.1499 4.5291 13.1499 4.1785V2.74955C13.1499 1.69974 12.2959 0.845703 11.2461 0.845703V4.81334H12.5151Z" fill="#FF9300"/>
|
||||||
|
<path d="M17.9733 19.9777H4.51899C3.96952 19.9777 3.52246 19.5306 3.52246 18.9811V18.0735C3.52246 17.0793 3.88851 16.1245 4.55319 15.3852C5.00799 14.8792 5.25846 14.226 5.25846 13.5457V9.43293C5.25846 6.13133 7.94448 3.44531 11.2461 3.44531C14.5477 3.44531 17.2337 6.13133 17.2337 9.43293V13.5457C17.2337 14.226 17.4842 14.8792 17.939 15.3851C18.6037 16.1245 18.9697 17.0792 18.9697 18.0734V18.9811C18.9698 19.5306 18.5228 19.9777 17.9733 19.9777Z" fill="#FFCF2C"/>
|
||||||
|
<path d="M17.9732 19.9776C18.5227 19.9776 18.9698 19.5306 18.9698 18.9811V18.0734C18.9698 17.0792 18.6037 16.1245 17.939 15.3851C17.4842 14.8792 17.2337 14.226 17.2337 13.5457V9.43293C17.2337 6.13133 14.5477 3.44531 11.2461 3.44531V19.9776H17.9732Z" fill="#FFC12E"/>
|
||||||
|
<path d="M3.52246 18.0734V18.9811C3.52246 19.5306 3.96952 19.9776 4.51899 19.9776H17.9732C18.5227 19.9776 18.9698 19.5306 18.9698 18.9811V18.0734C18.9698 17.638 18.8995 17.2102 18.7648 16.8047H3.72747C3.59272 17.2102 3.52246 17.638 3.52246 18.0734Z" fill="#FFF566"/>
|
||||||
|
<path d="M11.2461 16.8047V19.9776H17.9732C18.5227 19.9776 18.9698 19.5306 18.9698 18.9811V18.0734C18.9698 17.638 18.8995 17.2102 18.7647 16.8047H11.2461V16.8047Z" fill="#FFE645"/>
|
||||||
|
<path d="M1.04282 7.85721C0.998428 7.85721 0.953397 7.85255 0.908238 7.84278C0.565508 7.7688 0.347673 7.43097 0.421653 7.08824C0.930035 4.73345 2.22744 2.57028 4.07483 0.997187C4.3418 0.769872 4.74247 0.802079 4.96975 1.06897C5.19706 1.33594 5.16494 1.73657 4.89797 1.96388C3.2616 3.35728 2.11262 5.2723 1.66273 7.35619C1.59852 7.65376 1.33536 7.85721 1.04282 7.85721Z" fill="#FF8B6E"/>
|
||||||
|
<path d="M21.4417 7.85717C21.1491 7.85717 20.886 7.65377 20.8218 7.35619C20.3719 5.2723 19.2229 3.35728 17.5866 1.96393C17.3196 1.73661 17.2875 1.33594 17.5148 1.06901C17.7421 0.80204 18.1427 0.769875 18.4097 0.997233C20.2571 2.57024 21.5545 4.73345 22.0628 7.08825C22.1368 7.43098 21.919 7.7688 21.5763 7.84278C21.5311 7.85247 21.4861 7.85717 21.4417 7.85717Z" fill="#FF674F"/>
|
||||||
|
<path d="M3.48329 8.6005C3.4444 8.6005 3.40495 8.5969 3.36534 8.58945C3.02075 8.5247 2.79394 8.19284 2.85869 7.84829C3.20714 5.99413 4.18429 4.28141 5.61006 3.02565C5.87314 2.79385 6.27431 2.81937 6.50603 3.08245C6.73779 3.34557 6.71231 3.74671 6.44923 3.97842C5.23495 5.04796 4.40293 6.50556 4.1065 8.08276C4.04919 8.38778 3.78268 8.6005 3.48329 8.6005Z" fill="#FF8B6E"/>
|
||||||
|
<path d="M19.0004 8.60042C18.701 8.60042 18.4345 8.38771 18.3772 8.08273C18.0808 6.50557 17.2489 5.04793 16.0346 3.97843C15.7715 3.74667 15.7461 3.34554 15.9778 3.08241C16.2095 2.81934 16.6107 2.7939 16.8738 3.02562C18.2995 4.28138 19.2766 5.99405 19.625 7.84817C19.6898 8.19277 19.4629 8.52458 19.1183 8.58933C19.0788 8.59682 19.0393 8.60042 19.0004 8.60042Z" fill="#FF674F"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_7572_5102">
|
||||||
|
<rect width="21.67" height="21.67" fill="white" transform="translate(0.407227 0.845703)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
3
assets/icons/gear.svg
Normal file
3
assets/icons/gear.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21.412 9.9034L18.9398 9.28324C18.788 8.81496 18.5981 8.35938 18.3703 7.92902C18.7373 7.30886 19.522 6.00531 19.522 6.00531C19.6613 5.75219 19.6233 5.43578 19.4208 5.23324L17.6362 3.43609C17.4338 3.23364 17.1047 3.19563 16.8642 3.3475L14.9404 4.49922C14.4975 4.27141 14.0419 4.08152 13.5862 3.92969L12.9661 1.45754C12.9028 1.17902 12.6496 0.976562 12.3586 0.976562H9.82734C9.53629 0.976562 9.28312 1.17902 9.21989 1.4575C9.21989 1.4575 8.78953 3.18293 8.59973 3.92965C8.10614 4.09418 7.62516 4.29663 7.16957 4.5498L5.16984 3.34746C4.91672 3.19558 4.60031 3.23359 4.39781 3.43605L2.61328 5.23324C2.39817 5.43578 2.36016 5.75219 2.51199 6.00531L3.75234 8.06828C3.5498 8.46063 3.38527 8.86563 3.24609 9.28324L0.773948 9.9034C0.495427 9.96672 0.292969 10.2198 0.292969 10.5109V13.0422C0.292969 13.3332 0.495427 13.5864 0.773906 13.6496L3.24609 14.2698C3.39797 14.7381 3.60051 15.2064 3.82832 15.6494L2.72723 17.4845C2.57535 17.7376 2.61328 18.054 2.82844 18.2692L4.61301 20.0537C4.81547 20.2563 5.13188 20.2942 5.38504 20.1423C5.38504 20.1423 6.62531 19.4082 7.2329 19.0412C7.67578 19.2817 8.13136 19.4715 8.59973 19.6234L9.21989 22.0956C9.28317 22.374 9.53629 22.5765 9.82734 22.5765H12.3586C12.6496 22.5765 12.9028 22.374 12.9661 22.0956L13.5862 19.6234C14.0671 19.4715 14.5354 19.269 14.9911 19.0286C15.6112 19.3955 16.8642 20.1423 16.8642 20.1423C17.1046 20.2942 17.4337 20.2563 17.6362 20.0537L19.4208 18.2692C19.6232 18.054 19.6613 17.7376 19.522 17.4845L18.383 15.5987C18.6108 15.1684 18.788 14.7254 18.9398 14.2698L21.412 13.6496C21.6905 13.5864 21.8929 13.3332 21.8929 13.0422V10.5109C21.893 10.2198 21.6905 9.96672 21.412 9.9034ZM11.093 16.2063C8.65031 16.2063 6.66328 14.2192 6.66328 11.7766C6.66328 9.33391 8.65031 7.34688 11.093 7.34688C13.5356 7.34688 15.5227 9.33391 15.5227 11.7766C15.5227 14.2192 13.5356 16.2063 11.093 16.2063Z" fill="#A1A7B3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/icons/scenesPlayIcon.png
Normal file
BIN
assets/icons/scenesPlayIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
@ -1,17 +0,0 @@
|
|||||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g filter="url(#filter0_d_6675_32326)">
|
|
||||||
<path d="M18 3C9.71584 3 3 9.71572 3 18C3 26.2843 9.71584 33 18 33C26.2842 33 33 26.2843 33 18C33 9.71572 26.2842 3 18 3ZM23.1844 18.7951L15.6844 23.4826C15.5326 23.5774 15.3601 23.625 15.1875 23.625C15.0312 23.625 14.8746 23.5861 14.7329 23.5073C14.4349 23.3421 14.25 23.0285 14.25 22.6875V13.3125C14.25 12.9715 14.4349 12.6579 14.7329 12.4927C15.0309 12.3265 15.3953 12.3366 15.6844 12.5174L23.1844 17.2049C23.4584 17.3766 23.625 17.6769 23.625 18C23.625 18.3231 23.4584 18.6235 23.1844 18.7951Z" fill="#F4F4F4"/>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<filter id="filter0_d_6675_32326" x="0" y="0" width="36" height="36" 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.5 0"/>
|
|
||||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6675_32326"/>
|
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6675_32326" result="shape"/>
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
assets/icons/scenesPlayIconCheck.png
Normal file
BIN
assets/icons/scenesPlayIconCheck.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
@ -1,30 +0,0 @@
|
|||||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g filter="url(#filter0_d_7280_5211)">
|
|
||||||
<circle cx="18" cy="18" r="15" fill="#F4F4F4"/>
|
|
||||||
</g>
|
|
||||||
<g filter="url(#filter1_i_7280_5211)">
|
|
||||||
<path d="M25.1663 13.187C24.8231 12.8439 24.2666 12.8439 23.9234 13.1871L16.1621 20.9484L12.0766 16.8628C11.7334 16.5196 11.1768 16.5196 10.8336 16.8628C10.4904 17.206 10.4904 17.7625 10.8336 18.1057L15.5406 22.8127C15.7122 22.9844 15.9372 23.0701 16.1621 23.0701C16.3869 23.0701 16.6119 22.9843 16.7835 22.8127L25.1663 14.43C25.5095 14.0868 25.5095 13.5303 25.1663 13.187Z" fill="white"/>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<filter id="filter0_d_7280_5211" x="0" y="0" width="36" height="36" 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.5 0"/>
|
|
||||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7280_5211"/>
|
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7280_5211" result="shape"/>
|
|
||||||
</filter>
|
|
||||||
<filter id="filter1_i_7280_5211" x="10.5762" y="12.9297" width="14.8475" height="10.1406" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
|
||||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
|
||||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
|
||||||
<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="arithmetic" k2="-1" k3="1"/>
|
|
||||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
|
||||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_7280_5211"/>
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.0 KiB |
@ -201,20 +201,17 @@ class ForgetPasswordWebPage extends StatelessWidget {
|
|||||||
!state.isButtonEnabled &&
|
!state.isButtonEnabled &&
|
||||||
state.remainingTime != 1
|
state.remainingTime != 1
|
||||||
? null
|
? null
|
||||||
: () {
|
:
|
||||||
|
() {
|
||||||
if (forgetBloc
|
if (forgetBloc
|
||||||
.forgetEmailKey.currentState!
|
.forgetEmailKey
|
||||||
.validate() ||
|
.currentState!
|
||||||
forgetBloc
|
.validate()) {
|
||||||
.forgetRegionKey.currentState!
|
forgetBloc.add(
|
||||||
.validate()) {
|
StartTimerEvent());
|
||||||
if (forgetBloc
|
|
||||||
.forgetRegionKey.currentState!
|
|
||||||
.validate()) {
|
|
||||||
forgetBloc.add(StartTimerEvent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Text(
|
child: Text(
|
||||||
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
|
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -13,6 +13,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
late AcStatusModel deviceStatus;
|
late AcStatusModel deviceStatus;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
Timer? _countdownTimer;
|
||||||
|
|
||||||
AcBloc({required this.deviceId}) : super(AcsInitialState()) {
|
AcBloc({required this.deviceId}) : super(AcsInitialState()) {
|
||||||
on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
|
on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
|
||||||
@ -21,7 +22,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
on<AcBatchControlEvent>(_onAcBatchControl);
|
on<AcBatchControlEvent>(_onAcBatchControl);
|
||||||
on<AcFactoryResetEvent>(_onFactoryReset);
|
on<AcFactoryResetEvent>(_onFactoryReset);
|
||||||
on<AcStatusUpdated>(_onAcStatusUpdated);
|
on<AcStatusUpdated>(_onAcStatusUpdated);
|
||||||
|
on<OnClose>(_onClose);
|
||||||
|
on<IncreaseTimeEvent>(_handleIncreaseTime);
|
||||||
|
on<DecreaseTimeEvent>(_handleDecreaseTime);
|
||||||
|
on<UpdateTimerEvent>(_handleUpdateTimer);
|
||||||
|
on<ToggleScheduleEvent>(_handleToggleTimer);
|
||||||
|
on<ApiCountdownValueEvent>(_handleApiCountdownValue);
|
||||||
}
|
}
|
||||||
|
bool timerActive = false;
|
||||||
|
int scheduledHours = 0;
|
||||||
|
int scheduledMinutes = 0;
|
||||||
|
|
||||||
FutureOr<void> _onFetchAcStatus(
|
FutureOr<void> _onFetchAcStatus(
|
||||||
AcFetchDeviceStatusEvent event, Emitter<AcsState> emit) async {
|
AcFetchDeviceStatusEvent event, Emitter<AcsState> emit) async {
|
||||||
@ -30,8 +40,23 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
final status =
|
final status =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
if (deviceStatus.countdown1 != 0) {
|
||||||
|
// Convert API value to minutes
|
||||||
|
final totalMinutes = deviceStatus.countdown1 * 6;
|
||||||
|
scheduledHours = totalMinutes ~/ 60;
|
||||||
|
scheduledMinutes = totalMinutes % 60;
|
||||||
|
timerActive = true;
|
||||||
|
_startCountdownTimer(emit);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(ACStatusLoaded(
|
||||||
|
status: deviceStatus,
|
||||||
|
scheduledHours: scheduledHours,
|
||||||
|
scheduledMinutes: scheduledMinutes,
|
||||||
|
isTimerActive: timerActive,
|
||||||
|
));
|
||||||
|
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId);
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(AcsFailedState(error: e.toString()));
|
emit(AcsFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
@ -70,31 +95,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
|
|
||||||
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
void _onAcStatusUpdated(AcStatusUpdated event, Emitter<AcsState> emit) {
|
||||||
deviceStatus = event.deviceStatus;
|
deviceStatus = event.deviceStatus;
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> testFirebaseConnection() async {
|
|
||||||
// // Reference to a test node in your database
|
|
||||||
// final testRef = FirebaseDatabase.instance.ref("test");
|
|
||||||
|
|
||||||
// // Write a test value
|
|
||||||
// await testRef.set("Hello, Firebase!");
|
|
||||||
|
|
||||||
// // Listen for changes on the test node
|
|
||||||
// testRef.onValue.listen((DatabaseEvent event) {
|
|
||||||
// final data = event.snapshot.value;
|
|
||||||
// print("Data from Firebase: $data");
|
|
||||||
// // If you see "Hello, Firebase!" printed in your console, it means the connection works.
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
FutureOr<void> _onAcControl(
|
FutureOr<void> _onAcControl(
|
||||||
AcControlEvent event, Emitter<AcsState> emit) async {
|
AcControlEvent event, Emitter<AcsState> emit) async {
|
||||||
final oldValue = _getValueByCode(event.code);
|
final oldValue = _getValueByCode(event.code);
|
||||||
|
|
||||||
_updateLocalValue(event.code, event.value, emit);
|
_updateLocalValue(event.code, event.value, emit);
|
||||||
|
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
await _runDebounce(
|
||||||
isBatch: false,
|
isBatch: false,
|
||||||
@ -151,7 +161,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
void _revertValueAndEmit(
|
void _revertValueAndEmit(
|
||||||
String deviceId, String code, dynamic oldValue, Emitter<AcsState> emit) {
|
String deviceId, String code, dynamic oldValue, Emitter<AcsState> emit) {
|
||||||
_updateLocalValue(code, oldValue, emit);
|
_updateLocalValue(code, oldValue, emit);
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateLocalValue(String code, dynamic value, Emitter<AcsState> emit) {
|
void _updateLocalValue(String code, dynamic value, Emitter<AcsState> emit) {
|
||||||
@ -184,11 +194,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
if (value is bool) {
|
if (value is bool) {
|
||||||
deviceStatus = deviceStatus.copyWith(childLock: value);
|
deviceStatus = deviceStatus.copyWith(childLock: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'countdown_time':
|
||||||
|
if (value is int) {
|
||||||
|
deviceStatus = deviceStatus.copyWith(countdown1: value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic _getValueByCode(String code) {
|
dynamic _getValueByCode(String code) {
|
||||||
@ -203,6 +218,8 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
return deviceStatus.fanSpeedsString;
|
return deviceStatus.fanSpeedsString;
|
||||||
case 'child_lock':
|
case 'child_lock':
|
||||||
return deviceStatus.childLock;
|
return deviceStatus.childLock;
|
||||||
|
case 'countdown_time':
|
||||||
|
return deviceStatus.countdown1;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -216,7 +233,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
await DevicesManagementApi().getBatchStatus(event.devicesIds);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
AcStatusModel.fromJson(event.devicesIds.first, status.status);
|
AcStatusModel.fromJson(event.devicesIds.first, status.status);
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(AcsFailedState(error: e.toString()));
|
emit(AcsFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
@ -228,7 +245,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
|
|
||||||
_updateLocalValue(event.code, event.value, emit);
|
_updateLocalValue(event.code, event.value, emit);
|
||||||
|
|
||||||
emit(ACStatusLoaded(deviceStatus));
|
emit(ACStatusLoaded(status: deviceStatus));
|
||||||
|
|
||||||
await _runDebounce(
|
await _runDebounce(
|
||||||
isBatch: true,
|
isBatch: true,
|
||||||
@ -257,4 +274,144 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
|
|||||||
emit(AcsFailedState(error: e.toString()));
|
emit(AcsFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onClose(OnClose event, Emitter<AcsState> emit) {
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
_timer?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||||
|
if (state is! ACStatusLoaded) return;
|
||||||
|
final currentState = state as ACStatusLoaded;
|
||||||
|
int newHours = scheduledHours;
|
||||||
|
int newMinutes = scheduledMinutes + 30;
|
||||||
|
newHours += newMinutes ~/ 60;
|
||||||
|
newMinutes = newMinutes % 60;
|
||||||
|
if (newHours > 23) {
|
||||||
|
newHours = 23;
|
||||||
|
newMinutes = 59;
|
||||||
|
}
|
||||||
|
scheduledHours = newHours;
|
||||||
|
scheduledMinutes = newMinutes;
|
||||||
|
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
scheduledHours: scheduledHours,
|
||||||
|
scheduledMinutes: scheduledMinutes,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleDecreaseTime(DecreaseTimeEvent event, Emitter<AcsState> emit) {
|
||||||
|
if (state is! ACStatusLoaded) return;
|
||||||
|
final currentState = state as ACStatusLoaded;
|
||||||
|
int totalMinutes = (scheduledHours * 60) + scheduledMinutes;
|
||||||
|
totalMinutes = (totalMinutes - 30).clamp(0, 1440);
|
||||||
|
scheduledHours = totalMinutes ~/ 60;
|
||||||
|
scheduledMinutes = totalMinutes % 60;
|
||||||
|
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
scheduledHours: scheduledHours,
|
||||||
|
scheduledMinutes: scheduledMinutes,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleToggleTimer(
|
||||||
|
ToggleScheduleEvent event, Emitter<AcsState> emit) async {
|
||||||
|
if (state is! ACStatusLoaded) return;
|
||||||
|
final currentState = state as ACStatusLoaded;
|
||||||
|
|
||||||
|
timerActive = !timerActive;
|
||||||
|
|
||||||
|
if (timerActive) {
|
||||||
|
final totalMinutes = scheduledHours * 60 + scheduledMinutes;
|
||||||
|
if (totalMinutes <= 0) {
|
||||||
|
timerActive = false;
|
||||||
|
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final scaledValue = totalMinutes ~/ 6;
|
||||||
|
await _runDebounce(
|
||||||
|
isBatch: false,
|
||||||
|
deviceId: deviceId,
|
||||||
|
code: 'countdown_time',
|
||||||
|
value: scaledValue,
|
||||||
|
oldValue: scaledValue,
|
||||||
|
emit: emit,
|
||||||
|
);
|
||||||
|
_startCountdownTimer(emit);
|
||||||
|
emit(currentState.copyWith(isTimerActive: timerActive));
|
||||||
|
} catch (e) {
|
||||||
|
timerActive = false;
|
||||||
|
emit(AcsFailedState(error: e.toString()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await _runDebounce(
|
||||||
|
isBatch: false,
|
||||||
|
deviceId: deviceId,
|
||||||
|
code: 'countdown_time',
|
||||||
|
value: 0,
|
||||||
|
oldValue: 0,
|
||||||
|
emit: emit,
|
||||||
|
);
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
scheduledHours = 0;
|
||||||
|
scheduledMinutes = 0;
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
isTimerActive: timerActive,
|
||||||
|
scheduledHours: 0,
|
||||||
|
scheduledMinutes: 0,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startCountdownTimer(Emitter<AcsState> emit) {
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
int totalSeconds = (scheduledHours * 3600) + (scheduledMinutes * 60);
|
||||||
|
|
||||||
|
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
if (totalSeconds > 0) {
|
||||||
|
totalSeconds--;
|
||||||
|
scheduledHours = totalSeconds ~/ 3600;
|
||||||
|
scheduledMinutes = (totalSeconds % 3600) ~/ 60;
|
||||||
|
add(UpdateTimerEvent());
|
||||||
|
} else {
|
||||||
|
_countdownTimer?.cancel();
|
||||||
|
timerActive = false;
|
||||||
|
scheduledHours = 0;
|
||||||
|
scheduledMinutes = 0;
|
||||||
|
add(TimerCompletedEvent());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleUpdateTimer(UpdateTimerEvent event, Emitter<AcsState> emit) {
|
||||||
|
if (state is ACStatusLoaded) {
|
||||||
|
final currentState = state as ACStatusLoaded;
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
scheduledHours: scheduledHours,
|
||||||
|
scheduledMinutes: scheduledMinutes,
|
||||||
|
isTimerActive: timerActive,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleApiCountdownValue(
|
||||||
|
ApiCountdownValueEvent event, Emitter<AcsState> emit) {
|
||||||
|
if (state is ACStatusLoaded) {
|
||||||
|
final totalMinutes = event.apiValue * 6;
|
||||||
|
final scheduledHours = totalMinutes ~/ 60;
|
||||||
|
scheduledMinutes = totalMinutes % 60;
|
||||||
|
_startCountdownTimer(
|
||||||
|
emit,
|
||||||
|
);
|
||||||
|
add(UpdateTimerEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
add(OnClose());
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ sealed class AcsEvent extends Equatable {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class AcUpdated extends AcsEvent {}
|
class AcUpdated extends AcsEvent {}
|
||||||
|
|
||||||
class AcFetchDeviceStatusEvent extends AcsEvent {
|
class AcFetchDeviceStatusEvent extends AcsEvent {
|
||||||
@ -18,10 +19,12 @@ class AcFetchDeviceStatusEvent extends AcsEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId];
|
List<Object> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
class AcStatusUpdated extends AcsEvent {
|
class AcStatusUpdated extends AcsEvent {
|
||||||
final AcStatusModel deviceStatus;
|
final AcStatusModel deviceStatus;
|
||||||
AcStatusUpdated(this.deviceStatus);
|
AcStatusUpdated(this.deviceStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AcFetchBatchStatusEvent extends AcsEvent {
|
class AcFetchBatchStatusEvent extends AcsEvent {
|
||||||
final List<String> devicesIds;
|
final List<String> devicesIds;
|
||||||
|
|
||||||
@ -73,3 +76,30 @@ class AcFactoryResetEvent extends AcsEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId, factoryResetModel];
|
List<Object> get props => [deviceId, factoryResetModel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OnClose extends AcsEvent {}
|
||||||
|
|
||||||
|
class IncreaseTimeEvent extends AcsEvent {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class DecreaseTimeEvent extends AcsEvent {
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ToggleScheduleEvent extends AcsEvent {}
|
||||||
|
|
||||||
|
class TimerCompletedEvent extends AcsEvent {}
|
||||||
|
|
||||||
|
class UpdateTimerEvent extends AcsEvent {
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApiCountdownValueEvent extends AcsEvent {
|
||||||
|
final int apiValue;
|
||||||
|
|
||||||
|
const ApiCountdownValueEvent(this.apiValue);
|
||||||
|
}
|
||||||
|
@ -2,8 +2,9 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
|
||||||
|
|
||||||
abstract class AcsState extends Equatable {
|
abstract class AcsState extends Equatable {
|
||||||
const AcsState();
|
final bool isTimerActive;
|
||||||
|
|
||||||
|
const AcsState({this.isTimerActive = false});
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
@ -15,8 +16,30 @@ class AcsLoadingState extends AcsState {}
|
|||||||
class ACStatusLoaded extends AcsState {
|
class ACStatusLoaded extends AcsState {
|
||||||
final AcStatusModel status;
|
final AcStatusModel status;
|
||||||
final DateTime timestamp;
|
final DateTime timestamp;
|
||||||
|
final int scheduledHours;
|
||||||
|
final int scheduledMinutes;
|
||||||
|
final bool isTimerActive;
|
||||||
|
|
||||||
ACStatusLoaded(this.status) : timestamp = DateTime.now();
|
ACStatusLoaded({
|
||||||
|
required this.status,
|
||||||
|
this.scheduledHours = 0,
|
||||||
|
this.scheduledMinutes = 0,
|
||||||
|
this.isTimerActive = false,
|
||||||
|
}) : timestamp = DateTime.now();
|
||||||
|
ACStatusLoaded copyWith({
|
||||||
|
AcStatusModel? status,
|
||||||
|
int? scheduledHours,
|
||||||
|
int? scheduledMinutes,
|
||||||
|
bool? isTimerActive,
|
||||||
|
int? remainingTime,
|
||||||
|
}) {
|
||||||
|
return ACStatusLoaded(
|
||||||
|
status: status ?? this.status,
|
||||||
|
scheduledHours: scheduledHours ?? this.scheduledHours,
|
||||||
|
scheduledMinutes: scheduledMinutes ?? this.scheduledMinutes,
|
||||||
|
isTimerActive: isTimerActive ?? this.isTimerActive,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [status, timestamp];
|
List<Object> get props => [status, timestamp];
|
||||||
@ -40,3 +63,14 @@ class AcsFailedState extends AcsState {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [error];
|
List<Object> get props => [error];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TimerRunInProgress extends AcsState {
|
||||||
|
final int remainingTime;
|
||||||
|
|
||||||
|
const TimerRunInProgress(this.remainingTime);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [remainingTime];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ class AcStatusModel {
|
|||||||
final bool childLock;
|
final bool childLock;
|
||||||
final TempModes acMode;
|
final TempModes acMode;
|
||||||
final FanSpeeds acFanSpeed;
|
final FanSpeeds acFanSpeed;
|
||||||
|
final int countdown1;
|
||||||
|
|
||||||
AcStatusModel({
|
AcStatusModel({
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
@ -18,6 +19,7 @@ class AcStatusModel {
|
|||||||
required this.modeString,
|
required this.modeString,
|
||||||
required this.tempSet,
|
required this.tempSet,
|
||||||
required this.currentTemp,
|
required this.currentTemp,
|
||||||
|
required this.countdown1,
|
||||||
required this.fanSpeedsString,
|
required this.fanSpeedsString,
|
||||||
required this.childLock,
|
required this.childLock,
|
||||||
}) : acMode = getACMode(modeString),
|
}) : acMode = getACMode(modeString),
|
||||||
@ -30,6 +32,7 @@ class AcStatusModel {
|
|||||||
late int currentTemp;
|
late int currentTemp;
|
||||||
late String fanSpeeds;
|
late String fanSpeeds;
|
||||||
late bool childLock;
|
late bool childLock;
|
||||||
|
late int _countdown1 = 0;
|
||||||
|
|
||||||
for (var status in jsonList) {
|
for (var status in jsonList) {
|
||||||
switch (status.code) {
|
switch (status.code) {
|
||||||
@ -51,6 +54,9 @@ class AcStatusModel {
|
|||||||
case 'child_lock':
|
case 'child_lock':
|
||||||
childLock = status.value ?? false;
|
childLock = status.value ?? false;
|
||||||
break;
|
break;
|
||||||
|
case 'countdown_time':
|
||||||
|
_countdown1 = status.value ?? 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +68,7 @@ class AcStatusModel {
|
|||||||
currentTemp: currentTemp,
|
currentTemp: currentTemp,
|
||||||
fanSpeedsString: fanSpeeds,
|
fanSpeedsString: fanSpeeds,
|
||||||
childLock: childLock,
|
childLock: childLock,
|
||||||
|
countdown1: _countdown1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +80,7 @@ class AcStatusModel {
|
|||||||
int? currentTemp,
|
int? currentTemp,
|
||||||
String? fanSpeedsString,
|
String? fanSpeedsString,
|
||||||
bool? childLock,
|
bool? childLock,
|
||||||
|
int? countdown1,
|
||||||
}) {
|
}) {
|
||||||
return AcStatusModel(
|
return AcStatusModel(
|
||||||
uuid: uuid ?? this.uuid,
|
uuid: uuid ?? this.uuid,
|
||||||
@ -82,6 +90,7 @@ class AcStatusModel {
|
|||||||
currentTemp: currentTemp ?? this.currentTemp,
|
currentTemp: currentTemp ?? this.currentTemp,
|
||||||
fanSpeedsString: fanSpeedsString ?? this.fanSpeedsString,
|
fanSpeedsString: fanSpeedsString ?? this.fanSpeedsString,
|
||||||
childLock: childLock ?? this.childLock,
|
childLock: childLock ?? this.childLock,
|
||||||
|
countdown1: countdown1 ?? this.countdown1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,11 +10,10 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/toggle_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/extension/build_context_x.dart';
|
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||||
const AcDeviceControlsView({super.key, required this.device});
|
const AcDeviceControlsView({super.key, required this.device});
|
||||||
|
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
|
|
||||||
@ -23,11 +22,13 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => AcBloc(deviceId: device.uuid!)
|
create: (context) => AcBloc(deviceId: device.uuid!)
|
||||||
..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
..add(AcFetchDeviceStatusEvent(device.uuid!)),
|
||||||
child: BlocBuilder<AcBloc, AcsState>(
|
child: BlocBuilder<AcBloc, AcsState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
|
final acBloc = BlocProvider.of<AcBloc>(context);
|
||||||
if (state is ACStatusLoaded) {
|
if (state is ACStatusLoaded) {
|
||||||
return GridView(
|
return GridView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||||
@ -78,56 +79,101 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
),
|
),
|
||||||
ToggleWidget(
|
ToggleWidget(
|
||||||
label: '',
|
label: '',
|
||||||
labelWidget: Row(
|
labelWidget: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
Container(
|
||||||
padding: const EdgeInsets.all(0),
|
width: MediaQuery.of(context).size.width,
|
||||||
onPressed: () {},
|
decoration: const ShapeDecoration(
|
||||||
icon: const Icon(
|
color: ColorsManager.primaryColor,
|
||||||
Icons.remove,
|
shape: RoundedRectangleBorder(
|
||||||
size: 28,
|
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||||
color: ColorsManager.greyColor,
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Center(
|
||||||
'06',
|
child: SizedBox(
|
||||||
style: context.textTheme.titleLarge!.copyWith(
|
child: Row(
|
||||||
color: ColorsManager.dialogBlueTitle,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
fontWeight: FontWeight.bold,
|
children: [
|
||||||
),
|
IconButton(
|
||||||
),
|
onPressed: () {
|
||||||
Text(
|
if (acBloc.timerActive == false) {
|
||||||
'h',
|
context
|
||||||
style: context.textTheme.bodySmall!
|
.read<AcBloc>()
|
||||||
.copyWith(color: ColorsManager.blackColor),
|
.add(DecreaseTimeEvent());
|
||||||
),
|
}
|
||||||
Text(
|
},
|
||||||
'30',
|
icon: const Icon(Icons.remove,
|
||||||
style: context.textTheme.titleLarge!.copyWith(
|
color: ColorsManager.greyColor),
|
||||||
color: ColorsManager.dialogBlueTitle,
|
),
|
||||||
fontWeight: FontWeight.bold,
|
Text(
|
||||||
),
|
acBloc.scheduledHours
|
||||||
),
|
.toString()
|
||||||
Text('m',
|
.padLeft(2, '0'),
|
||||||
style: context.textTheme.bodySmall!
|
style: Theme.of(context)
|
||||||
.copyWith(color: ColorsManager.blackColor)),
|
.textTheme
|
||||||
IconButton(
|
.titleLarge!
|
||||||
padding: const EdgeInsets.all(0),
|
.copyWith(
|
||||||
onPressed: () {},
|
color: ColorsManager.dialogBlueTitle,
|
||||||
icon: const Icon(
|
fontWeight: FontWeight.bold,
|
||||||
Icons.add,
|
),
|
||||||
size: 28,
|
),
|
||||||
color: ColorsManager.greyColor,
|
Text(
|
||||||
|
'h',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall!
|
||||||
|
.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
acBloc.scheduledMinutes
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, '0'),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleLarge!
|
||||||
|
.copyWith(
|
||||||
|
color: ColorsManager.dialogBlueTitle,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'm',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall!
|
||||||
|
.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (acBloc.timerActive == false) {
|
||||||
|
context
|
||||||
|
.read<AcBloc>()
|
||||||
|
.add(IncreaseTimeEvent());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.add,
|
||||||
|
color: ColorsManager.greyColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
value: false,
|
value: acBloc.timerActive,
|
||||||
code: 'ac_schedule',
|
code: 'ac_schedule',
|
||||||
deviceId: device.uuid!,
|
deviceId: device.uuid!,
|
||||||
icon: Assets.acSchedule,
|
icon: Assets.acSchedule,
|
||||||
onChange: (value) {},
|
onChange: (value) {
|
||||||
|
context.read<AcBloc>().add(ToggleScheduleEvent());
|
||||||
|
},
|
||||||
),
|
),
|
||||||
ToggleWidget(
|
ToggleWidget(
|
||||||
deviceId: device.uuid!,
|
deviceId: device.uuid!,
|
||||||
|
@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
|||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/three_gang_switch/three_gang_switch.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/two_gang_switch/two_gang_switch.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/gateway.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/enum/device_types.dart';
|
import 'package:syncrow_web/utils/enum/device_types.dart';
|
||||||
@ -247,12 +248,18 @@ SOS
|
|||||||
switch (productType) {
|
switch (productType) {
|
||||||
case 'AC':
|
case 'AC':
|
||||||
return [
|
return [
|
||||||
SwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
SwitchFunction(
|
||||||
ModeFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
TempSetFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
ModeFunction(
|
||||||
CurrentTempFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
LevelFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
TempSetFunction(
|
||||||
ChildLockFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
|
CurrentTempFunction(
|
||||||
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||||
|
LevelFunction(
|
||||||
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
|
ChildLockFunction(
|
||||||
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
];
|
];
|
||||||
|
|
||||||
case '1G':
|
case '1G':
|
||||||
@ -275,44 +282,60 @@ SOS
|
|||||||
case '3G':
|
case '3G':
|
||||||
return [
|
return [
|
||||||
ThreeGangSwitch1Function(
|
ThreeGangSwitch1Function(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
ThreeGangSwitch2Function(
|
ThreeGangSwitch2Function(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
ThreeGangSwitch3Function(
|
ThreeGangSwitch3Function(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
ThreeGangCountdown1Function(
|
ThreeGangCountdown1Function(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
ThreeGangCountdown2Function(
|
ThreeGangCountdown2Function(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
ThreeGangCountdown3Function(
|
ThreeGangCountdown3Function(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? ''),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
];
|
];
|
||||||
case 'WPS':
|
case 'WPS':
|
||||||
return [
|
return [
|
||||||
//IF Functions
|
//IF Functions
|
||||||
PresenceStateFunction(
|
PresenceStateFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||||
CurrentDistanceFunction(
|
CurrentDistanceFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||||
IlluminanceValueFunction(
|
IlluminanceValueFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||||
PresenceTimeFunction(
|
PresenceTimeFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
||||||
|
|
||||||
//THEN Functions
|
//THEN Functions
|
||||||
FarDetectionFunction(
|
FarDetectionFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||||
MotionSensitivityFunction(
|
MotionSensitivityFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||||
MotionLessSensitivityFunction(
|
MotionLessSensitivityFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||||
IndicatorFunction(
|
IndicatorFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
|
||||||
NoOneTimeFunction(
|
NoOneTimeFunction(
|
||||||
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
|
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
|
||||||
|
|
||||||
// FarDetectionSliderFunction(
|
];
|
||||||
// deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN')
|
case 'GW':
|
||||||
|
return [
|
||||||
|
GatewaySwitchAlarmSound(
|
||||||
|
deviceId: uuid ?? '',
|
||||||
|
deviceName: name ?? '',
|
||||||
|
type: 'BOTH',
|
||||||
|
),
|
||||||
|
GatewayMasterState(
|
||||||
|
deviceId: uuid ?? '',
|
||||||
|
deviceName: name ?? '',
|
||||||
|
type: 'BOTH',
|
||||||
|
),
|
||||||
|
GatewayFactoryReset(
|
||||||
|
deviceId: uuid ?? '',
|
||||||
|
deviceName: name ?? '',
|
||||||
|
type: 'BOTH',
|
||||||
|
),
|
||||||
];
|
];
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
|
@ -2,14 +2,17 @@ import 'package:flutter/foundation.dart';
|
|||||||
|
|
||||||
class FactoryResetModel {
|
class FactoryResetModel {
|
||||||
final List<String> devicesUuid;
|
final List<String> devicesUuid;
|
||||||
|
final String operationType;
|
||||||
|
|
||||||
FactoryResetModel({
|
FactoryResetModel({
|
||||||
required this.devicesUuid,
|
required this.devicesUuid,
|
||||||
|
this.operationType = "RESET",
|
||||||
});
|
});
|
||||||
|
|
||||||
factory FactoryResetModel.fromJson(Map<String, dynamic> json) {
|
factory FactoryResetModel.fromJson(Map<String, dynamic> json) {
|
||||||
return FactoryResetModel(
|
return FactoryResetModel(
|
||||||
devicesUuid: List<String>.from(json['devicesUuid']),
|
devicesUuid: List<String>.from(json['devicesUuid']),
|
||||||
|
operationType: "RESET",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,77 +12,68 @@ class DeviceSearchFilters extends StatefulWidget {
|
|||||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||||
final TextEditingController communityController = TextEditingController();
|
with HelperResponsiveLayout {
|
||||||
final TextEditingController unitNameController = TextEditingController();
|
final _unitNameController = TextEditingController();
|
||||||
final TextEditingController productNameController = TextEditingController();
|
final _productNameController = TextEditingController();
|
||||||
|
|
||||||
|
List<Widget> get _widgets => [
|
||||||
|
_buildSearchField("Space Name", _unitNameController, 200),
|
||||||
|
_buildSearchField("Device Name / Product Name", _productNameController, 300),
|
||||||
|
_buildSearchResetButtons(),
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return isExtraLargeScreenSize(context)
|
if (isExtraLargeScreenSize(context)) {
|
||||||
? Row(
|
return Row(
|
||||||
children: [
|
children: _widgets
|
||||||
_buildSearchField("Community", communityController, 200),
|
.map((e) => Padding(padding: const EdgeInsets.all(10), child: e))
|
||||||
const SizedBox(width: 20),
|
.toList(),
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
);
|
||||||
const SizedBox(width: 20),
|
}
|
||||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
|
||||||
const SizedBox(width: 20),
|
return Wrap(
|
||||||
_buildSearchResetButtons(),
|
spacing: 20,
|
||||||
],
|
runSpacing: 10,
|
||||||
)
|
children: _widgets,
|
||||||
: Wrap(
|
);
|
||||||
spacing: 20,
|
|
||||||
runSpacing: 10,
|
|
||||||
children: [
|
|
||||||
_buildSearchField(
|
|
||||||
"Community",
|
|
||||||
communityController,
|
|
||||||
200,
|
|
||||||
),
|
|
||||||
_buildSearchField("Space Name", unitNameController, 200),
|
|
||||||
_buildSearchField(
|
|
||||||
"Device Name / Product Name",
|
|
||||||
productNameController,
|
|
||||||
300,
|
|
||||||
),
|
|
||||||
_buildSearchResetButtons(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
Widget _buildSearchField(
|
||||||
return Container(
|
String title,
|
||||||
child: StatefulTextField(
|
TextEditingController controller,
|
||||||
title: title,
|
double width,
|
||||||
width: width,
|
) {
|
||||||
elevation: 2,
|
return StatefulTextField(
|
||||||
controller: controller,
|
title: title,
|
||||||
onSubmitted: () {
|
width: width,
|
||||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
elevation: 2,
|
||||||
productName: productNameController.text,
|
controller: controller,
|
||||||
unitName: unitNameController.text,
|
onSubmitted: () {
|
||||||
community: communityController.text,
|
final searchDevicesEvent = SearchDevices(
|
||||||
searchField: true));
|
productName: _productNameController.text,
|
||||||
},
|
unitName: _unitNameController.text,
|
||||||
onChanged: (p0) {},
|
searchField: true,
|
||||||
),
|
);
|
||||||
|
context.read<DeviceManagementBloc>().add(searchDevicesEvent);
|
||||||
|
},
|
||||||
|
onChanged: (p0) {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchResetButtons() {
|
Widget _buildSearchResetButtons() {
|
||||||
return SearchResetButtons(
|
return SearchResetButtons(
|
||||||
onSearch: () {
|
onSearch: () => context.read<DeviceManagementBloc>().add(
|
||||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
SearchDevices(
|
||||||
community: communityController.text,
|
unitName: _unitNameController.text,
|
||||||
unitName: unitNameController.text,
|
productName: _productNameController.text,
|
||||||
productName: productNameController.text,
|
searchField: true,
|
||||||
searchField: true));
|
),
|
||||||
},
|
),
|
||||||
onReset: () {
|
onReset: () {
|
||||||
communityController.clear();
|
_unitNameController.clear();
|
||||||
unitNameController.clear();
|
_productNameController.clear();
|
||||||
productNameController.clear();
|
|
||||||
context.read<DeviceManagementBloc>()
|
context.read<DeviceManagementBloc>()
|
||||||
..add(ResetFilters())
|
..add(ResetFilters())
|
||||||
..add(FetchDevices(context));
|
..add(FetchDevices(context));
|
||||||
|
49
lib/pages/device_managment/gateway/model/gateway_model.dart
Normal file
49
lib/pages/device_managment/gateway/model/gateway_model.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
class GatewayModel {
|
||||||
|
final String uuid;
|
||||||
|
final bool switchAlarmSound;
|
||||||
|
final String masterState;
|
||||||
|
final bool factoryReset;
|
||||||
|
final String alarmActive;
|
||||||
|
|
||||||
|
GatewayModel({
|
||||||
|
required this.uuid,
|
||||||
|
required this.switchAlarmSound,
|
||||||
|
required this.masterState,
|
||||||
|
required this.factoryReset,
|
||||||
|
required this.alarmActive,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory GatewayModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
final status = json['status'] as List<dynamic>? ?? <dynamic>[];
|
||||||
|
|
||||||
|
bool? switchAlarmSound;
|
||||||
|
String? masterState;
|
||||||
|
bool? factoryReset;
|
||||||
|
String? alarmActive;
|
||||||
|
|
||||||
|
for (final item in status) {
|
||||||
|
switch (item['code']) {
|
||||||
|
case 'switch_alarm_sound':
|
||||||
|
switchAlarmSound = item['value'] as bool;
|
||||||
|
break;
|
||||||
|
case 'master_state':
|
||||||
|
masterState = item['value'] as String;
|
||||||
|
break;
|
||||||
|
case 'factory_reset':
|
||||||
|
factoryReset = item['value'] as bool;
|
||||||
|
break;
|
||||||
|
case 'alarm_active':
|
||||||
|
alarmActive = item['value'] as String;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GatewayModel(
|
||||||
|
uuid: json['uuid'] as String? ?? '',
|
||||||
|
switchAlarmSound: switchAlarmSound ?? false,
|
||||||
|
masterState: masterState ?? '',
|
||||||
|
factoryReset: factoryReset ?? false,
|
||||||
|
alarmActive: alarmActive ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -62,9 +62,6 @@ class ToggleWidget extends StatelessWidget {
|
|||||||
)),
|
)),
|
||||||
if (showToggle)
|
if (showToggle)
|
||||||
Container(
|
Container(
|
||||||
height: 20,
|
|
||||||
width: 35,
|
|
||||||
padding: const EdgeInsets.only(right: 16, top: 10),
|
|
||||||
child: CupertinoSwitch(
|
child: CupertinoSwitch(
|
||||||
value: value,
|
value: value,
|
||||||
activeColor: ColorsManager.dialogBlueTitle,
|
activeColor: ColorsManager.dialogBlueTitle,
|
||||||
|
@ -13,7 +13,8 @@ import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_la
|
|||||||
|
|
||||||
import '../models/sos_status_model.dart';
|
import '../models/sos_status_model.dart';
|
||||||
|
|
||||||
class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
class SosDeviceControlsView extends StatelessWidget
|
||||||
|
with HelperResponsiveLayout {
|
||||||
const SosDeviceControlsView({
|
const SosDeviceControlsView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.device,
|
required this.device,
|
||||||
@ -24,7 +25,8 @@ class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => SosDeviceBloc()..add(GetDeviceStatus(device.uuid!)),
|
create: (context) =>
|
||||||
|
SosDeviceBloc()..add(GetDeviceStatus(device.uuid!)),
|
||||||
child: BlocBuilder<SosDeviceBloc, SosDeviceState>(
|
child: BlocBuilder<SosDeviceBloc, SosDeviceState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is SosDeviceLoadingState) {
|
if (state is SosDeviceLoadingState) {
|
||||||
@ -63,7 +65,8 @@ class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatusControls(BuildContext context, SosStatusModel deviceStatus) {
|
Widget _buildStatusControls(
|
||||||
|
BuildContext context, SosStatusModel deviceStatus) {
|
||||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||||
final isLarge = isLargeScreenSize(context);
|
final isLarge = isLargeScreenSize(context);
|
||||||
final isMedium = isMediumScreenSize(context);
|
final isMedium = isMediumScreenSize(context);
|
||||||
@ -85,7 +88,7 @@ class SosDeviceControlsView extends StatelessWidget with HelperResponsiveLayout
|
|||||||
IconNameStatusContainer(
|
IconNameStatusContainer(
|
||||||
isFullIcon: false,
|
isFullIcon: false,
|
||||||
name: deviceStatus.sosStatus == 'sos' ? 'SOS' : 'Normal',
|
name: deviceStatus.sosStatus == 'sos' ? 'SOS' : 'Normal',
|
||||||
icon: deviceStatus.sosStatus == 'sos' ? Assets.sos : Assets.sosNormal,
|
icon: deviceStatus.sosStatus == 'sos' ? Assets.sosNormal : Assets.sos,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
status: false,
|
status: false,
|
||||||
textColor: ColorsManager.blackColor,
|
textColor: ColorsManager.blackColor,
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.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/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
|
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_state.dart';
|
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_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/services/space_mana_api.dart';
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
|
|
||||||
@ -10,11 +11,12 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
|
|||||||
on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices);
|
on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices);
|
||||||
on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId);
|
on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId);
|
||||||
on<ResetSelectedEvent>(resetSelected);
|
on<ResetSelectedEvent>(resetSelected);
|
||||||
|
on<FetchCommunityEvent>(_fetchCommunity);
|
||||||
}
|
}
|
||||||
|
|
||||||
String selectedSpaceId = '';
|
String selectedSpaceId = '';
|
||||||
String selectedCommunityId = '';
|
String selectedCommunityId = '';
|
||||||
|
List<CommunityModel> communities = [];
|
||||||
List<SpaceModel> spacesOnlyWithDevices = [];
|
List<SpaceModel> spacesOnlyWithDevices = [];
|
||||||
|
|
||||||
Future<void> _fetchSpaceOnlyWithDevices(
|
Future<void> _fetchSpaceOnlyWithDevices(
|
||||||
@ -30,7 +32,7 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
|
|||||||
|
|
||||||
emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices));
|
emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
emit(SpaceTreeErrorState('Error loading spaces: $e'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,4 +50,18 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
|
|||||||
selectedCommunityId = '';
|
selectedCommunityId = '';
|
||||||
emit(const ResetSelectedState());
|
emit(const ResetSelectedState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchCommunity(
|
||||||
|
FetchCommunityEvent event, Emitter<CreateRoutineState> emit) async {
|
||||||
|
emit(const CommunitiesLoadingState());
|
||||||
|
|
||||||
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
communities =
|
||||||
|
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
||||||
|
emit(const CommunityLoadedState());
|
||||||
|
} catch (e) {
|
||||||
|
emit(SpaceTreeErrorState('Error loading communities $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,3 +41,11 @@ class ResetSelectedEvent extends CreateRoutineEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FetchCommunityEvent extends CreateRoutineEvent {
|
||||||
|
const FetchCommunityEvent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
@ -44,3 +44,10 @@ class ResetSelectedState extends CreateRoutineState {
|
|||||||
const ResetSelectedState();
|
const ResetSelectedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CommunityLoadedState extends CreateRoutineState {
|
||||||
|
const CommunityLoadedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommunitiesLoadingState extends CreateRoutineState {
|
||||||
|
const CommunitiesLoadingState();
|
||||||
|
}
|
@ -1,19 +1,19 @@
|
|||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
|
||||||
|
|
||||||
class CommunityDropdown extends StatelessWidget {
|
class CommunityDropdown extends StatelessWidget {
|
||||||
final String? selectedValue;
|
final String? selectedValue;
|
||||||
|
final List<CommunityModel> communities;
|
||||||
final Function(String?) onChanged;
|
final Function(String?) onChanged;
|
||||||
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
|
||||||
const CommunityDropdown({
|
CommunityDropdown({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.selectedValue,
|
required this.selectedValue,
|
||||||
required this.onChanged,
|
required this.onChanged,
|
||||||
|
required this.communities,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -32,63 +32,123 @@ class CommunityDropdown extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
BlocBuilder<SpaceTreeBloc, SpaceTreeState>(
|
SizedBox(
|
||||||
builder: (context, state) {
|
child: Container(
|
||||||
List<CommunityModel> communities = state.isSearching
|
decoration: BoxDecoration(
|
||||||
? state.filteredCommunity
|
borderRadius: BorderRadius.circular(10),
|
||||||
: state.communityList;
|
),
|
||||||
|
child: DropdownButton2<String>(
|
||||||
return SizedBox(
|
underline: const SizedBox(),
|
||||||
child: DropdownButtonFormField<String>(
|
value: selectedValue,
|
||||||
dropdownColor: ColorsManager.whiteColors,
|
items: communities.map((community) {
|
||||||
value: selectedValue,
|
return DropdownMenuItem<String>(
|
||||||
items: communities.map((community) {
|
value: community.uuid,
|
||||||
return DropdownMenuItem<String>(
|
child: Text(
|
||||||
value: community.uuid,
|
' ${community.name}',
|
||||||
child: Text(' ${community.name}'),
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
maxLines: 1,
|
||||||
}).toList(),
|
|
||||||
onChanged: onChanged,
|
|
||||||
icon: const SizedBox.shrink(),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
|
||||||
hint: Padding(
|
|
||||||
padding: EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
"Please Select",
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
decoration: inputTextFormDeco().copyWith(
|
);
|
||||||
contentPadding: EdgeInsets.zero,
|
}).toList(),
|
||||||
suffixIcon: Container(
|
onChanged: onChanged,
|
||||||
padding: EdgeInsets.zero,
|
style: const TextStyle(color: Colors.black),
|
||||||
width: 70,
|
hint: Padding(
|
||||||
height: 45,
|
padding: const EdgeInsets.only(left: 10),
|
||||||
decoration: BoxDecoration(
|
child: Text(
|
||||||
color: Colors.grey[100],
|
" Please Select",
|
||||||
borderRadius: const BorderRadius.only(
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
bottomRight: Radius.circular(10),
|
color: ColorsManager.textGray,
|
||||||
topRight: Radius.circular(10),
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
width: 1.0,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
child: const Center(
|
),
|
||||||
child: Icon(
|
),
|
||||||
|
customButton: Container(
|
||||||
|
height: 45,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(color: ColorsManager.textGray, width: 1.0),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Text(
|
||||||
|
selectedValue != null
|
||||||
|
? " ${communities.firstWhere((element) => element.uuid == selectedValue).name}"
|
||||||
|
: ' Please Select',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: selectedValue != null
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[100],
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 45,
|
||||||
|
child: const Icon(
|
||||||
Icons.keyboard_arrow_down,
|
Icons.keyboard_arrow_down,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownStyleData: DropdownStyleData(
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownSearchData: DropdownSearchData(
|
||||||
|
searchController: _searchController,
|
||||||
|
searchInnerWidgetHeight: 50,
|
||||||
|
searchInnerWidget: Container(
|
||||||
|
height: 50,
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
|
child: TextFormField(
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
controller: _searchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
|
hintText: 'Search for community...',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
searchMatchFn: (item, searchValue) {
|
||||||
},
|
final communityName =
|
||||||
),
|
(item.child as Text).data?.toLowerCase() ?? '';
|
||||||
|
return communityName
|
||||||
|
.contains(searchValue.toLowerCase().trim());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
onMenuStateChange: (isOpen) {
|
||||||
|
if (!isOpen) {
|
||||||
|
_searchController.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -5,11 +5,10 @@ import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routi
|
|||||||
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/create_new_routines/commu_dropdown.dart';
|
import 'package:syncrow_web/pages/routines/create_new_routines/commu_dropdown.dart';
|
||||||
import 'package:syncrow_web/pages/routines/create_new_routines/space_dropdown.dart';
|
import 'package:syncrow_web/pages/routines/create_new_routines/space_dropdown.dart';
|
||||||
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CreateNewRoutinesDialog extends StatefulWidget {
|
class CreateNewRoutinesDialog extends StatefulWidget {
|
||||||
const CreateNewRoutinesDialog({Key? key}) : super(key: key);
|
const CreateNewRoutinesDialog({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CreateNewRoutinesDialog> createState() =>
|
State<CreateNewRoutinesDialog> createState() =>
|
||||||
@ -19,130 +18,160 @@ class CreateNewRoutinesDialog extends StatefulWidget {
|
|||||||
class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
|
class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
|
||||||
String? _selectedCommunity;
|
String? _selectedCommunity;
|
||||||
String? _selectedSpace;
|
String? _selectedSpace;
|
||||||
void _fetchSpaces(String communityId) {
|
|
||||||
context
|
|
||||||
.read<CreateRoutineBloc>()
|
|
||||||
.add(SpaceOnlyWithDevicesEvent(communityId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
|
return BlocProvider(
|
||||||
builder: (context, state) {
|
create: (BuildContext context) =>
|
||||||
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
|
CreateRoutineBloc()..add(const FetchCommunityEvent()),
|
||||||
final spaces = _bloc.spacesOnlyWithDevices;
|
child: BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
|
||||||
final isLoading = state is SpaceWithDeviceLoadingState;
|
builder: (context, state) {
|
||||||
|
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
|
||||||
|
final spaces = _bloc.spacesOnlyWithDevices;
|
||||||
|
final isLoadingCommunities = state is CommunitiesLoadingState;
|
||||||
|
final isLoadingSpaces = state is SpaceWithDeviceLoadingState;
|
||||||
|
String spaceHint = 'Select a community first';
|
||||||
|
if (_selectedCommunity != null) {
|
||||||
|
if (isLoadingSpaces) {
|
||||||
|
spaceHint = 'Loading spaces...';
|
||||||
|
} else if (spaces.isEmpty) {
|
||||||
|
spaceHint = 'No spaces available';
|
||||||
|
} else {
|
||||||
|
spaceHint = 'Select Space';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String spaceHint = 'Select a community first';
|
return AlertDialog(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
if (_selectedCommunity != null) {
|
insetPadding: EdgeInsets.zero,
|
||||||
if (isLoading) {
|
contentPadding: EdgeInsets.zero,
|
||||||
spaceHint = 'Loading spaces...';
|
shape: RoundedRectangleBorder(
|
||||||
} else if (spaces.isEmpty) {
|
borderRadius: BorderRadius.circular(12)),
|
||||||
spaceHint = 'No spaces available';
|
title: Text(
|
||||||
} else {
|
'Create New Routines',
|
||||||
spaceHint = 'Select Space';
|
textAlign: TextAlign.center,
|
||||||
}
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
}
|
color: ColorsManager.primaryColor,
|
||||||
|
),
|
||||||
return AlertDialog(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
insetPadding: EdgeInsets.zero,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
shape:
|
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
||||||
title: Text(
|
|
||||||
'Create New Routines',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
color: ColorsManager.primaryColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
const Divider(),
|
|
||||||
CommunityDropdown(
|
|
||||||
selectedValue: _selectedCommunity,
|
|
||||||
onChanged: (String? newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedCommunity = newValue;
|
|
||||||
_selectedSpace = null;
|
|
||||||
});
|
|
||||||
if (newValue != null) {
|
|
||||||
_fetchSpaces(newValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
content: Stack(
|
||||||
SpaceDropdown(
|
|
||||||
hintMessage: spaceHint,
|
|
||||||
spaces: spaces,
|
|
||||||
selectedValue: _selectedSpace,
|
|
||||||
onChanged: (String? newValue) {
|
|
||||||
setState(() {
|
|
||||||
_selectedSpace = newValue;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Column(
|
||||||
padding: const EdgeInsets.only(
|
mainAxisSize: MainAxisSize.min,
|
||||||
left: 20,
|
children: [
|
||||||
right: 20,
|
const Divider(),
|
||||||
),
|
Padding(
|
||||||
child: TextButton(
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
onPressed: () {
|
child: CommunityDropdown(
|
||||||
|
communities: _bloc.communities,
|
||||||
Navigator.of(context).pop();
|
selectedValue: _selectedCommunity,
|
||||||
},
|
onChanged: (String? newValue) {
|
||||||
child: Text(
|
setState(() {
|
||||||
'Cancel',
|
_selectedCommunity = newValue;
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
_selectedSpace = null;
|
||||||
fontWeight: FontWeight.w400,
|
});
|
||||||
fontSize: 14,
|
if (newValue != null) {
|
||||||
color: ColorsManager.blackColor,
|
_bloc.add(SpaceOnlyWithDevicesEvent(newValue));
|
||||||
),
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 5),
|
||||||
),
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
padding: const EdgeInsets.only(
|
child: SpaceDropdown(
|
||||||
left: 20,
|
hintMessage: spaceHint,
|
||||||
right: 20,
|
spaces: spaces,
|
||||||
),
|
selectedValue: _selectedSpace,
|
||||||
child: TextButton(
|
onChanged: (String? newValue) {
|
||||||
onPressed:
|
setState(() {
|
||||||
_selectedCommunity != null && _selectedSpace != null
|
_selectedSpace = newValue;
|
||||||
? () {
|
});
|
||||||
Navigator.of(context).pop({
|
},
|
||||||
'community': _selectedCommunity,
|
),
|
||||||
'space': _selectedSpace,
|
),
|
||||||
});
|
const Divider(),
|
||||||
}
|
Row(
|
||||||
: null,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
child: Text(
|
children: [
|
||||||
'Next',
|
Padding(
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
padding: const EdgeInsets.only(
|
||||||
fontWeight: FontWeight.w400,
|
left: 20,
|
||||||
fontSize: 14,
|
right: 20,
|
||||||
color: _selectedCommunity != null &&
|
),
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'Cancel',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium!
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14,
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
),
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: _selectedCommunity != null &&
|
||||||
_selectedSpace != null
|
_selectedSpace != null
|
||||||
? ColorsManager.blueColor
|
? () {
|
||||||
: Colors.blue.shade100,
|
Navigator.of(context).pop({
|
||||||
|
'community': _selectedCommunity,
|
||||||
|
'space': _selectedSpace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Text(
|
||||||
|
'Next',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium!
|
||||||
|
.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14,
|
||||||
|
color: _selectedCommunity != null &&
|
||||||
|
_selectedSpace != null
|
||||||
|
? ColorsManager.blueColor
|
||||||
|
: Colors.blue.shade100,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (isLoadingCommunities)
|
||||||
|
const SizedBox(
|
||||||
|
height: 200,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: ColorsManager.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
),
|
},
|
||||||
);
|
));
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
|
||||||
|
|
||||||
class SpaceDropdown extends StatelessWidget {
|
class SpaceDropdown extends StatelessWidget {
|
||||||
final List<SpaceModel> spaces;
|
final List<SpaceModel> spaces;
|
||||||
@ -33,62 +34,108 @@ class SpaceDropdown extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
DropdownButtonFormField<String>(
|
SizedBox(
|
||||||
value: selectedValue,
|
child: Container(
|
||||||
items: spaces.map((space) {
|
decoration: BoxDecoration(
|
||||||
return DropdownMenuItem<String>(
|
borderRadius: BorderRadius.circular(10),
|
||||||
value: space.uuid,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
' ${space.name}',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
' ${space.lastThreeParents}',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}).toList(),
|
|
||||||
onChanged: onChanged,
|
|
||||||
icon: const SizedBox.shrink(),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
|
||||||
hint: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
hintMessage,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
child: DropdownButton2<String>(
|
||||||
decoration: inputTextFormDeco().copyWith(
|
underline: const SizedBox(),
|
||||||
contentPadding: EdgeInsets.zero,
|
value: selectedValue,
|
||||||
suffixIcon: Container(
|
items: spaces.map((space) {
|
||||||
width: 70,
|
return DropdownMenuItem<String>(
|
||||||
height: 45,
|
value: space.uuid,
|
||||||
decoration: BoxDecoration(
|
child: Column(
|
||||||
color: Colors.grey[200],
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
borderRadius: const BorderRadius.only(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
bottomRight: Radius.circular(10),
|
children: [
|
||||||
topRight: Radius.circular(10),
|
Text(
|
||||||
),
|
' ${space.name}',
|
||||||
border: Border.all(
|
style:
|
||||||
color: ColorsManager.textGray,
|
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
width: 1.0,
|
fontSize: 12,
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
' ${space.lastThreeParents}',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: onChanged,
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
hint: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
hintMessage,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: const Icon(
|
customButton: Container(
|
||||||
Icons.keyboard_arrow_down,
|
height: 45,
|
||||||
color: ColorsManager.textGray,
|
decoration: BoxDecoration(
|
||||||
|
border:
|
||||||
|
Border.all(color: ColorsManager.textGray, width: 1.0),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
selectedValue != null
|
||||||
|
? spaces
|
||||||
|
.firstWhere((e) => e.uuid == selectedValue)
|
||||||
|
.name
|
||||||
|
: hintMessage,
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: selectedValue != null
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 45,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownStyleData: DropdownStyleData(
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 60,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
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/routines/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ac_dialog.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ac_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/three_gang_switch_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/two_gang_switch_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wall_presence_sensor.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wall_presence_sensor.dart';
|
||||||
|
|
||||||
class DeviceDialogHelper {
|
class DeviceDialogHelper {
|
||||||
@ -49,45 +50,45 @@ class DeviceDialogHelper {
|
|||||||
final deviceSelectedFunctions =
|
final deviceSelectedFunctions =
|
||||||
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
|
||||||
|
|
||||||
if (removeComparetors && data['productType'] != 'WPS') {
|
|
||||||
//remove the current temp function in the 'if container'
|
|
||||||
functions.removeAt(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (productType) {
|
switch (productType) {
|
||||||
case 'AC':
|
case 'AC':
|
||||||
return ACHelper.showACFunctionsDialog(
|
return ACHelper.showACFunctionsDialog(
|
||||||
context,
|
context: context,
|
||||||
functions,
|
functions: functions,
|
||||||
data['device'],
|
device: data['device'],
|
||||||
deviceSelectedFunctions,
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
data['uniqueCustomId'],
|
uniqueCustomId: data['uniqueCustomId'],
|
||||||
removeComparetors);
|
removeComparetors: removeComparetors,
|
||||||
|
dialogType: dialogType,
|
||||||
|
);
|
||||||
|
|
||||||
case '1G':
|
case '1G':
|
||||||
return OneGangSwitchHelper.showSwitchFunctionsDialog(
|
return OneGangSwitchHelper.showSwitchFunctionsDialog(
|
||||||
context,
|
dialogType: dialogType,
|
||||||
functions,
|
context: context,
|
||||||
data['device'],
|
functions: functions,
|
||||||
deviceSelectedFunctions,
|
device: data['device'],
|
||||||
data['uniqueCustomId'],
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
removeComparetors);
|
uniqueCustomId: data['uniqueCustomId'],
|
||||||
|
removeComparetors: removeComparetors);
|
||||||
case '2G':
|
case '2G':
|
||||||
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
|
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
|
||||||
context,
|
dialogType: dialogType,
|
||||||
functions,
|
context: context,
|
||||||
data['device'],
|
functions: functions,
|
||||||
deviceSelectedFunctions,
|
device: data['device'],
|
||||||
data['uniqueCustomId'],
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
removeComparetors);
|
uniqueCustomId: data['uniqueCustomId'],
|
||||||
|
removeComparetors: removeComparetors);
|
||||||
case '3G':
|
case '3G':
|
||||||
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
|
||||||
context,
|
dialogType: dialogType,
|
||||||
functions,
|
context: context,
|
||||||
data['device'],
|
functions: functions,
|
||||||
deviceSelectedFunctions,
|
device: data['device'],
|
||||||
data['uniqueCustomId'],
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
removeComparetors);
|
uniqueCustomId: data['uniqueCustomId'],
|
||||||
|
removeComparetors: removeComparetors);
|
||||||
case 'WPS':
|
case 'WPS':
|
||||||
return WallPresenceSensor.showWPSFunctionsDialog(
|
return WallPresenceSensor.showWPSFunctionsDialog(
|
||||||
dialogType: dialogType,
|
dialogType: dialogType,
|
||||||
@ -97,6 +98,15 @@ class DeviceDialogHelper {
|
|||||||
deviceSelectedFunctions: deviceSelectedFunctions,
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
uniqueCustomId: data['uniqueCustomId'],
|
uniqueCustomId: data['uniqueCustomId'],
|
||||||
removeComparetors: removeComparetors);
|
removeComparetors: removeComparetors);
|
||||||
|
case 'GW':
|
||||||
|
return GatewayHelper.showGatewayFunctionsDialog(
|
||||||
|
context: context,
|
||||||
|
functions: functions,
|
||||||
|
uniqueCustomId: data['uniqueCustomId'],
|
||||||
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
|
device: data['device'],
|
||||||
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,28 @@ import 'package:syncrow_web/utils/constants/app_enum.dart';
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
abstract class ACFunction extends DeviceFunction<AcStatusModel> {
|
abstract class ACFunction extends DeviceFunction<AcStatusModel> {
|
||||||
|
final String type;
|
||||||
|
|
||||||
ACFunction({
|
ACFunction({
|
||||||
required super.deviceId,
|
required super.deviceId,
|
||||||
required super.deviceName,
|
required super.deviceName,
|
||||||
required super.code,
|
required super.code,
|
||||||
required super.operationName,
|
required super.operationName,
|
||||||
required super.icon,
|
required super.icon,
|
||||||
|
required this.type,
|
||||||
});
|
});
|
||||||
|
|
||||||
List<ACOperationalValue> getOperationalValues();
|
List<ACOperationalValue> getOperationalValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
class SwitchFunction extends ACFunction {
|
class SwitchFunction extends ACFunction {
|
||||||
SwitchFunction({required super.deviceId, required super.deviceName})
|
SwitchFunction(
|
||||||
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'switch',
|
code: 'switch',
|
||||||
operationName: 'Power',
|
operationName: 'Power',
|
||||||
icon: Assets.assetsAcPower,
|
icon: Assets.assetsAcPower,
|
||||||
|
type: type,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -40,11 +45,13 @@ class SwitchFunction extends ACFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ModeFunction extends ACFunction {
|
class ModeFunction extends ACFunction {
|
||||||
ModeFunction({required super.deviceId, required super.deviceName})
|
ModeFunction(
|
||||||
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'mode',
|
code: 'mode',
|
||||||
operationName: 'Mode',
|
operationName: 'Mode',
|
||||||
icon: Assets.assetsFreezing,
|
icon: Assets.assetsFreezing,
|
||||||
|
type: type,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -72,7 +79,8 @@ class TempSetFunction extends ACFunction {
|
|||||||
final int max;
|
final int max;
|
||||||
final int step;
|
final int step;
|
||||||
|
|
||||||
TempSetFunction({required super.deviceId, required super.deviceName})
|
TempSetFunction(
|
||||||
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
: min = 160,
|
: min = 160,
|
||||||
max = 300,
|
max = 300,
|
||||||
step = 1,
|
step = 1,
|
||||||
@ -80,6 +88,7 @@ class TempSetFunction extends ACFunction {
|
|||||||
code: 'temp_set',
|
code: 'temp_set',
|
||||||
operationName: 'Set Temperature',
|
operationName: 'Set Temperature',
|
||||||
icon: Assets.assetsTempreture,
|
icon: Assets.assetsTempreture,
|
||||||
|
type: type,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -97,8 +106,10 @@ class TempSetFunction extends ACFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class LevelFunction extends ACFunction {
|
class LevelFunction extends ACFunction {
|
||||||
LevelFunction({required super.deviceId, required super.deviceName})
|
LevelFunction(
|
||||||
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
: super(
|
: super(
|
||||||
|
type: type,
|
||||||
code: 'level',
|
code: 'level',
|
||||||
operationName: 'Fan Speed',
|
operationName: 'Fan Speed',
|
||||||
icon: Assets.assetsFanSpeed,
|
icon: Assets.assetsFanSpeed,
|
||||||
@ -130,8 +141,10 @@ class LevelFunction extends ACFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ChildLockFunction extends ACFunction {
|
class ChildLockFunction extends ACFunction {
|
||||||
ChildLockFunction({required super.deviceId, required super.deviceName})
|
ChildLockFunction(
|
||||||
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
: super(
|
: super(
|
||||||
|
type: type,
|
||||||
code: 'child_lock',
|
code: 'child_lock',
|
||||||
operationName: 'Child Lock',
|
operationName: 'Child Lock',
|
||||||
icon: Assets.assetsChildLock,
|
icon: Assets.assetsChildLock,
|
||||||
@ -157,11 +170,13 @@ class CurrentTempFunction extends ACFunction {
|
|||||||
final int max;
|
final int max;
|
||||||
final int step;
|
final int step;
|
||||||
|
|
||||||
CurrentTempFunction({required super.deviceId, required super.deviceName})
|
CurrentTempFunction(
|
||||||
|
{required super.deviceId, required super.deviceName, required type})
|
||||||
: min = -100,
|
: min = -100,
|
||||||
max = 990,
|
max = 990,
|
||||||
step = 1,
|
step = 1,
|
||||||
super(
|
super(
|
||||||
|
type: type,
|
||||||
code: 'temp_current',
|
code: 'temp_current',
|
||||||
operationName: 'Current Temperature',
|
operationName: 'Current Temperature',
|
||||||
icon: Assets.currentTemp,
|
icon: Assets.currentTemp,
|
||||||
|
@ -3,7 +3,7 @@ import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operation
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
||||||
ThreeGangSwitch1Function({required super.deviceId, required super.deviceName})
|
ThreeGangSwitch1Function({required super.deviceId, required super.deviceName ,required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'switch_1',
|
code: 'switch_1',
|
||||||
operationName: 'Light 1 Switch',
|
operationName: 'Light 1 Switch',
|
||||||
@ -26,7 +26,7 @@ class ThreeGangSwitch1Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangCountdown1Function extends BaseSwitchFunction {
|
class ThreeGangCountdown1Function extends BaseSwitchFunction {
|
||||||
ThreeGangCountdown1Function({required super.deviceId, required super.deviceName})
|
ThreeGangCountdown1Function({required super.deviceId, required super.deviceName ,required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_1',
|
code: 'countdown_1',
|
||||||
operationName: 'Light 1 Countdown',
|
operationName: 'Light 1 Countdown',
|
||||||
@ -47,7 +47,7 @@ class ThreeGangCountdown1Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangSwitch2Function extends BaseSwitchFunction {
|
class ThreeGangSwitch2Function extends BaseSwitchFunction {
|
||||||
ThreeGangSwitch2Function({required super.deviceId, required super.deviceName})
|
ThreeGangSwitch2Function({required super.deviceId, required super.deviceName, required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'switch_2',
|
code: 'switch_2',
|
||||||
operationName: 'Light 2 Switch',
|
operationName: 'Light 2 Switch',
|
||||||
@ -70,7 +70,7 @@ class ThreeGangSwitch2Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangCountdown2Function extends BaseSwitchFunction {
|
class ThreeGangCountdown2Function extends BaseSwitchFunction {
|
||||||
ThreeGangCountdown2Function({required super.deviceId, required super.deviceName})
|
ThreeGangCountdown2Function({required super.deviceId, required super.deviceName ,required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_2',
|
code: 'countdown_2',
|
||||||
operationName: 'Light 2 Countdown',
|
operationName: 'Light 2 Countdown',
|
||||||
@ -91,7 +91,7 @@ class ThreeGangCountdown2Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangSwitch3Function extends BaseSwitchFunction {
|
class ThreeGangSwitch3Function extends BaseSwitchFunction {
|
||||||
ThreeGangSwitch3Function({required super.deviceId, required super.deviceName})
|
ThreeGangSwitch3Function({required super.deviceId, required super.deviceName ,required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'switch_3',
|
code: 'switch_3',
|
||||||
operationName: 'Light 3 Switch',
|
operationName: 'Light 3 Switch',
|
||||||
@ -114,7 +114,7 @@ class ThreeGangSwitch3Function extends BaseSwitchFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreeGangCountdown3Function extends BaseSwitchFunction {
|
class ThreeGangCountdown3Function extends BaseSwitchFunction {
|
||||||
ThreeGangCountdown3Function({required super.deviceId, required super.deviceName})
|
ThreeGangCountdown3Function({required super.deviceId, required super.deviceName ,required type})
|
||||||
: super(
|
: super(
|
||||||
code: 'countdown_3',
|
code: 'countdown_3',
|
||||||
operationName: 'Light 3 Countdown',
|
operationName: 'Light 3 Countdown',
|
||||||
|
111
lib/pages/routines/models/gateway.dart
Normal file
111
lib/pages/routines/models/gateway.dart
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
|
class GatewayOperationalValue {
|
||||||
|
final String icon;
|
||||||
|
final String description;
|
||||||
|
final dynamic value;
|
||||||
|
|
||||||
|
GatewayOperationalValue({
|
||||||
|
required this.icon,
|
||||||
|
required this.description,
|
||||||
|
required this.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GatewayFunctions extends DeviceFunction<GatewayOperationalValue> {
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
GatewayFunctions({
|
||||||
|
required super.deviceId,
|
||||||
|
required super.deviceName,
|
||||||
|
required super.code,
|
||||||
|
required super.operationName,
|
||||||
|
required super.icon,
|
||||||
|
required this.type,
|
||||||
|
});
|
||||||
|
|
||||||
|
List<GatewayOperationalValue> getOperationalValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
final class GatewaySwitchAlarmSound extends GatewayFunctions {
|
||||||
|
GatewaySwitchAlarmSound({
|
||||||
|
required super.deviceId,
|
||||||
|
required super.deviceName,
|
||||||
|
required super.type,
|
||||||
|
}) : super(
|
||||||
|
code: 'switch_alarm_sound',
|
||||||
|
operationName: 'Switch Alarm Sound',
|
||||||
|
icon: Assets.activeBell,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GatewayOperationalValue> getOperationalValues() => [
|
||||||
|
GatewayOperationalValue(
|
||||||
|
icon: Assets.assetsAcPower,
|
||||||
|
description: "ON",
|
||||||
|
value: true,
|
||||||
|
),
|
||||||
|
GatewayOperationalValue(
|
||||||
|
icon: Assets.assetsAcPowerOFF,
|
||||||
|
description: "OFF",
|
||||||
|
value: false,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class GatewayMasterState extends GatewayFunctions {
|
||||||
|
GatewayMasterState({
|
||||||
|
required super.deviceId,
|
||||||
|
required super.deviceName,
|
||||||
|
required super.type,
|
||||||
|
}) : super(
|
||||||
|
code: 'master_state',
|
||||||
|
operationName: 'Master State',
|
||||||
|
icon: Assets.gear,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GatewayOperationalValue> getOperationalValues() {
|
||||||
|
return [
|
||||||
|
GatewayOperationalValue(
|
||||||
|
icon: Assets.assetsAcPower,
|
||||||
|
description: "Normal",
|
||||||
|
value: 'normal',
|
||||||
|
),
|
||||||
|
GatewayOperationalValue(
|
||||||
|
icon: Assets.assetsAcPowerOFF,
|
||||||
|
description: "Alarm",
|
||||||
|
value: 'alarm',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class GatewayFactoryReset extends GatewayFunctions {
|
||||||
|
GatewayFactoryReset({
|
||||||
|
required super.deviceId,
|
||||||
|
required super.deviceName,
|
||||||
|
required super.type,
|
||||||
|
}) : super(
|
||||||
|
code: 'factory_reset',
|
||||||
|
operationName: 'Factory Reset',
|
||||||
|
icon: Assets.factoryReset,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<GatewayOperationalValue> getOperationalValues() {
|
||||||
|
return [
|
||||||
|
GatewayOperationalValue(
|
||||||
|
icon: Assets.assetsAcPower,
|
||||||
|
description: "ON",
|
||||||
|
value: true,
|
||||||
|
),
|
||||||
|
GatewayOperationalValue(
|
||||||
|
icon: Assets.assetsAcPowerOFF,
|
||||||
|
description: "OFF",
|
||||||
|
value: false,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/wps/wps_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/wps/wps_operational_value.dart';
|
||||||
@ -195,7 +193,7 @@ class NoOneTimeFunction extends WpsFunctions {
|
|||||||
WpsOperationalValue(
|
WpsOperationalValue(
|
||||||
icon: icon,
|
icon: icon,
|
||||||
description: 'Custom $unit',
|
description: 'Custom $unit',
|
||||||
value: null,
|
value: null,
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -216,12 +214,12 @@ class PresenceStateFunction extends WpsFunctions {
|
|||||||
WpsOperationalValue(
|
WpsOperationalValue(
|
||||||
icon: Assets.assetsAcPower,
|
icon: Assets.assetsAcPower,
|
||||||
description: "None",
|
description: "None",
|
||||||
value: true,
|
value: 'none',
|
||||||
),
|
),
|
||||||
WpsOperationalValue(
|
WpsOperationalValue(
|
||||||
icon: Assets.presenceStateIcon,
|
icon: Assets.presenceStateIcon,
|
||||||
description: "Presence",
|
description: "Presence",
|
||||||
value: false,
|
value: 'presence',
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -238,7 +236,7 @@ class CurrentDistanceFunction extends WpsFunctions {
|
|||||||
step = 1,
|
step = 1,
|
||||||
super(
|
super(
|
||||||
type: type,
|
type: type,
|
||||||
code: 'current_distance',
|
code: 'dis_current',
|
||||||
operationName: 'Current Distance',
|
operationName: 'Current Distance',
|
||||||
icon: Assets.currentDistanceIcon,
|
icon: Assets.currentDistanceIcon,
|
||||||
);
|
);
|
||||||
@ -246,11 +244,12 @@ class CurrentDistanceFunction extends WpsFunctions {
|
|||||||
@override
|
@override
|
||||||
List<WpsOperationalValue> getOperationalValues() {
|
List<WpsOperationalValue> getOperationalValues() {
|
||||||
List<WpsOperationalValue> values = [];
|
List<WpsOperationalValue> values = [];
|
||||||
for (int temp = min; temp <= max; temp += step) {
|
for (int cm = min; cm <= max; cm += step) {
|
||||||
values.add(WpsOperationalValue(
|
values.add(WpsOperationalValue(
|
||||||
icon: Assets.assetsTempreture,
|
icon: Assets.assetsTempreture,
|
||||||
description: "${temp}CM",
|
description: "${cm}CM",
|
||||||
value: temp,
|
|
||||||
|
value: cm,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
|
@ -33,8 +33,6 @@ class _RoutinesViewState extends State<RoutinesView> {
|
|||||||
communityID: communityId, spaceID: spaceId));
|
communityID: communityId, spaceID: spaceId));
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
|
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
|
||||||
await Future.delayed(const Duration(milliseconds:500));
|
|
||||||
_bloc.add(const ResetSelectedEvent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -92,6 +90,7 @@ class _RoutinesViewState extends State<RoutinesView> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 50),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -72,6 +72,7 @@ class IfContainer extends StatelessWidget {
|
|||||||
'2G',
|
'2G',
|
||||||
'3G',
|
'3G',
|
||||||
'WPS'
|
'WPS'
|
||||||
|
'GW',
|
||||||
].contains(
|
].contains(
|
||||||
state.ifItems[index]['productType'])) {
|
state.ifItems[index]['productType'])) {
|
||||||
context.read<RoutineBloc>().add(
|
context.read<RoutineBloc>().add(
|
||||||
@ -105,9 +106,7 @@ class IfContainer extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
onAcceptWithDetails: (data) async {
|
onAcceptWithDetails: (data) async {
|
||||||
print('data.data=${data.data}');
|
|
||||||
final uniqueCustomId = const Uuid().v4();
|
final uniqueCustomId = const Uuid().v4();
|
||||||
|
|
||||||
final mutableData = Map<String, dynamic>.from(data.data);
|
final mutableData = Map<String, dynamic>.from(data.data);
|
||||||
mutableData['uniqueCustomId'] = uniqueCustomId;
|
mutableData['uniqueCustomId'] = uniqueCustomId;
|
||||||
|
|
||||||
@ -131,7 +130,7 @@ class IfContainer extends StatelessWidget {
|
|||||||
context
|
context
|
||||||
.read<RoutineBloc>()
|
.read<RoutineBloc>()
|
||||||
.add(AddToIfContainer(mutableData, false));
|
.add(AddToIfContainer(mutableData, false));
|
||||||
} else if (!['AC', '1G', '2G', '3G', 'WPS']
|
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW']
|
||||||
.contains(mutableData['productType'])) {
|
.contains(mutableData['productType'])) {
|
||||||
context
|
context
|
||||||
.read<RoutineBloc>()
|
.read<RoutineBloc>()
|
||||||
|
@ -31,165 +31,185 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
|
|||||||
? const Center(
|
? const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
)
|
)
|
||||||
: Padding(
|
: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
child: Padding(
|
||||||
child: Column(
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
Text(
|
children: [
|
||||||
"Scenes (Tab to Run)",
|
Text(
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
"Scenes (Tab to Run)",
|
||||||
color: ColorsManager.grayColor,
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
color: ColorsManager.grayColor,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
),
|
||||||
if (state.scenes.isEmpty)
|
const SizedBox(height: 10),
|
||||||
Expanded(
|
if (state.scenes.isEmpty)
|
||||||
child: Text(
|
Text(
|
||||||
"No scenes found",
|
"No scenes found",
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
color: ColorsManager.grayColor,
|
color: ColorsManager.grayColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (state.scenes.isNotEmpty)
|
||||||
if (state.scenes.isNotEmpty)
|
SizedBox(
|
||||||
ConstrainedBox(
|
height: 200,
|
||||||
constraints: BoxConstraints(
|
child: ListView.builder(
|
||||||
maxHeight: isSmallScreenSize(context) ? 190 : 200,
|
shrinkWrap: true,
|
||||||
maxWidth: MediaQuery.sizeOf(context).width * 0.8),
|
scrollDirection: Axis.horizontal,
|
||||||
child: ListView.builder(
|
itemCount: state.scenes.length,
|
||||||
scrollDirection: Axis.horizontal,
|
itemBuilder: (context, index) {
|
||||||
itemCount: state.scenes.length,
|
final scene = state.scenes[index];
|
||||||
itemBuilder: (context, index) {
|
final isLoading =
|
||||||
final scene = state.scenes[index];
|
state.loadingSceneId == scene.id;
|
||||||
final isLoading =
|
|
||||||
state.loadingSceneId == scene.id;
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
right:
|
||||||
),
|
isSmallScreenSize(context) ? 4.0 : 8.0,
|
||||||
child: RoutineViewCard(
|
),
|
||||||
isLoading: isLoading,
|
child: Column(
|
||||||
sceneOnTap: () {
|
children: [
|
||||||
context.read<RoutineBloc>().add(
|
RoutineViewCard(
|
||||||
SceneTrigger(
|
isLoading: isLoading,
|
||||||
sceneId: scene.id,
|
sceneOnTap: () {
|
||||||
name: scene.name));
|
context.read<RoutineBloc>().add(
|
||||||
},
|
SceneTrigger(
|
||||||
status: state.scenes[index].status,
|
sceneId: scene.id,
|
||||||
communityId:
|
name: scene.name));
|
||||||
state.scenes[index].communityId ?? '',
|
},
|
||||||
spaceId: state.scenes[index].spaceId,
|
status: state.scenes[index].status,
|
||||||
sceneId: state.scenes[index].sceneTuyaId!,
|
communityId:
|
||||||
automationId: state.scenes[index].id,
|
state.scenes[index].communityId ??
|
||||||
cardType: 'scenes',
|
'',
|
||||||
spaceName: state.scenes[index].spaceName,
|
spaceId: state.scenes[index].spaceId,
|
||||||
onTap: () {
|
sceneId:
|
||||||
BlocProvider.of<RoutineBloc>(context).add(
|
state.scenes[index].sceneTuyaId!,
|
||||||
const CreateNewRoutineViewEvent(
|
automationId: state.scenes[index].id,
|
||||||
createRoutineView: true),
|
cardType: 'scenes',
|
||||||
);
|
spaceName:
|
||||||
context.read<RoutineBloc>().add(
|
state.scenes[index].spaceName,
|
||||||
GetSceneDetails(
|
onTap: () {
|
||||||
sceneId: state.scenes[index].id,
|
BlocProvider.of<RoutineBloc>(context)
|
||||||
isTabToRun: true,
|
.add(
|
||||||
isUpdate: true,
|
const CreateNewRoutineViewEvent(
|
||||||
),
|
createRoutineView: true),
|
||||||
);
|
);
|
||||||
},
|
context.read<RoutineBloc>().add(
|
||||||
textString: state.scenes[index].name,
|
GetSceneDetails(
|
||||||
icon: state.scenes[index].icon ??
|
sceneId:
|
||||||
Assets.logoHorizontal,
|
state.scenes[index].id,
|
||||||
isFromScenes: true,
|
isTabToRun: true,
|
||||||
iconInBytes: state.scenes[index].iconInBytes,
|
isUpdate: true,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
textString: state.scenes[index].name,
|
||||||
|
icon: state.scenes[index].icon ??
|
||||||
|
Assets.logoHorizontal,
|
||||||
|
isFromScenes: true,
|
||||||
|
iconInBytes:
|
||||||
|
state.scenes[index].iconInBytes,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
"Automations",
|
||||||
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 3),
|
||||||
Text(
|
if (state.automations.isEmpty)
|
||||||
"Automations",
|
Text(
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
if (state.automations.isEmpty)
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"No automations found",
|
"No automations found",
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
color: ColorsManager.grayColor,
|
color: ColorsManager.grayColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (state.automations.isNotEmpty)
|
||||||
if (state.automations.isNotEmpty)
|
SizedBox(
|
||||||
ConstrainedBox(
|
height: 200,
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxHeight: isSmallScreenSize(context) ? 185 : 192,
|
|
||||||
maxWidth: MediaQuery.sizeOf(context).width * 0.7),
|
|
||||||
child: ListView.builder(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
itemCount: state.automations.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final isLoading = state.automations!
|
|
||||||
.contains(state.automations[index].id);
|
|
||||||
|
|
||||||
return Padding(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.only(
|
shrinkWrap: true,
|
||||||
right: isSmallScreenSize(context) ? 4.0 : 8.0,
|
scrollDirection: Axis.horizontal,
|
||||||
),
|
itemCount: state.automations.length,
|
||||||
child: RoutineViewCard(
|
itemBuilder: (context, index) {
|
||||||
isLoading: isLoading,
|
final isLoading = state.automations!
|
||||||
onChanged: (v) {
|
.contains(state.automations[index].id);
|
||||||
// BlocProvider.of<RoutineBloc>(context)
|
|
||||||
context.read<RoutineBloc>().add(
|
return Column(
|
||||||
UpdateAutomationStatus(
|
children: [
|
||||||
automationId:
|
Padding(
|
||||||
state.automations[index].id,
|
padding: EdgeInsets.only(
|
||||||
automationStatusUpdate:
|
right: isSmallScreenSize(context)
|
||||||
AutomationStatusUpdate(
|
? 4.0
|
||||||
spaceUuid: state
|
: 8.0,
|
||||||
.automations[index]
|
),
|
||||||
.spaceId,
|
child: RoutineViewCard(
|
||||||
isEnable: v),
|
isLoading: isLoading,
|
||||||
communityId: state
|
onChanged: (v) {
|
||||||
.automations[index].communityId,
|
context.read<RoutineBloc>().add(
|
||||||
),
|
UpdateAutomationStatus(
|
||||||
);
|
automationId: state
|
||||||
},
|
.automations[index].id,
|
||||||
status: state.automations[index].status,
|
automationStatusUpdate:
|
||||||
communityId: '',
|
AutomationStatusUpdate(
|
||||||
spaceId: state.automations[index].spaceId,
|
spaceUuid: state
|
||||||
sceneId: '',
|
.automations[
|
||||||
automationId: state.automations[index].id,
|
index]
|
||||||
cardType: 'automations',
|
.spaceId,
|
||||||
spaceName: state.scenes[index].spaceName,
|
isEnable: v),
|
||||||
onTap: () {
|
communityId: state
|
||||||
BlocProvider.of<RoutineBloc>(context).add(
|
.automations[index]
|
||||||
const CreateNewRoutineViewEvent(
|
.communityId,
|
||||||
createRoutineView: true),
|
),
|
||||||
);
|
);
|
||||||
context.read<RoutineBloc>().add(
|
},
|
||||||
GetAutomationDetails(
|
status: state.automations[index].status,
|
||||||
automationId:
|
communityId: '',
|
||||||
state.automations[index].id,
|
spaceId:
|
||||||
isAutomation: true,
|
state.automations[index].spaceId,
|
||||||
isUpdate: true),
|
sceneId: '',
|
||||||
);
|
automationId:
|
||||||
},
|
state.automations[index].id,
|
||||||
textString: state.automations[index].name,
|
cardType: 'automations',
|
||||||
icon: state.automations[index].icon ??
|
spaceName:
|
||||||
Assets.automation,
|
state.automations[index].spaceName,
|
||||||
),
|
onTap: () {
|
||||||
);
|
BlocProvider.of<RoutineBloc>(context)
|
||||||
}),
|
.add(
|
||||||
),
|
const CreateNewRoutineViewEvent(
|
||||||
],
|
createRoutineView: true),
|
||||||
|
);
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
GetAutomationDetails(
|
||||||
|
automationId: state
|
||||||
|
.automations[index].id,
|
||||||
|
isAutomation: true,
|
||||||
|
isUpdate: true),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
textString:
|
||||||
|
state.automations[index].name,
|
||||||
|
icon: state.automations[index].icon ??
|
||||||
|
Assets.automation,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -106,10 +106,10 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
|||||||
if (widget.isFromScenes ?? false)
|
if (widget.isFromScenes ?? false)
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: _handleSceneTap,
|
onTap: _handleSceneTap,
|
||||||
child: SvgPicture.asset(
|
child: Image.asset(
|
||||||
_showTemporaryCheck
|
_showTemporaryCheck
|
||||||
? Assets.scenesPlayIconCheck
|
? Assets.scenesPlayIcon
|
||||||
: Assets.scenesPlayIcon,
|
: Assets.scenesPlayIconCheck,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -177,6 +177,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
|||||||
: (widget.icon is String &&
|
: (widget.icon is String &&
|
||||||
widget.icon.endsWith('.svg'))
|
widget.icon.endsWith('.svg'))
|
||||||
? SvgPicture.asset(
|
? SvgPicture.asset(
|
||||||
|
height: iconSize,
|
||||||
|
width: iconSize,
|
||||||
widget.icon,
|
widget.icon,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
)
|
)
|
||||||
|
@ -1,6 +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/pages/device_managment/all_devices/models/devices_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
|
||||||
|
|
||||||
@ -18,6 +17,8 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
|||||||
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
context.read<RoutineBloc>().add(FetchDevicesInRoutine());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const _allowedProductTypes = {'AC', '1G', '2G', '3G', 'WPS', 'GW'};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<RoutineBloc, RoutineState>(
|
return BlocBuilder<RoutineBloc, RoutineState>(
|
||||||
@ -32,13 +33,8 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
List<AllDevicesModel> deviceList = state.devices
|
final deviceList = state.devices
|
||||||
.where((device) =>
|
.where((device) => _allowedProductTypes.contains(device.productType))
|
||||||
device.productType == 'AC' ||
|
|
||||||
device.productType == '1G' ||
|
|
||||||
device.productType == '2G' ||
|
|
||||||
device.productType == '3G' ||
|
|
||||||
device.productType == 'WPS')
|
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return Wrap(
|
return Wrap(
|
||||||
@ -46,37 +42,32 @@ class _RoutineDevicesState extends State<RoutineDevices> {
|
|||||||
runSpacing: 10,
|
runSpacing: 10,
|
||||||
children: deviceList.asMap().entries.map((entry) {
|
children: deviceList.asMap().entries.map((entry) {
|
||||||
final device = entry.value;
|
final device = entry.value;
|
||||||
|
|
||||||
|
final deviceData = {
|
||||||
|
'device': device,
|
||||||
|
'imagePath': device.getDefaultIcon(device.productType),
|
||||||
|
'title': device.name ?? '',
|
||||||
|
'deviceId': device.uuid,
|
||||||
|
'productType': device.productType,
|
||||||
|
'functions': device.functions,
|
||||||
|
'uniqueCustomId': '',
|
||||||
|
};
|
||||||
|
|
||||||
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
if (state.searchText != null && state.searchText!.isNotEmpty) {
|
||||||
return device.name!
|
return device.name!
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.contains(state.searchText!.toLowerCase())
|
.contains(state.searchText!.toLowerCase())
|
||||||
? DraggableCard(
|
? DraggableCard(
|
||||||
imagePath: device.getDefaultIcon(device.productType),
|
imagePath: deviceData['imagePath'] as String,
|
||||||
title: device.name ?? '',
|
title: deviceData['title'] as String,
|
||||||
deviceData: {
|
deviceData: deviceData,
|
||||||
'device': device,
|
|
||||||
'imagePath': device.getDefaultIcon(device.productType),
|
|
||||||
'title': device.name ?? '',
|
|
||||||
'deviceId': device.uuid,
|
|
||||||
'productType': device.productType,
|
|
||||||
'functions': device.functions,
|
|
||||||
'uniqueCustomId': '',
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
: Container();
|
: const SizedBox.shrink();
|
||||||
} else {
|
} else {
|
||||||
return DraggableCard(
|
return DraggableCard(
|
||||||
imagePath: device.getDefaultIcon(device.productType),
|
imagePath: deviceData['imagePath'] as String,
|
||||||
title: device.name ?? '',
|
title: deviceData['title'] as String,
|
||||||
deviceData: {
|
deviceData: deviceData,
|
||||||
'device': device,
|
|
||||||
'imagePath': device.getDefaultIcon(device.productType),
|
|
||||||
'title': device.name ?? '',
|
|
||||||
'deviceId': device.uuid,
|
|
||||||
'productType': device.productType,
|
|
||||||
'functions': device.functions,
|
|
||||||
'uniqueCustomId': '',
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
class RoutineDialogFunctionListTile extends StatelessWidget {
|
||||||
|
const RoutineDialogFunctionListTile({
|
||||||
|
super.key,
|
||||||
|
required this.iconPath,
|
||||||
|
required this.operationName,
|
||||||
|
required this.onTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String iconPath;
|
||||||
|
final String operationName;
|
||||||
|
final void Function() onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: SvgPicture.asset(
|
||||||
|
iconPath,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
placeholderBuilder: (context) => const SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
operationName,
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
trailing: const Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
size: 16,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
onTap: onTap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
class RoutineDialogSelectionListTile extends StatelessWidget {
|
||||||
|
const RoutineDialogSelectionListTile({
|
||||||
|
required this.iconPath,
|
||||||
|
required this.description,
|
||||||
|
required this.isSelected,
|
||||||
|
required this.onTap,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool isSelected;
|
||||||
|
final String iconPath;
|
||||||
|
final String description;
|
||||||
|
final void Function() onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: SvgPicture.asset(
|
||||||
|
iconPath,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
placeholderBuilder: (context) => Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
description,
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
trailing: Icon(
|
||||||
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
|
size: 24,
|
||||||
|
color: isSelected
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
onTap: onTap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -13,29 +13,38 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
|
||||||
class ACHelper {
|
class ACHelper {
|
||||||
static Future<Map<String, dynamic>?> showACFunctionsDialog(
|
static Future<Map<String, dynamic>?> showACFunctionsDialog({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
List<DeviceFunction> functions,
|
required List<DeviceFunction> functions,
|
||||||
AllDevicesModel? device,
|
required AllDevicesModel? device,
|
||||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
required List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
String uniqueCustomId,
|
required String uniqueCustomId,
|
||||||
bool? removeComparetors,
|
required bool? removeComparetors,
|
||||||
) async {
|
required String dialogType,
|
||||||
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
}) async {
|
||||||
|
List<ACFunction> acFunctions =
|
||||||
|
functions.whereType<ACFunction>().where((function) {
|
||||||
|
if (dialogType == 'THEN') {
|
||||||
|
return function.type == 'THEN' || function.type == 'BOTH';
|
||||||
|
}
|
||||||
|
return function.type == 'IF' || function.type == 'BOTH';
|
||||||
|
}).toList();
|
||||||
|
// List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
create: (_) => FunctionBloc()
|
||||||
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData =
|
final selectedFunctionData = state.addedFunctions
|
||||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -65,8 +74,10 @@ class ACHelper {
|
|||||||
child: _buildFunctionsList(
|
child: _buildFunctionsList(
|
||||||
context: context,
|
context: context,
|
||||||
acFunctions: acFunctions,
|
acFunctions: acFunctions,
|
||||||
onFunctionSelected: (functionCode, operationName) =>
|
onFunctionSelected:
|
||||||
context.read<FunctionBloc>().add(SelectFunction(
|
(functionCode, operationName) => context
|
||||||
|
.read<FunctionBloc>()
|
||||||
|
.add(SelectFunction(
|
||||||
functionCode: functionCode,
|
functionCode: functionCode,
|
||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
)),
|
)),
|
||||||
@ -194,7 +205,8 @@ class ACHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
final selectedFn =
|
||||||
|
acFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -290,7 +302,8 @@ class ACHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
isSelected:
|
||||||
|
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -384,9 +397,13 @@ class ACHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
color: isSelected
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -398,7 +415,8 @@ class ACHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,130 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/gateway.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog_value_selector.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_functions_list.dart';
|
||||||
|
|
||||||
|
class GatewayDialog extends StatefulWidget {
|
||||||
|
const GatewayDialog({
|
||||||
|
required this.uniqueCustomId,
|
||||||
|
required this.functions,
|
||||||
|
required this.deviceSelectedFunctions,
|
||||||
|
required this.device,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String? uniqueCustomId;
|
||||||
|
final List<DeviceFunction> functions;
|
||||||
|
final List<DeviceFunctionData> deviceSelectedFunctions;
|
||||||
|
final AllDevicesModel? device;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GatewayDialog> createState() => _GatewayDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GatewayDialogState extends State<GatewayDialog> {
|
||||||
|
late final List<GatewayFunctions> _gatewayFunctions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_gatewayFunctions = widget.functions.whereType<GatewayFunctions>().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final selectedFunction = state.selectedFunction;
|
||||||
|
return Container(
|
||||||
|
width: selectedFunction != null ? 600 : 360,
|
||||||
|
height: 450,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.only(top: 20),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const DialogHeader('Gateway Conditions'),
|
||||||
|
Expanded(child: _buildMainContent(context, state)),
|
||||||
|
_buildDialogFooter(context, state),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMainContent(BuildContext context, FunctionBlocState state) {
|
||||||
|
final selectedFunction = state.selectedFunction;
|
||||||
|
final selectedOperationName = state.selectedOperationName;
|
||||||
|
final selectedFunctionData = state.addedFunctions.firstWhere(
|
||||||
|
(f) => f.functionCode == selectedFunction,
|
||||||
|
orElse: () => DeviceFunctionData(
|
||||||
|
entityId: '',
|
||||||
|
functionCode: selectedFunction ?? '',
|
||||||
|
operationName: '',
|
||||||
|
value: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final selectedGatewayFunctions = _gatewayFunctions.firstWhere(
|
||||||
|
(f) => f.code == selectedFunction,
|
||||||
|
orElse: () => GatewaySwitchAlarmSound(
|
||||||
|
deviceId: '',
|
||||||
|
deviceName: '',
|
||||||
|
type: '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final operations = selectedGatewayFunctions.getOperationalValues();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
GatewayFunctionsList(gatewayFunctions: _gatewayFunctions),
|
||||||
|
if (state.selectedFunction != null)
|
||||||
|
Expanded(
|
||||||
|
child: GatewayDialogValueSelector(
|
||||||
|
operations: operations,
|
||||||
|
selectedFunction: selectedFunction ?? '',
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
gatewayFunctions: _gatewayFunctions,
|
||||||
|
operationName: selectedOperationName ?? '',
|
||||||
|
device: widget.device,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDialogFooter(BuildContext context, FunctionBlocState state) {
|
||||||
|
return DialogFooter(
|
||||||
|
onCancel: () => Navigator.pop(context),
|
||||||
|
onConfirm: state.addedFunctions.isNotEmpty
|
||||||
|
? () {
|
||||||
|
context.read<RoutineBloc>().add(
|
||||||
|
AddFunctionToRoutine(
|
||||||
|
state.addedFunctions,
|
||||||
|
widget.uniqueCustomId ?? '-1',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Navigator.pop(
|
||||||
|
context,
|
||||||
|
{'deviceId': widget.functions.firstOrNull?.deviceId},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
isConfirmEnabled: state.selectedFunction != null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/gateway.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialog_selection_list_tile.dart';
|
||||||
|
|
||||||
|
class GatewayDialogValueSelector extends StatelessWidget {
|
||||||
|
const GatewayDialogValueSelector({
|
||||||
|
required this.operations,
|
||||||
|
required this.selectedFunction,
|
||||||
|
required this.selectedFunctionData,
|
||||||
|
required this.gatewayFunctions,
|
||||||
|
required this.device,
|
||||||
|
required this.operationName,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<GatewayOperationalValue> operations;
|
||||||
|
final String selectedFunction;
|
||||||
|
final DeviceFunctionData? selectedFunctionData;
|
||||||
|
final List<GatewayFunctions> gatewayFunctions;
|
||||||
|
final AllDevicesModel? device;
|
||||||
|
final String operationName;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: operations.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final operation = operations[index];
|
||||||
|
final isSelected = selectedFunctionData?.value == operation.value;
|
||||||
|
return RoutineDialogSelectionListTile(
|
||||||
|
iconPath: operation.icon,
|
||||||
|
description: operation.description,
|
||||||
|
isSelected: isSelected,
|
||||||
|
onTap: () {
|
||||||
|
if (!isSelected) {
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: device?.uuid ?? '',
|
||||||
|
functionCode: selectedFunction,
|
||||||
|
operationName: operationName,
|
||||||
|
value: operation.value,
|
||||||
|
condition: selectedFunctionData?.condition,
|
||||||
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/gateway.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialog_function_list_tile.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class GatewayFunctionsList extends StatelessWidget {
|
||||||
|
const GatewayFunctionsList({
|
||||||
|
required this.gatewayFunctions,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<GatewayFunctions> gatewayFunctions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 360,
|
||||||
|
child: ListView.separated(
|
||||||
|
shrinkWrap: false,
|
||||||
|
itemCount: gatewayFunctions.length,
|
||||||
|
separatorBuilder: (context, index) => const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||||
|
child: Divider(color: ColorsManager.dividerColor),
|
||||||
|
),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final function = gatewayFunctions[index];
|
||||||
|
return RoutineDialogFunctionListTile(
|
||||||
|
iconPath: function.icon,
|
||||||
|
operationName: function.operationName,
|
||||||
|
onTap: () => context.read<FunctionBloc>().add(
|
||||||
|
SelectFunction(
|
||||||
|
functionCode: function.code,
|
||||||
|
operationName: function.operationName,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/gateway/gateway_dialog.dart';
|
||||||
|
|
||||||
|
abstract final class GatewayHelper {
|
||||||
|
const GatewayHelper._();
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>?> showGatewayFunctionsDialog({
|
||||||
|
required BuildContext context,
|
||||||
|
required List<DeviceFunction> functions,
|
||||||
|
required String? uniqueCustomId,
|
||||||
|
required List<DeviceFunctionData> deviceSelectedFunctions,
|
||||||
|
required AllDevicesModel? device,
|
||||||
|
}) async {
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => BlocProvider<FunctionBloc>(
|
||||||
|
create: (context) => FunctionBloc()
|
||||||
|
..add(
|
||||||
|
InitializeFunctions(deviceSelectedFunctions),
|
||||||
|
),
|
||||||
|
child: GatewayDialog(
|
||||||
|
uniqueCustomId: uniqueCustomId,
|
||||||
|
functions: functions,
|
||||||
|
deviceSelectedFunctions: deviceSelectedFunctions,
|
||||||
|
device: device,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,10 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
|||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.dart';
|
||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
@ -14,29 +16,32 @@ 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';
|
||||||
|
|
||||||
class OneGangSwitchHelper {
|
class OneGangSwitchHelper {
|
||||||
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog({
|
||||||
BuildContext context,
|
required String dialogType,
|
||||||
List<DeviceFunction> functions,
|
required BuildContext context,
|
||||||
AllDevicesModel? device,
|
required List<DeviceFunction> functions,
|
||||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
required AllDevicesModel? device,
|
||||||
String uniqueCustomId,
|
required List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
bool removeComparetors,
|
required String uniqueCustomId,
|
||||||
) async {
|
required bool removeComparetors,
|
||||||
List<BaseSwitchFunction> acFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
}) async {
|
||||||
|
List<BaseSwitchFunction> oneGangFunctions =
|
||||||
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
create: (_) => FunctionBloc()
|
||||||
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData =
|
final selectedFunctionData = state.addedFunctions
|
||||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -61,12 +66,12 @@ class OneGangSwitchHelper {
|
|||||||
// Left side: Function list
|
// Left side: Function list
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
itemCount: acFunctions.length,
|
itemCount: oneGangFunctions.length,
|
||||||
separatorBuilder: (_, __) => const Divider(
|
separatorBuilder: (_, __) => const Divider(
|
||||||
color: ColorsManager.dividerColor,
|
color: ColorsManager.dividerColor,
|
||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final function = acFunctions[index];
|
final function = oneGangFunctions[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: SvgPicture.asset(
|
leading: SvgPicture.asset(
|
||||||
function.icon,
|
function.icon,
|
||||||
@ -83,9 +88,12 @@ class OneGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<FunctionBloc>().add(SelectFunction(
|
context
|
||||||
|
.read<FunctionBloc>()
|
||||||
|
.add(SelectFunction(
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName: function.operationName,
|
operationName:
|
||||||
|
function.operationName,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -99,7 +107,7 @@ class OneGangSwitchHelper {
|
|||||||
context: context,
|
context: context,
|
||||||
selectedFunction: selectedFunction,
|
selectedFunction: selectedFunction,
|
||||||
selectedFunctionData: selectedFunctionData,
|
selectedFunctionData: selectedFunctionData,
|
||||||
acFunctions: acFunctions,
|
acFunctions: oneGangFunctions,
|
||||||
device: device,
|
device: device,
|
||||||
operationName: selectedOperationName ?? '',
|
operationName: selectedOperationName ?? '',
|
||||||
removeComparetors: removeComparetors,
|
removeComparetors: removeComparetors,
|
||||||
@ -174,8 +182,14 @@ class OneGangSwitchHelper {
|
|||||||
removeComparetors: removeComparetors,
|
removeComparetors: removeComparetors,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
final selectedFn = acFunctions.firstWhere(
|
||||||
|
(f) => f.code == selectedFunction,
|
||||||
|
orElse: () => OneGangSwitchFunction(
|
||||||
|
deviceId: '',
|
||||||
|
deviceName: '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -212,11 +226,11 @@ class OneGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownDisplay(
|
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -257,7 +271,8 @@ class OneGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
isSelected:
|
||||||
|
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -305,7 +320,8 @@ class OneGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
divisions: (((operationalValues.maxValue ?? 0) -
|
||||||
|
(operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -357,9 +373,13 @@ class OneGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
color: isSelected
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -371,7 +391,8 @@ class OneGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -14,14 +14,15 @@ 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';
|
||||||
|
|
||||||
class ThreeGangSwitchHelper {
|
class ThreeGangSwitchHelper {
|
||||||
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
List<DeviceFunction> functions,
|
required List<DeviceFunction> functions,
|
||||||
AllDevicesModel? device,
|
required AllDevicesModel? device,
|
||||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
required List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
String uniqueCustomId,
|
required String uniqueCustomId,
|
||||||
bool removeComparetors,
|
required String dialogType,
|
||||||
) async {
|
required bool removeComparetors,
|
||||||
|
}) async {
|
||||||
List<BaseSwitchFunction> switchFunctions =
|
List<BaseSwitchFunction> switchFunctions =
|
||||||
functions.whereType<BaseSwitchFunction>().toList();
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
|
|
||||||
|
@ -14,29 +14,32 @@ 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';
|
||||||
|
|
||||||
class TwoGangSwitchHelper {
|
class TwoGangSwitchHelper {
|
||||||
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
|
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog({
|
||||||
BuildContext context,
|
required BuildContext context,
|
||||||
List<DeviceFunction> functions,
|
required List<DeviceFunction> functions,
|
||||||
AllDevicesModel? device,
|
required AllDevicesModel? device,
|
||||||
List<DeviceFunctionData>? deviceSelectedFunctions,
|
required List<DeviceFunctionData>? deviceSelectedFunctions,
|
||||||
String uniqueCustomId,
|
required String uniqueCustomId,
|
||||||
bool removeComparetors,
|
required bool removeComparetors,
|
||||||
) async {
|
required String dialogType,
|
||||||
List<BaseSwitchFunction> switchFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
}) async {
|
||||||
|
List<BaseSwitchFunction> switchFunctions =
|
||||||
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
create: (_) => FunctionBloc()
|
||||||
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData =
|
final selectedFunctionData = state.addedFunctions
|
||||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@ -83,9 +86,12 @@ class TwoGangSwitchHelper {
|
|||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<FunctionBloc>().add(SelectFunction(
|
context
|
||||||
|
.read<FunctionBloc>()
|
||||||
|
.add(SelectFunction(
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName: function.operationName,
|
operationName:
|
||||||
|
function.operationName,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -161,7 +167,8 @@ class TwoGangSwitchHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1' || selectedFunction == 'countdown_2') {
|
if (selectedFunction == 'countdown_1' ||
|
||||||
|
selectedFunction == 'countdown_2') {
|
||||||
final initialValue = selectedFunctionData?.value ?? 200;
|
final initialValue = selectedFunctionData?.value ?? 200;
|
||||||
return _buildTemperatureSelector(
|
return _buildTemperatureSelector(
|
||||||
context: context,
|
context: context,
|
||||||
@ -175,7 +182,8 @@ class TwoGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
final selectedFn =
|
||||||
|
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@ -212,11 +220,11 @@ class TwoGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownDisplay(
|
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -257,7 +265,8 @@ class TwoGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
isSelected:
|
||||||
|
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -305,7 +314,8 @@ class TwoGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
divisions: (((operationalValues.maxValue ?? 0) -
|
||||||
|
(operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -357,9 +367,13 @@ class TwoGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected
|
||||||
|
? Icons.radio_button_checked
|
||||||
|
: Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
color: isSelected
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@ -371,7 +385,8 @@ class TwoGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription: selectedFunctionData?.valueDescription,
|
valueDescription:
|
||||||
|
selectedFunctionData?.valueDescription,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
@ -28,9 +27,12 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_hoursController = FixedExtentScrollController(initialItem: widget.initialHours);
|
_hoursController =
|
||||||
_minutesController = FixedExtentScrollController(initialItem: widget.initialMinutes);
|
FixedExtentScrollController(initialItem: widget.initialHours);
|
||||||
_secondsController = FixedExtentScrollController(initialItem: widget.initialSeconds);
|
_minutesController =
|
||||||
|
FixedExtentScrollController(initialItem: widget.initialMinutes);
|
||||||
|
_secondsController =
|
||||||
|
FixedExtentScrollController(initialItem: widget.initialSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -47,6 +49,8 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_hoursController.dispose();
|
_hoursController.dispose();
|
||||||
@ -61,26 +65,28 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
_buildPickerColumn(
|
_buildPickerColumn(
|
||||||
label: 'h',
|
label: 'h',
|
||||||
controller: _hoursController,
|
controller: _hoursController,
|
||||||
itemCount: 24,
|
itemCount: 3,
|
||||||
onChanged: (value) => _handleTimeChange(
|
onChanged: (value) {
|
||||||
value,
|
_handleTimeChange(
|
||||||
_minutesController.selectedItem,
|
value,
|
||||||
_secondsController.selectedItem,
|
_minutesController.selectedItem,
|
||||||
),
|
_secondsController.selectedItem,
|
||||||
),
|
);
|
||||||
|
}),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
_buildPickerColumn(
|
_buildPickerColumn(
|
||||||
label: 'm',
|
label: 'm',
|
||||||
controller: _minutesController,
|
controller: _minutesController,
|
||||||
itemCount: 60,
|
itemCount: 60,
|
||||||
onChanged: (value) => _handleTimeChange(
|
onChanged: (value) {
|
||||||
_hoursController.selectedItem,
|
_handleTimeChange(
|
||||||
value,
|
_hoursController.selectedItem,
|
||||||
_secondsController.selectedItem,
|
value,
|
||||||
),
|
_secondsController.selectedItem,
|
||||||
),
|
);
|
||||||
|
}),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
_buildPickerColumn(
|
_buildPickerColumn(
|
||||||
label: 's',
|
label: 's',
|
||||||
@ -97,6 +103,19 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleTimeChange(int hours, int minutes, int seconds) {
|
void _handleTimeChange(int hours, int minutes, int seconds) {
|
||||||
|
int total = hours * 3600 + minutes * 60 + seconds;
|
||||||
|
if (total > 10000) {
|
||||||
|
hours = 2;
|
||||||
|
minutes = 46;
|
||||||
|
seconds = 40;
|
||||||
|
total = 10000;
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_hoursController.jumpToItem(hours);
|
||||||
|
_minutesController.jumpToItem(minutes);
|
||||||
|
_secondsController.jumpToItem(seconds);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
widget.onTimeChanged(hours, minutes, seconds);
|
widget.onTimeChanged(hours, minutes, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,4 +166,4 @@ class _TimeWheelPickerState extends State<TimeWheelPicker> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
|
||||||
|
|
||||||
class WallPresenceSensor extends StatefulWidget {
|
class WallPresenceSensor extends StatefulWidget {
|
||||||
final List<DeviceFunction> functions;
|
final List<DeviceFunction> functions;
|
||||||
final AllDevicesModel? device;
|
final AllDevicesModel? device;
|
||||||
@ -171,7 +170,7 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
|
|||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction,
|
functionCode: selectedFunction,
|
||||||
operationName: '',
|
operationName: state.selectedOperationName ?? '',
|
||||||
value: null,
|
value: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -251,11 +250,8 @@ class _ValueSelector extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isSliderFunction(String function) => [
|
bool _isSliderFunction(String function) =>
|
||||||
'current_distance',
|
['dis_current', 'presence_time', 'illuminance_value'].contains(function);
|
||||||
'presence_time',
|
|
||||||
'illuminance_value'
|
|
||||||
].contains(function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SliderValueSelector extends StatelessWidget {
|
class _SliderValueSelector extends StatelessWidget {
|
||||||
@ -382,7 +378,7 @@ class _ValueDisplay extends StatelessWidget {
|
|||||||
switch (functionCode) {
|
switch (functionCode) {
|
||||||
case 'presence_time':
|
case 'presence_time':
|
||||||
return '$intValue Min';
|
return '$intValue Min';
|
||||||
case 'current_distance':
|
case 'dis_current':
|
||||||
return '$intValue CM';
|
return '$intValue CM';
|
||||||
case 'illuminance_value':
|
case 'illuminance_value':
|
||||||
return '$intValue Lux';
|
return '$intValue Lux';
|
||||||
@ -421,7 +417,7 @@ class _FunctionSlider extends StatelessWidget {
|
|||||||
switch (functionCode) {
|
switch (functionCode) {
|
||||||
case 'presence_time':
|
case 'presence_time':
|
||||||
return (0, 65535);
|
return (0, 65535);
|
||||||
case 'current_distance':
|
case 'dis_current':
|
||||||
return (1, 600);
|
return (1, 600);
|
||||||
case 'illuminance_value':
|
case 'illuminance_value':
|
||||||
return (0, 10000);
|
return (0, 10000);
|
||||||
|
@ -113,7 +113,8 @@ class ThenContainer extends StatelessWidget {
|
|||||||
'1G',
|
'1G',
|
||||||
'2G',
|
'2G',
|
||||||
'3G',
|
'3G',
|
||||||
'WPS'
|
'WPS',
|
||||||
|
"GW",
|
||||||
].contains(state.thenItems[index]
|
].contains(state.thenItems[index]
|
||||||
['productType'])) {
|
['productType'])) {
|
||||||
context.read<RoutineBloc>().add(
|
context.read<RoutineBloc>().add(
|
||||||
@ -229,7 +230,7 @@ class ThenContainer extends StatelessWidget {
|
|||||||
dialogType: "THEN");
|
dialogType: "THEN");
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
||||||
} else if (!['AC', '1G', '2G', '3G', 'WPS']
|
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'GW']
|
||||||
.contains(mutableData['productType'])) {
|
.contains(mutableData['productType'])) {
|
||||||
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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/pages/space_tree/bloc/space_tree_event.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/model/pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_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/services/space_mana_api.dart';
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
@ -18,7 +21,10 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
on<ClearCachedData>(_clearCachedData);
|
on<ClearCachedData>(_clearCachedData);
|
||||||
on<OnCommunityAdded>(_onCommunityAdded);
|
on<OnCommunityAdded>(_onCommunityAdded);
|
||||||
on<OnCommunityUpdated>(_onCommunityUpdate);
|
on<OnCommunityUpdated>(_onCommunityUpdate);
|
||||||
|
on<PaginationEvent>(_fetchPaginationSpaces);
|
||||||
|
on<DebouncedSearchEvent>(_onDebouncedSearch);
|
||||||
}
|
}
|
||||||
|
Timer _timer = Timer(const Duration(microseconds: 0), () {});
|
||||||
|
|
||||||
void _onCommunityUpdate(
|
void _onCommunityUpdate(
|
||||||
OnCommunityUpdated event,
|
OnCommunityUpdated event,
|
||||||
@ -28,17 +34,16 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final updatedCommunity = event.updatedCommunity;
|
final updatedCommunity = event.updatedCommunity;
|
||||||
final updatedCommunities =
|
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
||||||
List<CommunityModel>.from(state.communityList);
|
|
||||||
|
|
||||||
final index = updatedCommunities
|
final index =
|
||||||
.indexWhere((community) => community.uuid == updatedCommunity.uuid);
|
updatedCommunities.indexWhere((community) => community.uuid == updatedCommunity.uuid);
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
updatedCommunities[index] = updatedCommunity;
|
updatedCommunities[index] = updatedCommunity;
|
||||||
emit(state.copyWith(communitiesList: updatedCommunities));
|
emit(state.copyWith(communitiesList: updatedCommunities));
|
||||||
} else {
|
} else {
|
||||||
emit(SpaceTreeErrorState('Community not found in the list.'));
|
emit(const SpaceTreeErrorState('Community not found in the list.'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceTreeErrorState('Error updating community: $e'));
|
emit(SpaceTreeErrorState('Error updating community: $e'));
|
||||||
@ -50,48 +55,68 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
try {
|
try {
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
List<CommunityModel> communities =
|
PaginationModel paginationModel = await CommunitySpaceManagementApi()
|
||||||
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
|
.fetchCommunitiesAndSpaces(projectId: projectUuid, page: 1);
|
||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
// List<CommunityModel> updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
// communities.map((community) async {
|
||||||
List<SpaceModel> spaces = await CommunitySpaceManagementApi()
|
// List<SpaceModel> spaces =
|
||||||
.getSpaceHierarchy(community.uuid, projectUuid);
|
// await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid, projectUuid);
|
||||||
|
|
||||||
return CommunityModel(
|
// return CommunityModel(
|
||||||
uuid: community.uuid,
|
// uuid: community.uuid,
|
||||||
createdAt: community.createdAt,
|
// createdAt: community.createdAt,
|
||||||
updatedAt: community.updatedAt,
|
// updatedAt: community.updatedAt,
|
||||||
name: community.name,
|
// name: community.name,
|
||||||
description: community.description,
|
// description: community.description,
|
||||||
spaces: spaces,
|
// spaces: spaces,
|
||||||
region: community.region,
|
// region: community.region,
|
||||||
);
|
// );
|
||||||
}).toList(),
|
// }).toList(),
|
||||||
);
|
// );
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
communitiesList: updatedCommunities,
|
communitiesList: paginationModel.communities,
|
||||||
expandedCommunity: [],
|
expandedCommunity: [],
|
||||||
expandedSpaces: []));
|
expandedSpaces: [],
|
||||||
|
paginationModel: paginationModel));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onCommunityAdded(
|
_fetchPaginationSpaces(PaginationEvent event, Emitter<SpaceTreeState> emit) async {
|
||||||
OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
|
emit(state.copyWith(paginationIsLoading: true));
|
||||||
|
PaginationModel paginationModel = event.paginationModel;
|
||||||
|
List<CommunityModel> communities = List<CommunityModel>.from(event.communities);
|
||||||
|
try {
|
||||||
|
if (paginationModel.hasNext && state.searchQuery.isEmpty) {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
paginationModel = await CommunitySpaceManagementApi().fetchCommunitiesAndSpaces(
|
||||||
|
projectId: projectUuid, page: paginationModel.pageNum, search: state.searchQuery);
|
||||||
|
|
||||||
|
communities.addAll(paginationModel.communities);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
emit(state.copyWith(
|
||||||
|
communitiesList: communities,
|
||||||
|
paginationModel: paginationModel,
|
||||||
|
paginationIsLoading: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onCommunityAdded(OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
|
||||||
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
final updatedCommunities = List<CommunityModel>.from(state.communityList);
|
||||||
updatedCommunities.add(event.newCommunity);
|
updatedCommunities.add(event.newCommunity);
|
||||||
|
|
||||||
emit(state.copyWith(communitiesList: updatedCommunities));
|
emit(state.copyWith(communitiesList: updatedCommunities));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCommunityExpanded(
|
_onCommunityExpanded(OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
||||||
OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
List<String> updatedExpandedCommunityList =
|
List<String> updatedExpandedCommunityList = List.from(state.expandedCommunities);
|
||||||
List.from(state.expandedCommunities);
|
|
||||||
|
|
||||||
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
if (updatedExpandedCommunityList.contains(event.communityId)) {
|
||||||
updatedExpandedCommunityList.remove(event.communityId);
|
updatedExpandedCommunityList.remove(event.communityId);
|
||||||
@ -123,19 +148,14 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCommunitySelected(
|
_onCommunitySelected(OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
||||||
OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
List<String> updatedSelectedCommunities =
|
List<String> updatedSelectedCommunities =
|
||||||
List.from(state.selectedCommunities.toSet().toList());
|
List.from(state.selectedCommunities.toSet().toList());
|
||||||
List<String> updatedSelectedSpaces =
|
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||||
List.from(state.selectedSpaces.toSet().toList());
|
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||||
List<String> updatedSoldChecks =
|
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||||
List.from(state.soldCheck.toSet().toList());
|
List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityId] ?? [];
|
||||||
Map<String, List<String>> communityAndSpaces =
|
|
||||||
Map.from(state.selectedCommunityAndSpaces);
|
|
||||||
List<String> selectedSpacesInCommunity =
|
|
||||||
communityAndSpaces[event.communityId] ?? [];
|
|
||||||
|
|
||||||
List<String> childrenIds = _getAllChildIds(event.children);
|
List<String> childrenIds = _getAllChildIds(event.children);
|
||||||
|
|
||||||
@ -168,15 +188,11 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
try {
|
try {
|
||||||
List<String> updatedSelectedCommunities =
|
List<String> updatedSelectedCommunities =
|
||||||
List.from(state.selectedCommunities.toSet().toList());
|
List.from(state.selectedCommunities.toSet().toList());
|
||||||
List<String> updatedSelectedSpaces =
|
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||||
List.from(state.selectedSpaces.toSet().toList());
|
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||||
List<String> updatedSoldChecks =
|
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||||
List.from(state.soldCheck.toSet().toList());
|
|
||||||
Map<String, List<String>> communityAndSpaces =
|
|
||||||
Map.from(state.selectedCommunityAndSpaces);
|
|
||||||
|
|
||||||
List<String> selectedSpacesInCommunity =
|
List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityModel.uuid] ?? [];
|
||||||
communityAndSpaces[event.communityModel.uuid] ?? [];
|
|
||||||
|
|
||||||
List<String> childrenIds = _getAllChildIds(event.children);
|
List<String> childrenIds = _getAllChildIds(event.children);
|
||||||
bool isChildSelected = false;
|
bool isChildSelected = false;
|
||||||
@ -199,11 +215,9 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
selectedSpacesInCommunity.addAll(childrenIds);
|
selectedSpacesInCommunity.addAll(childrenIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> spaces =
|
List<String> spaces = _getThePathToChild(event.communityModel.uuid, event.spaceId);
|
||||||
_getThePathToChild(event.communityModel.uuid, event.spaceId);
|
|
||||||
for (String space in spaces) {
|
for (String space in spaces) {
|
||||||
if (!updatedSelectedSpaces.contains(space) &&
|
if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) {
|
||||||
!updatedSoldChecks.contains(space)) {
|
|
||||||
updatedSoldChecks.add(space);
|
updatedSoldChecks.add(space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,9 +240,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
updatedSoldChecks.remove(event.spaceId);
|
updatedSoldChecks.remove(event.spaceId);
|
||||||
|
|
||||||
List<String> parents =
|
List<String> parents =
|
||||||
_getThePathToChild(event.communityModel.uuid, event.spaceId)
|
_getThePathToChild(event.communityModel.uuid, event.spaceId).toSet().toList();
|
||||||
.toSet()
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (updatedSelectedSpaces.isEmpty) {
|
if (updatedSelectedSpaces.isEmpty) {
|
||||||
updatedSoldChecks.removeWhere(parents.contains);
|
updatedSoldChecks.removeWhere(parents.contains);
|
||||||
@ -236,8 +248,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
} else {
|
} else {
|
||||||
// Check if any parent has selected children
|
// Check if any parent has selected children
|
||||||
for (String space in parents) {
|
for (String space in parents) {
|
||||||
if (!_noChildrenSelected(
|
if (!_noChildrenSelected(event.communityModel, space, updatedSelectedSpaces, parents)) {
|
||||||
event.communityModel, space, updatedSelectedSpaces, parents)) {
|
|
||||||
updatedSoldChecks.remove(space);
|
updatedSoldChecks.remove(space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,8 +273,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_noChildrenSelected(CommunityModel community, String spaceId,
|
_noChildrenSelected(
|
||||||
List<String> selectedSpaces, List<String> parents) {
|
CommunityModel community, String spaceId, List<String> selectedSpaces, List<String> parents) {
|
||||||
if (selectedSpaces.contains(spaceId)) {
|
if (selectedSpaces.contains(spaceId)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -285,29 +296,52 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
|
|
||||||
_onSearch(SearchQueryEvent event, Emitter<SpaceTreeState> emit) async {
|
_onSearch(SearchQueryEvent event, Emitter<SpaceTreeState> emit) async {
|
||||||
try {
|
try {
|
||||||
List<CommunityModel> communities = List.from(state.communityList);
|
const duration = Duration(seconds: 1);
|
||||||
List<CommunityModel> filteredCommunity = [];
|
if (_timer.isActive) {
|
||||||
|
_timer.cancel(); // clear timer
|
||||||
|
}
|
||||||
|
_timer = Timer(duration, () async => add(DebouncedSearchEvent(event.searchQuery)));
|
||||||
|
|
||||||
|
// List<CommunityModel> communities = List.from(state.communityList);
|
||||||
|
// List<CommunityModel> filteredCommunity = [];
|
||||||
|
|
||||||
// Filter communities and expand only those that match the query
|
// Filter communities and expand only those that match the query
|
||||||
filteredCommunity = communities.where((community) {
|
// filteredCommunity = communities.where((community) {
|
||||||
final containsQueryInCommunity = community.name
|
// final containsQueryInCommunity =
|
||||||
.toLowerCase()
|
// community.name.toLowerCase().contains(event.searchQuery.toLowerCase());
|
||||||
.contains(event.searchQuery.toLowerCase());
|
// final containsQueryInSpaces =
|
||||||
final containsQueryInSpaces = community.spaces.any(
|
// community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
||||||
(space) => _containsQuery(space, event.searchQuery.toLowerCase()));
|
|
||||||
|
|
||||||
return containsQueryInCommunity || containsQueryInSpaces;
|
// return containsQueryInCommunity || containsQueryInSpaces;
|
||||||
}).toList();
|
// }).toList();
|
||||||
|
|
||||||
emit(state.copyWith(
|
// emit(state.copyWith(
|
||||||
filteredCommunity: filteredCommunity,
|
// filteredCommunity: filteredCommunity,
|
||||||
isSearching: event.searchQuery.isNotEmpty,
|
// isSearching: event.searchQuery.isNotEmpty,
|
||||||
searchQuery: event.searchQuery));
|
// searchQuery: event.searchQuery));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onDebouncedSearch(DebouncedSearchEvent event, Emitter<SpaceTreeState> emit) async {
|
||||||
|
emit(state.copyWith(
|
||||||
|
isSearching: true,
|
||||||
|
));
|
||||||
|
PaginationModel paginationModel = const PaginationModel.emptyConstructor();
|
||||||
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
|
paginationModel = await CommunitySpaceManagementApi()
|
||||||
|
.fetchCommunitiesAndSpaces(projectId: projectUuid, page: 1, search: event.searchQuery);
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
emit(state.copyWith(
|
||||||
|
filteredCommunity: paginationModel.communities,
|
||||||
|
isSearching: false,
|
||||||
|
searchQuery: event.searchQuery));
|
||||||
|
}
|
||||||
|
|
||||||
_clearAllData(ClearAllData event, Emitter<SpaceTreeState> emit) async {
|
_clearAllData(ClearAllData event, Emitter<SpaceTreeState> emit) async {
|
||||||
try {
|
try {
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
@ -345,13 +379,13 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to determine if any space or its children match the search query
|
// Helper function to determine if any space or its children match the search query
|
||||||
bool _containsQuery(SpaceModel space, String query) {
|
// bool _containsQuery(SpaceModel space, String query) {
|
||||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
// final matchesSpace = space.name.toLowerCase().contains(query);
|
||||||
final matchesChildren = space.children.any((child) =>
|
// final matchesChildren =
|
||||||
_containsQuery(child, query)); // Recursive check for children
|
// space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
|
||||||
|
|
||||||
return matchesSpace || matchesChildren;
|
// return matchesSpace || matchesChildren;
|
||||||
}
|
// }
|
||||||
|
|
||||||
List<String> _getAllChildIds(List<SpaceModel> spaces) {
|
List<String> _getAllChildIds(List<SpaceModel> spaces) {
|
||||||
List<String> ids = [];
|
List<String> ids = [];
|
||||||
@ -371,8 +405,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _anySpacesSelectedInCommunity(CommunityModel community,
|
bool _anySpacesSelectedInCommunity(
|
||||||
List<String> selectedSpaces, List<String> partialCheckedList) {
|
CommunityModel community, List<String> selectedSpaces, List<String> partialCheckedList) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
List<String> ids = _getAllChildIds(community.spaces);
|
List<String> ids = _getAllChildIds(community.spaces);
|
||||||
for (var id in ids) {
|
for (var id in ids) {
|
||||||
@ -401,8 +435,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> _getAllParentsIds(
|
List<String> _getAllParentsIds(SpaceModel child, String spaceId, List<String> listIds) {
|
||||||
SpaceModel child, String spaceId, List<String> listIds) {
|
|
||||||
List<String> ids = listIds;
|
List<String> ids = listIds;
|
||||||
|
|
||||||
ids.add(child.uuid ?? '');
|
ids.add(child.uuid ?? '');
|
||||||
@ -426,6 +459,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
|
_timer.cancel();
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/model/pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_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';
|
||||||
|
|
||||||
@ -11,6 +12,16 @@ class SpaceTreeEvent extends Equatable {
|
|||||||
|
|
||||||
class InitialEvent extends SpaceTreeEvent {}
|
class InitialEvent extends SpaceTreeEvent {}
|
||||||
|
|
||||||
|
class PaginationEvent extends SpaceTreeEvent {
|
||||||
|
final PaginationModel paginationModel;
|
||||||
|
final List<CommunityModel> communities;
|
||||||
|
|
||||||
|
const PaginationEvent(this.paginationModel, this.communities);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [paginationModel, communities];
|
||||||
|
}
|
||||||
|
|
||||||
class SearchForSpace extends SpaceTreeEvent {
|
class SearchForSpace extends SpaceTreeEvent {
|
||||||
final String searchQuery;
|
final String searchQuery;
|
||||||
|
|
||||||
@ -69,6 +80,15 @@ class SearchQueryEvent extends SpaceTreeEvent {
|
|||||||
List<Object> get props => [searchQuery];
|
List<Object> get props => [searchQuery];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DebouncedSearchEvent extends SpaceTreeEvent {
|
||||||
|
final String searchQuery;
|
||||||
|
|
||||||
|
const DebouncedSearchEvent(this.searchQuery);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [searchQuery];
|
||||||
|
}
|
||||||
|
|
||||||
class OnCommunityAdded extends SpaceTreeEvent {
|
class OnCommunityAdded extends SpaceTreeEvent {
|
||||||
final CommunityModel newCommunity;
|
final CommunityModel newCommunity;
|
||||||
const OnCommunityAdded(this.newCommunity);
|
const OnCommunityAdded(this.newCommunity);
|
||||||
@ -85,7 +105,6 @@ class OnCommunityUpdated extends SpaceTreeEvent {
|
|||||||
List<Object> get props => [updatedCommunity];
|
List<Object> get props => [updatedCommunity];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ClearAllData extends SpaceTreeEvent {}
|
class ClearAllData extends SpaceTreeEvent {}
|
||||||
|
|
||||||
class ClearCachedData extends SpaceTreeEvent {}
|
class ClearCachedData extends SpaceTreeEvent {}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/model/pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
|
|
||||||
class SpaceTreeState extends Equatable {
|
class SpaceTreeState extends Equatable {
|
||||||
@ -12,6 +13,8 @@ class SpaceTreeState extends Equatable {
|
|||||||
final List<String> soldCheck;
|
final List<String> soldCheck;
|
||||||
final bool isSearching;
|
final bool isSearching;
|
||||||
final String searchQuery;
|
final String searchQuery;
|
||||||
|
final PaginationModel paginationModel;
|
||||||
|
final bool paginationIsLoading;
|
||||||
|
|
||||||
const SpaceTreeState(
|
const SpaceTreeState(
|
||||||
{this.communityList = const [],
|
{this.communityList = const [],
|
||||||
@ -23,7 +26,9 @@ class SpaceTreeState extends Equatable {
|
|||||||
this.soldCheck = const [],
|
this.soldCheck = const [],
|
||||||
this.isSearching = false,
|
this.isSearching = false,
|
||||||
this.selectedCommunityAndSpaces = const {},
|
this.selectedCommunityAndSpaces = const {},
|
||||||
this.searchQuery = ''});
|
this.searchQuery = '',
|
||||||
|
this.paginationModel = const PaginationModel.emptyConstructor(),
|
||||||
|
this.paginationIsLoading = false});
|
||||||
|
|
||||||
SpaceTreeState copyWith(
|
SpaceTreeState copyWith(
|
||||||
{List<CommunityModel>? communitiesList,
|
{List<CommunityModel>? communitiesList,
|
||||||
@ -35,7 +40,9 @@ class SpaceTreeState extends Equatable {
|
|||||||
List<String>? soldCheck,
|
List<String>? soldCheck,
|
||||||
bool? isSearching,
|
bool? isSearching,
|
||||||
Map<String, List<String>>? selectedCommunityAndSpaces,
|
Map<String, List<String>>? selectedCommunityAndSpaces,
|
||||||
String? searchQuery}) {
|
String? searchQuery,
|
||||||
|
PaginationModel? paginationModel,
|
||||||
|
bool? paginationIsLoading}) {
|
||||||
return SpaceTreeState(
|
return SpaceTreeState(
|
||||||
communityList: communitiesList ?? this.communityList,
|
communityList: communitiesList ?? this.communityList,
|
||||||
filteredCommunity: filteredCommunity ?? this.filteredCommunity,
|
filteredCommunity: filteredCommunity ?? this.filteredCommunity,
|
||||||
@ -46,7 +53,9 @@ class SpaceTreeState extends Equatable {
|
|||||||
soldCheck: soldCheck ?? this.soldCheck,
|
soldCheck: soldCheck ?? this.soldCheck,
|
||||||
isSearching: isSearching ?? this.isSearching,
|
isSearching: isSearching ?? this.isSearching,
|
||||||
selectedCommunityAndSpaces: selectedCommunityAndSpaces ?? this.selectedCommunityAndSpaces,
|
selectedCommunityAndSpaces: selectedCommunityAndSpaces ?? this.selectedCommunityAndSpaces,
|
||||||
searchQuery: searchQuery ?? this.searchQuery);
|
searchQuery: searchQuery ?? this.searchQuery,
|
||||||
|
paginationModel: paginationModel ?? this.paginationModel,
|
||||||
|
paginationIsLoading: paginationIsLoading ?? this.paginationIsLoading);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -60,7 +69,9 @@ class SpaceTreeState extends Equatable {
|
|||||||
soldCheck,
|
soldCheck,
|
||||||
isSearching,
|
isSearching,
|
||||||
selectedCommunityAndSpaces,
|
selectedCommunityAndSpaces,
|
||||||
searchQuery
|
searchQuery,
|
||||||
|
paginationModel,
|
||||||
|
paginationIsLoading
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
lib/pages/space_tree/model/pagination_model.dart
Normal file
20
lib/pages/space_tree/model/pagination_model.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
|
|
||||||
|
class PaginationModel {
|
||||||
|
final int pageNum;
|
||||||
|
final bool hasNext;
|
||||||
|
final int size;
|
||||||
|
final List<CommunityModel> communities;
|
||||||
|
|
||||||
|
const PaginationModel(
|
||||||
|
{required this.pageNum,
|
||||||
|
required this.hasNext,
|
||||||
|
required this.size,
|
||||||
|
required this.communities});
|
||||||
|
|
||||||
|
const PaginationModel.emptyConstructor()
|
||||||
|
: pageNum = 1,
|
||||||
|
hasNext = true,
|
||||||
|
size = 10,
|
||||||
|
communities = const [];
|
||||||
|
}
|
@ -34,7 +34,8 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<SpaceTreeBloc, SpaceTreeState>(builder: (context, state) {
|
return BlocBuilder<SpaceTreeBloc, SpaceTreeState>(builder: (context, state) {
|
||||||
List<CommunityModel> list = state.isSearching ? state.filteredCommunity : state.communityList;
|
List<CommunityModel> list =
|
||||||
|
state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList;
|
||||||
return Container(
|
return Container(
|
||||||
height: MediaQuery.sizeOf(context).height,
|
height: MediaQuery.sizeOf(context).height,
|
||||||
decoration: widget.isSide == true
|
decoration: widget.isSide == true
|
||||||
@ -61,7 +62,8 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
border: Border.all(color: ColorsManager.grayBorder)),
|
border: Border.all(color: ColorsManager.grayBorder)),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
style: const TextStyle(color: Colors.black),
|
style: context.textTheme.bodyMedium
|
||||||
|
?.copyWith(color: ColorsManager.blackColor),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<SpaceTreeBloc>().add(SearchQueryEvent(value));
|
context.read<SpaceTreeBloc>().add(SearchQueryEvent(value));
|
||||||
},
|
},
|
||||||
@ -94,88 +96,101 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: state.isSearching
|
||||||
shrinkWrap: true,
|
? const Center(child: CircularProgressIndicator())
|
||||||
scrollDirection: Axis.horizontal,
|
: ListView(
|
||||||
children: [
|
shrinkWrap: true,
|
||||||
Container(
|
scrollDirection: Axis.horizontal,
|
||||||
width: MediaQuery.sizeOf(context).width * 0.5,
|
children: [
|
||||||
padding: const EdgeInsets.all(8.0),
|
Container(
|
||||||
child: list.isEmpty
|
width: MediaQuery.sizeOf(context).width * 0.5,
|
||||||
? Center(
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: list.isEmpty
|
||||||
'No results found',
|
? Center(
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
child: Text(
|
||||||
color: ColorsManager.lightGrayColor,
|
'No results found',
|
||||||
fontWeight: FontWeight.w400,
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: ColorsManager.lightGrayColor,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
)
|
: Scrollbar(
|
||||||
: Scrollbar(
|
scrollbarOrientation: ScrollbarOrientation.left,
|
||||||
scrollbarOrientation: ScrollbarOrientation.left,
|
thumbVisibility: true,
|
||||||
thumbVisibility: true,
|
controller: _scrollController,
|
||||||
controller: _scrollController,
|
child: NotificationListener(
|
||||||
child: Padding(
|
onNotification: (notification) {
|
||||||
padding: const EdgeInsets.only(left: 16),
|
if (notification is ScrollEndNotification &&
|
||||||
child: ListView(
|
notification.metrics.extentAfter == 0) {
|
||||||
controller: _scrollController,
|
// If the user has reached the end of the list Load more data
|
||||||
shrinkWrap: true,
|
context.read<SpaceTreeBloc>().add(PaginationEvent(
|
||||||
children: list
|
state.paginationModel, state.communityList));
|
||||||
.map(
|
}
|
||||||
(community) => CustomExpansionTileSpaceTree(
|
return false;
|
||||||
title: community.name,
|
},
|
||||||
isSelected: state.selectedCommunities
|
child: Padding(
|
||||||
.contains(community.uuid),
|
padding: const EdgeInsets.only(left: 16),
|
||||||
isSoldCheck: state.selectedCommunities
|
child: ListView.builder(
|
||||||
.contains(community.uuid),
|
shrinkWrap: true,
|
||||||
onExpansionChanged: () {
|
itemCount: list.length,
|
||||||
context
|
controller: _scrollController,
|
||||||
.read<SpaceTreeBloc>()
|
itemBuilder: (context, index) {
|
||||||
.add(OnCommunityExpanded(community.uuid));
|
return CustomExpansionTileSpaceTree(
|
||||||
},
|
title: list[index].name,
|
||||||
isExpanded: state.expandedCommunities
|
isSelected: state.selectedCommunities
|
||||||
.contains(community.uuid),
|
.contains(list[index].uuid),
|
||||||
onItemSelected: () {
|
isSoldCheck: state.selectedCommunities
|
||||||
context.read<SpaceTreeBloc>().add(
|
.contains(list[index].uuid),
|
||||||
OnCommunitySelected(
|
onExpansionChanged: () {
|
||||||
community.uuid, community.spaces));
|
context.read<SpaceTreeBloc>().add(
|
||||||
widget.onSelect();
|
OnCommunityExpanded(list[index].uuid));
|
||||||
},
|
},
|
||||||
children: community.spaces.map((space) {
|
isExpanded: state.expandedCommunities
|
||||||
return CustomExpansionTileSpaceTree(
|
.contains(list[index].uuid),
|
||||||
title: space.name,
|
onItemSelected: () {
|
||||||
isExpanded:
|
context.read<SpaceTreeBloc>().add(
|
||||||
state.expandedSpaces.contains(space.uuid),
|
OnCommunitySelected(list[index].uuid,
|
||||||
onItemSelected: () {
|
list[index].spaces));
|
||||||
context.read<SpaceTreeBloc>().add(
|
widget.onSelect();
|
||||||
OnSpaceSelected(community, space.uuid ?? '',
|
},
|
||||||
space.children));
|
children: list[index].spaces.map((space) {
|
||||||
widget.onSelect();
|
return CustomExpansionTileSpaceTree(
|
||||||
},
|
title: space.name,
|
||||||
onExpansionChanged: () {
|
isExpanded: state.expandedSpaces
|
||||||
context.read<SpaceTreeBloc>().add(
|
.contains(space.uuid),
|
||||||
OnSpaceExpanded(
|
onItemSelected: () {
|
||||||
community.uuid, space.uuid ?? ''));
|
context.read<SpaceTreeBloc>().add(
|
||||||
},
|
OnSpaceSelected(
|
||||||
isSelected:
|
list[index],
|
||||||
state.selectedSpaces.contains(space.uuid) ||
|
space.uuid ?? '',
|
||||||
state.soldCheck.contains(space.uuid),
|
space.children));
|
||||||
isSoldCheck: state.soldCheck.contains(space.uuid),
|
widget.onSelect();
|
||||||
children: _buildNestedSpaces(
|
},
|
||||||
context, state, space, community),
|
onExpansionChanged: () {
|
||||||
);
|
context.read<SpaceTreeBloc>().add(
|
||||||
}).toList(),
|
OnSpaceExpanded(list[index].uuid,
|
||||||
),
|
space.uuid ?? ''));
|
||||||
)
|
},
|
||||||
.toList(),
|
isSelected: state.selectedSpaces
|
||||||
),
|
.contains(space.uuid) ||
|
||||||
),
|
state.soldCheck.contains(space.uuid),
|
||||||
),
|
isSoldCheck:
|
||||||
),
|
state.soldCheck.contains(space.uuid),
|
||||||
],
|
children: _buildNestedSpaces(
|
||||||
),
|
context, state, space, list[index]),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
if (state.paginationIsLoading) const CircularProgressIndicator(),
|
||||||
// Expanded(
|
// Expanded(
|
||||||
// child: Padding(
|
// child: Padding(
|
||||||
// padding: const EdgeInsets.all(8.0),
|
// padding: const EdgeInsets.all(8.0),
|
||||||
|
@ -22,11 +22,11 @@ class CommunityModel {
|
|||||||
|
|
||||||
factory CommunityModel.fromJson(Map<String, dynamic> json) {
|
factory CommunityModel.fromJson(Map<String, dynamic> json) {
|
||||||
return CommunityModel(
|
return CommunityModel(
|
||||||
uuid: json['uuid'],
|
uuid: json['uuid'] ?? '',
|
||||||
createdAt: DateTime.parse(json['createdAt']),
|
createdAt: DateTime.parse(json['createdAt'] ?? ''),
|
||||||
updatedAt: DateTime.parse(json['updatedAt']),
|
updatedAt: DateTime.parse(json['updatedAt'] ?? ''),
|
||||||
name: json['name'],
|
name: json['name'] ?? '',
|
||||||
description: json['description'],
|
description: json['description'] ?? '',
|
||||||
region: json['region'] != null ? RegionModel.fromJson(json['region']) : null,
|
region: json['region'] != null ? RegionModel.fromJson(json['region']) : null,
|
||||||
spaces: json['spaces'] != null
|
spaces: json['spaces'] != null
|
||||||
? (json['spaces'] as List).map((space) => SpaceModel.fromJson(space)).toList()
|
? (json['spaces'] as List).map((space) => SpaceModel.fromJson(space)).toList()
|
||||||
|
@ -301,11 +301,18 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
||||||
setState(() {
|
setState(() {
|
||||||
// Set the first space in the center or use passed position
|
// Set the first space in the center or use passed position
|
||||||
Offset centerPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
|
Offset newPosition;
|
||||||
|
if (parentIndex != null) {
|
||||||
|
newPosition =
|
||||||
|
getBalancedChildPosition(spaces[parentIndex]); // Ensure balanced position
|
||||||
|
} else {
|
||||||
|
newPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
|
||||||
|
}
|
||||||
|
|
||||||
SpaceModel newSpace = SpaceModel(
|
SpaceModel newSpace = SpaceModel(
|
||||||
name: name,
|
name: name,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
position: centerPosition,
|
position: newPosition,
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
children: [],
|
children: [],
|
||||||
status: SpaceStatus.newSpace,
|
status: SpaceStatus.newSpace,
|
||||||
@ -425,7 +432,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
Connection(
|
Connection(
|
||||||
startSpace: parent,
|
startSpace: parent,
|
||||||
endSpace: child,
|
endSpace: child,
|
||||||
direction: child.incomingConnection?.direction ?? "down",
|
direction: "down",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -522,6 +529,38 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Offset getBalancedChildPosition(SpaceModel parent) {
|
||||||
|
int totalSiblings = parent.children.length + 1;
|
||||||
|
double totalWidth = (totalSiblings - 1) * 250; // Horizontal spacing
|
||||||
|
double startX = parent.position.dx - (totalWidth / 2);
|
||||||
|
|
||||||
|
Offset position = Offset(startX + (parent.children.length * 250), parent.position.dy + 180);
|
||||||
|
|
||||||
|
// Check for overlaps & adjust
|
||||||
|
while (spaces.any((s) => (s.position - position).distance < 250)) {
|
||||||
|
position = Offset(position.dx + 250, position.dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void realignTree() {
|
||||||
|
void updatePositions(SpaceModel node, double x, double y) {
|
||||||
|
node.position = Offset(x, y);
|
||||||
|
|
||||||
|
int numChildren = node.children.length;
|
||||||
|
double childStartX = x - ((numChildren - 1) * 250) / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < numChildren; i++) {
|
||||||
|
updatePositions(node.children[i], childStartX + (i * 250), y + 180);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spaces.isNotEmpty) {
|
||||||
|
updatePositions(spaces.first, spaces.first.position.dx, spaces.first.position.dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onDuplicate(BuildContext parentContext) {
|
void _onDuplicate(BuildContext parentContext) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
@ -604,29 +643,57 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
void _duplicateSpace(SpaceModel space) {
|
void _duplicateSpace(SpaceModel space) {
|
||||||
final Map<SpaceModel, SpaceModel> originalToDuplicate = {};
|
final Map<SpaceModel, SpaceModel> originalToDuplicate = {};
|
||||||
const double horizontalGap = 200.0;
|
double horizontalGap = 250.0; // Increased spacing
|
||||||
const double verticalGap = 100.0;
|
double verticalGap = 180.0; // Adjusted for better visualization
|
||||||
|
|
||||||
SpaceModel duplicateRecursive(
|
print("🟢 Duplicating: ${space.name}");
|
||||||
SpaceModel original, Offset parentPosition, SpaceModel? duplicatedParent) {
|
|
||||||
Offset newPosition = Offset(parentPosition.dx + horizontalGap, original.position.dy);
|
|
||||||
|
|
||||||
while (spaces.any((s) =>
|
/// **Find a new position ensuring no overlap**
|
||||||
(s.position - newPosition).distance < horizontalGap && s.status != SpaceStatus.deleted)) {
|
Offset getBalancedChildPosition(SpaceModel parent) {
|
||||||
newPosition += Offset(horizontalGap, 0);
|
int totalSiblings = parent.children.length + 1;
|
||||||
|
double totalWidth = (totalSiblings - 1) * horizontalGap;
|
||||||
|
double startX = parent.position.dx - (totalWidth / 2);
|
||||||
|
Offset position = Offset(
|
||||||
|
startX + (parent.children.length * horizontalGap), parent.position.dy + verticalGap);
|
||||||
|
|
||||||
|
// **Check for overlaps & adjust**
|
||||||
|
while (spaces.any((s) => (s.position - position).distance < horizontalGap)) {
|
||||||
|
position = Offset(position.dx + horizontalGap, position.dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("🔹 New position for ${parent.name}: (${position.dx}, ${position.dy})");
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// **Realign the entire tree after duplication**
|
||||||
|
void realignTree() {
|
||||||
|
void updatePositions(SpaceModel node, double x, double y) {
|
||||||
|
node.position = Offset(x, y);
|
||||||
|
print("✅ Adjusted ${node.name} to (${x}, ${y})");
|
||||||
|
|
||||||
|
int numChildren = node.children.length;
|
||||||
|
double childStartX = x - ((numChildren - 1) * horizontalGap) / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < numChildren; i++) {
|
||||||
|
updatePositions(node.children[i], childStartX + (i * horizontalGap), y + verticalGap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spaces.isNotEmpty) {
|
||||||
|
print("🔄 Realigning tree...");
|
||||||
|
updatePositions(spaces.first, spaces.first.position.dx, spaces.first.position.dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// **Recursive duplication logic**
|
||||||
|
SpaceModel duplicateRecursive(SpaceModel original, SpaceModel? duplicatedParent) {
|
||||||
|
Offset newPosition = duplicatedParent == null
|
||||||
|
? Offset(original.position.dx + horizontalGap, original.position.dy)
|
||||||
|
: getBalancedChildPosition(duplicatedParent);
|
||||||
|
|
||||||
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
||||||
|
print(
|
||||||
final List<SubspaceModel>? duplicatedSubspaces;
|
"🟡 Duplicating ${original.name} → ${duplicatedName} at (${newPosition.dx}, ${newPosition.dy})");
|
||||||
final List<Tag>? duplicatedTags;
|
|
||||||
if (original.spaceModel != null) {
|
|
||||||
duplicatedTags = [];
|
|
||||||
duplicatedSubspaces = [];
|
|
||||||
} else {
|
|
||||||
duplicatedTags = original.tags;
|
|
||||||
duplicatedSubspaces = original.subspaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
final duplicated = SpaceModel(
|
final duplicated = SpaceModel(
|
||||||
name: duplicatedName,
|
name: duplicatedName,
|
||||||
@ -637,12 +704,10 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
status: SpaceStatus.newSpace,
|
status: SpaceStatus.newSpace,
|
||||||
parent: duplicatedParent,
|
parent: duplicatedParent,
|
||||||
spaceModel: original.spaceModel,
|
spaceModel: original.spaceModel,
|
||||||
subspaces: duplicatedSubspaces,
|
subspaces: original.subspaces,
|
||||||
tags: duplicatedTags,
|
tags: original.tags,
|
||||||
);
|
);
|
||||||
|
|
||||||
originalToDuplicate[original] = duplicated;
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
spaces.add(duplicated);
|
spaces.add(duplicated);
|
||||||
_updateNodePosition(duplicated, duplicated.position);
|
_updateNodePosition(duplicated, duplicated.position);
|
||||||
@ -651,60 +716,42 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
final newConnection = Connection(
|
final newConnection = Connection(
|
||||||
startSpace: duplicatedParent,
|
startSpace: duplicatedParent,
|
||||||
endSpace: duplicated,
|
endSpace: duplicated,
|
||||||
direction: original.incomingConnection?.direction ?? 'down',
|
direction: "down",
|
||||||
);
|
);
|
||||||
connections.add(newConnection);
|
connections.add(newConnection);
|
||||||
duplicated.incomingConnection = newConnection;
|
duplicated.incomingConnection = newConnection;
|
||||||
duplicatedParent.addOutgoingConnection(newConnection);
|
duplicatedParent.addOutgoingConnection(newConnection);
|
||||||
|
duplicatedParent.children.add(duplicated);
|
||||||
|
print("🔗 Created connection: ${duplicatedParent.name} → ${duplicated.name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (original.parent != null && duplicatedParent == null) {
|
// **Recalculate the whole tree to avoid overlaps**
|
||||||
final originalParent = original.parent!;
|
realignTree();
|
||||||
final duplicatedParent = originalToDuplicate[originalParent] ?? originalParent;
|
|
||||||
|
|
||||||
final parentConnection = Connection(
|
|
||||||
startSpace: duplicatedParent,
|
|
||||||
endSpace: duplicated,
|
|
||||||
direction: original.incomingConnection?.direction ?? "down",
|
|
||||||
);
|
|
||||||
|
|
||||||
connections.add(parentConnection);
|
|
||||||
duplicated.incomingConnection = parentConnection;
|
|
||||||
duplicatedParent.addOutgoingConnection(parentConnection);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final childrenWithDownDirection = original.children
|
// Recursively duplicate children
|
||||||
.where((child) =>
|
for (var child in original.children) {
|
||||||
child.incomingConnection?.direction == "down" && child.status != SpaceStatus.deleted)
|
duplicateRecursive(child, duplicated);
|
||||||
.toList();
|
|
||||||
|
|
||||||
Offset childStartPosition = childrenWithDownDirection.length == 1
|
|
||||||
? duplicated.position
|
|
||||||
: newPosition + Offset(0, verticalGap);
|
|
||||||
|
|
||||||
for (final child in original.children) {
|
|
||||||
final isDownDirection = child.incomingConnection?.direction == "down" ?? false;
|
|
||||||
|
|
||||||
if (isDownDirection && childrenWithDownDirection.length == 1) {
|
|
||||||
childStartPosition = duplicated.position + Offset(0, verticalGap);
|
|
||||||
} else if (!isDownDirection) {
|
|
||||||
childStartPosition = duplicated.position + Offset(horizontalGap, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
final duplicatedChild = duplicateRecursive(child, childStartPosition, duplicated);
|
|
||||||
duplicated.children.add(duplicatedChild);
|
|
||||||
childStartPosition += Offset(0, verticalGap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return duplicated;
|
return duplicated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// **Handle root duplication**
|
||||||
if (space.parent == null) {
|
if (space.parent == null) {
|
||||||
duplicateRecursive(space, space.position, null);
|
print("🟠 Duplicating root node: ${space.name}");
|
||||||
|
SpaceModel duplicatedRoot = duplicateRecursive(space, null);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
spaces.add(duplicatedRoot);
|
||||||
|
realignTree();
|
||||||
|
});
|
||||||
|
|
||||||
|
print("✅ Root duplication successful: ${duplicatedRoot.name}");
|
||||||
} else {
|
} else {
|
||||||
final duplicatedParent = originalToDuplicate[space.parent!] ?? space.parent!;
|
duplicateRecursive(space, space.parent);
|
||||||
duplicateRecursive(space, space.position, duplicatedParent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("🟢 Finished duplication process for: ${space.name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
|
class SidebarAddCommunityButton extends StatelessWidget {
|
||||||
|
const SidebarAddCommunityButton({
|
||||||
|
required this.existingCommunityNames,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<String> existingCommunityNames;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox.square(
|
||||||
|
dimension: 30,
|
||||||
|
child: IconButton(
|
||||||
|
style: IconButton.styleFrom(
|
||||||
|
iconSize: 20,
|
||||||
|
backgroundColor: ColorsManager.circleImageBackground,
|
||||||
|
shape: const CircleBorder(
|
||||||
|
side: BorderSide(
|
||||||
|
color: ColorsManager.lightGrayBorderColor,
|
||||||
|
width: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () => _showCreateCommunityDialog(context),
|
||||||
|
icon: SvgPicture.asset(Assets.addIcon),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showCreateCommunityDialog(BuildContext context) => showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => CreateCommunityDialog(
|
||||||
|
isEditMode: false,
|
||||||
|
existingCommunityNames: existingCommunityNames,
|
||||||
|
onCreateCommunity: (name, description) {
|
||||||
|
context.read<SpaceManagementBloc>().add(
|
||||||
|
CreateCommunityEvent(name, description, context),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
|
class SidebarHeader extends StatelessWidget {
|
||||||
|
const SidebarHeader({required this.existingCommunityNames, super.key});
|
||||||
|
|
||||||
|
final List<String> existingCommunityNames;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
decoration: subSectionContainerDecoration,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Communities',
|
||||||
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SidebarAddCommunityButton(existingCommunityNames: existingCommunityNames),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,15 @@
|
|||||||
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:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/common/widgets/search_bar.dart';
|
import 'package:syncrow_web/common/widgets/search_bar.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_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/widgets/community_tile.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_tile.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_header.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class SidebarWidget extends StatefulWidget {
|
class SidebarWidget extends StatefulWidget {
|
||||||
@ -19,62 +17,59 @@ class SidebarWidget extends StatefulWidget {
|
|||||||
final String? selectedSpaceUuid;
|
final String? selectedSpaceUuid;
|
||||||
|
|
||||||
const SidebarWidget({
|
const SidebarWidget({
|
||||||
super.key,
|
|
||||||
required this.communities,
|
required this.communities,
|
||||||
this.selectedSpaceUuid,
|
this.selectedSpaceUuid,
|
||||||
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SidebarWidgetState createState() => _SidebarWidgetState();
|
State<SidebarWidget> createState() => _SidebarWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SidebarWidgetState extends State<SidebarWidget> {
|
class _SidebarWidgetState extends State<SidebarWidget> {
|
||||||
String _searchQuery = ''; // Track search query
|
String _searchQuery = '';
|
||||||
String? _selectedSpaceUuid;
|
String? _selectedSpaceUuid;
|
||||||
String? _selectedId;
|
String? _selectedId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_selectedId = widget.selectedSpaceUuid;
|
||||||
super.initState();
|
super.initState();
|
||||||
_selectedId = widget.selectedSpaceUuid; // Initialize with the passed selected space UUID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant SidebarWidget oldWidget) {
|
void didUpdateWidget(covariant SidebarWidget oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
|
||||||
if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid) {
|
if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid) {
|
||||||
setState(() {
|
setState(() => _selectedId = widget.selectedSpaceUuid);
|
||||||
_selectedId = widget.selectedSpaceUuid;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to filter communities based on the search query
|
List<CommunityModel> _filteredCommunities() {
|
||||||
List<CommunityModel> _filterCommunities() {
|
|
||||||
if (_searchQuery.isEmpty) {
|
if (_searchQuery.isEmpty) {
|
||||||
// Reset the selected community and space UUIDs if there's no query
|
|
||||||
_selectedSpaceUuid = null;
|
_selectedSpaceUuid = null;
|
||||||
return widget.communities;
|
return widget.communities;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter communities and expand only those that match the query
|
|
||||||
return widget.communities.where((community) {
|
return widget.communities.where((community) {
|
||||||
final containsQueryInCommunity =
|
final containsQueryInCommunity =
|
||||||
community.name.toLowerCase().contains(_searchQuery.toLowerCase());
|
community.name.toLowerCase().contains(_searchQuery.toLowerCase());
|
||||||
final containsQueryInSpaces =
|
final containsQueryInSpaces = community.spaces.any((space) =>
|
||||||
community.spaces.any((space) => _containsQuery(space, _searchQuery.toLowerCase()));
|
_containsQuery(space: space, query: _searchQuery.toLowerCase()));
|
||||||
|
|
||||||
return containsQueryInCommunity || containsQueryInSpaces;
|
return containsQueryInCommunity || containsQueryInSpaces;
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to determine if any space or its children match the search query
|
bool _containsQuery({
|
||||||
bool _containsQuery(SpaceModel space, String query) {
|
required SpaceModel space,
|
||||||
|
required String query,
|
||||||
|
}) {
|
||||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
final matchesSpace = space.name.toLowerCase().contains(query);
|
||||||
final matchesChildren =
|
final matchesChildren = space.children.any(
|
||||||
space.children.any((child) => _containsQuery(child, query)); // Recursive check for children
|
(child) => _containsQuery(space: child, query: query),
|
||||||
|
);
|
||||||
|
|
||||||
// If the space or any of its children match the query, expand this space
|
|
||||||
if (matchesSpace || matchesChildren) {
|
if (matchesSpace || matchesChildren) {
|
||||||
_selectedSpaceUuid = space.uuid;
|
_selectedSpaceUuid = space.uuid;
|
||||||
}
|
}
|
||||||
@ -83,79 +78,35 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool _isSpaceOrChildSelected(SpaceModel space) {
|
bool _isSpaceOrChildSelected(SpaceModel space) {
|
||||||
// Return true if the current space or any of its child spaces is selected
|
final isSpaceSelected = _selectedSpaceUuid == space.uuid;
|
||||||
if (_selectedSpaceUuid == space.uuid) {
|
final anySubSpaceIsSelected = space.children.any(_isSpaceOrChildSelected);
|
||||||
return true;
|
return isSpaceSelected || anySubSpaceIsSelected;
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively check if any child spaces match the query
|
|
||||||
for (var child in space.children) {
|
|
||||||
if (_isSpaceOrChildSelected(child)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final filteredCommunities = _filterCommunities();
|
final filteredCommunities = _filteredCommunities();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: 300,
|
width: 300,
|
||||||
decoration: subSectionContainerDecoration,
|
decoration: subSectionContainerDecoration,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min, // Ensures the Column only takes necessary height
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// Communities title with the add button
|
SidebarHeader(
|
||||||
Container(
|
existingCommunityNames:
|
||||||
decoration: subSectionContainerDecoration,
|
widget.communities.map((community) => community.name).toList(),
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text('Communities',
|
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
)),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () => _navigateToBlank(context),
|
|
||||||
child: Container(
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.roundedAddIcon,
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
// Search bar
|
|
||||||
CustomSearchBar(
|
CustomSearchBar(
|
||||||
onSearchChanged: (query) {
|
onSearchChanged: (query) => setState(() => _searchQuery = query),
|
||||||
setState(() {
|
|
||||||
_searchQuery = query;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
// Community list
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: filteredCommunities.map((community) {
|
children: filteredCommunities
|
||||||
return _buildCommunityTile(context, community);
|
.map((community) => _buildCommunityTile(context, community))
|
||||||
}).toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -163,18 +114,7 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _navigateToBlank(BuildContext context) {
|
|
||||||
setState(() {
|
|
||||||
_selectedId = '';
|
|
||||||
});
|
|
||||||
context.read<SpaceManagementBloc>().add(
|
|
||||||
NewCommunityEvent(communities: widget.communities),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCommunityTile(BuildContext context, CommunityModel community) {
|
Widget _buildCommunityTile(BuildContext context, CommunityModel community) {
|
||||||
bool hasChildren = community.spaces.isNotEmpty;
|
|
||||||
|
|
||||||
return CommunityTile(
|
return CommunityTile(
|
||||||
title: community.name,
|
title: community.name,
|
||||||
key: ValueKey(community.uuid),
|
key: ValueKey(community.uuid),
|
||||||
@ -183,7 +123,7 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
onItemSelected: () {
|
onItemSelected: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedId = community.uuid;
|
_selectedId = community.uuid;
|
||||||
_selectedSpaceUuid = null; // Update the selected community
|
_selectedSpaceUuid = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
context.read<CenterBodyBloc>().add(CommunitySelectedEvent());
|
context.read<CenterBodyBloc>().add(CommunitySelectedEvent());
|
||||||
@ -192,46 +132,51 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
SelectCommunityEvent(selectedCommunity: community),
|
SelectCommunityEvent(selectedCommunity: community),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onExpansionChanged: (String title, bool expanded) {
|
onExpansionChanged: (title, expanded) {},
|
||||||
_handleExpansionChange(community.uuid, expanded);
|
children: community.spaces
|
||||||
},
|
.where((space) {
|
||||||
children: hasChildren
|
final isDeleted = space.status != SpaceStatus.deleted;
|
||||||
? community.spaces
|
final isParentDeleted = space.status != SpaceStatus.parentDeleted;
|
||||||
.where((space) => (space.status != SpaceStatus.deleted ||
|
return (isDeleted || isParentDeleted);
|
||||||
space.status != SpaceStatus.parentDeleted))
|
})
|
||||||
.map((space) => _buildSpaceTile(space, community))
|
.map((space) => _buildSpaceTile(space: space, community: community))
|
||||||
.toList()
|
.toList(),
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSpaceTile(SpaceModel space, CommunityModel community, {int depth = 1}) {
|
Widget _buildSpaceTile({
|
||||||
bool isExpandedSpace = _isSpaceOrChildSelected(space);
|
required SpaceModel space,
|
||||||
|
required CommunityModel community,
|
||||||
|
}) {
|
||||||
|
final spaceIsExpanded = _isSpaceOrChildSelected(space);
|
||||||
|
final isSelected = _selectedId == space.uuid;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(left: depth * 16.0),
|
padding: const EdgeInsetsDirectional.only(start: 16.0),
|
||||||
child: SpaceTile(
|
child: SpaceTile(
|
||||||
title: space.name,
|
title: space.name,
|
||||||
key: ValueKey(space.uuid),
|
key: ValueKey(space.uuid),
|
||||||
isSelected: _selectedId == space.uuid,
|
isSelected: isSelected,
|
||||||
initiallyExpanded: isExpandedSpace,
|
initiallyExpanded: spaceIsExpanded,
|
||||||
onExpansionChanged: (bool expanded) {
|
onExpansionChanged: (expanded) {},
|
||||||
_handleExpansionChange(space.uuid ?? '', expanded);
|
onItemSelected: () {
|
||||||
},
|
setState(() {
|
||||||
onItemSelected: () {
|
_selectedId = space.uuid;
|
||||||
setState(() {
|
_selectedSpaceUuid = space.uuid;
|
||||||
_selectedId = space.uuid;
|
});
|
||||||
_selectedSpaceUuid = space.uuid;
|
|
||||||
});
|
|
||||||
|
|
||||||
context.read<SpaceManagementBloc>().add(
|
context.read<SpaceManagementBloc>().add(
|
||||||
SelectSpaceEvent(selectedCommunity: community, selectedSpace: space),
|
SelectSpaceEvent(selectedCommunity: community, selectedSpace: space),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
children: space.children.isNotEmpty
|
children: space.children
|
||||||
? space.children.map((childSpace) => _buildSpaceTile(childSpace, community)).toList()
|
.map(
|
||||||
: [], // Recursively render child spaces if available
|
(childSpace) => _buildSpaceTile(
|
||||||
));
|
space: childSpace,
|
||||||
|
community: community,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleExpansionChange(String uuid, bool expanded) {}
|
|
||||||
}
|
}
|
||||||
|
@ -47,18 +47,6 @@ class SpaceCardWidget extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
buildSpaceContainer(index), // Build the space container
|
buildSpaceContainer(index), // Build the space container
|
||||||
if (isHovered) ...[
|
if (isHovered) ...[
|
||||||
PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'left',
|
|
||||||
offset: const Offset(-21, 20),
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
|
||||||
PlusButtonWidget(
|
|
||||||
index: index,
|
|
||||||
direction: 'right',
|
|
||||||
offset: const Offset(140, 20),
|
|
||||||
onButtonTap: onButtonTap,
|
|
||||||
),
|
|
||||||
PlusButtonWidget(
|
PlusButtonWidget(
|
||||||
index: index,
|
index: index,
|
||||||
direction: 'down',
|
direction: 'down',
|
||||||
|
@ -2,8 +2,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_m
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
|
|
||||||
class SpaceHelper {
|
class SpaceHelper {
|
||||||
static SpaceModel? findSpaceByUuid(
|
static SpaceModel? findSpaceByUuid(String? uuid, List<CommunityModel> communities) {
|
||||||
String? uuid, List<CommunityModel> communities) {
|
|
||||||
for (var community in communities) {
|
for (var community in communities) {
|
||||||
for (var space in community.spaces) {
|
for (var space in community.spaces) {
|
||||||
if (space.uuid == uuid) return space;
|
if (space.uuid == uuid) return space;
|
||||||
@ -12,8 +11,7 @@ class SpaceHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SpaceModel? findSpaceByInternalId(
|
static SpaceModel? findSpaceByInternalId(String? internalId, List<SpaceModel> spaces) {
|
||||||
String? internalId, List<SpaceModel> spaces) {
|
|
||||||
if (internalId != null) {
|
if (internalId != null) {
|
||||||
for (var space in spaces) {
|
for (var space in spaces) {
|
||||||
if (space.internalId == internalId) return space;
|
if (space.internalId == internalId) return space;
|
||||||
@ -23,8 +21,7 @@ class SpaceHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String generateUniqueSpaceName(
|
static String generateUniqueSpaceName(String originalName, List<SpaceModel> spaces) {
|
||||||
String originalName, List<SpaceModel> spaces) {
|
|
||||||
final baseName = originalName.replaceAll(RegExp(r'\(\d+\)$'), '').trim();
|
final baseName = originalName.replaceAll(RegExp(r'\(\d+\)$'), '').trim();
|
||||||
int maxNumber = 0;
|
int maxNumber = 0;
|
||||||
|
|
||||||
@ -54,13 +51,10 @@ class SpaceHelper {
|
|||||||
|
|
||||||
return space == selectedSpace ||
|
return space == selectedSpace ||
|
||||||
selectedSpace.parent?.internalId == space.internalId ||
|
selectedSpace.parent?.internalId == space.internalId ||
|
||||||
selectedSpace.children
|
selectedSpace.children?.any((child) => child.internalId == space.internalId) == true;
|
||||||
?.any((child) => child.internalId == space.internalId) ==
|
|
||||||
true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isNameConflict(
|
static bool isNameConflict(String value, SpaceModel? parentSpace, SpaceModel? editSpace) {
|
||||||
String value, SpaceModel? parentSpace, SpaceModel? editSpace) {
|
|
||||||
final siblings = parentSpace?.children
|
final siblings = parentSpace?.children
|
||||||
.where((child) => child.internalId != editSpace?.internalId)
|
.where((child) => child.internalId != editSpace?.internalId)
|
||||||
.toList() ??
|
.toList() ??
|
||||||
@ -71,19 +65,17 @@ class SpaceHelper {
|
|||||||
.toList() ??
|
.toList() ??
|
||||||
[];
|
[];
|
||||||
|
|
||||||
final editSiblingConflict =
|
final editSiblingConflict = editSiblings.any((child) => child.name == value);
|
||||||
editSiblings.any((child) => child.name == value);
|
|
||||||
|
|
||||||
final siblingConflict = siblings.any((child) => child.name == value);
|
final siblingConflict = siblings.any((child) => child.name == value);
|
||||||
|
|
||||||
final parentConflict = parentSpace?.name == value &&
|
final parentConflict =
|
||||||
parentSpace?.internalId != editSpace?.internalId;
|
parentSpace?.name == value && parentSpace?.internalId != editSpace?.internalId;
|
||||||
|
|
||||||
final parentOfEditSpaceConflict = editSpace?.parent?.name == value &&
|
final parentOfEditSpaceConflict =
|
||||||
editSpace?.parent?.internalId != editSpace?.internalId;
|
editSpace?.parent?.name == value && editSpace?.parent?.internalId != editSpace?.internalId;
|
||||||
|
|
||||||
final childConflict =
|
final childConflict = editSpace?.children.any((child) => child.name == value) ?? false;
|
||||||
editSpace?.children.any((child) => child.name == value) ?? false;
|
|
||||||
|
|
||||||
return siblingConflict ||
|
return siblingConflict ||
|
||||||
parentConflict ||
|
parentConflict ||
|
||||||
|
@ -194,9 +194,10 @@ class VisitorPasswordBloc
|
|||||||
emit(DeviceLoaded());
|
emit(DeviceLoaded());
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
data = await AccessMangApi().fetchDevices(projectUuid);
|
data = await AccessMangApi().fetchDoorLockDeviceList(projectUuid);
|
||||||
emit(TableLoaded(data));
|
emit(TableLoaded(data));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print("error: $e");
|
||||||
emit(FailedState(e.toString()));
|
emit(FailedState(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,23 @@ import 'package:syncrow_web/services/api/http_service.dart';
|
|||||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||||
|
|
||||||
class AccessMangApi {
|
class AccessMangApi {
|
||||||
|
AccessMangApi() {
|
||||||
|
_validateEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _validateEndpoints() {
|
||||||
|
if (!ApiEndpoints.getDevices.contains('{projectId}')) {
|
||||||
|
throw Exception("Endpoint 'getDevices' must contain '{projectId}' placeholder.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<PasswordModel>> fetchVisitorPassword(String projectId) async {
|
Future<List<PasswordModel>> fetchVisitorPassword(String projectId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.visitorPassword.replaceAll('{projectId}', projectId),
|
path: ApiEndpoints.visitorPassword,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = json;
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
List<PasswordModel> passwordList = jsonData.map((jsonItem) {
|
List<PasswordModel> passwordList = jsonData.map((jsonItem) {
|
||||||
return PasswordModel.fromJson(jsonItem);
|
return PasswordModel.fromJson(jsonItem);
|
||||||
}).toList();
|
}).toList();
|
||||||
@ -25,17 +35,22 @@ class AccessMangApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future fetchDevices(String projectId) async {
|
Future fetchDoorLockDeviceList(String projectId) async {
|
||||||
try {
|
try {
|
||||||
|
// The endpoint structure is already validated during initialization.
|
||||||
|
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getDevices.replaceAll('{projectId}', projectId),
|
path: ApiEndpoints.getDevices.replaceAll('{projectId}', projectId),
|
||||||
|
queryParameters: {
|
||||||
|
'deviceType': 'DOOR_LOCK',
|
||||||
|
},
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = json;
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
List<DeviceModel> passwordList = jsonData.map((jsonItem) {
|
List<DeviceModel> deviceList = jsonData.map((jsonItem) {
|
||||||
return DeviceModel.fromJson(jsonItem);
|
return DeviceModel.fromJson(jsonItem);
|
||||||
}).toList();
|
}).toList();
|
||||||
return passwordList;
|
return deviceList;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -52,14 +67,15 @@ class AccessMangApi {
|
|||||||
String? invalidTime,
|
String? invalidTime,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOnlineOneTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
"email": email,
|
"email": email,
|
||||||
"passwordName": passwordName,
|
"passwordName": passwordName,
|
||||||
"password": password,
|
"password": password,
|
||||||
"devicesUuid": devicesUuid,
|
"devicesUuid": devicesUuid,
|
||||||
"effectiveTime": effectiveTime,
|
"effectiveTime": effectiveTime,
|
||||||
"invalidTime": invalidTime
|
"invalidTime": invalidTime,
|
||||||
|
"operationType": "ONLINE_ONE_TIME",
|
||||||
}),
|
}),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
@ -84,13 +100,13 @@ class AccessMangApi {
|
|||||||
"password": password,
|
"password": password,
|
||||||
"effectiveTime": effectiveTime,
|
"effectiveTime": effectiveTime,
|
||||||
"invalidTime": invalidTime,
|
"invalidTime": invalidTime,
|
||||||
|
"operationType": "ONLINE_MULTIPLE_TIME",
|
||||||
};
|
};
|
||||||
if (scheduleList != null) {
|
if (scheduleList != null) {
|
||||||
body["scheduleList"] =
|
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
|
||||||
scheduleList.map((schedule) => schedule.toJson()).toList();
|
|
||||||
}
|
}
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOnlineMultipleTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode(body),
|
body: jsonEncode(body),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
@ -105,8 +121,9 @@ class AccessMangApi {
|
|||||||
Future postOffLineOneTime(
|
Future postOffLineOneTime(
|
||||||
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
{String? email, String? passwordName, List<String>? devicesUuid}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOffLineOneTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
|
"operationType": "OFFLINE_ONE_TIME",
|
||||||
"email": email,
|
"email": email,
|
||||||
"passwordName": passwordName,
|
"passwordName": passwordName,
|
||||||
"devicesUuid": devicesUuid
|
"devicesUuid": devicesUuid
|
||||||
@ -126,13 +143,14 @@ class AccessMangApi {
|
|||||||
String? invalidTime,
|
String? invalidTime,
|
||||||
List<String>? devicesUuid}) async {
|
List<String>? devicesUuid}) async {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.sendOffLineMultipleTime,
|
path: ApiEndpoints.visitorPassword,
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
"email": email,
|
"email": email,
|
||||||
"devicesUuid": devicesUuid,
|
"devicesUuid": devicesUuid,
|
||||||
"passwordName": passwordName,
|
"passwordName": passwordName,
|
||||||
"effectiveTime": effectiveTime,
|
"effectiveTime": effectiveTime,
|
||||||
"invalidTime": invalidTime,
|
"invalidTime": invalidTime,
|
||||||
|
"operationType": "OFFLINE_MULTIPLE_TIME",
|
||||||
}),
|
}),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
|
@ -23,9 +23,7 @@ class DevicesManagementApi {
|
|||||||
: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = communityId.isNotEmpty && spaceId.isNotEmpty
|
List<dynamic> jsonData = json['data'];
|
||||||
? json['data']
|
|
||||||
: json;
|
|
||||||
List<AllDevicesModel> devicesList = jsonData.map((jsonItem) {
|
List<AllDevicesModel> devicesList = jsonData.map((jsonItem) {
|
||||||
return AllDevicesModel.fromJson(jsonItem);
|
return AllDevicesModel.fromJson(jsonItem);
|
||||||
}).toList();
|
}).toList();
|
||||||
@ -34,7 +32,7 @@ class DevicesManagementApi {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('fetchDevices Error fetching $e');
|
debugPrint('Error fetching device $e');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +43,7 @@ class DevicesManagementApi {
|
|||||||
path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', uuid),
|
path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', uuid),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceStatus.fromJson(json);
|
return DeviceStatus.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -62,7 +60,7 @@ class DevicesManagementApi {
|
|||||||
Future getPowerClampInfo(String deviceId) async {
|
Future getPowerClampInfo(String deviceId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.powerClamp.replaceAll('{powerClampUuid}', deviceId),
|
path: ApiEndpoints.getDeviceStatus.replaceAll('{uuid}', deviceId),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return json;
|
return json;
|
||||||
@ -93,13 +91,13 @@ class DevicesManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deviceBatchControl(
|
Future<bool> deviceBatchControl(List<String> uuids, String code, dynamic value) async {
|
||||||
List<String> uuids, String code, dynamic value) async {
|
|
||||||
try {
|
try {
|
||||||
final body = {
|
final body = {
|
||||||
'devicesUuid': uuids,
|
'devicesUuid': uuids,
|
||||||
'code': code,
|
'code': code,
|
||||||
'value': value,
|
'value': value,
|
||||||
|
'operationType': 'COMMAND',
|
||||||
};
|
};
|
||||||
|
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
@ -107,7 +105,7 @@ class DevicesManagementApi {
|
|||||||
body: body,
|
body: body,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return (json['successResults'] as List).isNotEmpty;
|
return json['success'] ?? false;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -118,8 +116,7 @@ class DevicesManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<List<DeviceModel>> getDevicesByGatewayId(
|
static Future<List<DeviceModel>> getDevicesByGatewayId(String gatewayId) async {
|
||||||
String gatewayId) async {
|
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId),
|
path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId),
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
@ -128,7 +125,7 @@ class DevicesManagementApi {
|
|||||||
if (json == null || json.isEmpty || json == []) {
|
if (json == null || json.isEmpty || json == []) {
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
for (var device in json['devices']) {
|
for (var device in json['data']['devices']) {
|
||||||
devices.add(DeviceModel.fromJson(device));
|
devices.add(DeviceModel.fromJson(device));
|
||||||
}
|
}
|
||||||
return devices;
|
return devices;
|
||||||
@ -153,12 +150,10 @@ class DevicesManagementApi {
|
|||||||
String code,
|
String code,
|
||||||
) async {
|
) async {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getDeviceLogs
|
path: ApiEndpoints.getDeviceLogs.replaceAll('{uuid}', uuid).replaceAll('{code}', code),
|
||||||
.replaceAll('{uuid}', uuid)
|
|
||||||
.replaceAll('{code}', code),
|
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceReport.fromJson(json);
|
return DeviceReport.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -174,7 +169,7 @@ class DevicesManagementApi {
|
|||||||
.replaceAll('{endTime}', to ?? ''),
|
.replaceAll('{endTime}', to ?? ''),
|
||||||
showServerMessage: false,
|
showServerMessage: false,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceReport.fromJson(json);
|
return DeviceReport.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -190,7 +185,7 @@ class DevicesManagementApi {
|
|||||||
queryParameters: queryParameters,
|
queryParameters: queryParameters,
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return DeviceStatus.fromJson(json['status']);
|
return DeviceStatus.fromJson(json['data']['status']);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -228,8 +223,7 @@ class DevicesManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> addScheduleRecord(
|
Future<bool> addScheduleRecord(ScheduleEntry sendSchedule, String uuid) async {
|
||||||
ScheduleEntry sendSchedule, String uuid) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
|
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
|
||||||
@ -246,8 +240,7 @@ class DevicesManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<ScheduleModel>> getDeviceSchedules(
|
Future<List<ScheduleModel>> getDeviceSchedules(String uuid, String category) async {
|
||||||
String uuid, String category) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getScheduleByDeviceId
|
path: ApiEndpoints.getScheduleByDeviceId
|
||||||
@ -270,9 +263,7 @@ class DevicesManagementApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateScheduleRecord(
|
Future<bool> updateScheduleRecord(
|
||||||
{required bool enable,
|
{required bool enable, required String uuid, required String scheduleId}) async {
|
||||||
required String uuid,
|
|
||||||
required String scheduleId}) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().put(
|
final response = await HTTPService().put(
|
||||||
path: ApiEndpoints.updateScheduleByDeviceId
|
path: ApiEndpoints.updateScheduleByDeviceId
|
||||||
@ -293,8 +284,7 @@ class DevicesManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> editScheduleRecord(
|
Future<bool> editScheduleRecord(String uuid, ScheduleEntry newSchedule) async {
|
||||||
String uuid, ScheduleEntry newSchedule) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().put(
|
final response = await HTTPService().put(
|
||||||
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
|
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/model/pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_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/create_subspace_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_body_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
|
||||||
|
|
||||||
class CommunitySpaceManagementApi {
|
class CommunitySpaceManagementApi {
|
||||||
// Community Management APIs
|
// Community Management APIs
|
||||||
Future<List<CommunityModel>> fetchCommunities(String projectId,
|
Future<List<CommunityModel>> fetchCommunities(String projectId, {int page = 1}) async {
|
||||||
{int page = 1}) async {
|
|
||||||
try {
|
try {
|
||||||
List<CommunityModel> allCommunities = [];
|
List<CommunityModel> allCommunities = [];
|
||||||
bool hasNext = true;
|
bool hasNext = true;
|
||||||
|
|
||||||
while (hasNext) {
|
while (hasNext) {
|
||||||
await HTTPService().get(
|
await HTTPService().get(
|
||||||
path: ApiEndpoints.getCommunityList
|
path: ApiEndpoints.getCommunityList.replaceAll('{projectId}', projectId),
|
||||||
.replaceAll('{projectId}', projectId),
|
queryParameters: {
|
||||||
queryParameters: {'page': page},
|
'page': page,
|
||||||
|
},
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
try {
|
try {
|
||||||
List<dynamic> jsonData = json['data'] ?? [];
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
@ -49,11 +48,42 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<PaginationModel> fetchCommunitiesAndSpaces(
|
||||||
|
{required String projectId, int page = 1, String search = ''}) async {
|
||||||
|
PaginationModel paginationModel = const PaginationModel.emptyConstructor();
|
||||||
|
|
||||||
|
try {
|
||||||
|
bool hasNext = false;
|
||||||
|
await HTTPService().get(
|
||||||
|
path: ApiEndpoints.getCommunityList.replaceAll('{projectId}', projectId),
|
||||||
|
queryParameters: {'page': page, 'includeSpaces': true, 'size': 25, 'search': search},
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
try {
|
||||||
|
List<dynamic> jsonData = json['data'] ?? [];
|
||||||
|
hasNext = json['hasNext'] ?? false;
|
||||||
|
int currentPage = json['page'] ?? 1;
|
||||||
|
List<CommunityModel> communityList = jsonData.map((jsonItem) {
|
||||||
|
return CommunityModel.fromJson(jsonItem);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
page = currentPage + 1;
|
||||||
|
paginationModel = PaginationModel(
|
||||||
|
pageNum: page, hasNext: hasNext, size: 25, communities: communityList);
|
||||||
|
return paginationModel;
|
||||||
|
} catch (_) {
|
||||||
|
hasNext = false;
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
return paginationModel;
|
||||||
|
}
|
||||||
|
|
||||||
Future<CommunityModel?> getCommunityById(String communityId) async {
|
Future<CommunityModel?> getCommunityById(String communityId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getCommunityById
|
path: ApiEndpoints.getCommunityById.replaceAll('{communityId}', communityId),
|
||||||
.replaceAll('{communityId}', communityId),
|
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
return CommunityModel.fromJson(json['data']);
|
return CommunityModel.fromJson(json['data']);
|
||||||
},
|
},
|
||||||
@ -65,8 +95,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<CommunityModel?> createCommunity(
|
Future<CommunityModel?> createCommunity(String name, String description, String projectId) async {
|
||||||
String name, String description, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().post(
|
final response = await HTTPService().post(
|
||||||
path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId),
|
path: ApiEndpoints.createCommunity.replaceAll('{projectId}', projectId),
|
||||||
@ -85,8 +114,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateCommunity(
|
Future<bool> updateCommunity(String communityId, String name, String projectId) async {
|
||||||
String communityId, String name, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().put(
|
final response = await HTTPService().put(
|
||||||
path: ApiEndpoints.updateCommunity
|
path: ApiEndpoints.updateCommunity
|
||||||
@ -123,8 +151,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpacesResponse> fetchSpaces(
|
Future<SpacesResponse> fetchSpaces(String communityId, String projectId) async {
|
||||||
String communityId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.listSpaces
|
path: ApiEndpoints.listSpaces
|
||||||
@ -150,8 +177,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpaceModel?> getSpace(
|
Future<SpaceModel?> getSpace(String communityId, String spaceId, String projectId) async {
|
||||||
String communityId, String spaceId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getSpace
|
path: ApiEndpoints.getSpace
|
||||||
@ -262,8 +288,7 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deleteSpace(
|
Future<bool> deleteSpace(String communityId, String spaceId, String projectId) async {
|
||||||
String communityId, String spaceId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().delete(
|
final response = await HTTPService().delete(
|
||||||
path: ApiEndpoints.deleteSpace
|
path: ApiEndpoints.deleteSpace
|
||||||
@ -281,17 +306,15 @@ class CommunitySpaceManagementApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<SpaceModel>> getSpaceHierarchy(
|
Future<List<SpaceModel>> getSpaceHierarchy(String communityId, String projectId) async {
|
||||||
String communityId, String projectId) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getSpaceHierarchy
|
path: ApiEndpoints.getSpaceHierarchy
|
||||||
.replaceAll('{communityId}', communityId)
|
.replaceAll('{communityId}', communityId)
|
||||||
.replaceAll('{projectId}', projectId),
|
.replaceAll('{projectId}', projectId),
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final spaceModels = (json['data'] as List)
|
final spaceModels =
|
||||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
(json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
return spaceModels;
|
return spaceModels;
|
||||||
},
|
},
|
||||||
@ -302,17 +325,16 @@ class CommunitySpaceManagementApi {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Future<List<SpaceModel>> getSpaceOnlyWithDevices(
|
|
||||||
{String? communityId, String? projectId}) async {
|
Future<List<SpaceModel>> getSpaceOnlyWithDevices({String? communityId, String? projectId}) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.spaceOnlyWithDevices
|
path: ApiEndpoints.spaceOnlyWithDevices
|
||||||
.replaceAll('{communityId}', communityId!)
|
.replaceAll('{communityId}', communityId!)
|
||||||
.replaceAll('{projectId}', projectId!),
|
.replaceAll('{projectId}', projectId!),
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final spaceModels = (json['data'] as List)
|
final spaceModels =
|
||||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
(json['data'] as List).map((spaceJson) => SpaceModel.fromJson(spaceJson)).toList();
|
||||||
.toList();
|
|
||||||
return spaceModels;
|
return spaceModels;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -9,21 +9,8 @@ abstract class ApiEndpoints {
|
|||||||
static const String sendOtp = '/authentication/user/send-otp';
|
static const String sendOtp = '/authentication/user/send-otp';
|
||||||
static const String verifyOtp = '/authentication/user/verify-otp';
|
static const String verifyOtp = '/authentication/user/verify-otp';
|
||||||
static const String getRegion = '/region';
|
static const String getRegion = '/region';
|
||||||
static const String visitorPassword =
|
static const String visitorPassword = '/visitor-passwords';
|
||||||
'/projects/{projectId}/visitor-password';
|
static const String getDevices = '/projects/{projectId}/devices';
|
||||||
static const String getDevices =
|
|
||||||
'/projects/{projectId}/visitor-password/devices';
|
|
||||||
|
|
||||||
static const String sendOnlineOneTime =
|
|
||||||
'/visitor-password/temporary-password/online/one-time';
|
|
||||||
static const String sendOnlineMultipleTime =
|
|
||||||
'/visitor-password/temporary-password/online/multiple-time';
|
|
||||||
|
|
||||||
//offline Password
|
|
||||||
static const String sendOffLineOneTime =
|
|
||||||
'/visitor-password/temporary-password/offline/one-time';
|
|
||||||
static const String sendOffLineMultipleTime =
|
|
||||||
'/visitor-password/temporary-password/offline/multiple-time';
|
|
||||||
|
|
||||||
static const String getUser = '/user/{userUuid}';
|
static const String getUser = '/user/{userUuid}';
|
||||||
|
|
||||||
@ -32,15 +19,15 @@ abstract class ApiEndpoints {
|
|||||||
static const String getAllDevices = '/projects/{projectId}/devices';
|
static const String getAllDevices = '/projects/{projectId}/devices';
|
||||||
static const String getSpaceDevices =
|
static const String getSpaceDevices =
|
||||||
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
||||||
static const String getDeviceStatus = '/device/{uuid}/functions/status';
|
static const String getDeviceStatus = '/devices/{uuid}/functions/status';
|
||||||
static const String getBatchStatus = '/device/status/batch';
|
static const String getBatchStatus = '/devices/batch';
|
||||||
|
|
||||||
static const String deviceControl = '/device/{uuid}/control';
|
static const String deviceControl = '/devices/{uuid}/command';
|
||||||
static const String deviceBatchControl = '/device/control/batch';
|
static const String deviceBatchControl = '/devices/batch';
|
||||||
static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices';
|
static const String gatewayApi = '/devices/gateway/{gatewayUuid}/devices';
|
||||||
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
|
static const String openDoorLock = '/door-lock/open/{doorLockUuid}';
|
||||||
|
|
||||||
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
|
static const String getDeviceLogs = '/devices/{uuid}/report-logs?code={code}';
|
||||||
|
|
||||||
// Space Module
|
// Space Module
|
||||||
static const String createSpace =
|
static const String createSpace =
|
||||||
@ -70,18 +57,13 @@ abstract class ApiEndpoints {
|
|||||||
static const String createUserCommunity =
|
static const String createUserCommunity =
|
||||||
'/projects/{projectId}/communities/user';
|
'/projects/{projectId}/communities/user';
|
||||||
static const String getDeviceLogsByDate =
|
static const String getDeviceLogsByDate =
|
||||||
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
'/devices/{uuid}/report-logs?code={code}&startTime={startTime}&endTime={endTime}';
|
||||||
|
|
||||||
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
||||||
static const String getScheduleByDeviceId =
|
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}';
|
||||||
'/schedule/{deviceUuid}?category={category}';
|
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}';
|
||||||
static const String deleteScheduleByDeviceId =
|
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}';
|
||||||
'/schedule/{deviceUuid}/{scheduleUuid}';
|
static const String factoryReset = '/devices/batch';
|
||||||
static const String updateScheduleByDeviceId =
|
|
||||||
'/schedule/enable/{deviceUuid}';
|
|
||||||
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
|
|
||||||
static const String powerClamp =
|
|
||||||
'/device/{powerClampUuid}/power-clamp/status';
|
|
||||||
|
|
||||||
//product
|
//product
|
||||||
static const String listProducts = '/products';
|
static const String listProducts = '/products';
|
||||||
|
@ -408,9 +408,9 @@ class Assets {
|
|||||||
static const String spaceLinkIcon = 'assets/icons/space_link_icon.svg';
|
static const String spaceLinkIcon = 'assets/icons/space_link_icon.svg';
|
||||||
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.svg';
|
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
|
||||||
static const String scenesPlayIconCheck =
|
static const String scenesPlayIconCheck =
|
||||||
'assets/icons/scenesPlayIconCheck.svg';
|
'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 =
|
static const String currentDistanceIcon =
|
||||||
'assets/icons/current_distance_icon.svg';
|
'assets/icons/current_distance_icon.svg';
|
||||||
@ -426,6 +426,8 @@ class Assets {
|
|||||||
static const String motionDetectionSensitivityValueIcon = 'assets/icons/motion_detection_sensitivity_value_icon.svg';
|
static const String motionDetectionSensitivityValueIcon = 'assets/icons/motion_detection_sensitivity_value_icon.svg';
|
||||||
static const String presenceTimeIcon = 'assets/icons/presence_time_icon.svg';
|
static const String presenceTimeIcon = 'assets/icons/presence_time_icon.svg';
|
||||||
static const String IlluminanceIcon = 'assets/icons/Illuminance_icon.svg';
|
static const String IlluminanceIcon = 'assets/icons/Illuminance_icon.svg';
|
||||||
|
static const String gear = 'assets/icons/gear.svg';
|
||||||
|
static const String activeBell='assets/icons/active_bell.svg';
|
||||||
|
|
||||||
|
|
||||||
//Illuminance_icon
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user