mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Merge branch 'feat/update-space-model' of https://github.com/SyncrowIOT/web into dev
This commit is contained in:
21
assets/icons/delete_space_link_icon.svg
Normal file
21
assets/icons/delete_space_link_icon.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36698)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M26.4 13.1094H23.7333V12.582C23.7333 11.7097 23.0156 11 22.1333 11H17.8667C16.9844 11 16.2667 11.7097 16.2667 12.582V13.1094H13.6C12.7178 13.1094 12 13.8191 12 14.6914C12 15.392 12.4631 15.9873 13.1024 16.1947L14.0537 27.5493C14.1222 28.3628 14.8226 29 15.6481 29H24.3519C25.1775 29 25.8778 28.3628 25.9464 27.5491L26.8976 16.1947C27.5369 15.9873 28 15.392 28 14.6914C28 13.8191 27.2822 13.1094 26.4 13.1094ZM17.3333 12.582C17.3333 12.2913 17.5726 12.0547 17.8667 12.0547H22.1333C22.4274 12.0547 22.6667 12.2913 22.6667 12.582V13.1094H17.3333V12.582ZM24.8833 27.4618C24.8605 27.7329 24.6271 27.9453 24.3519 27.9453H15.6481C15.373 27.9453 15.1395 27.7329 15.1167 27.462L14.1793 16.2734H25.8207L24.8833 27.4618ZM26.4 15.2188H13.6C13.3059 15.2188 13.0667 14.9822 13.0667 14.6914C13.0667 14.4006 13.3059 14.1641 13.6 14.1641H26.4C26.6941 14.1641 26.9333 14.4006 26.9333 14.6914C26.9333 14.9822 26.6941 15.2188 26.4 15.2188Z" fill="#999999"/>
|
||||||
|
<path d="M17.8656 26.3307L17.3323 17.8229C17.314 17.5322 17.0596 17.3111 16.767 17.3292C16.473 17.3472 16.2494 17.5974 16.2676 17.8881L16.801 26.396C16.8185 26.6756 17.0533 26.8907 17.3328 26.8907C17.6416 26.8907 17.8846 26.6335 17.8656 26.3307Z" fill="#999999"/>
|
||||||
|
<path d="M20.0001 17.3281C19.7056 17.3281 19.4668 17.5642 19.4668 17.8555V26.3633C19.4668 26.6545 19.7056 26.8906 20.0001 26.8906C20.2947 26.8906 20.5335 26.6545 20.5335 26.3633V17.8555C20.5335 17.5642 20.2947 17.3281 20.0001 17.3281Z" fill="#999999"/>
|
||||||
|
<path d="M23.233 17.3292C22.9396 17.3111 22.6859 17.5321 22.6677 17.8229L22.1343 26.3307C22.1162 26.6213 22.3397 26.8716 22.6337 26.8896C22.9278 26.9076 23.1808 26.6865 23.199 26.3959L23.7323 17.8881C23.7505 17.5974 23.527 17.3472 23.233 17.3292Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36698" x="0" y="0" width="40" height="40" 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="2.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.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36698"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36698" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
25
assets/icons/space_link_icon.svg
Normal file
25
assets/icons/space_link_icon.svg
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36714)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M21.1979 12.3395L18.26 15.2772C17.7228 15.8146 17.3477 16.4536 17.1345 17.1328C16.437 17.3525 15.798 17.7393 15.2772 18.26L12.3395 21.1979C10.5536 22.9837 10.5534 25.8744 12.3395 27.6605C14.1253 29.4464 17.0161 29.4466 18.8022 27.6605L21.7399 24.7227C22.2773 24.1855 22.6522 23.5465 22.8655 22.8671C23.5631 22.6475 24.202 22.2607 24.7227 21.7399L27.6605 18.8022C29.4464 17.0162 29.4467 14.1256 27.6605 12.3395C25.8746 10.5536 22.984 10.5534 21.1979 12.3395ZM17.266 20.2484C17.4886 20.7914 17.8199 21.2998 18.26 21.7399C18.6877 22.1674 19.1965 22.5054 19.7513 22.7343L16.8137 25.6721C16.1284 26.3572 15.0133 26.3574 14.328 25.6721C13.6427 24.9867 13.6427 23.8717 14.328 23.1864L17.2657 20.2485C17.2659 20.2485 17.2659 20.2485 17.266 20.2484ZM21.2428 24.2256L18.3049 27.1633C16.7939 28.6745 14.3479 28.6747 12.8366 27.1633C11.3254 25.6523 11.3253 23.2062 12.8366 21.695L15.7744 18.7571C16.1166 18.4149 16.5191 18.1412 16.9579 17.9488C16.8924 18.4845 16.9223 19.014 17.0364 19.5199C16.9419 19.5905 16.8524 19.6676 16.7686 19.7514L13.8309 22.6892C12.8715 23.6487 12.8715 25.2097 13.8309 26.1691C14.7903 27.1285 16.3513 27.1285 17.3108 26.1691L20.2485 23.2313C21.2089 22.2709 21.209 20.7119 20.2485 19.7514C19.7355 19.2383 19.6105 18.4924 19.8554 17.8663C20.3734 18.059 20.8488 18.3631 21.2428 18.7571C22.7504 20.2647 22.7505 22.7179 21.2428 24.2256ZM27.1633 18.3049L24.2256 21.2428C23.8834 21.585 23.4809 21.8587 23.0421 22.0511C23.1076 21.5154 23.0777 20.986 22.9637 20.4801C23.058 20.4095 23.1477 20.3323 23.2313 20.2485L26.1692 17.3108C27.1286 16.3514 27.1286 14.7903 26.1692 13.8309C25.3077 12.9695 23.9604 12.8807 22.9987 13.5684C22.8408 13.6813 22.8044 13.9009 22.9173 14.0588C23.0301 14.2168 23.2497 14.2533 23.4077 14.1403C24.1093 13.6386 25.0615 13.7174 25.6721 14.328C26.3574 15.0133 26.3574 16.1283 25.6721 16.8137L22.7342 19.7514C22.7342 19.7514 22.7342 19.7514 22.7341 19.7515C22.5113 19.2085 22.1801 18.7002 21.7399 18.26C21.3124 17.8325 20.8035 17.4945 20.2487 17.2656L21.4465 16.0678C21.5837 15.9306 21.5837 15.708 21.4465 15.5707C21.3091 15.4335 21.0867 15.4335 20.9493 15.5707L19.7514 16.7686C18.7911 17.729 18.7909 19.2879 19.7514 20.2485C20.2645 20.7615 20.3894 21.5076 20.1446 22.1337C19.6266 21.941 19.1511 21.6368 18.7571 21.2427C17.2497 19.7352 17.2495 17.282 18.7571 15.7744L21.695 12.8366C23.2061 11.3254 25.6522 11.3252 27.1633 12.8366C28.6745 14.3476 28.6747 16.7937 27.1633 18.3049Z" fill="#999999"/>
|
||||||
|
<path d="M22.5443 14.8262C22.5443 15.0204 22.3869 15.1777 22.1929 15.1777C21.9987 15.1777 21.8413 15.0204 21.8413 14.8262C21.8413 14.632 21.9987 14.4746 22.1929 14.4746C22.3869 14.4746 22.5443 14.632 22.5443 14.8262Z" fill="#999999"/>
|
||||||
|
<path d="M15.7755 15.774C15.9128 15.6368 15.9128 15.4142 15.7755 15.2769L14.2841 13.7855C14.1468 13.6483 13.9243 13.6483 13.787 13.7855C13.6498 13.9228 13.6498 14.1455 13.787 14.2828L15.2784 15.7742C15.4158 15.9114 15.6383 15.9114 15.7755 15.774Z" fill="#999999"/>
|
||||||
|
<path d="M12.3378 16.9062C12.1437 16.9062 11.9863 17.0636 11.9863 17.2577C11.9863 17.4519 12.1437 17.6092 12.3378 17.6092H14.447C14.641 17.6092 14.7984 17.4519 14.7984 17.2577C14.7984 17.0636 14.641 16.9062 14.447 16.9062H12.3378Z" fill="#999999"/>
|
||||||
|
<path d="M16.9062 12.2314V14.3405C16.9062 14.5346 17.0636 14.6921 17.2577 14.6921C17.4519 14.6921 17.6092 14.5346 17.6092 14.3405V12.2314C17.6092 12.0373 17.4519 11.8799 17.2577 11.8799C17.0636 11.8799 16.9062 12.0373 16.9062 12.2314Z" fill="#999999"/>
|
||||||
|
<path d="M24.227 24.2259C24.0897 24.3631 24.0897 24.5857 24.227 24.7231L25.7184 26.2145C25.7871 26.2831 25.877 26.3175 25.967 26.3175C26.2772 26.3175 26.4377 25.9397 26.2155 25.7173L24.7242 24.2259C24.5868 24.0887 24.3643 24.0887 24.227 24.2259Z" fill="#999999"/>
|
||||||
|
<path d="M23.0605 27.7673V25.6581C23.0605 25.464 22.903 25.3066 22.709 25.3066C22.5148 25.3066 22.3574 25.464 22.3574 25.6581V27.7673C22.3574 27.9614 22.5148 28.1187 22.709 28.1187C22.903 28.1187 23.0605 27.9614 23.0605 27.7673Z" fill="#999999"/>
|
||||||
|
<path d="M27.7693 23.0586C27.9633 23.0586 28.1207 22.9011 28.1207 22.707C28.1207 22.5128 27.9633 22.3555 27.7693 22.3555H25.66C25.466 22.3555 25.3086 22.5128 25.3086 22.707C25.3086 22.9011 25.466 23.0586 25.66 23.0586H27.7693Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36714" x="0" y="0" width="40" height="40" 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="2.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.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36714"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36714" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
3
assets/icons/success_icon.svg
Normal file
3
assets/icons/success_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M43.2614 20.4808C44.1769 21.3963 44.1769 22.8804 43.2614 23.7955L27.5381 39.5192C26.6226 40.4343 25.139 40.4343 24.2235 39.5192L16.7386 32.0338C15.8231 31.1188 15.8231 29.6347 16.7386 28.7196C17.6537 27.8041 19.1377 27.8041 20.0528 28.7196L25.8806 34.5474L39.9467 20.4808C40.8623 19.5657 42.3463 19.5657 43.2614 20.4808ZM60 30C60 46.5825 46.5802 60 30 60C13.4175 60 0 46.5802 0 30C0 13.4175 13.4198 0 30 0C46.5825 0 60 13.4198 60 30ZM55.3125 30C55.3125 16.0085 43.9897 4.6875 30 4.6875C16.0085 4.6875 4.6875 16.0103 4.6875 30C4.6875 43.9915 16.0103 55.3125 30 55.3125C43.9915 55.3125 55.3125 43.9897 55.3125 30Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 761 B |
21
assets/images/delete_space_link_icon.svg
Normal file
21
assets/images/delete_space_link_icon.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36698)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M26.4 13.1094H23.7333V12.582C23.7333 11.7097 23.0156 11 22.1333 11H17.8667C16.9844 11 16.2667 11.7097 16.2667 12.582V13.1094H13.6C12.7178 13.1094 12 13.8191 12 14.6914C12 15.392 12.4631 15.9873 13.1024 16.1947L14.0537 27.5493C14.1222 28.3628 14.8226 29 15.6481 29H24.3519C25.1775 29 25.8778 28.3628 25.9464 27.5491L26.8976 16.1947C27.5369 15.9873 28 15.392 28 14.6914C28 13.8191 27.2822 13.1094 26.4 13.1094ZM17.3333 12.582C17.3333 12.2913 17.5726 12.0547 17.8667 12.0547H22.1333C22.4274 12.0547 22.6667 12.2913 22.6667 12.582V13.1094H17.3333V12.582ZM24.8833 27.4618C24.8605 27.7329 24.6271 27.9453 24.3519 27.9453H15.6481C15.373 27.9453 15.1395 27.7329 15.1167 27.462L14.1793 16.2734H25.8207L24.8833 27.4618ZM26.4 15.2188H13.6C13.3059 15.2188 13.0667 14.9822 13.0667 14.6914C13.0667 14.4006 13.3059 14.1641 13.6 14.1641H26.4C26.6941 14.1641 26.9333 14.4006 26.9333 14.6914C26.9333 14.9822 26.6941 15.2188 26.4 15.2188Z" fill="#999999"/>
|
||||||
|
<path d="M17.8656 26.3307L17.3323 17.8229C17.314 17.5322 17.0596 17.3111 16.767 17.3292C16.473 17.3472 16.2494 17.5974 16.2676 17.8881L16.801 26.396C16.8185 26.6756 17.0533 26.8907 17.3328 26.8907C17.6416 26.8907 17.8846 26.6335 17.8656 26.3307Z" fill="#999999"/>
|
||||||
|
<path d="M20.0001 17.3281C19.7056 17.3281 19.4668 17.5642 19.4668 17.8555V26.3633C19.4668 26.6545 19.7056 26.8906 20.0001 26.8906C20.2947 26.8906 20.5335 26.6545 20.5335 26.3633V17.8555C20.5335 17.5642 20.2947 17.3281 20.0001 17.3281Z" fill="#999999"/>
|
||||||
|
<path d="M23.233 17.3292C22.9396 17.3111 22.6859 17.5321 22.6677 17.8229L22.1343 26.3307C22.1162 26.6213 22.3397 26.8716 22.6337 26.8896C22.9278 26.9076 23.1808 26.6865 23.199 26.3959L23.7323 17.8881C23.7505 17.5974 23.527 17.3472 23.233 17.3292Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36698" x="0" y="0" width="40" height="40" 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="2.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.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36698"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36698" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
25
assets/images/space_link_icon.svg
Normal file
25
assets/images/space_link_icon.svg
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_6702_36714)">
|
||||||
|
<circle cx="20" cy="20" r="15" fill="#F4F4F4"/>
|
||||||
|
<path d="M21.1979 12.3395L18.26 15.2772C17.7228 15.8146 17.3477 16.4536 17.1345 17.1328C16.437 17.3525 15.798 17.7393 15.2772 18.26L12.3395 21.1979C10.5536 22.9837 10.5534 25.8744 12.3395 27.6605C14.1253 29.4464 17.0161 29.4466 18.8022 27.6605L21.7399 24.7227C22.2773 24.1855 22.6522 23.5465 22.8655 22.8671C23.5631 22.6475 24.202 22.2607 24.7227 21.7399L27.6605 18.8022C29.4464 17.0162 29.4467 14.1256 27.6605 12.3395C25.8746 10.5536 22.984 10.5534 21.1979 12.3395ZM17.266 20.2484C17.4886 20.7914 17.8199 21.2998 18.26 21.7399C18.6877 22.1674 19.1965 22.5054 19.7513 22.7343L16.8137 25.6721C16.1284 26.3572 15.0133 26.3574 14.328 25.6721C13.6427 24.9867 13.6427 23.8717 14.328 23.1864L17.2657 20.2485C17.2659 20.2485 17.2659 20.2485 17.266 20.2484ZM21.2428 24.2256L18.3049 27.1633C16.7939 28.6745 14.3479 28.6747 12.8366 27.1633C11.3254 25.6523 11.3253 23.2062 12.8366 21.695L15.7744 18.7571C16.1166 18.4149 16.5191 18.1412 16.9579 17.9488C16.8924 18.4845 16.9223 19.014 17.0364 19.5199C16.9419 19.5905 16.8524 19.6676 16.7686 19.7514L13.8309 22.6892C12.8715 23.6487 12.8715 25.2097 13.8309 26.1691C14.7903 27.1285 16.3513 27.1285 17.3108 26.1691L20.2485 23.2313C21.2089 22.2709 21.209 20.7119 20.2485 19.7514C19.7355 19.2383 19.6105 18.4924 19.8554 17.8663C20.3734 18.059 20.8488 18.3631 21.2428 18.7571C22.7504 20.2647 22.7505 22.7179 21.2428 24.2256ZM27.1633 18.3049L24.2256 21.2428C23.8834 21.585 23.4809 21.8587 23.0421 22.0511C23.1076 21.5154 23.0777 20.986 22.9637 20.4801C23.058 20.4095 23.1477 20.3323 23.2313 20.2485L26.1692 17.3108C27.1286 16.3514 27.1286 14.7903 26.1692 13.8309C25.3077 12.9695 23.9604 12.8807 22.9987 13.5684C22.8408 13.6813 22.8044 13.9009 22.9173 14.0588C23.0301 14.2168 23.2497 14.2533 23.4077 14.1403C24.1093 13.6386 25.0615 13.7174 25.6721 14.328C26.3574 15.0133 26.3574 16.1283 25.6721 16.8137L22.7342 19.7514C22.7342 19.7514 22.7342 19.7514 22.7341 19.7515C22.5113 19.2085 22.1801 18.7002 21.7399 18.26C21.3124 17.8325 20.8035 17.4945 20.2487 17.2656L21.4465 16.0678C21.5837 15.9306 21.5837 15.708 21.4465 15.5707C21.3091 15.4335 21.0867 15.4335 20.9493 15.5707L19.7514 16.7686C18.7911 17.729 18.7909 19.2879 19.7514 20.2485C20.2645 20.7615 20.3894 21.5076 20.1446 22.1337C19.6266 21.941 19.1511 21.6368 18.7571 21.2427C17.2497 19.7352 17.2495 17.282 18.7571 15.7744L21.695 12.8366C23.2061 11.3254 25.6522 11.3252 27.1633 12.8366C28.6745 14.3476 28.6747 16.7937 27.1633 18.3049Z" fill="#999999"/>
|
||||||
|
<path d="M22.5443 14.8262C22.5443 15.0204 22.3869 15.1777 22.1929 15.1777C21.9987 15.1777 21.8413 15.0204 21.8413 14.8262C21.8413 14.632 21.9987 14.4746 22.1929 14.4746C22.3869 14.4746 22.5443 14.632 22.5443 14.8262Z" fill="#999999"/>
|
||||||
|
<path d="M15.7755 15.774C15.9128 15.6368 15.9128 15.4142 15.7755 15.2769L14.2841 13.7855C14.1468 13.6483 13.9243 13.6483 13.787 13.7855C13.6498 13.9228 13.6498 14.1455 13.787 14.2828L15.2784 15.7742C15.4158 15.9114 15.6383 15.9114 15.7755 15.774Z" fill="#999999"/>
|
||||||
|
<path d="M12.3378 16.9062C12.1437 16.9062 11.9863 17.0636 11.9863 17.2577C11.9863 17.4519 12.1437 17.6092 12.3378 17.6092H14.447C14.641 17.6092 14.7984 17.4519 14.7984 17.2577C14.7984 17.0636 14.641 16.9062 14.447 16.9062H12.3378Z" fill="#999999"/>
|
||||||
|
<path d="M16.9062 12.2314V14.3405C16.9062 14.5346 17.0636 14.6921 17.2577 14.6921C17.4519 14.6921 17.6092 14.5346 17.6092 14.3405V12.2314C17.6092 12.0373 17.4519 11.8799 17.2577 11.8799C17.0636 11.8799 16.9062 12.0373 16.9062 12.2314Z" fill="#999999"/>
|
||||||
|
<path d="M24.227 24.2259C24.0897 24.3631 24.0897 24.5857 24.227 24.7231L25.7184 26.2145C25.7871 26.2831 25.877 26.3175 25.967 26.3175C26.2772 26.3175 26.4377 25.9397 26.2155 25.7173L24.7242 24.2259C24.5868 24.0887 24.3643 24.0887 24.227 24.2259Z" fill="#999999"/>
|
||||||
|
<path d="M23.0605 27.7673V25.6581C23.0605 25.464 22.903 25.3066 22.709 25.3066C22.5148 25.3066 22.3574 25.464 22.3574 25.6581V27.7673C22.3574 27.9614 22.5148 28.1187 22.709 28.1187C22.903 28.1187 23.0605 27.9614 23.0605 27.7673Z" fill="#999999"/>
|
||||||
|
<path d="M27.7693 23.0586C27.9633 23.0586 28.1207 22.9011 28.1207 22.707C28.1207 22.5128 27.9633 22.3555 27.7693 22.3555H25.66C25.466 22.3555 25.3086 22.5128 25.3086 22.707C25.3086 22.9011 25.466 23.0586 25.66 23.0586H27.7693Z" fill="#999999"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_6702_36714" x="0" y="0" width="40" height="40" 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="2.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.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_6702_36714"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_6702_36714" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
3
assets/images/success_icon.svg
Normal file
3
assets/images/success_icon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M43.2614 20.4808C44.1769 21.3963 44.1769 22.8804 43.2614 23.7955L27.5381 39.5192C26.6226 40.4343 25.139 40.4343 24.2235 39.5192L16.7386 32.0338C15.8231 31.1188 15.8231 29.6347 16.7386 28.7196C17.6537 27.8041 19.1377 27.8041 20.0528 28.7196L25.8806 34.5474L39.9467 20.4808C40.8623 19.5657 42.3463 19.5657 43.2614 20.4808ZM60 30C60 46.5825 46.5802 60 30 60C13.4175 60 0 46.5802 0 30C0 13.4175 13.4198 0 30 0C46.5825 0 60 13.4198 60 30ZM55.3125 30C55.3125 16.0085 43.9897 4.6875 30 4.6875C16.0085 4.6875 4.6875 16.0103 4.6875 30C4.6875 43.9915 16.0103 55.3125 30 55.3125C43.9915 55.3125 55.3125 43.9897 55.3125 30Z" fill="#023DFE" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 761 B |
@ -1,35 +1,38 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class DialogTextfieldDropdown extends StatefulWidget {
|
class TagDialogTextfieldDropdown extends StatefulWidget {
|
||||||
final List<String> items;
|
final List<Tag> items;
|
||||||
final ValueChanged<String> onSelected;
|
final ValueChanged<Tag> onSelected;
|
||||||
final String? initialValue;
|
final Tag? initialValue;
|
||||||
|
final String product;
|
||||||
|
|
||||||
const DialogTextfieldDropdown({
|
const TagDialogTextfieldDropdown({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.items,
|
required this.items,
|
||||||
required this.onSelected,
|
required this.onSelected,
|
||||||
this.initialValue,
|
this.initialValue,
|
||||||
|
required this.product,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_DialogTextfieldDropdownState createState() =>
|
_DialogTextfieldDropdownState createState() => _DialogTextfieldDropdownState();
|
||||||
_DialogTextfieldDropdownState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
class _DialogTextfieldDropdownState extends State<TagDialogTextfieldDropdown> {
|
||||||
bool _isOpen = false;
|
bool _isOpen = false;
|
||||||
OverlayEntry? _overlayEntry;
|
OverlayEntry? _overlayEntry;
|
||||||
final TextEditingController _controller = TextEditingController();
|
final TextEditingController _controller = TextEditingController();
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
List<String> _filteredItems = [];
|
List<Tag> _filteredItems = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller.text = widget.initialValue ?? '';
|
_controller.text = widget.initialValue?.tag ?? '';
|
||||||
_filteredItems = List.from(widget.items);
|
|
||||||
|
_filterItems();
|
||||||
|
|
||||||
_focusNode.addListener(() {
|
_focusNode.addListener(() {
|
||||||
if (!_focusNode.hasFocus) {
|
if (!_focusNode.hasFocus) {
|
||||||
@ -38,6 +41,12 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _filterItems() {
|
||||||
|
setState(() {
|
||||||
|
_filteredItems = widget.items.where((tag) => tag.product?.uuid == widget.product).toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void _toggleDropdown() {
|
void _toggleDropdown() {
|
||||||
if (_isOpen) {
|
if (_isOpen) {
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
@ -87,7 +96,7 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: _filteredItems.length,
|
itemCount: _filteredItems.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = _filteredItems[index];
|
final tag = _filteredItems[index];
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
@ -99,19 +108,16 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(item,
|
title: Text(tag.tag ?? '',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium
|
.bodyMedium
|
||||||
?.copyWith(
|
?.copyWith(color: ColorsManager.textPrimaryColor)),
|
||||||
color: ColorsManager
|
|
||||||
.textPrimaryColor)),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_controller.text = item;
|
_controller.text = tag.tag ?? '';
|
||||||
widget.onSelected(item);
|
widget.onSelected(tag);
|
||||||
setState(() {
|
setState(() {
|
||||||
_filteredItems
|
_filteredItems.remove(tag);
|
||||||
.remove(item); // Remove selected item
|
|
||||||
});
|
});
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
},
|
},
|
||||||
@ -150,11 +156,14 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
|||||||
controller: _controller,
|
controller: _controller,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
onFieldSubmitted: (value) {
|
onFieldSubmitted: (value) {
|
||||||
widget.onSelected(value);
|
final selectedTag = _filteredItems.firstWhere((tag) => tag.tag == value,
|
||||||
|
orElse: () => Tag(tag: value));
|
||||||
|
widget.onSelected(selectedTag);
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
},
|
},
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
widget.onSelected(_controller.text);
|
widget.onSelected(_filteredItems.firstWhere((tag) => tag.tag == _controller.text,
|
||||||
|
orElse: () => Tag(tag: _controller.text)));
|
||||||
_closeDropdown();
|
_closeDropdown();
|
||||||
},
|
},
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: Theme.of(context).textTheme.bodyMedium,
|
@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:syncrow_web/firebase_options_dev.dart';
|
|
||||||
import 'package:syncrow_web/firebase_options_prod.dart';
|
import 'package:syncrow_web/firebase_options_prod.dart';
|
||||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||||
|
@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_event.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
||||||
import 'package:syncrow_web/pages/common/custom_table.dart';
|
import 'package:syncrow_web/pages/common/custom_table.dart';
|
||||||
|
@ -15,7 +15,6 @@ import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
|||||||
import 'package:syncrow_web/services/auth_api.dart';
|
import 'package:syncrow_web/services/auth_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
|
||||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||||
|
|
||||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||||
|
@ -5,9 +5,6 @@ import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
|
||||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
|
||||||
|
|
||||||
part 'device_managment_event.dart';
|
part 'device_managment_event.dart';
|
||||||
part 'device_managment_state.dart';
|
part 'device_managment_state.dart';
|
||||||
|
@ -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/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||||
|
@ -20,7 +20,6 @@ class TreeView extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||||
debugPrint('TreeView constructed with userId = $userId');
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => UsersBloc(),
|
create: (_) => UsersBloc(),
|
||||||
// ..add(const LoadCommunityAndSpacesEvent()),
|
// ..add(const LoadCommunityAndSpacesEvent()),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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/space_tree/bloc/space_tree_bloc.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||||
@ -8,11 +9,14 @@ import 'package:syncrow_web/pages/space_tree/view/custom_expansion.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/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/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class SpaceTreeView extends StatefulWidget {
|
class SpaceTreeView extends StatefulWidget {
|
||||||
|
final bool? isSide;
|
||||||
final Function onSelect;
|
final Function onSelect;
|
||||||
const SpaceTreeView({required this.onSelect, super.key});
|
const SpaceTreeView({required this.onSelect, this.isSide, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SpaceTreeView> createState() => _SpaceTreeViewState();
|
State<SpaceTreeView> createState() => _SpaceTreeViewState();
|
||||||
@ -29,21 +33,77 @@ 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>(
|
||||||
List<CommunityModel> list = state.isSearching ? state.filteredCommunity : state.communityList;
|
builder: (context, state) {
|
||||||
|
List<CommunityModel> list =
|
||||||
|
state.isSearching ? state.filteredCommunity : state.communityList;
|
||||||
return Container(
|
return Container(
|
||||||
height: MediaQuery.sizeOf(context).height,
|
height: MediaQuery.sizeOf(context).height,
|
||||||
decoration: subSectionContainerDecoration,
|
decoration:
|
||||||
|
widget.isSide == true ? subSectionContainerDecoration : null,
|
||||||
child: state is SpaceTreeLoadingState
|
child: state is SpaceTreeLoadingState
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: Column(
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
CustomSearchBar(
|
widget.isSide == true
|
||||||
searchQuery: state.searchQuery,
|
? Container(
|
||||||
onSearchChanged: (query) {
|
decoration: const BoxDecoration(
|
||||||
context.read<SpaceTreeBloc>().add(SearchQueryEvent(query));
|
color: ColorsManager.circleRolesBackground,
|
||||||
},
|
borderRadius: BorderRadius.only(
|
||||||
),
|
topRight: Radius.circular(20),
|
||||||
|
topLeft: Radius.circular(20)),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(20)),
|
||||||
|
border: Border.all(
|
||||||
|
color: ColorsManager.grayBorder)),
|
||||||
|
child: TextFormField(
|
||||||
|
style:
|
||||||
|
const TextStyle(color: Colors.black),
|
||||||
|
onChanged: (value) {
|
||||||
|
context
|
||||||
|
.read<SpaceTreeBloc>()
|
||||||
|
.add(SearchQueryEvent(value));
|
||||||
|
},
|
||||||
|
decoration: textBoxDecoration(radios: 20)!
|
||||||
|
.copyWith(
|
||||||
|
fillColor: Colors.white,
|
||||||
|
suffixIcon: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(right: 16),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.textFieldSearch,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
hintStyle: context.textTheme.bodyMedium
|
||||||
|
?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 12,
|
||||||
|
color: ColorsManager.textGray),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: CustomSearchBar(
|
||||||
|
onSearchChanged: (query) {
|
||||||
|
context
|
||||||
|
.read<SpaceTreeBloc>()
|
||||||
|
.add(SearchQueryEvent(query));
|
||||||
|
},
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
@ -57,14 +117,18 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
? Center(
|
? Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'No results found',
|
'No results found',
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall!
|
||||||
|
.copyWith(
|
||||||
color: ColorsManager.lightGrayColor,
|
color: ColorsManager.lightGrayColor,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Scrollbar(
|
: Scrollbar(
|
||||||
scrollbarOrientation: ScrollbarOrientation.left,
|
scrollbarOrientation:
|
||||||
|
ScrollbarOrientation.left,
|
||||||
thumbVisibility: true,
|
thumbVisibility: true,
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -74,30 +138,39 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: list
|
children: list
|
||||||
.map(
|
.map(
|
||||||
(community) => CustomExpansionTileSpaceTree(
|
(community) =>
|
||||||
|
CustomExpansionTileSpaceTree(
|
||||||
title: community.name,
|
title: community.name,
|
||||||
isSelected: state.selectedCommunities
|
isSelected: state
|
||||||
|
.selectedCommunities
|
||||||
.contains(community.uuid),
|
.contains(community.uuid),
|
||||||
isSoldCheck: state.selectedCommunities
|
isSoldCheck: state
|
||||||
|
.selectedCommunities
|
||||||
.contains(community.uuid),
|
.contains(community.uuid),
|
||||||
onExpansionChanged: () {
|
onExpansionChanged: () {
|
||||||
context
|
context
|
||||||
.read<SpaceTreeBloc>()
|
.read<SpaceTreeBloc>()
|
||||||
.add(OnCommunityExpanded(community.uuid));
|
.add(OnCommunityExpanded(
|
||||||
|
community.uuid));
|
||||||
},
|
},
|
||||||
isExpanded: state.expandedCommunities
|
isExpanded: state
|
||||||
|
.expandedCommunities
|
||||||
.contains(community.uuid),
|
.contains(community.uuid),
|
||||||
onItemSelected: () {
|
onItemSelected: () {
|
||||||
context.read<SpaceTreeBloc>().add(
|
context
|
||||||
OnCommunitySelected(
|
.read<SpaceTreeBloc>()
|
||||||
community.uuid, community.spaces));
|
.add(OnCommunitySelected(
|
||||||
|
community.uuid,
|
||||||
|
community.spaces));
|
||||||
widget.onSelect();
|
widget.onSelect();
|
||||||
},
|
},
|
||||||
children: community.spaces.map((space) {
|
children:
|
||||||
|
community.spaces.map((space) {
|
||||||
return CustomExpansionTileSpaceTree(
|
return CustomExpansionTileSpaceTree(
|
||||||
title: space.name,
|
title: space.name,
|
||||||
isExpanded:
|
isExpanded: state
|
||||||
state.expandedSpaces.contains(space.uuid),
|
.expandedSpaces
|
||||||
|
.contains(space.uuid),
|
||||||
onItemSelected: () {
|
onItemSelected: () {
|
||||||
context.read<SpaceTreeBloc>().add(
|
context.read<SpaceTreeBloc>().add(
|
||||||
OnSpaceSelected(community, space.uuid ?? '',
|
OnSpaceSelected(community, space.uuid ?? '',
|
||||||
@ -105,14 +178,20 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
widget.onSelect();
|
widget.onSelect();
|
||||||
},
|
},
|
||||||
onExpansionChanged: () {
|
onExpansionChanged: () {
|
||||||
context.read<SpaceTreeBloc>().add(
|
context
|
||||||
OnSpaceExpanded(
|
.read<SpaceTreeBloc>()
|
||||||
community.uuid, space.uuid ?? ''));
|
.add(OnSpaceExpanded(
|
||||||
|
community.uuid,
|
||||||
|
space.uuid ?? ''));
|
||||||
},
|
},
|
||||||
isSelected:
|
isSelected: state
|
||||||
state.selectedSpaces.contains(space.uuid) ||
|
.selectedSpaces
|
||||||
state.soldCheck.contains(space.uuid),
|
.contains(
|
||||||
isSoldCheck: state.soldCheck.contains(space.uuid),
|
space.uuid) ||
|
||||||
|
state.soldCheck
|
||||||
|
.contains(space.uuid),
|
||||||
|
isSoldCheck: state.soldCheck
|
||||||
|
.contains(space.uuid),
|
||||||
children: _buildNestedSpaces(
|
children: _buildNestedSpaces(
|
||||||
context, state, space, community),
|
context, state, space, community),
|
||||||
);
|
);
|
||||||
@ -200,8 +279,8 @@ class _SpaceTreeViewState extends State<SpaceTreeView> {
|
|||||||
BuildContext context, SpaceTreeState state, SpaceModel space, CommunityModel community) {
|
BuildContext context, SpaceTreeState state, SpaceModel space, CommunityModel community) {
|
||||||
return space.children.map((child) {
|
return space.children.map((child) {
|
||||||
return CustomExpansionTileSpaceTree(
|
return CustomExpansionTileSpaceTree(
|
||||||
isSelected:
|
isSelected: state.selectedSpaces.contains(child.uuid) ||
|
||||||
state.selectedSpaces.contains(child.uuid) || state.soldCheck.contains(child.uuid),
|
state.soldCheck.contains(child.uuid),
|
||||||
isSoldCheck: state.soldCheck.contains(child.uuid),
|
isSoldCheck: state.soldCheck.contains(child.uuid),
|
||||||
title: child.name,
|
title: child.name,
|
||||||
isExpanded: state.expandedSpaces.contains(child.uuid),
|
isExpanded: state.expandedSpaces.contains(child.uuid),
|
||||||
|
@ -24,6 +24,8 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
|||||||
final String spaceName;
|
final String spaceName;
|
||||||
final bool isCreate;
|
final bool isCreate;
|
||||||
final Function(List<Tag>, List<SubspaceModel>?)? onSave;
|
final Function(List<Tag>, List<SubspaceModel>?)? onSave;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
|
|
||||||
const AddDeviceTypeWidget(
|
const AddDeviceTypeWidget(
|
||||||
{super.key,
|
{super.key,
|
||||||
@ -35,7 +37,8 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
|||||||
this.allTags,
|
this.allTags,
|
||||||
this.spaceTags,
|
this.spaceTags,
|
||||||
this.onSave,
|
this.onSave,
|
||||||
required this.spaceName});
|
required this.spaceName,
|
||||||
|
required this.projectTags});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -134,7 +137,8 @@ class AddDeviceTypeWidget extends StatelessWidget {
|
|||||||
spaceName: spaceName,
|
spaceName: spaceName,
|
||||||
initialTags: initialTags,
|
initialTags: initialTags,
|
||||||
title: dialogTitle,
|
title: dialogTitle,
|
||||||
onSave: onSave),
|
onSave: onSave,
|
||||||
|
projectTags: projectTags),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -19,8 +19,7 @@ import 'package:syncrow_web/services/space_mana_api.dart';
|
|||||||
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/action_enum.dart' as custom_action;
|
import 'package:syncrow_web/utils/constants/action_enum.dart' as custom_action;
|
||||||
|
|
||||||
class SpaceManagementBloc
|
class SpaceManagementBloc extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
||||||
extends Bloc<SpaceManagementEvent, SpaceManagementState> {
|
|
||||||
final CommunitySpaceManagementApi _api;
|
final CommunitySpaceManagementApi _api;
|
||||||
final ProductApi _productApi;
|
final ProductApi _productApi;
|
||||||
final SpaceModelManagementApi _spaceModelApi;
|
final SpaceModelManagementApi _spaceModelApi;
|
||||||
@ -28,6 +27,7 @@ class SpaceManagementBloc
|
|||||||
List<ProductModel>? _cachedProducts;
|
List<ProductModel>? _cachedProducts;
|
||||||
List<SpaceTemplateModel>? _cachedSpaceModels;
|
List<SpaceTemplateModel>? _cachedSpaceModels;
|
||||||
final SpaceTreeBloc _spaceTreeBloc;
|
final SpaceTreeBloc _spaceTreeBloc;
|
||||||
|
List<Tag>? _cachedTags;
|
||||||
|
|
||||||
SpaceManagementBloc(
|
SpaceManagementBloc(
|
||||||
this._api,
|
this._api,
|
||||||
@ -54,40 +54,38 @@ class SpaceManagementBloc
|
|||||||
UpdateSpaceModelCache event, Emitter<SpaceManagementState> emit) async {
|
UpdateSpaceModelCache event, Emitter<SpaceManagementState> emit) async {
|
||||||
if (_cachedSpaceModels != null) {
|
if (_cachedSpaceModels != null) {
|
||||||
_cachedSpaceModels = _cachedSpaceModels!.map((model) {
|
_cachedSpaceModels = _cachedSpaceModels!.map((model) {
|
||||||
return model.uuid == event.updatedModel.uuid
|
return model.uuid == event.updatedModel.uuid ? event.updatedModel : model;
|
||||||
? event.updatedModel
|
|
||||||
: model;
|
|
||||||
}).toList();
|
}).toList();
|
||||||
} else {
|
} else {
|
||||||
_cachedSpaceModels = await fetchSpaceModels();
|
_cachedSpaceModels = await fetchSpaceModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await fetchTags();
|
||||||
|
|
||||||
emit(SpaceModelLoaded(
|
emit(SpaceModelLoaded(
|
||||||
communities: state is SpaceManagementLoaded
|
communities:
|
||||||
? (state as SpaceManagementLoaded).communities
|
state is SpaceManagementLoaded ? (state as SpaceManagementLoaded).communities : [],
|
||||||
: [],
|
products: _cachedProducts ?? [],
|
||||||
products: _cachedProducts ?? [],
|
spaceModels: List.from(_cachedSpaceModels ?? []),
|
||||||
spaceModels: List.from(_cachedSpaceModels ?? []),
|
allTags: _cachedTags ?? []));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deleteSpaceModelFromCache(DeleteSpaceModelFromCache event,
|
void _deleteSpaceModelFromCache(
|
||||||
Emitter<SpaceManagementState> emit) async {
|
DeleteSpaceModelFromCache event, Emitter<SpaceManagementState> emit) async {
|
||||||
if (_cachedSpaceModels != null) {
|
if (_cachedSpaceModels != null) {
|
||||||
_cachedSpaceModels = _cachedSpaceModels!
|
_cachedSpaceModels =
|
||||||
.where((model) => model.uuid != event.deletedUuid)
|
_cachedSpaceModels!.where((model) => model.uuid != event.deletedUuid).toList();
|
||||||
.toList();
|
|
||||||
} else {
|
} else {
|
||||||
_cachedSpaceModels = await fetchSpaceModels();
|
_cachedSpaceModels = await fetchSpaceModels();
|
||||||
}
|
}
|
||||||
|
await fetchTags();
|
||||||
|
|
||||||
emit(SpaceModelLoaded(
|
emit(SpaceModelLoaded(
|
||||||
communities: state is SpaceManagementLoaded
|
communities:
|
||||||
? (state as SpaceManagementLoaded).communities
|
state is SpaceManagementLoaded ? (state as SpaceManagementLoaded).communities : [],
|
||||||
: [],
|
products: _cachedProducts ?? [],
|
||||||
products: _cachedProducts ?? [],
|
spaceModels: List.from(_cachedSpaceModels ?? []),
|
||||||
spaceModels: List.from(_cachedSpaceModels ?? []),
|
allTags: _cachedTags ?? []));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateCachedSpaceModels(List<SpaceTemplateModel> updatedModels) {
|
void updateCachedSpaceModels(List<SpaceTemplateModel> updatedModels) {
|
||||||
@ -112,8 +110,8 @@ class SpaceManagementBloc
|
|||||||
int page = 1;
|
int page = 1;
|
||||||
|
|
||||||
while (hasNext) {
|
while (hasNext) {
|
||||||
final spaceModels = await _spaceModelApi.listSpaceModels(
|
final spaceModels =
|
||||||
page: page, projectId: projectUuid);
|
await _spaceModelApi.listSpaceModels(page: page, projectId: projectUuid);
|
||||||
if (spaceModels.isNotEmpty) {
|
if (spaceModels.isNotEmpty) {
|
||||||
allSpaceModels.addAll(spaceModels);
|
allSpaceModels.addAll(spaceModels);
|
||||||
page++;
|
page++;
|
||||||
@ -130,6 +128,20 @@ class SpaceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<Tag>> fetchTags() async {
|
||||||
|
try {
|
||||||
|
if (_cachedTags != null) {
|
||||||
|
return _cachedTags!;
|
||||||
|
}
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
final allTags = await _spaceModelApi.listTags(projectId: projectUuid);
|
||||||
|
_cachedTags = allTags;
|
||||||
|
return allTags;
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _onUpdateCommunity(
|
void _onUpdateCommunity(
|
||||||
UpdateCommunityEvent event,
|
UpdateCommunityEvent event,
|
||||||
Emitter<SpaceManagementState> emit,
|
Emitter<SpaceManagementState> emit,
|
||||||
@ -137,14 +149,13 @@ class SpaceManagementBloc
|
|||||||
final previousState = state;
|
final previousState = state;
|
||||||
try {
|
try {
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
await fetchTags();
|
||||||
|
|
||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
final success = await _api.updateCommunity(
|
final success = await _api.updateCommunity(event.communityUuid, event.name, projectUuid);
|
||||||
event.communityUuid, event.name, projectUuid);
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (previousState is SpaceManagementLoaded) {
|
if (previousState is SpaceManagementLoaded) {
|
||||||
final updatedCommunities =
|
final updatedCommunities = List<CommunityModel>.from(previousState.communities);
|
||||||
List<CommunityModel>.from(previousState.communities);
|
|
||||||
for (var community in updatedCommunities) {
|
for (var community in updatedCommunities) {
|
||||||
if (community.uuid == event.communityUuid) {
|
if (community.uuid == event.communityUuid) {
|
||||||
community.name = event.name;
|
community.name = event.name;
|
||||||
@ -157,11 +168,11 @@ class SpaceManagementBloc
|
|||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
emit(SpaceManagementLoaded(
|
emit(SpaceManagementLoaded(
|
||||||
communities: updatedCommunities,
|
communities: updatedCommunities,
|
||||||
products: previousState.products,
|
products: previousState.products,
|
||||||
selectedCommunity: previousState.selectedCommunity,
|
selectedCommunity: previousState.selectedCommunity,
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
));
|
allTags: _cachedTags ?? []));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(const SpaceManagementError('Failed to update the community.'));
|
emit(const SpaceManagementError('Failed to update the community.'));
|
||||||
@ -189,8 +200,7 @@ class SpaceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
Future<List<SpaceModel>> _fetchSpacesForCommunity(String communityUuid) async {
|
||||||
String communityUuid) async {
|
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
return await _api.getSpaceHierarchy(communityUuid, projectUuid);
|
return await _api.getSpaceHierarchy(communityUuid, projectUuid);
|
||||||
@ -201,7 +211,7 @@ class SpaceManagementBloc
|
|||||||
Emitter<SpaceManagementState> emit,
|
Emitter<SpaceManagementState> emit,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
final previousState = state;
|
await fetchTags();
|
||||||
|
|
||||||
if (event.communities.isEmpty) {
|
if (event.communities.isEmpty) {
|
||||||
emit(const SpaceManagementError('No communities provided.'));
|
emit(const SpaceManagementError('No communities provided.'));
|
||||||
@ -211,33 +221,33 @@ class SpaceManagementBloc
|
|||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
emit(BlankState(
|
emit(BlankState(
|
||||||
communities: event.communities,
|
communities: event.communities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
));
|
allTags: _cachedTags ?? []));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
emit(SpaceManagementError('Error loading communities: $error'));
|
emit(SpaceManagementError('Error loading communities: $error'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onBlankState(
|
Future<void> _onBlankState(BlankStateEvent event, Emitter<SpaceManagementState> emit) async {
|
||||||
BlankStateEvent event, Emitter<SpaceManagementState> emit) async {
|
|
||||||
try {
|
try {
|
||||||
final previousState = state;
|
final previousState = state;
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc);
|
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc);
|
||||||
|
await fetchSpaceModels();
|
||||||
|
await fetchTags();
|
||||||
|
|
||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
if (previousState is SpaceManagementLoaded ||
|
if (previousState is SpaceManagementLoaded || previousState is BlankState) {
|
||||||
previousState is BlankState) {
|
|
||||||
final prevCommunities = (previousState as dynamic).communities ?? [];
|
final prevCommunities = (previousState as dynamic).communities ?? [];
|
||||||
emit(BlankState(
|
emit(BlankState(
|
||||||
communities: List<CommunityModel>.from(prevCommunities),
|
communities: List<CommunityModel>.from(prevCommunities),
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
));
|
allTags: _cachedTags ?? []));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,8 +256,7 @@ class SpaceManagementBloc
|
|||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
communities.map((community) async {
|
||||||
List<SpaceModel> spaces =
|
List<SpaceModel> spaces = await _fetchSpacesForCommunity(community.uuid);
|
||||||
await _fetchSpacesForCommunity(community.uuid);
|
|
||||||
return CommunityModel(
|
return CommunityModel(
|
||||||
uuid: community.uuid,
|
uuid: community.uuid,
|
||||||
createdAt: community.createdAt,
|
createdAt: community.createdAt,
|
||||||
@ -267,6 +276,7 @@ class SpaceManagementBloc
|
|||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
communities: communities,
|
communities: communities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
|
allTags: _cachedTags ?? [],
|
||||||
));
|
));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
emit(SpaceManagementError('Error loading communities: $error'));
|
emit(SpaceManagementError('Error loading communities: $error'));
|
||||||
@ -279,21 +289,20 @@ class SpaceManagementBloc
|
|||||||
) async {
|
) async {
|
||||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
_onloadProducts();
|
_onloadProducts();
|
||||||
|
await fetchTags();
|
||||||
// Wait until `communityList` is loaded
|
// Wait until `communityList` is loaded
|
||||||
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc);
|
List<CommunityModel> communities = await _waitForCommunityList(spaceBloc);
|
||||||
|
|
||||||
// Fetch space models after communities are available
|
// Fetch space models after communities are available
|
||||||
final prevSpaceModels = await fetchSpaceModels();
|
final prevSpaceModels = await fetchSpaceModels();
|
||||||
emit(SpaceManagementLoaded(
|
emit(SpaceManagementLoaded(
|
||||||
communities: communities,
|
communities: communities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
));
|
allTags: _cachedTags ?? []));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<CommunityModel>> _waitForCommunityList(
|
Future<List<CommunityModel>> _waitForCommunityList(SpaceTreeBloc spaceBloc) async {
|
||||||
SpaceTreeBloc spaceBloc) async {
|
|
||||||
// Check if communityList is already populated
|
// Check if communityList is already populated
|
||||||
if (spaceBloc.state.communityList.isNotEmpty) {
|
if (spaceBloc.state.communityList.isNotEmpty) {
|
||||||
return spaceBloc.state.communityList;
|
return spaceBloc.state.communityList;
|
||||||
@ -320,8 +329,7 @@ class SpaceManagementBloc
|
|||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
final success =
|
final success = await _api.deleteCommunity(event.communityUuid, projectUuid);
|
||||||
await _api.deleteCommunity(event.communityUuid, projectUuid);
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// add(LoadCommunityAndSpacesEvent());
|
// add(LoadCommunityAndSpacesEvent());
|
||||||
} else {
|
} else {
|
||||||
@ -342,14 +350,13 @@ class SpaceManagementBloc
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
await fetchTags();
|
||||||
CommunityModel? newCommunity = await _api.createCommunity(
|
CommunityModel? newCommunity =
|
||||||
event.name, event.description, projectUuid);
|
await _api.createCommunity(event.name, event.description, projectUuid);
|
||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
|
||||||
if (newCommunity != null) {
|
if (newCommunity != null) {
|
||||||
if (previousState is SpaceManagementLoaded ||
|
if (previousState is SpaceManagementLoaded || previousState is BlankState) {
|
||||||
previousState is BlankState) {
|
|
||||||
final prevCommunities = List<CommunityModel>.from(
|
final prevCommunities = List<CommunityModel>.from(
|
||||||
(previousState as dynamic).communities,
|
(previousState as dynamic).communities,
|
||||||
);
|
);
|
||||||
@ -357,11 +364,13 @@ class SpaceManagementBloc
|
|||||||
_spaceTreeBloc.add(OnCommunityAdded(newCommunity));
|
_spaceTreeBloc.add(OnCommunityAdded(newCommunity));
|
||||||
|
|
||||||
emit(SpaceManagementLoaded(
|
emit(SpaceManagementLoaded(
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
communities: updatedCommunities,
|
communities: updatedCommunities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
selectedCommunity: newCommunity,
|
selectedCommunity: newCommunity,
|
||||||
selectedSpace: null));
|
selectedSpace: null,
|
||||||
|
allTags: _cachedTags ?? [],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(const SpaceManagementError('Error creating community'));
|
emit(const SpaceManagementError('Error creating community'));
|
||||||
@ -401,11 +410,12 @@ class SpaceManagementBloc
|
|||||||
required Emitter<SpaceManagementState> emit,
|
required Emitter<SpaceManagementState> emit,
|
||||||
CommunityModel? selectedCommunity,
|
CommunityModel? selectedCommunity,
|
||||||
SpaceModel? selectedSpace,
|
SpaceModel? selectedSpace,
|
||||||
}) {
|
}) async {
|
||||||
final previousState = state;
|
final previousState = state;
|
||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await fetchTags();
|
||||||
if (previousState is SpaceManagementLoaded ||
|
if (previousState is SpaceManagementLoaded ||
|
||||||
previousState is BlankState ||
|
previousState is BlankState ||
|
||||||
previousState is SpaceModelLoaded) {
|
previousState is SpaceModelLoaded) {
|
||||||
@ -421,7 +431,8 @@ class SpaceManagementBloc
|
|||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
selectedCommunity: selectedCommunity,
|
selectedCommunity: selectedCommunity,
|
||||||
selectedSpace: selectedSpace,
|
selectedSpace: selectedSpace,
|
||||||
spaceModels: spaceModels));
|
spaceModels: spaceModels,
|
||||||
|
allTags: _cachedTags ?? []));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceManagementError('Error updating state: $e'));
|
emit(SpaceManagementError('Error updating state: $e'));
|
||||||
@ -436,8 +447,7 @@ class SpaceManagementBloc
|
|||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final updatedSpaces =
|
final updatedSpaces = await saveSpacesHierarchically(event.spaces, event.communityUuid);
|
||||||
await saveSpacesHierarchically(event.spaces, event.communityUuid);
|
|
||||||
|
|
||||||
final allSpaces = await _fetchSpacesForCommunity(event.communityUuid);
|
final allSpaces = await _fetchSpacesForCommunity(event.communityUuid);
|
||||||
|
|
||||||
@ -467,20 +477,21 @@ class SpaceManagementBloc
|
|||||||
Emitter<SpaceManagementState> emit,
|
Emitter<SpaceManagementState> emit,
|
||||||
) async {
|
) async {
|
||||||
var prevSpaceModels = await fetchSpaceModels();
|
var prevSpaceModels = await fetchSpaceModels();
|
||||||
|
await fetchTags();
|
||||||
final communities = List<CommunityModel>.from(previousState.communities);
|
final communities = List<CommunityModel>.from(previousState.communities);
|
||||||
|
|
||||||
for (var community in communities) {
|
for (var community in communities) {
|
||||||
if (community.uuid == communityUuid) {
|
if (community.uuid == communityUuid) {
|
||||||
community.spaces = allSpaces;
|
community.spaces = allSpaces;
|
||||||
_spaceTreeBloc.add(OnCommunityUpdated(community));
|
_spaceTreeBloc.add(InitialEvent());
|
||||||
|
|
||||||
emit(SpaceManagementLoaded(
|
emit(SpaceManagementLoaded(
|
||||||
communities: communities,
|
communities: communities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
selectedCommunity: community,
|
selectedCommunity: community,
|
||||||
selectedSpace: null,
|
selectedSpace: null,
|
||||||
spaceModels: prevSpaceModels));
|
spaceModels: prevSpaceModels,
|
||||||
|
allTags: _cachedTags ?? []));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,8 +522,7 @@ class SpaceManagementBloc
|
|||||||
if (space.uuid != null && space.uuid!.isNotEmpty) {
|
if (space.uuid != null && space.uuid!.isNotEmpty) {
|
||||||
List<TagModelUpdate> tagUpdates = [];
|
List<TagModelUpdate> tagUpdates = [];
|
||||||
|
|
||||||
final prevSpace =
|
final prevSpace = await _api.getSpace(communityUuid, space.uuid!, projectUuid);
|
||||||
await _api.getSpace(communityUuid, space.uuid!, projectUuid);
|
|
||||||
final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
|
final List<UpdateSubspaceTemplateModel> subspaceUpdates = [];
|
||||||
final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
|
final List<SubspaceModel>? prevSubspaces = prevSpace?.subspaces;
|
||||||
final List<SubspaceModel>? newSubspaces = space.subspaces;
|
final List<SubspaceModel>? newSubspaces = space.subspaces;
|
||||||
@ -522,19 +532,17 @@ class SpaceManagementBloc
|
|||||||
if (prevSubspaces != null || newSubspaces != null) {
|
if (prevSubspaces != null || newSubspaces != null) {
|
||||||
if (prevSubspaces != null && newSubspaces != null) {
|
if (prevSubspaces != null && newSubspaces != null) {
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
final existsInNew = newSubspaces
|
final existsInNew =
|
||||||
.any((subspace) => subspace.uuid == prevSubspace.uuid);
|
newSubspaces.any((subspace) => subspace.uuid == prevSubspace.uuid);
|
||||||
if (!existsInNew) {
|
if (!existsInNew) {
|
||||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||||
action: custom_action.Action.delete,
|
action: custom_action.Action.delete, uuid: prevSubspace.uuid));
|
||||||
uuid: prevSubspace.uuid));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (prevSubspaces != null && newSubspaces == null) {
|
} else if (prevSubspaces != null && newSubspaces == null) {
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
subspaceUpdates.add(UpdateSubspaceTemplateModel(
|
||||||
action: custom_action.Action.delete,
|
action: custom_action.Action.delete, uuid: prevSubspace.uuid));
|
||||||
uuid: prevSubspace.uuid));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,7 +556,7 @@ class SpaceManagementBloc
|
|||||||
for (var tag in newSubspace.tags!) {
|
for (var tag in newSubspace.tags!) {
|
||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: custom_action.Action.add,
|
action: custom_action.Action.add,
|
||||||
uuid: tag.uuid == '' ? null : tag.uuid,
|
newTagUuid: tag.uuid == '' ? null : tag.uuid,
|
||||||
tag: tag.tag,
|
tag: tag.tag,
|
||||||
productUuid: tag.product?.uuid));
|
productUuid: tag.product?.uuid));
|
||||||
}
|
}
|
||||||
@ -562,9 +570,7 @@ class SpaceManagementBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prevSubspaces != null && newSubspaces != null) {
|
if (prevSubspaces != null && newSubspaces != null) {
|
||||||
final newSubspaceMap = {
|
final newSubspaceMap = {for (var subspace in newSubspaces) subspace.uuid: subspace};
|
||||||
for (var subspace in newSubspaces) subspace.uuid: subspace
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
final newSubspace = newSubspaceMap[prevSubspace.uuid];
|
final newSubspace = newSubspaceMap[prevSubspace.uuid];
|
||||||
@ -601,10 +607,8 @@ class SpaceManagementBloc
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
final createSubspaceBodyModels = space.subspaces?.map((subspace) {
|
final createSubspaceBodyModels = space.subspaces?.map((subspace) {
|
||||||
final tagBodyModels = subspace.tags
|
final tagBodyModels =
|
||||||
?.map((tag) => tag.toCreateTagBodyModel())
|
subspace.tags?.map((tag) => tag.toCreateTagBodyModel()).toList() ?? [];
|
||||||
.toList() ??
|
|
||||||
[];
|
|
||||||
return CreateSubspaceModel()
|
return CreateSubspaceModel()
|
||||||
..subspaceName = subspace.subspaceName
|
..subspaceName = subspace.subspaceName
|
||||||
..tags = tagBodyModels;
|
..tags = tagBodyModels;
|
||||||
@ -657,12 +661,11 @@ class SpaceManagementBloc
|
|||||||
return result.toList(); // Convert back to a list
|
return result.toList(); // Convert back to a list
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onLoadSpaceModel(
|
void _onLoadSpaceModel(SpaceModelLoadEvent event, Emitter<SpaceManagementState> emit) async {
|
||||||
SpaceModelLoadEvent event, Emitter<SpaceManagementState> emit) async {
|
|
||||||
emit(SpaceManagementLoading());
|
emit(SpaceManagementLoading());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var prevState = state;
|
await fetchTags();
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
List<CommunityModel> communities = spaceBloc.state.communityList;
|
List<CommunityModel> communities = spaceBloc.state.communityList;
|
||||||
@ -674,8 +677,7 @@ class SpaceManagementBloc
|
|||||||
|
|
||||||
List<CommunityModel> updatedCommunities = await Future.wait(
|
List<CommunityModel> updatedCommunities = await Future.wait(
|
||||||
communities.map((community) async {
|
communities.map((community) async {
|
||||||
List<SpaceModel> spaces =
|
List<SpaceModel> spaces = await _fetchSpacesForCommunity(community.uuid);
|
||||||
await _fetchSpacesForCommunity(community.uuid);
|
|
||||||
return CommunityModel(
|
return CommunityModel(
|
||||||
uuid: community.uuid,
|
uuid: community.uuid,
|
||||||
createdAt: community.createdAt,
|
createdAt: community.createdAt,
|
||||||
@ -692,10 +694,10 @@ class SpaceManagementBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit(SpaceModelLoaded(
|
emit(SpaceModelLoaded(
|
||||||
communities: communities,
|
communities: communities,
|
||||||
products: _cachedProducts ?? [],
|
products: _cachedProducts ?? [],
|
||||||
spaceModels: prevSpaceModels,
|
spaceModels: prevSpaceModels,
|
||||||
));
|
allTags: _cachedTags ?? []));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(SpaceManagementError('Error loading communities and spaces: $e'));
|
emit(SpaceManagementError('Error loading communities and spaces: $e'));
|
||||||
}
|
}
|
||||||
@ -713,7 +715,7 @@ class SpaceManagementBloc
|
|||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: custom_action.Action.add,
|
action: custom_action.Action.add,
|
||||||
tag: newTag.tag,
|
tag: newTag.tag,
|
||||||
uuid: newTag.uuid,
|
newTagUuid: newTag.uuid,
|
||||||
productUuid: newTag.product?.uuid,
|
productUuid: newTag.product?.uuid,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -724,17 +726,14 @@ class SpaceManagementBloc
|
|||||||
// Case 1: Tags deleted
|
// Case 1: Tags deleted
|
||||||
if (prevTags != null && newTags != null) {
|
if (prevTags != null && newTags != null) {
|
||||||
for (var prevTag in prevTags) {
|
for (var prevTag in prevTags) {
|
||||||
final existsInNew =
|
final existsInNew = newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
||||||
newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
|
||||||
if (!existsInNew) {
|
if (!existsInNew) {
|
||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(action: custom_action.Action.delete, uuid: prevTag.uuid));
|
||||||
action: custom_action.Action.delete, uuid: prevTag.uuid));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (prevTags != null && newTags == null) {
|
} else if (prevTags != null && newTags == null) {
|
||||||
for (var prevTag in prevTags) {
|
for (var prevTag in prevTags) {
|
||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(action: custom_action.Action.delete, uuid: prevTag.uuid));
|
||||||
action: custom_action.Action.delete, uuid: prevTag.uuid));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,7 +748,7 @@ class SpaceManagementBloc
|
|||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: custom_action.Action.add,
|
action: custom_action.Action.add,
|
||||||
tag: newTag.tag,
|
tag: newTag.tag,
|
||||||
uuid: newTag.uuid == '' ? null : newTag.uuid,
|
newTagUuid: newTag.uuid == '' ? null : newTag.uuid,
|
||||||
productUuid: newTag.product?.uuid));
|
productUuid: newTag.product?.uuid));
|
||||||
processedTags.add(newTag.tag);
|
processedTags.add(newTag.tag);
|
||||||
}
|
}
|
||||||
@ -766,6 +765,7 @@ class SpaceManagementBloc
|
|||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: custom_action.Action.update,
|
action: custom_action.Action.update,
|
||||||
uuid: newTag.uuid,
|
uuid: newTag.uuid,
|
||||||
|
newTagUuid: newTag.uuid,
|
||||||
tag: newTag.tag,
|
tag: newTag.tag,
|
||||||
));
|
));
|
||||||
} else {}
|
} else {}
|
||||||
|
@ -2,6 +2,7 @@ import 'package:equatable/equatable.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/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/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/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
|
||||||
abstract class SpaceManagementState extends Equatable {
|
abstract class SpaceManagementState extends Equatable {
|
||||||
@ -21,22 +22,25 @@ class SpaceManagementLoaded extends SpaceManagementState {
|
|||||||
CommunityModel? selectedCommunity;
|
CommunityModel? selectedCommunity;
|
||||||
SpaceModel? selectedSpace;
|
SpaceModel? selectedSpace;
|
||||||
List<SpaceTemplateModel>? spaceModels;
|
List<SpaceTemplateModel>? spaceModels;
|
||||||
|
List<Tag> allTags;
|
||||||
|
|
||||||
SpaceManagementLoaded(
|
SpaceManagementLoaded(
|
||||||
{required this.communities,
|
{required this.communities,
|
||||||
required this.products,
|
required this.products,
|
||||||
this.selectedCommunity,
|
this.selectedCommunity,
|
||||||
this.selectedSpace,
|
this.selectedSpace,
|
||||||
this.spaceModels});
|
this.spaceModels,
|
||||||
|
required this.allTags});
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlankState extends SpaceManagementState {
|
class BlankState extends SpaceManagementState {
|
||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
final List<ProductModel> products;
|
final List<ProductModel> products;
|
||||||
List<SpaceTemplateModel>? spaceModels;
|
List<SpaceTemplateModel>? spaceModels;
|
||||||
|
final List<Tag> allTags;
|
||||||
|
|
||||||
BlankState(
|
BlankState(
|
||||||
{required this.communities, required this.products, this.spaceModels});
|
{required this.communities, required this.products, this.spaceModels, required this.allTags});
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpaceCreationSuccess extends SpaceManagementState {
|
class SpaceCreationSuccess extends SpaceManagementState {
|
||||||
@ -61,14 +65,14 @@ class SpaceModelLoaded extends SpaceManagementState {
|
|||||||
List<SpaceTemplateModel> spaceModels;
|
List<SpaceTemplateModel> spaceModels;
|
||||||
final List<ProductModel> products;
|
final List<ProductModel> products;
|
||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
|
final List<Tag> allTags;
|
||||||
|
|
||||||
SpaceModelLoaded({
|
SpaceModelLoaded(
|
||||||
required this.communities,
|
{required this.communities,
|
||||||
required this.products,
|
required this.products,
|
||||||
required this.spaceModels,
|
required this.spaceModels,
|
||||||
});
|
required this.allTags});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [communities, products, spaceModels];
|
List<Object> get props => [communities, products, spaceModels, allTags];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,22 +25,21 @@ class Tag extends BaseTag {
|
|||||||
return Tag(
|
return Tag(
|
||||||
uuid: json['uuid'] ?? '',
|
uuid: json['uuid'] ?? '',
|
||||||
internalId: internalId,
|
internalId: internalId,
|
||||||
tag: json['tag'] ?? '',
|
tag: json['name'] ?? '',
|
||||||
product: json['product'] != null
|
product: json['product'] != null ? ProductModel.fromMap(json['product']) : null,
|
||||||
? ProductModel.fromMap(json['product'])
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Tag copyWith({
|
Tag copyWith({
|
||||||
|
String? uuid,
|
||||||
String? tag,
|
String? tag,
|
||||||
ProductModel? product,
|
ProductModel? product,
|
||||||
String? location,
|
String? location,
|
||||||
String? internalId,
|
String? internalId,
|
||||||
}) {
|
}) {
|
||||||
return Tag(
|
return Tag(
|
||||||
uuid: uuid,
|
uuid: uuid ?? this.uuid,
|
||||||
tag: tag ?? this.tag,
|
tag: tag ?? this.tag,
|
||||||
product: product ?? this.product,
|
product: product ?? this.product,
|
||||||
location: location ?? this.location,
|
location: location ?? this.location,
|
||||||
@ -60,7 +59,7 @@ class Tag extends BaseTag {
|
|||||||
extension TagModelExtensions on Tag {
|
extension TagModelExtensions on Tag {
|
||||||
TagBodyModel toTagBodyModel() {
|
TagBodyModel toTagBodyModel() {
|
||||||
return TagBodyModel()
|
return TagBodyModel()
|
||||||
..uuid = uuid ?? ''
|
..uuid = uuid
|
||||||
..tag = tag ?? ''
|
..tag = tag ?? ''
|
||||||
..productUuid = product?.uuid;
|
..productUuid = product?.uuid;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
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/shared/navigate_home_grid_view.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||||
@ -62,9 +60,9 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
|||||||
selectedSpace: null,
|
selectedSpace: null,
|
||||||
products: state.products,
|
products: state.products,
|
||||||
shouldNavigateToSpaceModelPage: false,
|
shouldNavigateToSpaceModelPage: false,
|
||||||
|
projectTags: state.allTags,
|
||||||
);
|
);
|
||||||
} else if (state is SpaceManagementLoaded) {
|
} else if (state is SpaceManagementLoaded) {
|
||||||
|
|
||||||
return LoadedSpaceView(
|
return LoadedSpaceView(
|
||||||
communities: state.communities,
|
communities: state.communities,
|
||||||
selectedCommunity: state.selectedCommunity,
|
selectedCommunity: state.selectedCommunity,
|
||||||
@ -72,6 +70,7 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
|||||||
products: state.products,
|
products: state.products,
|
||||||
spaceModels: state.spaceModels,
|
spaceModels: state.spaceModels,
|
||||||
shouldNavigateToSpaceModelPage: false,
|
shouldNavigateToSpaceModelPage: false,
|
||||||
|
projectTags: state.allTags,
|
||||||
);
|
);
|
||||||
} else if (state is SpaceModelLoaded) {
|
} else if (state is SpaceModelLoaded) {
|
||||||
return LoadedSpaceView(
|
return LoadedSpaceView(
|
||||||
@ -79,6 +78,7 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
|||||||
products: state.products,
|
products: state.products,
|
||||||
spaceModels: state.spaceModels,
|
spaceModels: state.spaceModels,
|
||||||
shouldNavigateToSpaceModelPage: true,
|
shouldNavigateToSpaceModelPage: true,
|
||||||
|
projectTags: state.allTags,
|
||||||
);
|
);
|
||||||
} else if (state is SpaceManagementError) {
|
} else if (state is SpaceManagementError) {
|
||||||
return Center(child: Text('Error: ${state.errorMessage}'));
|
return Center(child: Text('Error: ${state.errorMessage}'));
|
||||||
|
@ -36,16 +36,17 @@ class CommunityStructureArea extends StatefulWidget {
|
|||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
final List<SpaceModel> spaces;
|
final List<SpaceModel> spaces;
|
||||||
final List<SpaceTemplateModel>? spaceModels;
|
final List<SpaceTemplateModel>? spaceModels;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
CommunityStructureArea({
|
CommunityStructureArea(
|
||||||
this.selectedCommunity,
|
{this.selectedCommunity,
|
||||||
this.selectedSpace,
|
this.selectedSpace,
|
||||||
required this.communities,
|
required this.communities,
|
||||||
this.products,
|
this.products,
|
||||||
required this.spaces,
|
required this.spaces,
|
||||||
this.onSpaceSelected,
|
this.onSpaceSelected,
|
||||||
this.spaceModels,
|
this.spaceModels,
|
||||||
});
|
required this.projectTags});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_CommunityStructureAreaState createState() => _CommunityStructureAreaState();
|
_CommunityStructureAreaState createState() => _CommunityStructureAreaState();
|
||||||
@ -64,8 +65,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
||||||
connections =
|
connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
||||||
widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
|
||||||
_adjustCanvasSizeForSpaces();
|
_adjustCanvasSizeForSpaces();
|
||||||
_nameController = TextEditingController(
|
_nameController = TextEditingController(
|
||||||
text: widget.selectedCommunity?.name ?? '',
|
text: widget.selectedCommunity?.name ?? '',
|
||||||
@ -92,14 +92,12 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
if (oldWidget.spaces != widget.spaces) {
|
if (oldWidget.spaces != widget.spaces) {
|
||||||
setState(() {
|
setState(() {
|
||||||
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
|
||||||
connections =
|
connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
||||||
widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
|
|
||||||
_adjustCanvasSizeForSpaces();
|
_adjustCanvasSizeForSpaces();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget.selectedSpace != oldWidget.selectedSpace &&
|
if (widget.selectedSpace != oldWidget.selectedSpace && widget.selectedSpace != null) {
|
||||||
widget.selectedSpace != null) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_moveToSpace(widget.selectedSpace!);
|
_moveToSpace(widget.selectedSpace!);
|
||||||
});
|
});
|
||||||
@ -182,8 +180,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
connection, widget.selectedSpace)
|
connection, widget.selectedSpace)
|
||||||
? 1.0
|
? 1.0
|
||||||
: 0.3, // Adjust opacity
|
: 0.3, // Adjust opacity
|
||||||
child: CustomPaint(
|
child: CustomPaint(painter: CurvedLinePainter([connection])),
|
||||||
painter: CurvedLinePainter([connection])),
|
|
||||||
),
|
),
|
||||||
for (var entry in spaces.asMap().entries)
|
for (var entry in spaces.asMap().entries)
|
||||||
if (entry.value.status != SpaceStatus.deleted &&
|
if (entry.value.status != SpaceStatus.deleted &&
|
||||||
@ -193,15 +190,12 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
top: entry.value.position.dy,
|
top: entry.value.position.dy,
|
||||||
child: SpaceCardWidget(
|
child: SpaceCardWidget(
|
||||||
index: entry.key,
|
index: entry.key,
|
||||||
onButtonTap: (int index, Offset newPosition,
|
onButtonTap: (int index, Offset newPosition, String direction) {
|
||||||
String direction) {
|
_showCreateSpaceDialog(screenSize,
|
||||||
_showCreateSpaceDialog(
|
position: spaces[index].position + newPosition,
|
||||||
screenSize,
|
parentIndex: index,
|
||||||
position:
|
direction: direction,
|
||||||
spaces[index].position + newPosition,
|
projectTags: widget.projectTags);
|
||||||
parentIndex: index,
|
|
||||||
direction: direction,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
position: entry.value.position,
|
position: entry.value.position,
|
||||||
isHovered: entry.value.isHovered,
|
isHovered: entry.value.isHovered,
|
||||||
@ -211,9 +205,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
_updateNodePosition(entry.value, newPosition);
|
_updateNodePosition(entry.value, newPosition);
|
||||||
},
|
},
|
||||||
buildSpaceContainer: (int index) {
|
buildSpaceContainer: (int index) {
|
||||||
final bool isHighlighted =
|
final bool isHighlighted = SpaceHelper.isHighlightedSpace(
|
||||||
SpaceHelper.isHighlightedSpace(
|
spaces[index], widget.selectedSpace);
|
||||||
spaces[index], widget.selectedSpace);
|
|
||||||
|
|
||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: isHighlighted ? 1.0 : 0.3,
|
opacity: isHighlighted ? 1.0 : 0.3,
|
||||||
@ -238,7 +231,8 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
_showCreateSpaceDialog(screenSize,
|
_showCreateSpaceDialog(screenSize,
|
||||||
canvasHeight: canvasHeight,
|
canvasHeight: canvasHeight,
|
||||||
canvasWidth: canvasWidth);
|
canvasWidth: canvasWidth,
|
||||||
|
projectTags: widget.projectTags);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -292,26 +286,22 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
int? parentIndex,
|
int? parentIndex,
|
||||||
String? direction,
|
String? direction,
|
||||||
double? canvasWidth,
|
double? canvasWidth,
|
||||||
double? canvasHeight}) {
|
double? canvasHeight,
|
||||||
|
required List<Tag> projectTags}) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return CreateSpaceDialog(
|
return CreateSpaceDialog(
|
||||||
products: widget.products,
|
products: widget.products,
|
||||||
spaceModels: widget.spaceModels,
|
spaceModels: widget.spaceModels,
|
||||||
allTags:
|
allTags: TagHelper.getAllTagValues(widget.communities, widget.spaceModels),
|
||||||
TagHelper.getAllTagValues(widget.communities, widget.spaceModels),
|
|
||||||
parentSpace: parentIndex != null ? spaces[parentIndex] : null,
|
parentSpace: parentIndex != null ? spaces[parentIndex] : null,
|
||||||
onCreateSpace: (String name,
|
projectTags: projectTags,
|
||||||
String icon,
|
onCreateSpace: (String name, String icon, List<SelectedProduct> selectedProducts,
|
||||||
List<SelectedProduct> selectedProducts,
|
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 =
|
Offset centerPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
|
||||||
position ?? ConnectionHelper.getCenterPosition(screenSize);
|
|
||||||
SpaceModel newSpace = SpaceModel(
|
SpaceModel newSpace = SpaceModel(
|
||||||
name: name,
|
name: name,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
@ -356,21 +346,17 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
spaceModels: widget.spaceModels,
|
spaceModels: widget.spaceModels,
|
||||||
name: widget.selectedSpace!.name,
|
name: widget.selectedSpace!.name,
|
||||||
icon: widget.selectedSpace!.icon,
|
icon: widget.selectedSpace!.icon,
|
||||||
parentSpace: SpaceHelper.findSpaceByInternalId(
|
projectTags: widget.projectTags,
|
||||||
widget.selectedSpace?.parent?.internalId, spaces),
|
parentSpace:
|
||||||
|
SpaceHelper.findSpaceByInternalId(widget.selectedSpace?.parent?.internalId, spaces),
|
||||||
editSpace: widget.selectedSpace,
|
editSpace: widget.selectedSpace,
|
||||||
currentSpaceModel: widget.selectedSpace?.spaceModel,
|
currentSpaceModel: widget.selectedSpace?.spaceModel,
|
||||||
tags: widget.selectedSpace?.tags,
|
tags: widget.selectedSpace?.tags,
|
||||||
subspaces: widget.selectedSpace?.subspaces,
|
subspaces: widget.selectedSpace?.subspaces,
|
||||||
isEdit: true,
|
isEdit: true,
|
||||||
allTags: TagHelper.getAllTagValues(
|
allTags: TagHelper.getAllTagValues(widget.communities, widget.spaceModels),
|
||||||
widget.communities, widget.spaceModels),
|
onCreateSpace: (String name, String icon, List<SelectedProduct> selectedProducts,
|
||||||
onCreateSpace: (String name,
|
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
|
||||||
String icon,
|
|
||||||
List<SelectedProduct> selectedProducts,
|
|
||||||
SpaceTemplateModel? spaceModel,
|
|
||||||
List<SubspaceModel>? subspaces,
|
|
||||||
List<Tag>? tags) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// Update the space's properties
|
// Update the space's properties
|
||||||
widget.selectedSpace!.name = name;
|
widget.selectedSpace!.name = name;
|
||||||
@ -380,8 +366,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
widget.selectedSpace!.tags = tags;
|
widget.selectedSpace!.tags = tags;
|
||||||
|
|
||||||
if (widget.selectedSpace!.status != SpaceStatus.newSpace) {
|
if (widget.selectedSpace!.status != SpaceStatus.newSpace) {
|
||||||
widget.selectedSpace!.status =
|
widget.selectedSpace!.status = SpaceStatus.modified; // Mark as modified
|
||||||
SpaceStatus.modified; // Mark as modified
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var space in spaces) {
|
for (var space in spaces) {
|
||||||
@ -411,8 +396,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
List<SpaceModel> result = [];
|
List<SpaceModel> result = [];
|
||||||
|
|
||||||
void flatten(SpaceModel space) {
|
void flatten(SpaceModel space) {
|
||||||
if (space.status == SpaceStatus.deleted ||
|
if (space.status == SpaceStatus.deleted || space.status == SpaceStatus.parentDeleted) {
|
||||||
space.status == SpaceStatus.parentDeleted) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
result.add(space);
|
result.add(space);
|
||||||
@ -527,16 +511,13 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
void _selectSpace(BuildContext context, SpaceModel space) {
|
void _selectSpace(BuildContext context, SpaceModel space) {
|
||||||
context.read<SpaceManagementBloc>().add(
|
context.read<SpaceManagementBloc>().add(
|
||||||
SelectSpaceEvent(
|
SelectSpaceEvent(selectedCommunity: widget.selectedCommunity, selectedSpace: space),
|
||||||
selectedCommunity: widget.selectedCommunity,
|
|
||||||
selectedSpace: space),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deselectSpace(BuildContext context) {
|
void _deselectSpace(BuildContext context) {
|
||||||
context.read<SpaceManagementBloc>().add(
|
context.read<SpaceManagementBloc>().add(
|
||||||
SelectSpaceEvent(
|
SelectSpaceEvent(selectedCommunity: widget.selectedCommunity, selectedSpace: null),
|
||||||
selectedCommunity: widget.selectedCommunity, selectedSpace: null),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,19 +606,16 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
const double horizontalGap = 200.0;
|
const double horizontalGap = 200.0;
|
||||||
const double verticalGap = 100.0;
|
const double verticalGap = 100.0;
|
||||||
|
|
||||||
SpaceModel duplicateRecursive(SpaceModel original, Offset parentPosition,
|
SpaceModel duplicateRecursive(
|
||||||
SpaceModel? duplicatedParent) {
|
SpaceModel original, Offset parentPosition, SpaceModel? duplicatedParent) {
|
||||||
Offset newPosition =
|
Offset newPosition = Offset(parentPosition.dx + horizontalGap, original.position.dy);
|
||||||
Offset(parentPosition.dx + horizontalGap, original.position.dy);
|
|
||||||
|
|
||||||
while (spaces.any((s) =>
|
while (spaces.any((s) =>
|
||||||
(s.position - newPosition).distance < horizontalGap &&
|
(s.position - newPosition).distance < horizontalGap && s.status != SpaceStatus.deleted)) {
|
||||||
s.status != SpaceStatus.deleted)) {
|
|
||||||
newPosition += Offset(horizontalGap, 0);
|
newPosition += Offset(horizontalGap, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final duplicatedName =
|
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
||||||
SpaceHelper.generateUniqueSpaceName(original.name, spaces);
|
|
||||||
|
|
||||||
final List<SubspaceModel>? duplicatedSubspaces;
|
final List<SubspaceModel>? duplicatedSubspaces;
|
||||||
final List<Tag>? duplicatedTags;
|
final List<Tag>? duplicatedTags;
|
||||||
@ -681,8 +659,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
if (original.parent != null && duplicatedParent == null) {
|
if (original.parent != null && duplicatedParent == null) {
|
||||||
final originalParent = original.parent!;
|
final originalParent = original.parent!;
|
||||||
final duplicatedParent =
|
final duplicatedParent = originalToDuplicate[originalParent] ?? originalParent;
|
||||||
originalToDuplicate[originalParent] ?? originalParent;
|
|
||||||
|
|
||||||
final parentConnection = Connection(
|
final parentConnection = Connection(
|
||||||
startSpace: duplicatedParent,
|
startSpace: duplicatedParent,
|
||||||
@ -698,8 +675,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
|
|
||||||
final childrenWithDownDirection = original.children
|
final childrenWithDownDirection = original.children
|
||||||
.where((child) =>
|
.where((child) =>
|
||||||
child.incomingConnection?.direction == "down" &&
|
child.incomingConnection?.direction == "down" && child.status != SpaceStatus.deleted)
|
||||||
child.status != SpaceStatus.deleted)
|
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
Offset childStartPosition = childrenWithDownDirection.length == 1
|
Offset childStartPosition = childrenWithDownDirection.length == 1
|
||||||
@ -707,8 +683,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
: newPosition + Offset(0, verticalGap);
|
: newPosition + Offset(0, verticalGap);
|
||||||
|
|
||||||
for (final child in original.children) {
|
for (final child in original.children) {
|
||||||
final isDownDirection =
|
final isDownDirection = child.incomingConnection?.direction == "down" ?? false;
|
||||||
child.incomingConnection?.direction == "down" ?? false;
|
|
||||||
|
|
||||||
if (isDownDirection && childrenWithDownDirection.length == 1) {
|
if (isDownDirection && childrenWithDownDirection.length == 1) {
|
||||||
childStartPosition = duplicated.position + Offset(0, verticalGap);
|
childStartPosition = duplicated.position + Offset(0, verticalGap);
|
||||||
@ -716,8 +691,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
childStartPosition = duplicated.position + Offset(horizontalGap, 0);
|
childStartPosition = duplicated.position + Offset(horizontalGap, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final duplicatedChild =
|
final duplicatedChild = duplicateRecursive(child, childStartPosition, duplicated);
|
||||||
duplicateRecursive(child, childStartPosition, duplicated);
|
|
||||||
duplicated.children.add(duplicatedChild);
|
duplicated.children.add(duplicatedChild);
|
||||||
childStartPosition += Offset(0, verticalGap);
|
childStartPosition += Offset(0, verticalGap);
|
||||||
}
|
}
|
||||||
@ -728,8 +702,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
|
|||||||
if (space.parent == null) {
|
if (space.parent == null) {
|
||||||
duplicateRecursive(space, space.position, null);
|
duplicateRecursive(space, space.position, null);
|
||||||
} else {
|
} else {
|
||||||
final duplicatedParent =
|
final duplicatedParent = originalToDuplicate[space.parent!] ?? space.parent!;
|
||||||
originalToDuplicate[space.parent!] ?? space.parent!;
|
|
||||||
duplicateRecursive(space, space.position, duplicatedParent);
|
duplicateRecursive(space, space.position, duplicatedParent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ class CreateSpaceDialog extends StatefulWidget {
|
|||||||
final List<Tag>? tags;
|
final List<Tag>? tags;
|
||||||
final List<String>? allTags;
|
final List<String>? allTags;
|
||||||
final SpaceTemplateModel? currentSpaceModel;
|
final SpaceTemplateModel? currentSpaceModel;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const CreateSpaceDialog(
|
const CreateSpaceDialog(
|
||||||
{super.key,
|
{super.key,
|
||||||
@ -57,7 +58,8 @@ class CreateSpaceDialog extends StatefulWidget {
|
|||||||
this.spaceModels,
|
this.spaceModels,
|
||||||
this.subspaces,
|
this.subspaces,
|
||||||
this.tags,
|
this.tags,
|
||||||
this.currentSpaceModel});
|
this.currentSpaceModel,
|
||||||
|
required this.projectTags});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
CreateSpaceDialogState createState() => CreateSpaceDialogState();
|
CreateSpaceDialogState createState() => CreateSpaceDialogState();
|
||||||
@ -80,10 +82,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
selectedIcon = widget.icon ?? Assets.location;
|
selectedIcon = widget.icon ?? Assets.location;
|
||||||
nameController = TextEditingController(text: widget.name ?? '');
|
nameController = TextEditingController(text: widget.name ?? '');
|
||||||
selectedProducts =
|
selectedProducts = widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
|
||||||
widget.selectedProducts.isNotEmpty ? widget.selectedProducts : [];
|
isOkButtonEnabled = enteredName.isNotEmpty || nameController.text.isNotEmpty;
|
||||||
isOkButtonEnabled =
|
|
||||||
enteredName.isNotEmpty || nameController.text.isNotEmpty;
|
|
||||||
if (widget.currentSpaceModel != null) {
|
if (widget.currentSpaceModel != null) {
|
||||||
subspaces = [];
|
subspaces = [];
|
||||||
tags = [];
|
tags = [];
|
||||||
@ -96,15 +96,13 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool isSpaceModelDisabled = (tags != null && tags!.isNotEmpty ||
|
bool isSpaceModelDisabled =
|
||||||
subspaces != null && subspaces!.isNotEmpty);
|
(tags != null && tags!.isNotEmpty || subspaces != null && subspaces!.isNotEmpty);
|
||||||
bool isTagsAndSubspaceModelDisabled = (selectedSpaceModel != null);
|
bool isTagsAndSubspaceModelDisabled = (selectedSpaceModel != null);
|
||||||
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: widget.isEdit
|
title: widget.isEdit ? const Text('Edit Space') : const Text('Create New Space'),
|
||||||
? const Text('Edit Space')
|
|
||||||
: const Text('Create New Space'),
|
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: screenWidth * 0.5,
|
width: screenWidth * 0.5,
|
||||||
@ -178,7 +176,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
isNameFieldInvalid = value.isEmpty;
|
isNameFieldInvalid = value.isEmpty;
|
||||||
|
|
||||||
if (!isNameFieldInvalid) {
|
if (!isNameFieldInvalid) {
|
||||||
if (SpaceHelper.isNameConflict(value, widget.parentSpace, widget.editSpace)) {
|
if (SpaceHelper.isNameConflict(
|
||||||
|
value, widget.parentSpace, widget.editSpace)) {
|
||||||
isNameFieldExist = true;
|
isNameFieldExist = true;
|
||||||
isOkButtonEnabled = false;
|
isOkButtonEnabled = false;
|
||||||
} else {
|
} else {
|
||||||
@ -245,9 +244,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
isSpaceModelDisabled
|
isSpaceModelDisabled ? null : _showLinkSpaceModelDialog(context);
|
||||||
? null
|
|
||||||
: _showLinkSpaceModelDialog(context);
|
|
||||||
},
|
},
|
||||||
child: ButtonContentWidget(
|
child: ButtonContentWidget(
|
||||||
svgAssets: Assets.link,
|
svgAssets: Assets.link,
|
||||||
@ -257,8 +254,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
)
|
)
|
||||||
: Container(
|
: Container(
|
||||||
width: screenWidth * 0.25,
|
width: screenWidth * 0.25,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
|
||||||
vertical: 10.0, horizontal: 16.0),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: ColorsManager.boxColor,
|
color: ColorsManager.boxColor,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
@ -273,8 +269,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium!
|
.bodyMedium!
|
||||||
.copyWith(
|
.copyWith(color: ColorsManager.spaceColor),
|
||||||
color: ColorsManager.spaceColor),
|
|
||||||
),
|
),
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@ -343,8 +338,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
isTagsAndSubspaceModelDisabled
|
isTagsAndSubspaceModelDisabled
|
||||||
? null
|
? null
|
||||||
: _showSubSpaceDialog(context, enteredName,
|
: _showSubSpaceDialog(
|
||||||
[], false, widget.products, subspaces);
|
context, enteredName, [], false, widget.products, subspaces);
|
||||||
},
|
},
|
||||||
child: ButtonContentWidget(
|
child: ButtonContentWidget(
|
||||||
icon: Icons.add,
|
icon: Icons.add,
|
||||||
@ -371,22 +366,16 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
if (subspaces != null)
|
if (subspaces != null)
|
||||||
...subspaces!.map((subspace) {
|
...subspaces!.map((subspace) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
SubspaceNameDisplayWidget(
|
SubspaceNameDisplayWidget(
|
||||||
text: subspace.subspaceName,
|
text: subspace.subspaceName,
|
||||||
validateName: (updatedName) {
|
validateName: (updatedName) {
|
||||||
bool nameExists =
|
bool nameExists = subspaces!.any((s) {
|
||||||
subspaces!.any((s) {
|
bool isSameId = s.internalId == subspace.internalId;
|
||||||
bool isSameId = s.internalId ==
|
bool isSameName =
|
||||||
subspace.internalId;
|
s.subspaceName.trim().toLowerCase() ==
|
||||||
bool isSameName = s.subspaceName
|
updatedName.trim().toLowerCase();
|
||||||
.trim()
|
|
||||||
.toLowerCase() ==
|
|
||||||
updatedName
|
|
||||||
.trim()
|
|
||||||
.toLowerCase();
|
|
||||||
|
|
||||||
return !isSameId && isSameName;
|
return !isSameId && isSameName;
|
||||||
});
|
});
|
||||||
@ -395,8 +384,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
},
|
},
|
||||||
onNameChanged: (updatedName) {
|
onNameChanged: (updatedName) {
|
||||||
setState(() {
|
setState(() {
|
||||||
subspace.subspaceName =
|
subspace.subspaceName = updatedName;
|
||||||
updatedName;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -405,8 +393,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
}),
|
}),
|
||||||
EditChip(
|
EditChip(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
_showSubSpaceDialog(context, enteredName,
|
_showSubSpaceDialog(context, enteredName, [], true,
|
||||||
[], true, widget.products, subspaces);
|
widget.products, subspaces);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -415,9 +403,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
(tags?.isNotEmpty == true ||
|
(tags?.isNotEmpty == true ||
|
||||||
subspaces?.any((subspace) =>
|
subspaces?.any((subspace) => subspace.tags?.isNotEmpty == true) == true)
|
||||||
subspace.tags?.isNotEmpty == true) ==
|
|
||||||
true)
|
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
width: screenWidth * 0.25,
|
width: screenWidth * 0.25,
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -437,16 +423,14 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
// Combine tags from spaceModel and subspaces
|
// Combine tags from spaceModel and subspaces
|
||||||
...TagHelper.groupTags([
|
...TagHelper.groupTags([
|
||||||
...?tags,
|
...?tags,
|
||||||
...?subspaces?.expand(
|
...?subspaces?.expand((subspace) => subspace.tags ?? [])
|
||||||
(subspace) => subspace.tags ?? [])
|
|
||||||
]).entries.map(
|
]).entries.map(
|
||||||
(entry) => Chip(
|
(entry) => Chip(
|
||||||
avatar: SizedBox(
|
avatar: SizedBox(
|
||||||
width: 24,
|
width: 24,
|
||||||
height: 24,
|
height: 24,
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
entry.key.icon ??
|
entry.key.icon ?? 'assets/icons/gateway.svg',
|
||||||
'assets/icons/gateway.svg',
|
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -455,15 +439,11 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall
|
.bodySmall
|
||||||
?.copyWith(
|
?.copyWith(color: ColorsManager.spaceColor),
|
||||||
color: ColorsManager
|
|
||||||
.spaceColor),
|
|
||||||
),
|
),
|
||||||
backgroundColor:
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
ColorsManager.whiteColors,
|
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.circular(16),
|
||||||
BorderRadius.circular(16),
|
|
||||||
side: const BorderSide(
|
side: const BorderSide(
|
||||||
color: ColorsManager.spaceColor,
|
color: ColorsManager.spaceColor,
|
||||||
),
|
),
|
||||||
@ -472,23 +452,21 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
EditChip(onTap: () async {
|
EditChip(onTap: () async {
|
||||||
final result = await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AssignTagDialog(
|
builder: (context) => AssignTagDialog(
|
||||||
products: widget.products,
|
products: widget.products,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
allTags: widget.allTags,
|
allTags: widget.allTags,
|
||||||
addedProducts: TagHelper
|
addedProducts:
|
||||||
.createInitialSelectedProductsForTags(
|
TagHelper.createInitialSelectedProductsForTags(
|
||||||
tags ?? [], subspaces),
|
tags ?? [], subspaces),
|
||||||
title: 'Edit Device',
|
title: 'Edit Device',
|
||||||
initialTags:
|
initialTags: TagHelper.generateInitialForTags(
|
||||||
TagHelper.generateInitialForTags(
|
spaceTags: tags, subspaces: subspaces),
|
||||||
spaceTags: tags,
|
|
||||||
subspaces: subspaces),
|
|
||||||
spaceName: widget.name ?? '',
|
spaceName: widget.name ?? '',
|
||||||
onSave:
|
projectTags: widget.projectTags,
|
||||||
(updatedTags, updatedSubspaces) {
|
onSave: (updatedTags, updatedSubspaces) {
|
||||||
setState(() {
|
setState(() {
|
||||||
tags = updatedTags;
|
tags = updatedTags;
|
||||||
subspaces = updatedSubspaces;
|
subspaces = updatedSubspaces;
|
||||||
@ -547,25 +525,17 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
String newName = enteredName.isNotEmpty
|
String newName = enteredName.isNotEmpty ? enteredName : (widget.name ?? '');
|
||||||
? enteredName
|
|
||||||
: (widget.name ?? '');
|
|
||||||
if (newName.isNotEmpty) {
|
if (newName.isNotEmpty) {
|
||||||
widget.onCreateSpace(
|
widget.onCreateSpace(newName, selectedIcon, selectedProducts,
|
||||||
newName,
|
selectedSpaceModel, subspaces, tags);
|
||||||
selectedIcon,
|
|
||||||
selectedProducts,
|
|
||||||
selectedSpaceModel,
|
|
||||||
subspaces,
|
|
||||||
tags);
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
backgroundColor: isOkButtonEnabled
|
backgroundColor:
|
||||||
? ColorsManager.secondaryColor
|
isOkButtonEnabled ? ColorsManager.secondaryColor : ColorsManager.grayColor,
|
||||||
: ColorsManager.grayColor,
|
|
||||||
foregroundColor: ColorsManager.whiteColors,
|
foregroundColor: ColorsManager.whiteColors,
|
||||||
child: const Text('OK'),
|
child: const Text('OK'),
|
||||||
),
|
),
|
||||||
@ -592,7 +562,6 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _showLinkSpaceModelDialog(BuildContext context) {
|
void _showLinkSpaceModelDialog(BuildContext context) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -613,13 +582,8 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showSubSpaceDialog(
|
void _showSubSpaceDialog(BuildContext context, String name, final List<Tag>? spaceTags,
|
||||||
BuildContext context,
|
bool isEdit, List<ProductModel>? products, final List<SubspaceModel>? existingSubSpaces) {
|
||||||
String name,
|
|
||||||
final List<Tag>? spaceTags,
|
|
||||||
bool isEdit,
|
|
||||||
List<ProductModel>? products,
|
|
||||||
final List<SubspaceModel>? existingSubSpaces) {
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@ -634,12 +598,10 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
final List<Tag> tagsToAppendToSpace = [];
|
final List<Tag> tagsToAppendToSpace = [];
|
||||||
|
|
||||||
if (slectedSubspaces != null) {
|
if (slectedSubspaces != null) {
|
||||||
final updatedIds =
|
final updatedIds = slectedSubspaces.map((s) => s.internalId).toSet();
|
||||||
slectedSubspaces.map((s) => s.internalId).toSet();
|
|
||||||
if (existingSubSpaces != null) {
|
if (existingSubSpaces != null) {
|
||||||
final deletedSubspaces = existingSubSpaces
|
final deletedSubspaces =
|
||||||
.where((s) => !updatedIds.contains(s.internalId))
|
existingSubSpaces.where((s) => !updatedIds.contains(s.internalId)).toList();
|
||||||
.toList();
|
|
||||||
for (var s in deletedSubspaces) {
|
for (var s in deletedSubspaces) {
|
||||||
if (s.tags != null) {
|
if (s.tags != null) {
|
||||||
tagsToAppendToSpace.addAll(s.tags!);
|
tagsToAppendToSpace.addAll(s.tags!);
|
||||||
@ -659,20 +621,20 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showTagCreateDialog(BuildContext context, String name, bool isEdit,
|
void _showTagCreateDialog(
|
||||||
List<ProductModel>? products) {
|
BuildContext context, String name, bool isEdit, List<ProductModel>? products) {
|
||||||
isEdit
|
isEdit
|
||||||
? showDialog(
|
? showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AssignTagDialog(
|
return AssignTagDialog(
|
||||||
title: 'Edit Device',
|
title: 'Edit Device',
|
||||||
addedProducts: TagHelper.createInitialSelectedProductsForTags(
|
addedProducts: TagHelper.createInitialSelectedProductsForTags(tags, subspaces),
|
||||||
tags, subspaces),
|
|
||||||
spaceName: name,
|
spaceName: name,
|
||||||
products: products,
|
products: products,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
allTags: widget.allTags,
|
allTags: widget.allTags,
|
||||||
|
projectTags: widget.projectTags,
|
||||||
onSave: (selectedSpaceTags, selectedSubspaces) {
|
onSave: (selectedSpaceTags, selectedSubspaces) {
|
||||||
setState(() {
|
setState(() {
|
||||||
tags = selectedSpaceTags;
|
tags = selectedSpaceTags;
|
||||||
@ -682,8 +644,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
if (subspaces != null) {
|
if (subspaces != null) {
|
||||||
for (final subspace in subspaces!) {
|
for (final subspace in subspaces!) {
|
||||||
for (final selectedSubspace in selectedSubspaces) {
|
for (final selectedSubspace in selectedSubspaces) {
|
||||||
if (subspace.subspaceName ==
|
if (subspace.subspaceName == selectedSubspace.subspaceName) {
|
||||||
selectedSubspace.subspaceName) {
|
|
||||||
subspace.tags = selectedSubspace.tags;
|
subspace.tags = selectedSubspace.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -705,9 +666,9 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
spaceTags: tags,
|
spaceTags: tags,
|
||||||
isCreate: true,
|
isCreate: true,
|
||||||
allTags: widget.allTags,
|
allTags: widget.allTags,
|
||||||
|
projectTags: widget.projectTags,
|
||||||
initialSelectedProducts:
|
initialSelectedProducts:
|
||||||
TagHelper.createInitialSelectedProductsForTags(
|
TagHelper.createInitialSelectedProductsForTags(tags, subspaces),
|
||||||
tags, subspaces),
|
|
||||||
onSave: (selectedSpaceTags, selectedSubspaces) {
|
onSave: (selectedSpaceTags, selectedSubspaces) {
|
||||||
setState(() {
|
setState(() {
|
||||||
tags = selectedSpaceTags;
|
tags = selectedSpaceTags;
|
||||||
@ -717,8 +678,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
|
|||||||
if (subspaces != null) {
|
if (subspaces != null) {
|
||||||
for (final subspace in subspaces!) {
|
for (final subspace in subspaces!) {
|
||||||
for (final selectedSubspace in selectedSubspaces) {
|
for (final selectedSubspace in selectedSubspaces) {
|
||||||
if (subspace.subspaceName ==
|
if (subspace.subspaceName == selectedSubspace.subspaceName) {
|
||||||
selectedSubspace.subspaceName) {
|
|
||||||
subspace.tags = selectedSubspace.tags;
|
subspace.tags = selectedSubspace.tags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/space_tree/view/space_tree_view.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/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/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/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/gradient_canvas_border_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/gradient_canvas_border_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart';
|
||||||
@ -20,16 +21,17 @@ class LoadedSpaceView extends StatefulWidget {
|
|||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
final List<SpaceTemplateModel>? spaceModels;
|
final List<SpaceTemplateModel>? spaceModels;
|
||||||
final bool shouldNavigateToSpaceModelPage;
|
final bool shouldNavigateToSpaceModelPage;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const LoadedSpaceView({
|
const LoadedSpaceView(
|
||||||
super.key,
|
{super.key,
|
||||||
required this.communities,
|
required this.communities,
|
||||||
this.selectedCommunity,
|
this.selectedCommunity,
|
||||||
this.selectedSpace,
|
this.selectedSpace,
|
||||||
this.products,
|
this.products,
|
||||||
this.spaceModels,
|
this.spaceModels,
|
||||||
required this.shouldNavigateToSpaceModelPage,
|
required this.shouldNavigateToSpaceModelPage,
|
||||||
});
|
required this.projectTags});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LoadedSpaceViewState createState() => _LoadedSpaceViewState();
|
_LoadedSpaceViewState createState() => _LoadedSpaceViewState();
|
||||||
@ -93,6 +95,7 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
|||||||
child: SpaceModelPage(
|
child: SpaceModelPage(
|
||||||
products: widget.products,
|
products: widget.products,
|
||||||
onSpaceModelsUpdated: _onSpaceModelsUpdated,
|
onSpaceModelsUpdated: _onSpaceModelsUpdated,
|
||||||
|
projectTags: widget.projectTags,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -113,6 +116,7 @@ class _LoadedSpaceViewState extends State<LoadedSpaceView> {
|
|||||||
products: widget.products,
|
products: widget.products,
|
||||||
communities: widget.communities,
|
communities: widget.communities,
|
||||||
spaceModels: _spaceModels,
|
spaceModels: _spaceModels,
|
||||||
|
projectTags: widget.projectTags,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -4,17 +4,16 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_e
|
|||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
|
||||||
|
|
||||||
class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
||||||
final List<String> allTags;
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
AssignTagBloc(this.allTags) : super(AssignTagInitial()) {
|
AssignTagBloc(this.projectTags) : super(AssignTagInitial()) {
|
||||||
on<InitializeTags>((event, emit) {
|
on<InitializeTags>((event, emit) {
|
||||||
final initialTags = event.initialTags ?? [];
|
final initialTags = event.initialTags ?? [];
|
||||||
|
|
||||||
final existingTagCounts = <String, int>{};
|
final existingTagCounts = <String, int>{};
|
||||||
for (var tag in initialTags) {
|
for (var tag in initialTags) {
|
||||||
if (tag.product != null) {
|
if (tag.product != null) {
|
||||||
existingTagCounts[tag.product!.uuid] =
|
existingTagCounts[tag.product!.uuid] = (existingTagCounts[tag.product!.uuid] ?? 0) + 1;
|
||||||
(existingTagCounts[tag.product!.uuid] ?? 0) + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,17 +22,14 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
for (var selectedProduct in event.addedProducts) {
|
for (var selectedProduct in event.addedProducts) {
|
||||||
final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;
|
final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;
|
||||||
|
|
||||||
if (selectedProduct.count == 0 ||
|
if (selectedProduct.count == 0 || selectedProduct.count <= existingCount) {
|
||||||
selectedProduct.count <= existingCount) {
|
tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
||||||
tags.addAll(initialTags
|
|
||||||
.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final missingCount = selectedProduct.count - existingCount;
|
final missingCount = selectedProduct.count - existingCount;
|
||||||
|
|
||||||
tags.addAll(initialTags
|
tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
||||||
.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
|
||||||
|
|
||||||
if (missingCount > 0) {
|
if (missingCount > 0) {
|
||||||
tags.addAll(List.generate(
|
tags.addAll(List.generate(
|
||||||
@ -47,11 +43,11 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
updatedTags: updatedTags,
|
updatedTags: updatedTags,
|
||||||
isSaveEnabled: _validateTags(tags),
|
isSaveEnabled: _validateTags(tags),
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
));
|
));
|
||||||
@ -62,9 +58,16 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
|
|
||||||
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
final tags = List<Tag>.from(currentState.tags);
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
tags[event.index] = tags[event.index].copyWith(tag: event.tag);
|
if (event.index < 0 || event.index >= tags.length) return;
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
tags[event.index] = tags[event.index].copyWith(
|
||||||
|
tag: event.tag.tag,
|
||||||
|
uuid: event.tag.uuid,
|
||||||
|
product: event.tag.product,
|
||||||
|
internalId: event.tag.internalId,
|
||||||
|
location: event.tag.location,
|
||||||
|
);
|
||||||
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -82,10 +85,9 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
final tags = List<Tag>.from(currentState.tags);
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
|
|
||||||
// Update the location
|
// Update the location
|
||||||
tags[event.index] =
|
tags[event.index] = tags[event.index].copyWith(location: event.location);
|
||||||
tags[event.index].copyWith(location: event.location);
|
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -104,7 +106,7 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
|
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
updatedTags: _calculateAvailableTags(allTags, tags),
|
updatedTags: _calculateAvailableTags(projectTags, tags),
|
||||||
isSaveEnabled: _validateTags(tags),
|
isSaveEnabled: _validateTags(tags),
|
||||||
errorMessage: _getValidationError(tags),
|
errorMessage: _getValidationError(tags),
|
||||||
));
|
));
|
||||||
@ -115,11 +117,10 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
final tags = List<Tag>.from(currentState.tags)
|
final tags = List<Tag>.from(currentState.tags)..remove(event.tagToDelete);
|
||||||
..remove(event.tagToDelete);
|
|
||||||
|
|
||||||
// Recalculate available tags
|
// Recalculate available tags
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -140,10 +141,8 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
|
|
||||||
// Get validation error for duplicate tags
|
// Get validation error for duplicate tags
|
||||||
String? _getValidationError(List<Tag> tags) {
|
String? _getValidationError(List<Tag> tags) {
|
||||||
final nonEmptyTags = tags
|
final nonEmptyTags =
|
||||||
.map((tag) => tag.tag?.trim() ?? '')
|
tags.map((tag) => tag.tag?.trim() ?? '').where((tag) => tag.isNotEmpty).toList();
|
||||||
.where((tag) => tag.isNotEmpty)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final duplicateTags = nonEmptyTags
|
final duplicateTags = nonEmptyTags
|
||||||
.fold<Map<String, int>>({}, (map, tag) {
|
.fold<Map<String, int>>({}, (map, tag) {
|
||||||
@ -162,14 +161,16 @@ class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> _calculateAvailableTags(List<String> allTags, List<Tag> tags) {
|
List<Tag> _calculateAvailableTags(List<Tag> allTags, List<Tag> selectedTags) {
|
||||||
final selectedTags = tags
|
final selectedTagSet = selectedTags
|
||||||
.where((tag) => (tag.tag?.trim().isNotEmpty ?? false))
|
.where((tag) => (tag.tag?.trim().isNotEmpty ?? false))
|
||||||
.map((tag) => tag.tag!.trim())
|
.map((tag) => tag.tag!.trim())
|
||||||
.toSet();
|
.toSet();
|
||||||
|
|
||||||
final availableTags =
|
final availableTags = allTags
|
||||||
allTags.where((tag) => !selectedTags.contains(tag.trim())).toList();
|
.where((tag) => tag.tag != null && !selectedTagSet.contains(tag.tag!.trim()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
return availableTags;
|
return availableTags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class InitializeTags extends AssignTagEvent {
|
|||||||
|
|
||||||
class UpdateTagEvent extends AssignTagEvent {
|
class UpdateTagEvent extends AssignTagEvent {
|
||||||
final int index;
|
final int index;
|
||||||
final String tag;
|
final Tag tag;
|
||||||
|
|
||||||
const UpdateTagEvent({required this.index, required this.tag});
|
const UpdateTagEvent({required this.index, required this.tag});
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ abstract class AssignTagState extends Equatable {
|
|||||||
const AssignTagState();
|
const AssignTagState();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [];
|
List<Object?> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssignTagInitial extends AssignTagState {}
|
class AssignTagInitial extends AssignTagState {}
|
||||||
@ -14,7 +14,7 @@ class AssignTagLoading extends AssignTagState {}
|
|||||||
|
|
||||||
class AssignTagLoaded extends AssignTagState {
|
class AssignTagLoaded extends AssignTagState {
|
||||||
final List<Tag> tags;
|
final List<Tag> tags;
|
||||||
final List<String> updatedTags;
|
final List<Tag> updatedTags;
|
||||||
|
|
||||||
final bool isSaveEnabled;
|
final bool isSaveEnabled;
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
@ -27,8 +27,7 @@ class AssignTagLoaded extends AssignTagState {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props =>
|
List<Object?> get props => [tags, updatedTags, isSaveEnabled, errorMessage ?? ''];
|
||||||
[tags, updatedTags, isSaveEnabled, errorMessage ?? ''];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AssignTagError extends AssignTagState {
|
class AssignTagError extends AssignTagState {
|
||||||
@ -37,5 +36,5 @@ class AssignTagError extends AssignTagState {
|
|||||||
const AssignTagError(this.errorMessage);
|
const AssignTagError(this.errorMessage);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [errorMessage];
|
List<Object?> get props => [errorMessage];
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/common/dialog_dropdown.dart';
|
import 'package:syncrow_web/common/dialog_dropdown.dart';
|
||||||
import 'package:syncrow_web/common/dialog_textfield_dropdown.dart';
|
import 'package:syncrow_web/common/tag_dialog_textfield_dropdown.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/add_device_type/views/add_device_type_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/add_device_type/views/add_device_type_widget.dart';
|
||||||
@ -26,6 +26,7 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
final String spaceName;
|
final String spaceName;
|
||||||
final String title;
|
final String title;
|
||||||
final Function(List<Tag>, List<SubspaceModel>?)? onSave;
|
final Function(List<Tag>, List<SubspaceModel>?)? onSave;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const AssignTagDialog(
|
const AssignTagDialog(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@ -37,18 +38,17 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
this.allTags,
|
this.allTags,
|
||||||
required this.spaceName,
|
required this.spaceName,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.onSave})
|
this.onSave,
|
||||||
|
required this.projectTags})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<String> locations = (subspaces ?? [])
|
final List<String> locations =
|
||||||
.map((subspace) => subspace.subspaceName)
|
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space');
|
||||||
.toList()
|
|
||||||
..add('Main Space');
|
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => AssignTagBloc(allTags ?? [])
|
create: (_) => AssignTagBloc(projectTags)
|
||||||
..add(InitializeTags(
|
..add(InitializeTags(
|
||||||
initialTags: initialTags,
|
initialTags: initialTags,
|
||||||
addedProducts: addedProducts,
|
addedProducts: addedProducts,
|
||||||
@ -70,8 +70,7 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
child: DataTable(
|
child: DataTable(
|
||||||
headingRowColor: WidgetStateProperty.all(
|
headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey),
|
||||||
ColorsManager.dataHeaderGrey),
|
|
||||||
key: ValueKey(state.tags.length),
|
key: ValueKey(state.tags.length),
|
||||||
border: TableBorder.all(
|
border: TableBorder.all(
|
||||||
color: ColorsManager.dataHeaderGrey,
|
color: ColorsManager.dataHeaderGrey,
|
||||||
@ -80,22 +79,15 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
columns: [
|
columns: [
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('#',
|
label: Text('#', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
style:
|
|
||||||
Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('Device',
|
label: Text('Device', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
style:
|
|
||||||
Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
DataColumn(
|
||||||
numeric: false,
|
numeric: false,
|
||||||
label: Text('Tag',
|
label: Text('Tag', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
style:
|
|
||||||
Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('Location',
|
label:
|
||||||
style:
|
Text('Location', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
Theme.of(context).textTheme.bodyMedium)),
|
|
||||||
],
|
],
|
||||||
rows: state.tags.isEmpty
|
rows: state.tags.isEmpty
|
||||||
? [
|
? [
|
||||||
@ -103,12 +95,8 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
DataCell(
|
DataCell(
|
||||||
Center(
|
Center(
|
||||||
child: Text('No Data Available',
|
child: Text('No Data Available',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
.textTheme
|
color: ColorsManager.lightGrayColor,
|
||||||
.bodyMedium
|
|
||||||
?.copyWith(
|
|
||||||
color: ColorsManager
|
|
||||||
.lightGrayColor,
|
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -126,8 +114,7 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
DataCell(Text((index + 1).toString())),
|
DataCell(Text((index + 1).toString())),
|
||||||
DataCell(
|
DataCell(
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -141,31 +128,25 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: ColorsManager
|
color: ColorsManager.lightGrayColor,
|
||||||
.lightGrayColor,
|
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
color: ColorsManager
|
color: ColorsManager.lightGreyColor,
|
||||||
.lightGreyColor,
|
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context.read<AssignTagBloc>().add(
|
||||||
.read<AssignTagBloc>()
|
DeleteTag(tagToDelete: tag, tags: state.tags));
|
||||||
.add(DeleteTag(
|
|
||||||
tagToDelete: tag,
|
|
||||||
tags: state.tags));
|
|
||||||
|
|
||||||
controllers.removeAt(index);
|
controllers.removeAt(index);
|
||||||
},
|
},
|
||||||
tooltip: 'Delete Tag',
|
tooltip: 'Delete Tag',
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints:
|
constraints: const BoxConstraints(),
|
||||||
const BoxConstraints(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -173,23 +154,20 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
DataCell(
|
DataCell(
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment
|
alignment:
|
||||||
.centerLeft, // Align cell content to the left
|
Alignment.centerLeft, // Align cell content to the left
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: double
|
width: double.infinity,
|
||||||
.infinity, // Ensure full width for dropdown
|
child: TagDialogTextfieldDropdown(
|
||||||
child: DialogTextfieldDropdown(
|
key: ValueKey('dropdown_${const Uuid().v4()}_$index'),
|
||||||
key: ValueKey(
|
|
||||||
'dropdown_${Uuid().v4()}_${index}'),
|
|
||||||
items: state.updatedTags,
|
items: state.updatedTags,
|
||||||
initialValue: tag.tag,
|
product: tag.product?.uuid ?? 'Unknown',
|
||||||
|
initialValue: tag,
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
controller.text = value;
|
controller.text = value.tag ?? '';
|
||||||
context
|
context.read<AssignTagBloc>().add(UpdateTagEvent(
|
||||||
.read<AssignTagBloc>()
|
|
||||||
.add(UpdateTagEvent(
|
|
||||||
index: index,
|
index: index,
|
||||||
tag: value.trim(),
|
tag: value,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -201,12 +179,9 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: DialogDropdown(
|
child: DialogDropdown(
|
||||||
items: locations,
|
items: locations,
|
||||||
selectedValue:
|
selectedValue: tag.location ?? 'Main Space',
|
||||||
tag.location ?? 'Main Space',
|
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
context
|
context.read<AssignTagBloc>().add(UpdateLocation(
|
||||||
.read<AssignTagBloc>()
|
|
||||||
.add(UpdateLocation(
|
|
||||||
index: index,
|
index: index,
|
||||||
location: value,
|
location: value,
|
||||||
));
|
));
|
||||||
@ -238,13 +213,11 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
label: 'Add New Device',
|
label: 'Add New Device',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final updatedTags = List<Tag>.from(state.tags);
|
final updatedTags = List<Tag>.from(state.tags);
|
||||||
final result =
|
final result = TagHelper.processTags(updatedTags, subspaces);
|
||||||
TagHelper.processTags(updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags =
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
result['updatedTags'] as List<Tag>;
|
final processedSubspaces =
|
||||||
final processedSubspaces = List<SubspaceModel>.from(
|
List<SubspaceModel>.from(result['subspaces'] as List<dynamic>);
|
||||||
result['subspaces'] as List<dynamic>);
|
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
@ -253,8 +226,9 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
builder: (context) => AddDeviceTypeWidget(
|
builder: (context) => AddDeviceTypeWidget(
|
||||||
products: products,
|
products: products,
|
||||||
subspaces: processedSubspaces,
|
subspaces: processedSubspaces,
|
||||||
initialSelectedProducts: TagHelper
|
projectTags: projectTags,
|
||||||
.createInitialSelectedProductsForTags(
|
initialSelectedProducts:
|
||||||
|
TagHelper.createInitialSelectedProductsForTags(
|
||||||
processedTags, processedSubspaces),
|
processedTags, processedSubspaces),
|
||||||
spaceName: spaceName,
|
spaceName: spaceName,
|
||||||
spaceTags: processedTags,
|
spaceTags: processedTags,
|
||||||
@ -278,14 +252,11 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
onPressed: state.isSaveEnabled
|
onPressed: state.isSaveEnabled
|
||||||
? () async {
|
? () async {
|
||||||
final updatedTags = List<Tag>.from(state.tags);
|
final updatedTags = List<Tag>.from(state.tags);
|
||||||
final result = TagHelper.processTags(
|
final result = TagHelper.processTags(updatedTags, subspaces);
|
||||||
updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags =
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
result['updatedTags'] as List<Tag>;
|
|
||||||
final processedSubspaces =
|
final processedSubspaces =
|
||||||
List<SubspaceModel>.from(
|
List<SubspaceModel>.from(result['subspaces'] as List<dynamic>);
|
||||||
result['subspaces'] as List<dynamic>);
|
|
||||||
onSave?.call(processedTags, processedSubspaces);
|
onSave?.call(processedTags, processedSubspaces);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,40 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
|
||||||
|
|
||||||
class AssignTagModelBloc
|
class AssignTagModelBloc extends Bloc<AssignTagModelEvent, AssignTagModelState> {
|
||||||
extends Bloc<AssignTagModelEvent, AssignTagModelState> {
|
final List<Tag> projectTags;
|
||||||
final List<String> allTags;
|
|
||||||
|
|
||||||
AssignTagModelBloc(this.allTags) : super(AssignTagModelInitial()) {
|
AssignTagModelBloc(this.projectTags) : super(AssignTagModelInitial()) {
|
||||||
on<InitializeTagModels>((event, emit) {
|
on<InitializeTagModels>((event, emit) {
|
||||||
final initialTags = event.initialTags ?? [];
|
final initialTags = event.initialTags;
|
||||||
|
|
||||||
final existingTagCounts = <String, int>{};
|
final existingTagCounts = <String, int>{};
|
||||||
for (var tag in initialTags) {
|
for (var tag in initialTags) {
|
||||||
if (tag.product != null) {
|
if (tag.product != null) {
|
||||||
existingTagCounts[tag.product!.uuid] =
|
existingTagCounts[tag.product!.uuid] = (existingTagCounts[tag.product!.uuid] ?? 0) + 1;
|
||||||
(existingTagCounts[tag.product!.uuid] ?? 0) + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final tags = <TagModel>[];
|
final tags = <Tag>[];
|
||||||
|
|
||||||
for (var selectedProduct in event.addedProducts) {
|
for (var selectedProduct in event.addedProducts) {
|
||||||
final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;
|
final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;
|
||||||
|
|
||||||
if (selectedProduct.count == 0 ||
|
if (selectedProduct.count == 0 || selectedProduct.count <= existingCount) {
|
||||||
selectedProduct.count <= existingCount) {
|
tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
||||||
tags.addAll(initialTags
|
|
||||||
.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final missingCount = selectedProduct.count - existingCount;
|
final missingCount = selectedProduct.count - existingCount;
|
||||||
|
|
||||||
tags.addAll(initialTags
|
tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
||||||
.where((tag) => tag.product?.uuid == selectedProduct.productId));
|
|
||||||
|
|
||||||
if (missingCount > 0) {
|
if (missingCount > 0) {
|
||||||
tags.addAll(List.generate(
|
tags.addAll(List.generate(
|
||||||
missingCount,
|
missingCount,
|
||||||
(index) => TagModel(
|
(index) => Tag(
|
||||||
tag: '',
|
tag: '',
|
||||||
product: selectedProduct.product,
|
product: selectedProduct.product,
|
||||||
location: 'Main Space',
|
location: 'Main Space',
|
||||||
@ -48,7 +43,7 @@ class AssignTagModelBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagModelLoaded(
|
emit(AssignTagModelLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -59,11 +54,20 @@ class AssignTagModelBloc
|
|||||||
|
|
||||||
on<UpdateTag>((event, emit) {
|
on<UpdateTag>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is AssignTagModelLoaded &&
|
if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
final tags = List<TagModel>.from(currentState.tags);
|
|
||||||
tags[event.index] = tags[event.index].copyWith(tag: event.tag);
|
if (event.index < 0 || event.index >= tags.length) return;
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
|
||||||
|
tags[event.index] = tags[event.index].copyWith(
|
||||||
|
tag: event.tag.tag,
|
||||||
|
uuid: event.tag.uuid,
|
||||||
|
product: event.tag.product,
|
||||||
|
internalId: event.tag.internalId,
|
||||||
|
location: event.tag.location,
|
||||||
|
);
|
||||||
|
|
||||||
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagModelLoaded(
|
emit(AssignTagModelLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -77,15 +81,12 @@ class AssignTagModelBloc
|
|||||||
on<UpdateLocation>((event, emit) {
|
on<UpdateLocation>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagModelLoaded &&
|
if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
final tags = List<TagModel>.from(currentState.tags);
|
|
||||||
|
|
||||||
// Use copyWith for immutability
|
// Use copyWith for immutability
|
||||||
tags[event.index] =
|
tags[event.index] = tags[event.index].copyWith(location: event.location);
|
||||||
tags[event.index].copyWith(location: event.location);
|
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagModelLoaded(
|
emit(AssignTagModelLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -99,13 +100,12 @@ class AssignTagModelBloc
|
|||||||
on<ValidateTagModels>((event, emit) {
|
on<ValidateTagModels>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagModelLoaded &&
|
if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
final tags = List<TagModel>.from(currentState.tags);
|
|
||||||
|
|
||||||
emit(AssignTagModelLoaded(
|
emit(AssignTagModelLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
updatedTags: _calculateAvailableTags(allTags, tags),
|
updatedTags: _calculateAvailableTags(projectTags, tags),
|
||||||
isSaveEnabled: _validateTags(tags),
|
isSaveEnabled: _validateTags(tags),
|
||||||
errorMessage: _getValidationError(tags),
|
errorMessage: _getValidationError(tags),
|
||||||
));
|
));
|
||||||
@ -115,12 +115,10 @@ class AssignTagModelBloc
|
|||||||
on<DeleteTagModel>((event, emit) {
|
on<DeleteTagModel>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagModelLoaded &&
|
if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
final tags = List<Tag>.from(currentState.tags)..remove(event.tagToDelete);
|
||||||
final tags = List<TagModel>.from(currentState.tags)
|
|
||||||
..remove(event.tagToDelete);
|
|
||||||
|
|
||||||
final updatedTags = _calculateAvailableTags(allTags, tags);
|
final updatedTags = _calculateAvailableTags(projectTags, tags);
|
||||||
|
|
||||||
emit(AssignTagModelLoaded(
|
emit(AssignTagModelLoaded(
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -128,24 +126,22 @@ class AssignTagModelBloc
|
|||||||
isSaveEnabled: _validateTags(tags),
|
isSaveEnabled: _validateTags(tags),
|
||||||
errorMessage: _getValidationError(tags),
|
errorMessage: _getValidationError(tags),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _validateTags(List<TagModel> tags) {
|
bool _validateTags(List<Tag> tags) {
|
||||||
final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet();
|
final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet();
|
||||||
final hasEmptyTag = tags.any((tag) => (tag.tag?.trim() ?? '').isEmpty);
|
final hasEmptyTag = tags.any((tag) => (tag.tag?.trim() ?? '').isEmpty);
|
||||||
final isValid = uniqueTags.length == tags.length && !hasEmptyTag;
|
final isValid = uniqueTags.length == tags.length && !hasEmptyTag;
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _getValidationError(List<TagModel> tags) {
|
String? _getValidationError(List<Tag> tags) {
|
||||||
// Check for duplicate tags
|
// Check for duplicate tags
|
||||||
|
|
||||||
final nonEmptyTags = tags
|
final nonEmptyTags =
|
||||||
.map((tag) => tag.tag?.trim() ?? '')
|
tags.map((tag) => tag.tag?.trim() ?? '').where((tag) => tag.isNotEmpty).toList();
|
||||||
.where((tag) => tag.isNotEmpty)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final duplicateTags = nonEmptyTags
|
final duplicateTags = nonEmptyTags
|
||||||
.fold<Map<String, int>>({}, (map, tag) {
|
.fold<Map<String, int>>({}, (map, tag) {
|
||||||
@ -164,15 +160,16 @@ class AssignTagModelBloc
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> _calculateAvailableTags(
|
List<Tag> _calculateAvailableTags(List<Tag> allTags, List<Tag> selectedTags) {
|
||||||
List<String> allTags, List<TagModel> tags) {
|
final selectedTagSet = selectedTags
|
||||||
final selectedTags = tags
|
|
||||||
.where((tag) => (tag.tag?.trim().isNotEmpty ?? false))
|
.where((tag) => (tag.tag?.trim().isNotEmpty ?? false))
|
||||||
.map((tag) => tag.tag!.trim())
|
.map((tag) => tag.tag!.trim())
|
||||||
.toSet();
|
.toSet();
|
||||||
|
|
||||||
final availableTags =
|
final availableTags = allTags
|
||||||
allTags.where((tag) => !selectedTags.contains(tag.trim())).toList();
|
.where((tag) => tag.tag != null && !selectedTagSet.contains(tag.tag!.trim()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
return availableTags;
|
return availableTags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
|
|
||||||
abstract class AssignTagModelEvent extends Equatable {
|
abstract class AssignTagModelEvent extends Equatable {
|
||||||
@ -10,7 +10,7 @@ abstract class AssignTagModelEvent extends Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class InitializeTagModels extends AssignTagModelEvent {
|
class InitializeTagModels extends AssignTagModelEvent {
|
||||||
final List<TagModel> initialTags;
|
final List<Tag> initialTags;
|
||||||
final List<SelectedProduct> addedProducts;
|
final List<SelectedProduct> addedProducts;
|
||||||
|
|
||||||
const InitializeTagModels({
|
const InitializeTagModels({
|
||||||
@ -24,7 +24,7 @@ class InitializeTagModels extends AssignTagModelEvent {
|
|||||||
|
|
||||||
class UpdateTag extends AssignTagModelEvent {
|
class UpdateTag extends AssignTagModelEvent {
|
||||||
final int index;
|
final int index;
|
||||||
final String tag;
|
final Tag tag;
|
||||||
|
|
||||||
const UpdateTag({required this.index, required this.tag});
|
const UpdateTag({required this.index, required this.tag});
|
||||||
|
|
||||||
@ -45,8 +45,8 @@ class UpdateLocation extends AssignTagModelEvent {
|
|||||||
class ValidateTagModels extends AssignTagModelEvent {}
|
class ValidateTagModels extends AssignTagModelEvent {}
|
||||||
|
|
||||||
class DeleteTagModel extends AssignTagModelEvent {
|
class DeleteTagModel extends AssignTagModelEvent {
|
||||||
final TagModel tagToDelete;
|
final Tag tagToDelete;
|
||||||
final List<TagModel> tags;
|
final List<Tag> tags;
|
||||||
|
|
||||||
const DeleteTagModel({required this.tagToDelete, required this.tags});
|
const DeleteTagModel({required this.tagToDelete, required this.tags});
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
|
||||||
abstract class AssignTagModelState extends Equatable {
|
abstract class AssignTagModelState extends Equatable {
|
||||||
const AssignTagModelState();
|
const AssignTagModelState();
|
||||||
@ -13,11 +13,11 @@ class AssignTagModelInitial extends AssignTagModelState {}
|
|||||||
class AssignTagModelLoading extends AssignTagModelState {}
|
class AssignTagModelLoading extends AssignTagModelState {}
|
||||||
|
|
||||||
class AssignTagModelLoaded extends AssignTagModelState {
|
class AssignTagModelLoaded extends AssignTagModelState {
|
||||||
final List<TagModel> tags;
|
final List<Tag> tags;
|
||||||
final bool isSaveEnabled;
|
final bool isSaveEnabled;
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
|
|
||||||
final List<String> updatedTags;
|
final List<Tag> updatedTags;
|
||||||
|
|
||||||
const AssignTagModelLoaded({
|
const AssignTagModelLoaded({
|
||||||
required this.tags,
|
required this.tags,
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/common/dialog_dropdown.dart';
|
import 'package:syncrow_web/common/dialog_dropdown.dart';
|
||||||
import 'package:syncrow_web/common/dialog_textfield_dropdown.dart';
|
import 'package:syncrow_web/common/tag_dialog_textfield_dropdown.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -23,8 +23,8 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
final List<SubspaceTemplateModel>? subspaces;
|
final List<SubspaceTemplateModel>? subspaces;
|
||||||
final SpaceTemplateModel? spaceModel;
|
final SpaceTemplateModel? spaceModel;
|
||||||
|
|
||||||
final List<TagModel> initialTags;
|
final List<Tag> initialTags;
|
||||||
final ValueChanged<List<TagModel>>? onTagsAssigned;
|
final ValueChanged<List<Tag>>? onTagsAssigned;
|
||||||
final List<SelectedProduct> addedProducts;
|
final List<SelectedProduct> addedProducts;
|
||||||
final List<String>? allTags;
|
final List<String>? allTags;
|
||||||
final String spaceName;
|
final String spaceName;
|
||||||
@ -32,6 +32,7 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
final BuildContext? pageContext;
|
final BuildContext? pageContext;
|
||||||
final List<String>? otherSpaceModels;
|
final List<String>? otherSpaceModels;
|
||||||
final List<SpaceTemplateModel>? allSpaceModels;
|
final List<SpaceTemplateModel>? allSpaceModels;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const AssignTagModelsDialog(
|
const AssignTagModelsDialog(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@ -46,18 +47,17 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
this.pageContext,
|
this.pageContext,
|
||||||
this.otherSpaceModels,
|
this.otherSpaceModels,
|
||||||
this.spaceModel,
|
this.spaceModel,
|
||||||
this.allSpaceModels})
|
this.allSpaceModels,
|
||||||
|
required this.projectTags})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<String> locations = (subspaces ?? [])
|
final List<String> locations =
|
||||||
.map((subspace) => subspace.subspaceName)
|
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space');
|
||||||
.toList()
|
|
||||||
..add('Main Space');
|
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => AssignTagModelBloc(allTags ?? [])
|
create: (_) => AssignTagModelBloc(projectTags)
|
||||||
..add(InitializeTagModels(
|
..add(InitializeTagModels(
|
||||||
initialTags: initialTags,
|
initialTags: initialTags,
|
||||||
addedProducts: addedProducts,
|
addedProducts: addedProducts,
|
||||||
@ -81,8 +81,7 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
child: DataTable(
|
child: DataTable(
|
||||||
headingRowColor: WidgetStateProperty.all(
|
headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey),
|
||||||
ColorsManager.dataHeaderGrey),
|
|
||||||
key: ValueKey(state.tags.length),
|
key: ValueKey(state.tags.length),
|
||||||
border: TableBorder.all(
|
border: TableBorder.all(
|
||||||
color: ColorsManager.dataHeaderGrey,
|
color: ColorsManager.dataHeaderGrey,
|
||||||
@ -91,26 +90,17 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
columns: [
|
columns: [
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('#',
|
label: Text('#', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyMedium)),
|
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('Device',
|
label: Text('Device',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
.textTheme
|
|
||||||
.bodyMedium)),
|
|
||||||
DataColumn(
|
DataColumn(
|
||||||
numeric: false,
|
numeric: false,
|
||||||
label: Text('Tag',
|
label:
|
||||||
style: Theme.of(context)
|
Text('Tag', style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
.textTheme
|
|
||||||
.bodyMedium)),
|
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text('Location',
|
label: Text('Location',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodyMedium)),
|
||||||
.textTheme
|
|
||||||
.bodyMedium)),
|
|
||||||
],
|
],
|
||||||
rows: state.tags.isEmpty
|
rows: state.tags.isEmpty
|
||||||
? [
|
? [
|
||||||
@ -118,13 +108,10 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
DataCell(
|
DataCell(
|
||||||
Center(
|
Center(
|
||||||
child: Text('No Devices Available',
|
child: Text('No Devices Available',
|
||||||
style: Theme.of(context)
|
style:
|
||||||
.textTheme
|
Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
.bodyMedium
|
color: ColorsManager.lightGrayColor,
|
||||||
?.copyWith(
|
)),
|
||||||
color: ColorsManager
|
|
||||||
.lightGrayColor,
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const DataCell(SizedBox()),
|
const DataCell(SizedBox()),
|
||||||
@ -141,8 +128,7 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
DataCell(Text((index + 1).toString())),
|
DataCell(Text((index + 1).toString())),
|
||||||
DataCell(
|
DataCell(
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -156,31 +142,25 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: ColorsManager
|
color: ColorsManager.lightGrayColor,
|
||||||
.lightGrayColor,
|
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
color: ColorsManager
|
color: ColorsManager.lightGreyColor,
|
||||||
.lightGreyColor,
|
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context.read<AssignTagModelBloc>().add(
|
||||||
.read<
|
DeleteTagModel(
|
||||||
AssignTagModelBloc>()
|
tagToDelete: tag, tags: state.tags));
|
||||||
.add(DeleteTagModel(
|
|
||||||
tagToDelete: tag,
|
|
||||||
tags: state.tags));
|
|
||||||
controllers.removeAt(index);
|
controllers.removeAt(index);
|
||||||
},
|
},
|
||||||
tooltip: 'Delete Tag',
|
tooltip: 'Delete Tag',
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints:
|
constraints: const BoxConstraints(),
|
||||||
const BoxConstraints(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -191,19 +171,16 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
alignment: Alignment
|
alignment: Alignment
|
||||||
.centerLeft, // Align cell content to the left
|
.centerLeft, // Align cell content to the left
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: double
|
width: double.infinity,
|
||||||
.infinity, // Ensure full width for dropdown
|
child: TagDialogTextfieldDropdown(
|
||||||
child: DialogTextfieldDropdown(
|
key: ValueKey(
|
||||||
key: ValueKey(
|
'dropdown_${const Uuid().v4()}_$index'),
|
||||||
'dropdown_${Uuid().v4()}_${index}'),
|
product: tag.product?.uuid ?? 'Unknown',
|
||||||
items: state.updatedTags,
|
items: state.updatedTags,
|
||||||
initialValue: tag.tag,
|
initialValue: tag,
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
controller.text = value;
|
controller.text = value.tag ?? '';
|
||||||
context
|
context.read<AssignTagModelBloc>().add(UpdateTag(
|
||||||
.read<
|
|
||||||
AssignTagModelBloc>()
|
|
||||||
.add(UpdateTag(
|
|
||||||
index: index,
|
index: index,
|
||||||
tag: value,
|
tag: value,
|
||||||
));
|
));
|
||||||
@ -217,12 +194,10 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: DialogDropdown(
|
child: DialogDropdown(
|
||||||
items: locations,
|
items: locations,
|
||||||
selectedValue: tag.location ??
|
selectedValue: tag.location ?? 'Main Space',
|
||||||
'Main Space',
|
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
context
|
context
|
||||||
.read<
|
.read<AssignTagModelBloc>()
|
||||||
AssignTagModelBloc>()
|
|
||||||
.add(UpdateLocation(
|
.add(UpdateLocation(
|
||||||
index: index,
|
index: index,
|
||||||
location: value,
|
location: value,
|
||||||
@ -254,17 +229,13 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
builder: (buttonContext) => CancelButton(
|
builder: (buttonContext) => CancelButton(
|
||||||
label: 'Add New Device',
|
label: 'Add New Device',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final updatedTags =
|
final updatedTags = List<Tag>.from(state.tags);
|
||||||
List<TagModel>.from(state.tags);
|
|
||||||
final result =
|
final result =
|
||||||
TagHelper.updateSubspaceTagModels(
|
TagHelper.updateSubspaceTagModels(updatedTags, subspaces);
|
||||||
updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags =
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
result['updatedTags'] as List<TagModel>;
|
final processedSubspaces = List<SubspaceTemplateModel>.from(
|
||||||
final processedSubspaces =
|
result['subspaces'] as List<dynamic>);
|
||||||
List<SubspaceTemplateModel>.from(
|
|
||||||
result['subspaces'] as List<dynamic>);
|
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@ -272,28 +243,25 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
await showDialog<bool>(
|
await showDialog<bool>(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) =>
|
builder: (dialogContext) => AddDeviceTypeModelWidget(
|
||||||
AddDeviceTypeModelWidget(
|
products: products,
|
||||||
products: products,
|
subspaces: processedSubspaces,
|
||||||
subspaces: processedSubspaces,
|
isCreate: false,
|
||||||
isCreate: false,
|
initialSelectedProducts:
|
||||||
initialSelectedProducts: TagHelper
|
TagHelper.createInitialSelectedProducts(
|
||||||
.createInitialSelectedProducts(
|
processedTags, processedSubspaces),
|
||||||
processedTags,
|
allTags: allTags,
|
||||||
processedSubspaces),
|
spaceName: spaceName,
|
||||||
allTags: allTags,
|
otherSpaceModels: otherSpaceModels,
|
||||||
spaceName: spaceName,
|
spaceTagModels: processedTags,
|
||||||
otherSpaceModels: otherSpaceModels,
|
pageContext: pageContext,
|
||||||
spaceTagModels: processedTags,
|
projectTags: projectTags,
|
||||||
pageContext: pageContext,
|
spaceModel: SpaceTemplateModel(
|
||||||
spaceModel: SpaceTemplateModel(
|
modelName: spaceName,
|
||||||
modelName: spaceName,
|
tags: updatedTags,
|
||||||
tags: updatedTags,
|
uuid: spaceModel?.uuid,
|
||||||
uuid: spaceModel?.uuid,
|
internalId: spaceModel?.internalId,
|
||||||
internalId:
|
subspaceModels: processedSubspaces)),
|
||||||
spaceModel?.internalId,
|
|
||||||
subspaceModels:
|
|
||||||
processedSubspaces)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -310,22 +278,16 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
: ColorsManager.whiteColorsWithOpacity,
|
: ColorsManager.whiteColorsWithOpacity,
|
||||||
onPressed: state.isSaveEnabled
|
onPressed: state.isSaveEnabled
|
||||||
? () async {
|
? () async {
|
||||||
final updatedTags =
|
final updatedTags = List<Tag>.from(state.tags);
|
||||||
List<TagModel>.from(state.tags);
|
|
||||||
|
|
||||||
final result =
|
final result =
|
||||||
TagHelper.updateSubspaceTagModels(
|
TagHelper.updateSubspaceTagModels(updatedTags, subspaces);
|
||||||
updatedTags, subspaces);
|
|
||||||
|
|
||||||
final processedTags =
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
result['updatedTags'] as List<TagModel>;
|
final processedSubspaces = List<SubspaceTemplateModel>.from(
|
||||||
final processedSubspaces =
|
result['subspaces'] as List<dynamic>);
|
||||||
List<SubspaceTemplateModel>.from(
|
|
||||||
result['subspaces']
|
|
||||||
as List<dynamic>);
|
|
||||||
|
|
||||||
Navigator.of(context)
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
.popUntil((route) => route.isFirst);
|
|
||||||
|
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -334,16 +296,15 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
products: products,
|
products: products,
|
||||||
allSpaceModels: allSpaceModels,
|
allSpaceModels: allSpaceModels,
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
|
projectTags: projectTags,
|
||||||
pageContext: pageContext,
|
pageContext: pageContext,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
spaceModel: SpaceTemplateModel(
|
spaceModel: SpaceTemplateModel(
|
||||||
modelName: spaceName,
|
modelName: spaceName,
|
||||||
tags: processedTags,
|
tags: processedTags,
|
||||||
uuid: spaceModel?.uuid,
|
uuid: spaceModel?.uuid,
|
||||||
internalId:
|
internalId: spaceModel?.internalId,
|
||||||
spaceModel?.internalId,
|
subspaceModels: processedSubspaces),
|
||||||
subspaceModels:
|
|
||||||
processedSubspaces),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -7,7 +7,6 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_mo
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
|
||||||
|
|
||||||
class TagHelper {
|
class TagHelper {
|
||||||
static Map<String, dynamic> updateTags<T>({
|
static Map<String, dynamic> updateTags<T>({
|
||||||
@ -131,9 +130,9 @@ class TagHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<String> getAvailableTagModels(
|
static List<String> getAvailableTagModels(
|
||||||
List<String> allTags, List<TagModel> currentTags, TagModel currentTag) {
|
List<String> allTags, List<Tag> currentTags, Tag currentTag) {
|
||||||
List<String> availableTagsForTagModel =
|
List<String> availableTagsForTagModel =
|
||||||
TagHelper.getAvailableTags<TagModel>(
|
TagHelper.getAvailableTags<Tag>(
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
currentTags: currentTags,
|
currentTags: currentTags,
|
||||||
currentTag: currentTag,
|
currentTag: currentTag,
|
||||||
@ -142,11 +141,11 @@ class TagHelper {
|
|||||||
return availableTagsForTagModel;
|
return availableTagsForTagModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<TagModel> generateInitialTags({
|
static List<Tag> generateInitialTags({
|
||||||
List<TagModel>? spaceTagModels,
|
List<Tag>? spaceTagModels,
|
||||||
List<SubspaceTemplateModel>? subspaces,
|
List<SubspaceTemplateModel>? subspaces,
|
||||||
}) {
|
}) {
|
||||||
final List<TagModel> initialTags = [];
|
final List<Tag> initialTags = [];
|
||||||
|
|
||||||
if (spaceTagModels != null) {
|
if (spaceTagModels != null) {
|
||||||
initialTags.addAll(spaceTagModels);
|
initialTags.addAll(spaceTagModels);
|
||||||
@ -212,7 +211,7 @@ class TagHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<SelectedProduct> createInitialSelectedProducts(
|
static List<SelectedProduct> createInitialSelectedProducts(
|
||||||
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces) {
|
List<Tag>? tags, List<SubspaceTemplateModel>? subspaces) {
|
||||||
final Map<ProductModel, int> productCounts = {};
|
final Map<ProductModel, int> productCounts = {};
|
||||||
|
|
||||||
if (tags != null) {
|
if (tags != null) {
|
||||||
@ -282,7 +281,7 @@ class TagHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int? checkTagExistInSubspaceModels(
|
static int? checkTagExistInSubspaceModels(
|
||||||
TagModel tag, List<dynamic>? subspaces) {
|
Tag tag, List<dynamic>? subspaces) {
|
||||||
if (subspaces == null) return null;
|
if (subspaces == null) return null;
|
||||||
|
|
||||||
for (int i = 0; i < subspaces.length; i++) {
|
for (int i = 0; i < subspaces.length; i++) {
|
||||||
@ -298,8 +297,8 @@ class TagHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, dynamic> updateSubspaceTagModels(
|
static Map<String, dynamic> updateSubspaceTagModels(
|
||||||
List<TagModel> updatedTags, List<SubspaceTemplateModel>? subspaces) {
|
List<Tag> updatedTags, List<SubspaceTemplateModel>? subspaces) {
|
||||||
final result = TagHelper.updateTags<TagModel>(
|
final result = TagHelper.updateTags<Tag>(
|
||||||
updatedTags: updatedTags,
|
updatedTags: updatedTags,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
getInternalId: (tag) => tag.internalId,
|
getInternalId: (tag) => tag.internalId,
|
||||||
@ -311,7 +310,7 @@ class TagHelper {
|
|||||||
checkTagExistInSubspace: checkTagExistInSubspaceModels,
|
checkTagExistInSubspace: checkTagExistInSubspaceModels,
|
||||||
);
|
);
|
||||||
|
|
||||||
final processedTags = result['updatedTags'] as List<TagModel>;
|
final processedTags = result['updatedTags'] as List<Tag>;
|
||||||
final processedSubspaces =
|
final processedSubspaces =
|
||||||
List<SubspaceTemplateModel>.from(result['subspaces'] as List<dynamic>);
|
List<SubspaceTemplateModel>.from(result['subspaces'] as List<dynamic>);
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
|
||||||
SpaceModelBloc() : super(SpaceModelInitial()) {
|
|
||||||
on<SpaceModelSelectedEvent>((event, emit) {
|
|
||||||
emit(SpaceModelSelectedState(event.selectedIndex));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
abstract class SpaceModelEvent {}
|
|
||||||
|
|
||||||
class SpaceModelSelectedEvent extends SpaceModelEvent {
|
|
||||||
final int selectedIndex;
|
|
||||||
|
|
||||||
SpaceModelSelectedEvent(this.selectedIndex);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
abstract class SpaceModelState {}
|
|
||||||
|
|
||||||
class SpaceModelInitial extends SpaceModelState {}
|
|
||||||
|
|
||||||
class SpaceModelSelectedState extends SpaceModelState {
|
|
||||||
final int selectedIndex;
|
|
||||||
|
|
||||||
SpaceModelSelectedState(this.selectedIndex);
|
|
||||||
}
|
|
@ -0,0 +1,104 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart';
|
||||||
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
|
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||||
|
|
||||||
|
class LinkSpaceToModelBloc
|
||||||
|
extends Bloc<LinkSpaceToModelEvent, LinkSpaceToModelState> {
|
||||||
|
LinkSpaceToModelBloc() : super(SpaceModelInitial()) {
|
||||||
|
on<LinkSpaceModelSelectedIdsEvent>(_getSpaceIds);
|
||||||
|
on<LinkSpaceModelEvent>(_handleLinkSpaceModel);
|
||||||
|
on<ValidateSpaceModelEvent>(_validateLinkSpaceModel);
|
||||||
|
on<LinkSpaceModelSelectedEvent>((event, emit) {
|
||||||
|
emit(SpaceModelSelectedState(event.selectedIndex));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> spacesListIds = [];
|
||||||
|
bool hasSelectedSpaces = false;
|
||||||
|
String validate = '';
|
||||||
|
|
||||||
|
Future<void> _getSpaceIds(LinkSpaceModelSelectedIdsEvent event,
|
||||||
|
Emitter<LinkSpaceToModelState> emit) async {
|
||||||
|
try {
|
||||||
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
|
List<String> spacesList =
|
||||||
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
|
spacesListIds = spacesList;
|
||||||
|
}
|
||||||
|
hasSelectedSpaces =
|
||||||
|
spaceBloc.state.selectedCommunities.any((communityId) {
|
||||||
|
List<String> spacesList =
|
||||||
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
|
return spacesList.isNotEmpty;
|
||||||
|
});
|
||||||
|
if (hasSelectedSpaces) {
|
||||||
|
debugPrint("At least one space is selected.");
|
||||||
|
} else {
|
||||||
|
debugPrint("No spaces selected.");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Error in _getSpaceIds: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleLinkSpaceModel(
|
||||||
|
LinkSpaceModelEvent event,
|
||||||
|
Emitter<LinkSpaceToModelState> emit,
|
||||||
|
) async {
|
||||||
|
emit(SpaceModelLoading());
|
||||||
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
await SpaceModelManagementApi().linkSpaceModel(
|
||||||
|
spaceModelUuid: event.selectedSpaceMode!,
|
||||||
|
projectId: projectUuid,
|
||||||
|
spaceUuids: spacesListIds,
|
||||||
|
isOverWrite: event.isOverWrite);
|
||||||
|
emit(SpaceModelLinkSuccess());
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorMessage = _parseDioError(e);
|
||||||
|
emit(SpaceModelOperationFailure(errorMessage));
|
||||||
|
} catch (e) {
|
||||||
|
emit(SpaceModelOperationFailure('Unexpected error: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _validateLinkSpaceModel(
|
||||||
|
ValidateSpaceModelEvent event,
|
||||||
|
Emitter<LinkSpaceToModelState> emit,
|
||||||
|
) async {
|
||||||
|
emit(SpaceModelLoading());
|
||||||
|
try {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
await SpaceModelManagementApi().validateSpaceModel(
|
||||||
|
projectUuid,
|
||||||
|
spacesListIds,
|
||||||
|
);
|
||||||
|
emit(SpaceValidationSuccess());
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorMessage = _parseDioError(e);
|
||||||
|
if (errorMessage ==
|
||||||
|
'Selected spaces already have linked space model / sub-spaces and devices') {
|
||||||
|
emit(const AlreadyHaveLinkedState());
|
||||||
|
} else {
|
||||||
|
emit(SpaceModelOperationFailure(errorMessage));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(SpaceModelOperationFailure('Unexpected error: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _parseDioError(DioException e) {
|
||||||
|
if (e.response?.data is Map<String, dynamic>) {
|
||||||
|
return e.response!.data['error']['message'] ?? 'Unknown error occurred';
|
||||||
|
}
|
||||||
|
return e.message ?? 'Network request failed';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
abstract class LinkSpaceToModelEvent {}
|
||||||
|
|
||||||
|
class LinkSpaceModelSelectedEvent extends LinkSpaceToModelEvent {
|
||||||
|
final int selectedIndex;
|
||||||
|
|
||||||
|
LinkSpaceModelSelectedEvent(this.selectedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinkSpaceModelSelectedIdsEvent extends LinkSpaceToModelEvent {}
|
||||||
|
|
||||||
|
class LinkSpaceModelEvent extends LinkSpaceToModelEvent {
|
||||||
|
final String? selectedSpaceMode;
|
||||||
|
final bool isOverWrite;
|
||||||
|
LinkSpaceModelEvent({this.selectedSpaceMode, this.isOverWrite = false});
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValidateSpaceModelEvent extends LinkSpaceToModelEvent {
|
||||||
|
BuildContext? context;
|
||||||
|
ValidateSpaceModelEvent({this.context});
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
abstract class LinkSpaceToModelState {
|
||||||
|
const LinkSpaceToModelState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpaceModelInitial extends LinkSpaceToModelState {}
|
||||||
|
|
||||||
|
class SpaceModelLoading extends LinkSpaceToModelState {}
|
||||||
|
|
||||||
|
class SpaceModelSelectedState extends LinkSpaceToModelState {
|
||||||
|
final int selectedIndex;
|
||||||
|
const SpaceModelSelectedState(this.selectedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpaceModelSelectionUpdated extends LinkSpaceToModelState {
|
||||||
|
final bool hasSelectedSpaces;
|
||||||
|
const SpaceModelSelectionUpdated(this.hasSelectedSpaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpaceValidationSuccess extends LinkSpaceToModelState {}
|
||||||
|
|
||||||
|
class SpaceModelLinkSuccess extends LinkSpaceToModelState {}
|
||||||
|
|
||||||
|
class ValidationError extends LinkSpaceToModelState {
|
||||||
|
final String message;
|
||||||
|
const ValidationError(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpaceModelOperationFailure extends LinkSpaceToModelState {
|
||||||
|
final String message;
|
||||||
|
const SpaceModelOperationFailure(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AlreadyHaveLinkedState extends LinkSpaceToModelState {
|
||||||
|
const AlreadyHaveLinkedState();
|
||||||
|
}
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/space_model_card_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/space_model_card_widget.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
@ -24,13 +24,13 @@ class LinkSpaceModelDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => SpaceModelBloc()
|
create: (context) => LinkSpaceToModelBloc()
|
||||||
..add(
|
..add(
|
||||||
SpaceModelSelectedEvent(initialSelectedIndex ?? -1),
|
LinkSpaceModelSelectedEvent(initialSelectedIndex ?? -1),
|
||||||
),
|
),
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final bloc = context.read<SpaceModelBloc>();
|
final bloc = context.read<LinkSpaceToModelBloc>();
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
title: const Text('Link a space model'),
|
title: const Text('Link a space model'),
|
||||||
@ -39,7 +39,7 @@ class LinkSpaceModelDialog extends StatelessWidget {
|
|||||||
color: ColorsManager.textFieldGreyColor,
|
color: ColorsManager.textFieldGreyColor,
|
||||||
width: MediaQuery.of(context).size.width * 0.7,
|
width: MediaQuery.of(context).size.width * 0.7,
|
||||||
height: MediaQuery.of(context).size.height * 0.6,
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
child: BlocBuilder<SpaceModelBloc, SpaceModelState>(
|
child: BlocBuilder<LinkSpaceToModelBloc, LinkSpaceToModelState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
int selectedIndex = -1;
|
int selectedIndex = -1;
|
||||||
if (state is SpaceModelSelectedState) {
|
if (state is SpaceModelSelectedState) {
|
||||||
@ -59,7 +59,7 @@ class LinkSpaceModelDialog extends StatelessWidget {
|
|||||||
final isSelected = selectedIndex == index;
|
final isSelected = selectedIndex == index;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
bloc.add(SpaceModelSelectedEvent(index));
|
bloc.add(LinkSpaceModelSelectedEvent(index));
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.all(10.0),
|
margin: const EdgeInsets.all(10.0),
|
||||||
@ -93,7 +93,7 @@ class LinkSpaceModelDialog extends StatelessWidget {
|
|||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
BlocBuilder<SpaceModelBloc, SpaceModelState>(
|
BlocBuilder<LinkSpaceToModelBloc, LinkSpaceToModelState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final isEnabled = state is SpaceModelSelectedState &&
|
final isEnabled = state is SpaceModelSelectedState &&
|
||||||
state.selectedIndex >= 0;
|
state.selectedIndex >= 0;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
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/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_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/space_model_mang_api.dart';
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
import 'package:syncrow_web/utils/constants/action_enum.dart';
|
import 'package:syncrow_web/utils/constants/action_enum.dart';
|
||||||
@ -94,14 +94,9 @@ class CreateSpaceModelBloc
|
|||||||
orElse: () => subspace,
|
orElse: () => subspace,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update the subspace's tags
|
|
||||||
final eventTagIds = matchingEventSubspace.tags
|
|
||||||
?.map((e) => e.internalId)
|
|
||||||
.toSet() ??
|
|
||||||
{};
|
|
||||||
|
|
||||||
final updatedTags = [
|
final updatedTags = [
|
||||||
...?subspace.tags?.map<TagModel>((tag) {
|
...?subspace.tags?.map<Tag>((tag) {
|
||||||
final matchingTag =
|
final matchingTag =
|
||||||
matchingEventSubspace.tags?.firstWhere(
|
matchingEventSubspace.tags?.firstWhere(
|
||||||
(e) => e.internalId == tag.internalId,
|
(e) => e.internalId == tag.internalId,
|
||||||
@ -112,14 +107,14 @@ class CreateSpaceModelBloc
|
|||||||
? tag.copyWith(tag: matchingTag?.tag)
|
? tag.copyWith(tag: matchingTag?.tag)
|
||||||
: tag;
|
: tag;
|
||||||
}) ??
|
}) ??
|
||||||
<TagModel>[],
|
<Tag>[],
|
||||||
...?matchingEventSubspace.tags?.where(
|
...?matchingEventSubspace.tags?.where(
|
||||||
(e) =>
|
(e) =>
|
||||||
subspace.tags
|
subspace.tags
|
||||||
?.every((t) => t.internalId != e.internalId) ??
|
?.every((t) => t.internalId != e.internalId) ??
|
||||||
true,
|
true,
|
||||||
) ??
|
) ??
|
||||||
<TagModel>[],
|
<Tag>[],
|
||||||
];
|
];
|
||||||
return subspace.copyWith(
|
return subspace.copyWith(
|
||||||
subspaceName: matchingEventSubspace.subspaceName,
|
subspaceName: matchingEventSubspace.subspaceName,
|
||||||
@ -244,7 +239,7 @@ class CreateSpaceModelBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newSubspaces != null) {
|
if (newSubspaces != null) {
|
||||||
for (var newSubspace in newSubspaces!) {
|
for (var newSubspace in newSubspaces) {
|
||||||
// Tag without UUID
|
// Tag without UUID
|
||||||
if ((newSubspace.uuid == null || newSubspace.uuid!.isEmpty)) {
|
if ((newSubspace.uuid == null || newSubspace.uuid!.isEmpty)) {
|
||||||
final List<TagModelUpdate> tagUpdates = [];
|
final List<TagModelUpdate> tagUpdates = [];
|
||||||
@ -253,7 +248,7 @@ class CreateSpaceModelBloc
|
|||||||
for (var tag in newSubspace.tags!) {
|
for (var tag in newSubspace.tags!) {
|
||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: Action.add,
|
action: Action.add,
|
||||||
uuid: tag.uuid == '' ? null : tag.uuid,
|
newTagUuid: tag.uuid == '' ? null : tag.uuid,
|
||||||
tag: tag.tag,
|
tag: tag.tag,
|
||||||
productUuid: tag.product?.uuid));
|
productUuid: tag.product?.uuid));
|
||||||
}
|
}
|
||||||
@ -268,7 +263,7 @@ class CreateSpaceModelBloc
|
|||||||
|
|
||||||
if (prevSubspaces != null && newSubspaces != null) {
|
if (prevSubspaces != null && newSubspaces != null) {
|
||||||
final newSubspaceMap = {
|
final newSubspaceMap = {
|
||||||
for (var subspace in newSubspaces!) subspace.uuid: subspace
|
for (var subspace in newSubspaces) subspace.uuid: subspace
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var prevSubspace in prevSubspaces) {
|
for (var prevSubspace in prevSubspaces) {
|
||||||
@ -309,8 +304,8 @@ class CreateSpaceModelBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<TagModelUpdate> processTagUpdates(
|
List<TagModelUpdate> processTagUpdates(
|
||||||
List<TagModel>? prevTags,
|
List<Tag>? prevTags,
|
||||||
List<TagModel>? newTags,
|
List<Tag>? newTags,
|
||||||
) {
|
) {
|
||||||
final List<TagModelUpdate> tagUpdates = [];
|
final List<TagModelUpdate> tagUpdates = [];
|
||||||
final processedTags = <String?>{};
|
final processedTags = <String?>{};
|
||||||
@ -320,7 +315,7 @@ class CreateSpaceModelBloc
|
|||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: Action.add,
|
action: Action.add,
|
||||||
tag: newTag.tag,
|
tag: newTag.tag,
|
||||||
uuid: newTag.uuid,
|
newTagUuid: newTag.uuid,
|
||||||
productUuid: newTag.product?.uuid,
|
productUuid: newTag.product?.uuid,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -332,7 +327,7 @@ class CreateSpaceModelBloc
|
|||||||
if (prevTags != null && newTags != null) {
|
if (prevTags != null && newTags != null) {
|
||||||
for (var prevTag in prevTags) {
|
for (var prevTag in prevTags) {
|
||||||
final existsInNew =
|
final existsInNew =
|
||||||
newTags!.any((newTag) => newTag.uuid == prevTag.uuid);
|
newTags.any((newTag) => newTag.uuid == prevTag.uuid);
|
||||||
if (!existsInNew) {
|
if (!existsInNew) {
|
||||||
tagUpdates
|
tagUpdates
|
||||||
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
|
.add(TagModelUpdate(action: Action.delete, uuid: prevTag.uuid));
|
||||||
@ -349,14 +344,14 @@ class CreateSpaceModelBloc
|
|||||||
if (newTags != null) {
|
if (newTags != null) {
|
||||||
final prevTagUuids = prevTags?.map((t) => t.uuid).toSet() ?? {};
|
final prevTagUuids = prevTags?.map((t) => t.uuid).toSet() ?? {};
|
||||||
|
|
||||||
for (var newTag in newTags!) {
|
for (var newTag in newTags) {
|
||||||
// Tag without UUID
|
// Tag without UUID
|
||||||
if ((newTag.uuid == null || !prevTagUuids.contains(newTag.uuid)) &&
|
if ((newTag.uuid == null || !prevTagUuids.contains(newTag.uuid)) &&
|
||||||
!processedTags.contains(newTag.tag)) {
|
!processedTags.contains(newTag.tag)) {
|
||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: Action.add,
|
action: Action.add,
|
||||||
tag: newTag.tag,
|
tag: newTag.tag,
|
||||||
uuid: newTag.uuid == '' ? null : newTag.uuid,
|
newTagUuid: newTag.uuid == '' ? null : newTag.uuid,
|
||||||
productUuid: newTag.product?.uuid));
|
productUuid: newTag.product?.uuid));
|
||||||
processedTags.add(newTag.tag);
|
processedTags.add(newTag.tag);
|
||||||
}
|
}
|
||||||
@ -365,14 +360,15 @@ class CreateSpaceModelBloc
|
|||||||
|
|
||||||
// Case 3: Tags updated
|
// Case 3: Tags updated
|
||||||
if (prevTags != null && newTags != null) {
|
if (prevTags != null && newTags != null) {
|
||||||
final newTagMap = {for (var tag in newTags!) tag.uuid: tag};
|
final newTagMap = {for (var tag in newTags) tag.uuid: tag};
|
||||||
|
|
||||||
for (var prevTag in prevTags!) {
|
for (var prevTag in prevTags) {
|
||||||
final newTag = newTagMap[prevTag.uuid];
|
final newTag = newTagMap[prevTag.uuid];
|
||||||
if (newTag != null) {
|
if (newTag != null) {
|
||||||
tagUpdates.add(TagModelUpdate(
|
tagUpdates.add(TagModelUpdate(
|
||||||
action: Action.update,
|
action: Action.update,
|
||||||
uuid: newTag.uuid,
|
uuid: prevTag.uuid,
|
||||||
|
newTagUuid: newTag.uuid,
|
||||||
tag: newTag.tag,
|
tag: newTag.tag,
|
||||||
));
|
));
|
||||||
} else {}
|
} else {}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
|
||||||
|
|
||||||
abstract class CreateSpaceModelEvent extends Equatable {
|
abstract class CreateSpaceModelEvent extends Equatable {
|
||||||
const CreateSpaceModelEvent();
|
const CreateSpaceModelEvent();
|
||||||
@ -49,7 +49,7 @@ class AddSubspacesToSpaceTemplate extends CreateSpaceModelEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AddTagsToSpaceTemplate extends CreateSpaceModelEvent {
|
class AddTagsToSpaceTemplate extends CreateSpaceModelEvent {
|
||||||
final List<TagModel> tags;
|
final List<Tag> tags;
|
||||||
|
|
||||||
AddTagsToSpaceTemplate(this.tags);
|
AddTagsToSpaceTemplate(this.tags);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ class TagBodyModel {
|
|||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'uuid': uuid,
|
'uuid': uuid,
|
||||||
'tag': tag,
|
'name': tag,
|
||||||
'productUuid': productUuid,
|
'productUuid': productUuid,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_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/utils/constants/action_enum.dart';
|
import 'package:syncrow_web/utils/constants/action_enum.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
@ -9,8 +9,9 @@ class SpaceTemplateModel extends Equatable {
|
|||||||
String? uuid;
|
String? uuid;
|
||||||
String modelName;
|
String modelName;
|
||||||
List<SubspaceTemplateModel>? subspaceModels;
|
List<SubspaceTemplateModel>? subspaceModels;
|
||||||
final List<TagModel>? tags;
|
final List<Tag>? tags;
|
||||||
String internalId;
|
String internalId;
|
||||||
|
String? createdAt;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [modelName, subspaceModels, tags];
|
List<Object?> get props => [modelName, subspaceModels, tags];
|
||||||
@ -21,6 +22,7 @@ class SpaceTemplateModel extends Equatable {
|
|||||||
required this.modelName,
|
required this.modelName,
|
||||||
this.subspaceModels,
|
this.subspaceModels,
|
||||||
this.tags,
|
this.tags,
|
||||||
|
this.createdAt,
|
||||||
}) : internalId = internalId ?? const Uuid().v4();
|
}) : internalId = internalId ?? const Uuid().v4();
|
||||||
|
|
||||||
factory SpaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -28,6 +30,7 @@ class SpaceTemplateModel extends Equatable {
|
|||||||
|
|
||||||
return SpaceTemplateModel(
|
return SpaceTemplateModel(
|
||||||
uuid: json['uuid'] ?? '',
|
uuid: json['uuid'] ?? '',
|
||||||
|
createdAt: json['createdAt'] ?? '',
|
||||||
internalId: internalId,
|
internalId: internalId,
|
||||||
modelName: json['modelName'] ?? '',
|
modelName: json['modelName'] ?? '',
|
||||||
subspaceModels: (json['subspaceModels'] as List<dynamic>?)
|
subspaceModels: (json['subspaceModels'] as List<dynamic>?)
|
||||||
@ -38,7 +41,7 @@ class SpaceTemplateModel extends Equatable {
|
|||||||
[],
|
[],
|
||||||
tags: (json['tags'] as List<dynamic>?)
|
tags: (json['tags'] as List<dynamic>?)
|
||||||
?.where((item) => item is Map<String, dynamic>) // Validate type
|
?.where((item) => item is Map<String, dynamic>) // Validate type
|
||||||
.map((item) => TagModel.fromJson(item as Map<String, dynamic>))
|
.map((item) => Tag.fromJson(item as Map<String, dynamic>))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
@ -47,7 +50,7 @@ class SpaceTemplateModel extends Equatable {
|
|||||||
String? uuid,
|
String? uuid,
|
||||||
String? modelName,
|
String? modelName,
|
||||||
List<SubspaceTemplateModel>? subspaceModels,
|
List<SubspaceTemplateModel>? subspaceModels,
|
||||||
List<TagModel>? tags,
|
List<Tag>? tags,
|
||||||
String? internalId,
|
String? internalId,
|
||||||
}) {
|
}) {
|
||||||
return SpaceTemplateModel(
|
return SpaceTemplateModel(
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class SubspaceTemplateModel {
|
class SubspaceTemplateModel {
|
||||||
final String? uuid;
|
final String? uuid;
|
||||||
String subspaceName;
|
String subspaceName;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
List<TagModel>? tags;
|
List<Tag>? tags;
|
||||||
String internalId;
|
String internalId;
|
||||||
|
|
||||||
SubspaceTemplateModel({
|
SubspaceTemplateModel({
|
||||||
@ -25,7 +25,7 @@ class SubspaceTemplateModel {
|
|||||||
internalId: internalId,
|
internalId: internalId,
|
||||||
disabled: json['disabled'] ?? false,
|
disabled: json['disabled'] ?? false,
|
||||||
tags: (json['tags'] as List<dynamic>?)
|
tags: (json['tags'] as List<dynamic>?)
|
||||||
?.map((item) => TagModel.fromJson(item))
|
?.map((item) => Tag.fromJson(item))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
@ -44,7 +44,7 @@ class SubspaceTemplateModel {
|
|||||||
String? uuid,
|
String? uuid,
|
||||||
String? subspaceName,
|
String? subspaceName,
|
||||||
bool? disabled,
|
bool? disabled,
|
||||||
List<TagModel>? tags,
|
List<Tag>? tags,
|
||||||
String? internalId,
|
String? internalId,
|
||||||
}) {
|
}) {
|
||||||
return SubspaceTemplateModel(
|
return SubspaceTemplateModel(
|
||||||
|
@ -4,7 +4,7 @@ class CreateTagBodyModel {
|
|||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'tag': tag,
|
'name': tag,
|
||||||
'productUuid': productUuid,
|
'productUuid': productUuid,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/base_tag.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class TagModel extends BaseTag {
|
|
||||||
TagModel({
|
|
||||||
String? uuid,
|
|
||||||
required String? tag,
|
|
||||||
ProductModel? product,
|
|
||||||
String? internalId,
|
|
||||||
String? location,
|
|
||||||
}) : super(
|
|
||||||
uuid: uuid,
|
|
||||||
tag: tag,
|
|
||||||
product: product,
|
|
||||||
internalId: internalId,
|
|
||||||
location: location,
|
|
||||||
);
|
|
||||||
factory TagModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
final String internalId = json['internalId'] ?? const Uuid().v4();
|
|
||||||
|
|
||||||
return TagModel(
|
|
||||||
uuid: json['uuid'] ,
|
|
||||||
internalId: internalId,
|
|
||||||
tag: json['tag'] ?? '',
|
|
||||||
product: json['product'] != null
|
|
||||||
? ProductModel.fromMap(json['product'])
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
TagModel copyWith(
|
|
||||||
{String? tag,
|
|
||||||
ProductModel? product,
|
|
||||||
String? uuid,
|
|
||||||
String? location,
|
|
||||||
String? internalId}) {
|
|
||||||
return TagModel(
|
|
||||||
tag: tag ?? this.tag,
|
|
||||||
product: product ?? this.product,
|
|
||||||
location: location ?? this.location,
|
|
||||||
internalId: internalId ?? this.internalId,
|
|
||||||
uuid:uuid?? this.uuid
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'uuid': uuid,
|
|
||||||
'tag': tag,
|
|
||||||
'product': product?.toMap(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TagModelExtensions on TagModel {
|
|
||||||
TagBodyModel toTagBodyModel() {
|
|
||||||
return TagBodyModel()
|
|
||||||
..uuid = uuid
|
|
||||||
..tag = tag ?? ''
|
|
||||||
..productUuid = product?.uuid;
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,12 +5,14 @@ class TagModelUpdate {
|
|||||||
final String? uuid;
|
final String? uuid;
|
||||||
final String? tag;
|
final String? tag;
|
||||||
final String? productUuid;
|
final String? productUuid;
|
||||||
|
final String? newTagUuid;
|
||||||
|
|
||||||
TagModelUpdate({
|
TagModelUpdate({
|
||||||
required this.action,
|
required this.action,
|
||||||
this.uuid,
|
this.uuid,
|
||||||
this.tag,
|
this.tag,
|
||||||
this.productUuid,
|
this.productUuid,
|
||||||
|
this.newTagUuid,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory TagModelUpdate.fromJson(Map<String, dynamic> json) {
|
factory TagModelUpdate.fromJson(Map<String, dynamic> json) {
|
||||||
@ -26,9 +28,10 @@ class TagModelUpdate {
|
|||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'action': action.value,
|
'action': action.value,
|
||||||
'uuid': uuid, // Nullable field
|
'tagUuid': uuid,
|
||||||
'tag': tag,
|
'name': tag,
|
||||||
'productUuid': productUuid,
|
'productUuid': productUuid,
|
||||||
|
'newTagUuid': newTagUuid
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
@ -12,8 +13,10 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
|||||||
class SpaceModelPage extends StatelessWidget {
|
class SpaceModelPage extends StatelessWidget {
|
||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
final Function(List<SpaceTemplateModel>)? onSpaceModelsUpdated;
|
final Function(List<SpaceTemplateModel>)? onSpaceModelsUpdated;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const SpaceModelPage({Key? key, this.products, this.onSpaceModelsUpdated})
|
const SpaceModelPage(
|
||||||
|
{Key? key, this.products, this.onSpaceModelsUpdated, required this.projectTags})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -60,6 +63,7 @@ class SpaceModelPage extends StatelessWidget {
|
|||||||
allTags: allTagValues,
|
allTags: allTagValues,
|
||||||
pageContext: context,
|
pageContext: context,
|
||||||
otherSpaceModels: allSpaceModelNames,
|
otherSpaceModels: allSpaceModelNames,
|
||||||
|
projectTags: projectTags,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -69,8 +73,7 @@ class SpaceModelPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
// Render existing space model
|
// Render existing space model
|
||||||
final model = spaceModels[index];
|
final model = spaceModels[index];
|
||||||
final otherModel =
|
final otherModel = List<String>.from(allSpaceModelNames);
|
||||||
List<String>.from(allSpaceModelNames);
|
|
||||||
otherModel.remove(model.modelName);
|
otherModel.remove(model.modelName);
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -84,6 +87,7 @@ class SpaceModelPage extends StatelessWidget {
|
|||||||
otherSpaceModels: otherModel,
|
otherSpaceModels: otherModel,
|
||||||
pageContext: context,
|
pageContext: context,
|
||||||
allSpaceModels: spaceModels,
|
allSpaceModels: spaceModels,
|
||||||
|
projectTags: projectTags,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -107,10 +111,8 @@ class SpaceModelPage extends StatelessWidget {
|
|||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Error: ${state.message}',
|
'Error: ${state.message}',
|
||||||
style: Theme.of(context)
|
style:
|
||||||
.textTheme
|
Theme.of(context).textTheme.bodySmall?.copyWith(color: ColorsManager.warningRed),
|
||||||
.bodySmall
|
|
||||||
?.copyWith(color: ColorsManager.warningRed),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class ConfirmMergeDialog extends StatelessWidget {
|
||||||
|
const ConfirmMergeDialog({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
title: Center(
|
||||||
|
child: Text(
|
||||||
|
'Merge',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 30),
|
||||||
|
)),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Are you sure you want to merge?',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 18),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: ColorsManager.boxColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Cancel",
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Ok",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class ConfirmOverwriteDialog extends StatelessWidget {
|
||||||
|
const ConfirmOverwriteDialog({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
title: Center(
|
||||||
|
child: Text(
|
||||||
|
'Overwrite',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 30),
|
||||||
|
)),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Are you sure you want to overwrite?',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 18),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'Selected spaces already have linked space \nmodel / sub-spaces and devices',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14,
|
||||||
|
color: ColorsManager.grayColor),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: ColorsManager.boxColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Cancel",
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return const LinkingSuccessful();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Ok",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 16,
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/common/buttons/default_button.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/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
||||||
@ -25,6 +26,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
final BuildContext? pageContext;
|
final BuildContext? pageContext;
|
||||||
final List<String>? otherSpaceModels;
|
final List<String>? otherSpaceModels;
|
||||||
final List<SpaceTemplateModel>? allSpaceModels;
|
final List<SpaceTemplateModel>? allSpaceModels;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const CreateSpaceModelDialog(
|
const CreateSpaceModelDialog(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@ -33,7 +35,8 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
this.spaceModel,
|
this.spaceModel,
|
||||||
this.pageContext,
|
this.pageContext,
|
||||||
this.otherSpaceModels,
|
this.otherSpaceModels,
|
||||||
this.allSpaceModels})
|
this.allSpaceModels,
|
||||||
|
required this.projectTags})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -68,8 +71,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
|
|
||||||
spaceNameController.addListener(() {
|
spaceNameController.addListener(() {
|
||||||
bloc.add(UpdateSpaceTemplateName(
|
bloc.add(UpdateSpaceTemplateName(
|
||||||
name: spaceNameController.text,
|
name: spaceNameController.text, allModels: otherSpaceModels ?? []));
|
||||||
allModels: otherSpaceModels ?? []));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return bloc;
|
return bloc;
|
||||||
@ -87,9 +89,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
spaceModel?.uuid == null
|
spaceModel?.uuid == null ? 'Create New Space Model' : 'Edit Space Model',
|
||||||
? 'Create New Space Model'
|
|
||||||
: 'Edit Space Model',
|
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.headlineLarge
|
.headlineLarge
|
||||||
@ -101,10 +101,8 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
controller: spaceNameController,
|
controller: spaceNameController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<CreateSpaceModelBloc>().add(
|
context.read<CreateSpaceModelBloc>().add(UpdateSpaceTemplateName(
|
||||||
UpdateSpaceTemplateName(
|
name: value, allModels: otherSpaceModels ?? []));
|
||||||
name: value,
|
|
||||||
allModels: otherSpaceModels ?? []));
|
|
||||||
},
|
},
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
@ -157,6 +155,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
pageContext: pageContext,
|
pageContext: pageContext,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
allSpaceModels: allSpaceModels,
|
allSpaceModels: allSpaceModels,
|
||||||
|
projectTags: projectTags,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -179,84 +178,55 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
!isNameValid)
|
!isNameValid)
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
final updatedSpaceTemplate =
|
final updatedSpaceTemplate = updatedSpaceModel.copyWith(
|
||||||
updatedSpaceModel.copyWith(
|
modelName: spaceNameController.text.trim(),
|
||||||
modelName:
|
|
||||||
spaceNameController.text.trim(),
|
|
||||||
);
|
);
|
||||||
if (updatedSpaceModel.uuid == null) {
|
if (updatedSpaceModel.uuid == null) {
|
||||||
context
|
context.read<CreateSpaceModelBloc>().add(
|
||||||
.read<CreateSpaceModelBloc>()
|
|
||||||
.add(
|
|
||||||
CreateSpaceTemplate(
|
CreateSpaceTemplate(
|
||||||
spaceTemplate:
|
spaceTemplate: updatedSpaceTemplate,
|
||||||
updatedSpaceTemplate,
|
|
||||||
onCreate: (newModel) {
|
onCreate: (newModel) {
|
||||||
if (pageContext != null) {
|
if (pageContext != null) {
|
||||||
|
pageContext!.read<SpaceModelBloc>().add(
|
||||||
|
CreateSpaceModel(newSpaceModel: newModel));
|
||||||
pageContext!
|
pageContext!
|
||||||
.read<SpaceModelBloc>()
|
.read<SpaceManagementBloc>()
|
||||||
.add(CreateSpaceModel(
|
.add(UpdateSpaceModelCache(newModel));
|
||||||
newSpaceModel:
|
|
||||||
newModel));
|
|
||||||
pageContext!
|
|
||||||
.read<
|
|
||||||
SpaceManagementBloc>()
|
|
||||||
.add(
|
|
||||||
UpdateSpaceModelCache(
|
|
||||||
newModel));
|
|
||||||
}
|
}
|
||||||
Navigator.of(context)
|
Navigator.of(context).pop(); // Close the dialog
|
||||||
.pop(); // Close the dialog
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (pageContext != null) {
|
if (pageContext != null) {
|
||||||
final currentState = pageContext!
|
final currentState =
|
||||||
.read<SpaceModelBloc>()
|
pageContext!.read<SpaceModelBloc>().state;
|
||||||
.state;
|
if (currentState is SpaceModelLoaded) {
|
||||||
if (currentState
|
final spaceModels = List<SpaceTemplateModel>.from(
|
||||||
is SpaceModelLoaded) {
|
currentState.spaceModels);
|
||||||
final spaceModels =
|
|
||||||
List<SpaceTemplateModel>.from(
|
|
||||||
currentState.spaceModels);
|
|
||||||
|
|
||||||
final SpaceTemplateModel?
|
final SpaceTemplateModel? currentSpaceModel =
|
||||||
currentSpaceModel = spaceModels
|
spaceModels.cast<SpaceTemplateModel?>().firstWhere(
|
||||||
.cast<SpaceTemplateModel?>()
|
(sm) => sm?.uuid == updatedSpaceModel.uuid,
|
||||||
.firstWhere(
|
|
||||||
(sm) =>
|
|
||||||
sm?.uuid ==
|
|
||||||
updatedSpaceModel
|
|
||||||
.uuid,
|
|
||||||
orElse: () => null,
|
orElse: () => null,
|
||||||
);
|
);
|
||||||
if (currentSpaceModel != null) {
|
if (currentSpaceModel != null) {
|
||||||
context
|
context
|
||||||
.read<CreateSpaceModelBloc>()
|
.read<CreateSpaceModelBloc>()
|
||||||
.add(ModifySpaceTemplate(
|
.add(ModifySpaceTemplate(
|
||||||
spaceTemplate:
|
spaceTemplate: currentSpaceModel,
|
||||||
currentSpaceModel,
|
updatedSpaceTemplate: updatedSpaceTemplate,
|
||||||
updatedSpaceTemplate:
|
|
||||||
updatedSpaceTemplate,
|
|
||||||
onUpdate: (newModel) {
|
onUpdate: (newModel) {
|
||||||
if (pageContext !=
|
if (pageContext != null) {
|
||||||
null) {
|
pageContext!.read<SpaceModelBloc>().add(
|
||||||
pageContext!
|
UpdateSpaceModel(
|
||||||
.read<
|
|
||||||
SpaceModelBloc>()
|
|
||||||
.add(UpdateSpaceModel(
|
|
||||||
spaceModelUuid:
|
spaceModelUuid:
|
||||||
newModel.uuid ??
|
newModel.uuid ?? ''));
|
||||||
''));
|
|
||||||
pageContext!
|
pageContext!
|
||||||
.read<
|
.read<SpaceManagementBloc>()
|
||||||
SpaceManagementBloc>()
|
.add(UpdateSpaceModelCache(newModel));
|
||||||
.add(UpdateSpaceModelCache(
|
|
||||||
newModel));
|
|
||||||
}
|
}
|
||||||
Navigator.of(context)
|
Navigator.of(context).pop();
|
||||||
.pop();
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,11 +235,11 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
backgroundColor: ColorsManager.secondaryColor,
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
foregroundColor: ((state.errorMessage != null &&
|
foregroundColor:
|
||||||
state.errorMessage != '') ||
|
((state.errorMessage != null && state.errorMessage != '') ||
|
||||||
!isNameValid)
|
!isNameValid)
|
||||||
? ColorsManager.whiteColorsWithOpacity
|
? ColorsManager.whiteColorsWithOpacity
|
||||||
: ColorsManager.whiteColors,
|
: ColorsManager.whiteColors,
|
||||||
child: const Text('OK'),
|
child: const Text('OK'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class CustomLoadingIndicator extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_CustomLoadingIndicatorState createState() => _CustomLoadingIndicatorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomLoadingIndicatorState extends State<CustomLoadingIndicator>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: const Duration(seconds: 1),
|
||||||
|
)..repeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: _controller,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Transform.rotate(
|
||||||
|
angle: _controller.value * 2 * pi,
|
||||||
|
child: CustomPaint(
|
||||||
|
painter: LoadingPainter(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoadingPainter extends CustomPainter {
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final Paint paint = Paint()
|
||||||
|
..strokeWidth = 5
|
||||||
|
..strokeCap = StrokeCap.round
|
||||||
|
..style = PaintingStyle.stroke;
|
||||||
|
|
||||||
|
final double radius = size.width / 2;
|
||||||
|
final Offset center = Offset(size.width / 2, size.height / 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
final double angle = (i * 30) * (pi / 180);
|
||||||
|
final double startX = center.dx + radius * cos(angle);
|
||||||
|
final double startY = center.dy + radius * sin(angle);
|
||||||
|
final double endX = center.dx + (radius - 8) * cos(angle);
|
||||||
|
final double endY = center.dy + (radius - 8) * sin(angle);
|
||||||
|
|
||||||
|
paint.color = Colors.blue.withOpacity(i / 12); // Gradient effect
|
||||||
|
canvas.drawLine(Offset(startX, startY), Offset(endX, endY), paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
||||||
|
}
|
@ -0,0 +1,221 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class LinkSpaceModelSpacesDialog extends StatefulWidget {
|
||||||
|
final SpaceTemplateModel spaceModel;
|
||||||
|
|
||||||
|
const LinkSpaceModelSpacesDialog({super.key, required this.spaceModel});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LinkSpaceModelSpacesDialog> createState() =>
|
||||||
|
_LinkSpaceModelSpacesDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LinkSpaceModelSpacesDialogState
|
||||||
|
extends State<LinkSpaceModelSpacesDialog> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
context.read<LinkSpaceToModelBloc>().add(LinkSpaceModelSelectedIdsEvent());
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
content: SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.4,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildDialogContent(),
|
||||||
|
_buildActionButtons(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDialogContent() {
|
||||||
|
return Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.4,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Center(
|
||||||
|
child: Text(
|
||||||
|
"Link Space Model to Spaces",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.blueAccent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildDetailRow(
|
||||||
|
"Space model name:", widget.spaceModel.modelName),
|
||||||
|
_buildDetailRow("Creation date and time:",
|
||||||
|
widget.spaceModel.createdAt.toString()),
|
||||||
|
_buildDetailRow("Created by:", "Admin"),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
const Text(
|
||||||
|
"Link to:",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
"Please select all the spaces where you would like to link the Routine.",
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Expanded(
|
||||||
|
child: SizedBox(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 7,
|
||||||
|
child: Container(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
child: SpaceTreeView(
|
||||||
|
isSide: true,
|
||||||
|
onSelect: () {
|
||||||
|
context
|
||||||
|
.read<LinkSpaceToModelBloc>()
|
||||||
|
.add(
|
||||||
|
LinkSpaceModelSelectedIdsEvent());
|
||||||
|
})))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildActionButtons() {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
height: 50,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: BorderSide(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: _buildButton("Cancel", Colors.grey, () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
height: 50,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
left: BorderSide(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
top: BorderSide(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
width: 1.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: _buildButton(
|
||||||
|
"Confirm",
|
||||||
|
ColorsManager.onSecondaryColor,
|
||||||
|
() {
|
||||||
|
final spaceModelBloc = context.read<LinkSpaceToModelBloc>();
|
||||||
|
if (!spaceModelBloc.hasSelectedSpaces) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text("Please select at least one space")),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
spaceModelBloc.add(ValidateSpaceModelEvent(context: context));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDetailRow(String label, String value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold, color: Colors.black),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildButton(String text, Color color, VoidCallback onPressed) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onPressed,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style:
|
||||||
|
TextStyle(color: color, fontWeight: FontWeight.w400, fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/confirm_merge_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
|
class LinkingAttentionDialog extends StatelessWidget {
|
||||||
|
const LinkingAttentionDialog({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
title: Center(
|
||||||
|
child: Text(
|
||||||
|
'Linking Attention',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 30),
|
||||||
|
)),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Do you want to merge or overwrite?',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 18),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'Selected spaces already have commissioned Devices',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 14),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
// Cancel Button
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return const ConfirmOverwriteDialog();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: ColorsManager.boxColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Overwrite",
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
|
||||||
|
// OK Button
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return const ConfirmMergeDialog();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: ColorsManager.boxColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Merge",
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
|
|
||||||
|
class LinkingSuccessful extends StatelessWidget {
|
||||||
|
const LinkingSuccessful({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
|
title: Center(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.successIcon,
|
||||||
|
)),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Linking successful',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.w400, fontSize: 18),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
|
||||||
|
void showOverwriteDialog(
|
||||||
|
BuildContext context, LinkSpaceToModelBloc bloc, SpaceTemplateModel model) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
child: Dialog(
|
||||||
|
shape:
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
|
elevation: 10,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
child: SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width * 0.3,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
"Overwrite",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
const Text(
|
||||||
|
"Are you sure you want to overwrite?",
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
"Selected spaces already have linked space model / sub-spaces and devices",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: Colors.grey[200],
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"Cancel",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
bloc.add(LinkSpaceModelEvent(
|
||||||
|
isOverWrite: true,
|
||||||
|
selectedSpaceMode: model.uuid));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
elevation: 3,
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
"OK",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -1,13 +1,18 @@
|
|||||||
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:flutter_svg/svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.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/space_model/bloc/space_model_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart';
|
||||||
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/delete_space_model_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/delete_space_model_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_product_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_product_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart';
|
||||||
@ -69,48 +74,174 @@ class SpaceModelCardWidget extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Text(
|
||||||
child: Text(
|
model.modelName,
|
||||||
model.modelName,
|
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||||
style:
|
color: Colors.black,
|
||||||
Theme.of(context).textTheme.headlineMedium?.copyWith(
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!topActionsDisabled)
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () => _showDeleteDialog(context),
|
|
||||||
child: Container(
|
|
||||||
width: 36, // Adjust size as needed
|
|
||||||
height: 36,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: Colors.white,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withOpacity(0.1),
|
|
||||||
spreadRadius: 2,
|
|
||||||
blurRadius: 5,
|
|
||||||
offset: const Offset(0, 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
child: Center(
|
maxLines: 1,
|
||||||
child: SvgPicture.asset(
|
overflow: TextOverflow.ellipsis,
|
||||||
Assets.deleteSpaceModel, // Your actual SVG path
|
),
|
||||||
width: 20,
|
Row(
|
||||||
height: 20,
|
children: [
|
||||||
colorFilter: const ColorFilter.mode(
|
InkWell(
|
||||||
Colors.grey, BlendMode.srcIn),
|
onTap: () {
|
||||||
),
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return BlocProvider<LinkSpaceToModelBloc>(
|
||||||
|
create: (_) => LinkSpaceToModelBloc(),
|
||||||
|
child: BlocListener<LinkSpaceToModelBloc,
|
||||||
|
LinkSpaceToModelState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
final _bloc =
|
||||||
|
BlocProvider.of<LinkSpaceToModelBloc>(
|
||||||
|
context);
|
||||||
|
if (state is SpaceModelLoading) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(20)),
|
||||||
|
elevation: 10,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(
|
||||||
|
vertical: 30,
|
||||||
|
horizontal: 50),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
CustomLoadingIndicator(),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
const Text(
|
||||||
|
"Linking in progress",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight:
|
||||||
|
FontWeight.w500,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (state
|
||||||
|
is AlreadyHaveLinkedState) {
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
showOverwriteDialog(
|
||||||
|
context, _bloc, model);
|
||||||
|
} else if (state
|
||||||
|
is SpaceValidationSuccess) {
|
||||||
|
_bloc.add(LinkSpaceModelEvent(
|
||||||
|
isOverWrite: false,
|
||||||
|
selectedSpaceMode: model.uuid));
|
||||||
|
|
||||||
|
Future.delayed(const Duration(seconds: 1),
|
||||||
|
() {
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
});
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return const LinkingSuccessful();
|
||||||
|
},
|
||||||
|
).then((v) {
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(seconds: 2), () {
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (state is SpaceModelLinkSuccess) {
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return const LinkingSuccessful();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: LinkSpaceModelSpacesDialog(
|
||||||
|
spaceModel: model,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.spaceLinkIcon,
|
||||||
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (!topActionsDisabled)
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
_showDeleteDialog(context);
|
||||||
|
},
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.deleteSpaceLinkIcon,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: Text(
|
||||||
|
// model.modelName,
|
||||||
|
// style:
|
||||||
|
// Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||||
|
// color: Colors.black,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// ),
|
||||||
|
// maxLines: 1,
|
||||||
|
// overflow: TextOverflow.ellipsis,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// if (!topActionsDisabled)
|
||||||
|
// GestureDetector(
|
||||||
|
// onTap: () => _showDeleteDialog(context),
|
||||||
|
// child: Container(
|
||||||
|
// width: 36, // Adjust size as needed
|
||||||
|
// height: 36,
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// shape: BoxShape.circle,
|
||||||
|
// color: Colors.white,
|
||||||
|
// boxShadow: [
|
||||||
|
// BoxShadow(
|
||||||
|
// color: Colors.black.withOpacity(0.1),
|
||||||
|
// spreadRadius: 2,
|
||||||
|
// blurRadius: 5,
|
||||||
|
// offset: const Offset(0, 2),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// child: Center(
|
||||||
|
// child: SvgPicture.asset(
|
||||||
|
// Assets.deleteSpaceModel, // Your actual SVG path
|
||||||
|
// width: 20,
|
||||||
|
// height: 20,
|
||||||
|
// colorFilter: const ColorFilter.mode(
|
||||||
|
// Colors.grey, BlendMode.srcIn),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (!showOnlyName) ...[
|
if (!showOnlyName) ...[
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/common/edit_chip.dart';
|
import 'package:syncrow_web/common/edit_chip.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/button_content_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/button_content_widget.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart';
|
||||||
@ -10,9 +10,9 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
|||||||
class SubspaceModelCreate extends StatefulWidget {
|
class SubspaceModelCreate extends StatefulWidget {
|
||||||
final List<SubspaceTemplateModel> subspaces;
|
final List<SubspaceTemplateModel> subspaces;
|
||||||
final void Function(
|
final void Function(
|
||||||
List<SubspaceTemplateModel> newSubspaces, List<TagModel>? tags)?
|
List<SubspaceTemplateModel> newSubspaces, List<Tag>? tags)?
|
||||||
onSpaceModelUpdate;
|
onSpaceModelUpdate;
|
||||||
final List<TagModel> tags;
|
final List<Tag> tags;
|
||||||
|
|
||||||
const SubspaceModelCreate({
|
const SubspaceModelCreate({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -28,7 +28,7 @@ class SubspaceModelCreate extends StatefulWidget {
|
|||||||
class _SubspaceModelCreateState extends State<SubspaceModelCreate> {
|
class _SubspaceModelCreateState extends State<SubspaceModelCreate> {
|
||||||
late List<SubspaceTemplateModel> _subspaces;
|
late List<SubspaceTemplateModel> _subspaces;
|
||||||
String? errorSubspaceId;
|
String? errorSubspaceId;
|
||||||
late List<TagModel> _tags;
|
late List<Tag> _tags;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -117,7 +117,7 @@ class _SubspaceModelCreateState extends State<SubspaceModelCreate> {
|
|||||||
.where((s) => !updatedIds.contains(s.internalId))
|
.where((s) => !updatedIds.contains(s.internalId))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final List<TagModel> tagsToAppendToSpace = [];
|
final List<Tag> tagsToAppendToSpace = [];
|
||||||
|
|
||||||
for (var s in deletedSubspaces) {
|
for (var s in deletedSubspaces) {
|
||||||
if (s.tags != null) {
|
if (s.tags != null) {
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_web/common/edit_chip.dart';
|
import 'package:syncrow_web/common/edit_chip.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
@ -20,6 +21,7 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
final BuildContext? pageContext;
|
final BuildContext? pageContext;
|
||||||
final List<String>? otherSpaceModels;
|
final List<String>? otherSpaceModels;
|
||||||
final List<SpaceTemplateModel>? allSpaceModels;
|
final List<SpaceTemplateModel>? allSpaceModels;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const TagChipDisplay(BuildContext context,
|
const TagChipDisplay(BuildContext context,
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@ -31,14 +33,14 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
required this.spaceNameController,
|
required this.spaceNameController,
|
||||||
this.pageContext,
|
this.pageContext,
|
||||||
this.otherSpaceModels,
|
this.otherSpaceModels,
|
||||||
this.allSpaceModels})
|
this.allSpaceModels,
|
||||||
|
required this.projectTags})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return (spaceModel?.tags?.isNotEmpty == true ||
|
return (spaceModel?.tags?.isNotEmpty == true ||
|
||||||
spaceModel?.subspaceModels
|
spaceModel?.subspaceModels?.any((subspace) => subspace.tags?.isNotEmpty == true) ==
|
||||||
?.any((subspace) => subspace.tags?.isNotEmpty == true) ==
|
|
||||||
true)
|
true)
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
width: screenWidth * 0.25,
|
width: screenWidth * 0.25,
|
||||||
@ -59,8 +61,7 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
// Combine tags from spaceModel and subspaces
|
// Combine tags from spaceModel and subspaces
|
||||||
...TagHelper.groupTags([
|
...TagHelper.groupTags([
|
||||||
...?spaceModel?.tags,
|
...?spaceModel?.tags,
|
||||||
...?spaceModel?.subspaceModels
|
...?spaceModel?.subspaceModels?.expand((subspace) => subspace.tags ?? [])
|
||||||
?.expand((subspace) => subspace.tags ?? [])
|
|
||||||
]).entries.map(
|
]).entries.map(
|
||||||
(entry) => Chip(
|
(entry) => Chip(
|
||||||
avatar: SizedBox(
|
avatar: SizedBox(
|
||||||
@ -76,9 +77,7 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(color: ColorsManager.spaceColor),
|
||||||
color:
|
|
||||||
ColorsManager.spaceColor),
|
|
||||||
),
|
),
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@ -105,13 +104,12 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
spaceModel: spaceModel,
|
spaceModel: spaceModel,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
initialTags: TagHelper.generateInitialTags(
|
initialTags: TagHelper.generateInitialTags(
|
||||||
subspaces: subspaces,
|
subspaces: subspaces, spaceTagModels: spaceModel?.tags ?? []),
|
||||||
spaceTagModels: spaceModel?.tags ?? []),
|
|
||||||
title: 'Edit Device',
|
title: 'Edit Device',
|
||||||
addedProducts:
|
addedProducts: TagHelper.createInitialSelectedProducts(
|
||||||
TagHelper.createInitialSelectedProducts(
|
spaceModel?.tags ?? [], subspaces),
|
||||||
spaceModel?.tags ?? [], subspaces),
|
|
||||||
spaceName: spaceModel?.modelName ?? '',
|
spaceName: spaceModel?.modelName ?? '',
|
||||||
|
projectTags: projectTags,
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
@ -134,6 +132,7 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
isCreate: true,
|
isCreate: true,
|
||||||
spaceModel: spaceModel,
|
spaceModel: spaceModel,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
|
projectTags: projectTags,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
|
||||||
abstract class AddDeviceModelState extends Equatable {
|
abstract class AddDeviceModelState extends Equatable {
|
||||||
const AddDeviceModelState();
|
const AddDeviceModelState();
|
||||||
@ -15,7 +15,7 @@ class AddDeviceModelLoading extends AddDeviceModelState {}
|
|||||||
|
|
||||||
class AddDeviceModelLoaded extends AddDeviceModelState {
|
class AddDeviceModelLoaded extends AddDeviceModelState {
|
||||||
final List<SelectedProduct> selectedProducts;
|
final List<SelectedProduct> selectedProducts;
|
||||||
final List<TagModel> initialTag;
|
final List<Tag> initialTag;
|
||||||
|
|
||||||
const AddDeviceModelLoaded({
|
const AddDeviceModelLoaded({
|
||||||
required this.selectedProducts,
|
required this.selectedProducts,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
|
|
||||||
abstract class AddDeviceTypeModelEvent extends Equatable {
|
abstract class AddDeviceTypeModelEvent extends Equatable {
|
||||||
const AddDeviceTypeModelEvent();
|
const AddDeviceTypeModelEvent();
|
||||||
@ -25,7 +25,7 @@ class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
|
|||||||
|
|
||||||
|
|
||||||
class InitializeDeviceTypeModel extends AddDeviceTypeModelEvent {
|
class InitializeDeviceTypeModel extends AddDeviceTypeModelEvent {
|
||||||
final List<TagModel> initialTags;
|
final List<Tag> initialTags;
|
||||||
final List<SelectedProduct> addedProducts;
|
final List<SelectedProduct> addedProducts;
|
||||||
|
|
||||||
const InitializeDeviceTypeModel({
|
const InitializeDeviceTypeModel({
|
||||||
|
@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/tag_model/bloc/add_device_model_state.dart';
|
||||||
@ -20,7 +20,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
final List<ProductModel>? products;
|
final List<ProductModel>? products;
|
||||||
final List<SelectedProduct>? initialSelectedProducts;
|
final List<SelectedProduct>? initialSelectedProducts;
|
||||||
final List<SubspaceTemplateModel>? subspaces;
|
final List<SubspaceTemplateModel>? subspaces;
|
||||||
final List<TagModel>? spaceTagModels;
|
final List<Tag>? spaceTagModels;
|
||||||
final List<String>? allTags;
|
final List<String>? allTags;
|
||||||
final String spaceName;
|
final String spaceName;
|
||||||
final bool isCreate;
|
final bool isCreate;
|
||||||
@ -28,6 +28,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
final BuildContext? pageContext;
|
final BuildContext? pageContext;
|
||||||
final SpaceTemplateModel? spaceModel;
|
final SpaceTemplateModel? spaceModel;
|
||||||
final List<SpaceTemplateModel>? allSpaceModels;
|
final List<SpaceTemplateModel>? allSpaceModels;
|
||||||
|
final List<Tag> projectTags;
|
||||||
|
|
||||||
const AddDeviceTypeModelWidget(
|
const AddDeviceTypeModelWidget(
|
||||||
{super.key,
|
{super.key,
|
||||||
@ -41,7 +42,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
this.pageContext,
|
this.pageContext,
|
||||||
this.otherSpaceModels,
|
this.otherSpaceModels,
|
||||||
this.spaceModel,
|
this.spaceModel,
|
||||||
this.allSpaceModels});
|
this.allSpaceModels,
|
||||||
|
required this.projectTags});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -78,8 +80,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
const EdgeInsets.symmetric(horizontal: 20.0),
|
|
||||||
child: ScrollableGridViewWidget(
|
child: ScrollableGridViewWidget(
|
||||||
isCreate: isCreate,
|
isCreate: isCreate,
|
||||||
products: products,
|
products: products,
|
||||||
@ -112,6 +113,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
allSpaceModels: allSpaceModels,
|
allSpaceModels: allSpaceModels,
|
||||||
products: products,
|
products: products,
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
|
projectTags: projectTags,
|
||||||
pageContext: pageContext,
|
pageContext: pageContext,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
spaceModel: SpaceTemplateModel(
|
spaceModel: SpaceTemplateModel(
|
||||||
@ -137,6 +139,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
addedProducts: initialSelectedProducts ?? [],
|
addedProducts: initialSelectedProducts ?? [],
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
|
projectTags: projectTags,
|
||||||
spaceName: spaceName,
|
spaceName: spaceName,
|
||||||
initialTags: initialTags,
|
initialTags: initialTags,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
@ -149,11 +152,10 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 140,
|
width: 140,
|
||||||
child:
|
child: BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
|
||||||
BlocBuilder<AddDeviceTypeModelBloc, AddDeviceModelState>(
|
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final isDisabled = state is AddDeviceModelLoaded &&
|
final isDisabled =
|
||||||
state.selectedProducts.isEmpty;
|
state is AddDeviceModelLoaded && state.selectedProducts.isEmpty;
|
||||||
|
|
||||||
return DefaultButton(
|
return DefaultButton(
|
||||||
backgroundColor: ColorsManager.secondaryColor,
|
backgroundColor: ColorsManager.secondaryColor,
|
||||||
@ -166,15 +168,13 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
: () async {
|
: () async {
|
||||||
if (state is AddDeviceModelLoaded &&
|
if (state is AddDeviceModelLoaded &&
|
||||||
state.selectedProducts.isNotEmpty) {
|
state.selectedProducts.isNotEmpty) {
|
||||||
final initialTags =
|
final initialTags = TagHelper.generateInitialTags(
|
||||||
TagHelper.generateInitialTags(
|
|
||||||
spaceTagModels: spaceTagModels,
|
spaceTagModels: spaceTagModels,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
);
|
);
|
||||||
|
|
||||||
final dialogTitle = initialTags.isNotEmpty
|
final dialogTitle =
|
||||||
? 'Edit Device'
|
initialTags.isNotEmpty ? 'Edit Device' : 'Assign Tags';
|
||||||
: 'Assign Tags';
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
await showDialog<bool>(
|
await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
@ -184,6 +184,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
addedProducts: state.selectedProducts,
|
addedProducts: state.selectedProducts,
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
|
projectTags: projectTags,
|
||||||
spaceName: spaceName,
|
spaceName: spaceName,
|
||||||
initialTags: initialTags,
|
initialTags: initialTags,
|
||||||
otherSpaceModels: otherSpaceModels,
|
otherSpaceModels: otherSpaceModels,
|
||||||
|
@ -9,10 +9,10 @@ import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_
|
|||||||
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
|
import 'package:syncrow_web/pages/visitor_password/model/device_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 DevicesManagementApi {
|
class DevicesManagementApi {
|
||||||
Future<List<AllDevicesModel>> fetchDevices(String communityId, String spaceId, String projectId) async {
|
Future<List<AllDevicesModel>> fetchDevices(
|
||||||
|
String communityId, String spaceId, String projectId) async {
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: communityId.isNotEmpty && spaceId.isNotEmpty
|
path: communityId.isNotEmpty && spaceId.isNotEmpty
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||||
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 SpaceModelManagementApi {
|
class SpaceModelManagementApi {
|
||||||
Future<List<SpaceTemplateModel>> listSpaceModels(
|
Future<List<SpaceTemplateModel>> listSpaceModels(
|
||||||
@ -33,8 +33,8 @@ class SpaceModelManagementApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> updateSpaceModel(CreateSpaceTemplateBodyModel spaceModel,
|
Future<String?> updateSpaceModel(
|
||||||
String spaceModelUuid, String projectId) async {
|
CreateSpaceTemplateBodyModel spaceModel, String spaceModelUuid, String projectId) async {
|
||||||
final response = await HTTPService().put(
|
final response = await HTTPService().put(
|
||||||
path: ApiEndpoints.updateSpaceModel
|
path: ApiEndpoints.updateSpaceModel
|
||||||
.replaceAll('{projectId}', projectId)
|
.replaceAll('{projectId}', projectId)
|
||||||
@ -47,8 +47,7 @@ class SpaceModelManagementApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SpaceTemplateModel?> getSpaceModel(
|
Future<SpaceTemplateModel?> getSpaceModel(String spaceModelUuid, String projectId) async {
|
||||||
String spaceModelUuid, String projectId) async {
|
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
path: ApiEndpoints.getSpaceModel
|
path: ApiEndpoints.getSpaceModel
|
||||||
.replaceAll('{projectId}', projectId)
|
.replaceAll('{projectId}', projectId)
|
||||||
@ -61,6 +60,36 @@ class SpaceModelManagementApi {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future linkSpaceModel(
|
||||||
|
{required String spaceModelUuid,
|
||||||
|
required String projectId,
|
||||||
|
required List<String> spaceUuids,
|
||||||
|
required bool isOverWrite}) async {
|
||||||
|
final response = await HTTPService().post(
|
||||||
|
path: ApiEndpoints.linkSpaceModel
|
||||||
|
.replaceAll('{projectId}', projectId)
|
||||||
|
.replaceAll('{spaceModelUuid}', spaceModelUuid),
|
||||||
|
showServerMessage: true,
|
||||||
|
body: {"spaceUuids": spaceUuids, "overwrite": isOverWrite},
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
return json;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future validateSpaceModel(String projectId, List<String> spaceUuids) async {
|
||||||
|
final response = await HTTPService().post(
|
||||||
|
path: ApiEndpoints.validateSpaceModel
|
||||||
|
.replaceAll('{projectId}', projectId),
|
||||||
|
showServerMessage: true,
|
||||||
|
body: {"spacesUuids": spaceUuids},
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> deleteSpaceModel(String spaceModelUuid, String projectId) async {
|
Future<bool> deleteSpaceModel(String spaceModelUuid, String projectId) async {
|
||||||
final response = await HTTPService().delete(
|
final response = await HTTPService().delete(
|
||||||
path: ApiEndpoints.getSpaceModel
|
path: ApiEndpoints.getSpaceModel
|
||||||
@ -73,4 +102,17 @@ class SpaceModelManagementApi {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<Tag>> listTags({required String projectId}) async {
|
||||||
|
final response = await HTTPService().get(
|
||||||
|
path: ApiEndpoints.listTags.replaceAll('{projectId}', projectId),
|
||||||
|
expectedResponseModel: (json) {
|
||||||
|
List<dynamic> jsonData = json['data'];
|
||||||
|
return jsonData.map((jsonItem) {
|
||||||
|
return Tag.fromJson(jsonItem);
|
||||||
|
}).toList();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ abstract class ColorsManager {
|
|||||||
static const Color semiTransparentBlackColor = Color(0x3F000000);
|
static const Color semiTransparentBlackColor = Color(0x3F000000);
|
||||||
static const Color transparentColor = Color(0x00000000);
|
static const Color transparentColor = Color(0x00000000);
|
||||||
static const Color spaceColor = Color(0xB2023DFE);
|
static const Color spaceColor = Color(0xB2023DFE);
|
||||||
static const Color counterBackgroundColor = Color(0xCCF4F4F4);
|
static const Color counterBackgroundColor = Color.fromARGB(204, 105, 2, 2);
|
||||||
static const Color neutralGray = Color(0xFFE5E5E5);
|
static const Color neutralGray = Color(0xFFE5E5E5);
|
||||||
static const Color warningRed = Color(0xFFFF6465);
|
static const Color warningRed = Color(0xFFFF6465);
|
||||||
static const Color borderColor = Color(0xFFE5E5E5);
|
static const Color borderColor = Color(0xFFE5E5E5);
|
||||||
|
@ -89,6 +89,13 @@ abstract class ApiEndpoints {
|
|||||||
static const String createSpaceModel = '/projects/{projectId}/space-models';
|
static const String createSpaceModel = '/projects/{projectId}/space-models';
|
||||||
static const String getSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}';
|
static const String getSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}';
|
||||||
static const String updateSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}';
|
static const String updateSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}';
|
||||||
|
//tag
|
||||||
|
static const String listTags = '/projects/{projectId}/tags';
|
||||||
|
|
||||||
|
static const String linkSpaceModel =
|
||||||
|
'/projects/{projectId}/space-models/{spaceModelUuid}/spaces/link';
|
||||||
|
|
||||||
|
static const String validateSpaceModel = '/projects/{projectId}/spaces/validate';
|
||||||
|
|
||||||
static const String roleTypes = '/role/types';
|
static const String roleTypes = '/role/types';
|
||||||
static const String permission = '/permission/{roleUuid}';
|
static const String permission = '/permission/{roleUuid}';
|
||||||
|
@ -402,5 +402,10 @@ class Assets {
|
|||||||
static const String link = 'assets/icons/link.svg';
|
static const String link = 'assets/icons/link.svg';
|
||||||
static const String duplicate = 'assets/icons/duplicate.svg';
|
static const String duplicate = 'assets/icons/duplicate.svg';
|
||||||
static const String spaceDelete = 'assets/icons/space_delete.svg';
|
static const String spaceDelete = 'assets/icons/space_delete.svg';
|
||||||
|
|
||||||
|
static const String deleteSpaceLinkIcon =
|
||||||
|
'assets/icons/delete_space_link_icon.svg';
|
||||||
|
static const String spaceLinkIcon = 'assets/icons/space_link_icon.svg';
|
||||||
|
static const String successIcon = 'assets/icons/success_icon.svg';
|
||||||
|
|
||||||
}
|
}
|
||||||
//user_management.svg
|
|
||||||
|
Reference in New Issue
Block a user