Compare commits
1 Commits
SP-1716-FE
...
revert-SP-
Author | SHA1 | Date | |
---|---|---|---|
b6664ec1ba |
@ -1,8 +0,0 @@
|
|||||||
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<line x1="0.5" y1="2.18557e-08" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
|
|
||||||
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
|
|
||||||
<rect x="16.0922" y="66.3794" width="28.1609" height="66.3793" fill="#C7CDD1"/>
|
|
||||||
<rect x="54.3105" y="24.1379" width="28.1609" height="108.621" fill="#ABB4BA"/>
|
|
||||||
<rect x="92.5288" y="78.4484" width="28.1609" height="54.3103" fill="#C7CDD1"/>
|
|
||||||
<rect x="130.747" y="48.2759" width="28.1609" height="84.4828" fill="#ABB4BA"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 583 B |
@ -1,5 +0,0 @@
|
|||||||
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<line x1="0.5" y1="3.05394e-05" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
|
|
||||||
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
|
|
||||||
<path d="M1.5 132.5C13 132.5 6.58852 66.5 29.5 66.5C46.5 66.5 46.1214 24.9349 68.5 24.5C94.2816 23.999 80.7136 78.5065 106.5 78.5C125.715 78.4952 131.5 48.5 145.5 48.5C159.5 48.5 156.5 96 171.5 96" stroke="#ABB4BA" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 520 B |
@ -1,7 +0,0 @@
|
|||||||
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<line x1="0.5" y1="2.18557e-08" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
|
|
||||||
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
|
|
||||||
<path d="M1.5 132.5C13 132.5 6.58852 66.5 29.5 66.5C46.5 66.5 46.1214 24.9348 68.5 24.5C94.2816 23.999 80.7136 78.5064 106.5 78.5C125.715 78.4951 131.5 48.5 145.5 48.5C159.5 48.5 156.5 95.9999 171.5 95.9999" stroke="#ABB4BA" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="4 4"/>
|
|
||||||
<path d="M1.5 132.5C13 132.5 6.58852 78.4999 29.5 78.4999C46.5 78.4999 45.6214 44.9349 68 44.5C93.7816 43.999 80.7136 27.0065 106.5 27C125.715 26.9952 131.5 63.5 145.5 63.5C159.5 63.5 156.5 113.5 171.5 113.5" stroke="#C7CDD1" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="4 4"/>
|
|
||||||
<path d="M1.5 132.5C13 132.5 6.58852 85.9999 29.5 85.9999C46.5 85.9999 45.6214 11.9348 68 11.4999C93.7816 10.9989 80.7136 43.5064 106.5 43.4999C125.715 43.4951 131.5 35.4999 145.5 35.4999C159.5 35.4999 156.5 105.5 171.5 105.5" stroke="#D5D5D5" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="4 4"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,99 +0,0 @@
|
|||||||
<svg width="181" height="121" viewBox="0 0 181 121" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<line x1="15.5" y1="-2.52181e-08" x2="15.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="45.5" y1="-2.52181e-08" x2="45.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="75.5" y1="-2.52181e-08" x2="75.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="105.5" y1="-2.52181e-08" x2="105.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="135.5" y1="-2.52181e-08" x2="135.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="165.5" y1="-2.52181e-08" x2="165.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="30.5" y1="-2.52181e-08" x2="30.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="60.5" y1="-2.52181e-08" x2="60.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="90.5" y1="-2.52181e-08" x2="90.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="120.5" y1="-2.52181e-08" x2="120.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="150.5" y1="-2.52181e-08" x2="150.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="180.5" y1="-2.52181e-08" x2="180.5" y2="120" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="120.5" x2="-4.52101e-08" y2="120.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="60.5" x2="-4.52101e-08" y2="60.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="90.5" x2="-4.52101e-08" y2="90.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="30.5" x2="-4.52101e-08" y2="30.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="105.5" x2="-4.52101e-08" y2="105.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="45.5" x2="-4.52101e-08" y2="45.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="75.5" x2="-4.52101e-08" y2="75.5" stroke="#B9B9B9"/>
|
|
||||||
<line x1="181" y1="15.5" x2="-4.52101e-08" y2="15.5" stroke="#B9B9B9"/>
|
|
||||||
<rect x="16" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="46" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="61" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="76" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="91" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="106" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="121" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="136" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="151" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="166" y="16" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="16" y="31" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="46" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="61" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="76" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="91" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="106" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="121" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="136" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="151" y="31" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="166" y="31" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="16" y="46" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="46" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="61" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="76" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="91" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="106" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="121" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="136" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="151" y="46" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="166" y="46" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="16" y="61" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="61" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="46" y="61" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="61" y="61" width="14" height="14" fill="#B1B1B1"/>
|
|
||||||
<rect x="76" y="61" width="14" height="14" fill="#B1B1B1"/>
|
|
||||||
<rect x="91" y="61" width="14" height="14" fill="#B1B1B1"/>
|
|
||||||
<rect x="106" y="61" width="14" height="14" fill="#B1B1B1"/>
|
|
||||||
<rect x="121" y="61" width="14" height="14" fill="#B1B1B1"/>
|
|
||||||
<rect x="136" y="61" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="151" y="61" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="166" y="61" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="16" y="76" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="46" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="61" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="76" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="91" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="106" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="121" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="136" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="151" y="76" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="166" y="76" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="16" y="91" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="46" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="61" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="76" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="91" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="106" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="121" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="136" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="151" y="91" width="14" height="14" fill="#D5D5D5"/>
|
|
||||||
<rect x="166" y="91" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="16" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="31" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="46" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="61" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="76" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="91" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="106" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="121" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="136" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="151" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
<rect x="166" y="106" width="14" height="14" fill="#F2F2F2"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 6.1 KiB |
@ -1,7 +0,0 @@
|
|||||||
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<line x1="0.5" y1="2.18557e-08" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
|
|
||||||
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
|
|
||||||
<path d="M1.5 95.9999C13 95.9999 6.58853 66.4999 29.5 66.4999C46.5 66.4999 46.1214 34.9348 68.5 34.4999C94.2816 33.9989 80.7136 65.0065 106.5 65C125.715 64.9952 131.5 50.5 145.5 50.5C159.5 50.5 156.5 70.5 171.5 70.5" stroke="#C7CDD1" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<path d="M1.5 106C13 106 6.58853 76.4999 29.5 76.4999C46.5 76.4999 46.1214 44.9348 68.5 44.4999C94.2816 43.9989 80.7136 75.0065 106.5 75C125.715 74.9952 131.5 60.5 145.5 60.5C159.5 60.5 156.5 80.5 171.5 80.5" stroke="#F2F2F2" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<path d="M1.5 116C13 116 6.58853 86.4999 29.5 86.4999C46.5 86.4999 46.1214 54.9348 68.5 54.4999C94.2816 53.9989 80.7136 85.0065 106.5 85C125.715 84.9952 131.5 70.5 145.5 70.5C159.5 70.5 156.5 90.5 171.5 90.5" stroke="#ABB4BA" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,15 +0,0 @@
|
|||||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<g clip-path="url(#clip0_9717_7433)">
|
|
||||||
<path d="M17.1131 10.6766H15.5664C15.7241 11.1083 15.8102 11.5741 15.8102 12.0596V17.9053C15.8102 18.1077 15.775 18.302 15.7109 18.4827H18.2679C19.2231 18.4827 20.0002 17.7056 20.0002 16.7505V13.5637C20.0002 11.9718 18.7051 10.6766 17.1131 10.6766Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M4.19005 12.0596C4.19005 11.5741 4.27618 11.1083 4.43384 10.6766H2.88712C1.29516 10.6766 0 11.9718 0 13.5637V16.7505C0 17.7057 0.777072 18.4828 1.73227 18.4828H4.28938C4.22528 18.302 4.19005 18.1077 4.19005 17.9053V12.0596Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M11.7679 9.17249H8.23184C6.63989 9.17249 5.34473 10.4676 5.34473 12.0596V17.9053C5.34473 18.2242 5.60324 18.4827 5.92215 18.4827H14.0776C14.3965 18.4827 14.655 18.2242 14.655 17.9053V12.0596C14.655 10.4676 13.3598 9.17249 11.7679 9.17249Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M9.99995 1.51721C8.08541 1.51721 6.52783 3.07479 6.52783 4.98937C6.52783 6.288 7.24459 7.42218 8.30311 8.01765C8.80518 8.30008 9.38401 8.46148 9.99995 8.46148C10.6159 8.46148 11.1947 8.30008 11.6968 8.01765C12.7553 7.42218 13.4721 6.28796 13.4721 4.98937C13.4721 3.07483 11.9145 1.51721 9.99995 1.51721Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M3.90284 4.75354C2.471 4.75354 1.30615 5.91839 1.30615 7.35022C1.30615 8.78206 2.471 9.94691 3.90284 9.94691C4.26604 9.94691 4.6119 9.87168 4.92608 9.73644C5.46929 9.50257 5.91718 9.08859 6.19433 8.57003C6.38886 8.20609 6.49952 7.79089 6.49952 7.35022C6.49952 5.91843 5.33468 4.75354 3.90284 4.75354Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M16.0972 4.75354C14.6653 4.75354 13.5005 5.91839 13.5005 7.35022C13.5005 7.79093 13.6112 8.20612 13.8057 8.57003C14.0828 9.08863 14.5307 9.50261 15.0739 9.73644C15.3881 9.87168 15.734 9.94691 16.0972 9.94691C17.529 9.94691 18.6939 8.78206 18.6939 7.35022C18.6939 5.91839 17.529 4.75354 16.0972 4.75354Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<clipPath id="clip0_9717_7433">
|
|
||||||
<rect width="20" height="20" fill="white"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.1 KiB |
@ -1,4 +0,0 @@
|
|||||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M10.0002 5.97498L3.12109 11.2683V18.3601H8.64871V13.163H11.5852V18.3601H16.8794V11.2683L10.0002 5.97498Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M17.1673 7.15356V3.52759H14.2702V4.92485L10 1.63989L0 9.33274L1.38043 11.1271L10 4.49458L18.6196 11.1272L20 9.33278L17.1673 7.15356Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 433 B |
@ -1,4 +0,0 @@
|
|||||||
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M37.8033 16.3567C37.2313 15.7848 36.3039 15.7847 35.7318 16.3568L21.5532 30.5353L14.2681 23.2504C13.6962 22.6784 12.7686 22.6783 12.1966 23.2505C11.6246 23.8226 11.6246 24.75 12.1966 25.3221L20.5174 33.6427C20.8034 33.9287 21.1783 34.0717 21.5531 34.0717C21.928 34.0717 22.3029 33.9287 22.5888 33.6426L37.8033 18.4283C38.3754 17.8563 38.3754 16.9288 37.8033 16.3567Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
<path d="M42.6776 7.32236C37.9558 2.60049 31.6776 0 25 0C18.3223 0 12.0442 2.60049 7.32236 7.32236C2.60039 12.0443 0 18.3224 0 25C0 31.6778 2.60039 37.9559 7.32236 42.6777C12.0441 47.3996 18.3223 50 25 50C31.6777 50 37.9558 47.3996 42.6776 42.6777C47.3995 37.9559 50 31.6778 50 25C50 18.3224 47.3995 12.0443 42.6776 7.32236ZM25 47.0703C12.8304 47.0703 2.92969 37.1696 2.92969 25C2.92969 12.8304 12.8304 2.92969 25 2.92969C37.1696 2.92969 47.0703 12.8304 47.0703 25C47.0703 37.1696 37.1696 47.0703 25 47.0703Z" fill="#023DFE" fill-opacity="0.7"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,52 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/icon_text_button.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class BookingPage extends StatelessWidget {
|
|
||||||
const BookingPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
color: Colors.blueGrey[100],
|
|
||||||
child: const Center(
|
|
||||||
child: Text(
|
|
||||||
'Side bar',
|
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
Expanded(
|
|
||||||
flex: 4,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(20.0),
|
|
||||||
child: SizedBox(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SvgTextButton(
|
|
||||||
svgAsset: Assets.homeIcon,
|
|
||||||
label: 'Manage Bookable Spaces',
|
|
||||||
onPressed: () {}),
|
|
||||||
SizedBox(width: 20),
|
|
||||||
SvgTextButton(
|
|
||||||
svgAsset: Assets.groupIcon,
|
|
||||||
label: 'Manage Users',
|
|
||||||
onPressed: () {})
|
|
||||||
],
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class SvgTextButton extends StatelessWidget {
|
|
||||||
final String svgAsset;
|
|
||||||
final String label;
|
|
||||||
final VoidCallback onPressed;
|
|
||||||
final Color backgroundColor;
|
|
||||||
final Color svgColor;
|
|
||||||
final Color labelColor;
|
|
||||||
final double borderRadius;
|
|
||||||
final List<BoxShadow> boxShadow;
|
|
||||||
final double svgSize;
|
|
||||||
|
|
||||||
const SvgTextButton({
|
|
||||||
super.key,
|
|
||||||
required this.svgAsset,
|
|
||||||
required this.label,
|
|
||||||
required this.onPressed,
|
|
||||||
this.backgroundColor = ColorsManager.circleRolesBackground,
|
|
||||||
this.svgColor = const Color(0xFF496EFF),
|
|
||||||
this.labelColor = Colors.black87,
|
|
||||||
this.borderRadius = 10.0,
|
|
||||||
this.boxShadow = const [
|
|
||||||
BoxShadow(
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
blurRadius: 12,
|
|
||||||
offset: Offset(0, 4),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
this.svgSize = 24.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius: BorderRadius.circular(borderRadius),
|
|
||||||
onTap: onPressed,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: backgroundColor,
|
|
||||||
borderRadius: BorderRadius.circular(borderRadius),
|
|
||||||
boxShadow: boxShadow,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SvgPicture.asset(
|
|
||||||
svgAsset,
|
|
||||||
width: svgSize,
|
|
||||||
height: svgSize,
|
|
||||||
color: svgColor,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: TextStyle(
|
|
||||||
color: labelColor,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,86 +2,302 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
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/booking_system/view/booking_page.dart';
|
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/view/access_overview_content.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/custom_table.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/date_time_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.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';
|
||||||
|
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
|
||||||
|
// import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
|
|
||||||
class AccessManagementPage extends StatefulWidget {
|
class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
|
||||||
const AccessManagementPage({super.key});
|
const AccessManagementPage({super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
State<AccessManagementPage> createState() => _AccessManagementPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AccessManagementPageState extends State<AccessManagementPage>
|
|
||||||
with HelperResponsiveLayout {
|
|
||||||
final PageController _pageController = PageController(initialPage: 0);
|
|
||||||
int _currentPageIndex = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_pageController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
final isLargeScreen = isLargeScreenSize(context);
|
||||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
final isSmallScreen = isSmallScreenSize(context);
|
||||||
child: WebScaffold(
|
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
||||||
|
final padding =
|
||||||
|
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
||||||
|
|
||||||
|
return WebScaffold(
|
||||||
enableMenuSidebar: false,
|
enableMenuSidebar: false,
|
||||||
appBarTitle: Text(
|
appBarTitle: Text(
|
||||||
'Access Management',
|
'Access Management',
|
||||||
style: ResponsiveTextTheme.of(context).deviceManagementTitle,
|
style: ResponsiveTextTheme.of(context).deviceManagementTitle,
|
||||||
),
|
),
|
||||||
centerBody: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => _switchPage(0),
|
|
||||||
child: Text(
|
|
||||||
'Access Overview',
|
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
|
||||||
color: _currentPageIndex == 0 ? Colors.white : Colors.grey,
|
|
||||||
fontWeight: _currentPageIndex == 0
|
|
||||||
? FontWeight.w700
|
|
||||||
: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => _switchPage(1),
|
|
||||||
child: Text(
|
|
||||||
'Booking System',
|
|
||||||
style: context.textTheme.titleMedium?.copyWith(
|
|
||||||
color: _currentPageIndex == 1 ? Colors.white : Colors.grey,
|
|
||||||
fontWeight: _currentPageIndex == 1
|
|
||||||
? FontWeight.w700
|
|
||||||
: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
rightBody: const NavigateHomeGridView(),
|
rightBody: const NavigateHomeGridView(),
|
||||||
scaffoldBody: PageView(
|
scaffoldBody: BlocProvider(
|
||||||
controller: _pageController,
|
create: (BuildContext context) =>
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
AccessBloc()..add(FetchTableData()),
|
||||||
children: const [
|
child: BlocConsumer<AccessBloc, AccessState>(
|
||||||
AccessOverviewContent(),
|
listener: (context, state) {},
|
||||||
BookingPage(),
|
builder: (context, state) {
|
||||||
],
|
final accessBloc = BlocProvider.of<AccessBloc>(context);
|
||||||
|
final filteredData = accessBloc.filteredData;
|
||||||
|
return state is AccessLoaded
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: Container(
|
||||||
|
padding: padding,
|
||||||
|
height: MediaQuery.of(context).size.height,
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
FilterWidget(
|
||||||
|
size: MediaQuery.of(context).size,
|
||||||
|
tabs: accessBloc.tabs,
|
||||||
|
selectedIndex: accessBloc.selectedIndex,
|
||||||
|
onTabChanged: (index) {
|
||||||
|
accessBloc.add(TabChangedEvent(index));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
if (isSmallScreen || isHalfMediumScreen)
|
||||||
|
_buildSmallSearchFilters(context, accessBloc)
|
||||||
|
else
|
||||||
|
_buildNormalSearchWidgets(context, accessBloc),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
_buildVisitorAdminPasswords(context, accessBloc),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Expanded(
|
||||||
|
child: DynamicTable(
|
||||||
|
tableName: 'AccessManagement',
|
||||||
|
uuidIndex: 1,
|
||||||
|
withSelectAll: true,
|
||||||
|
isEmpty: filteredData.isEmpty,
|
||||||
|
withCheckBox: false,
|
||||||
|
size: MediaQuery.of(context).size,
|
||||||
|
cellDecoration: containerDecoration,
|
||||||
|
headers: const [
|
||||||
|
'Name',
|
||||||
|
'Access Type',
|
||||||
|
'Access Start',
|
||||||
|
'Access End',
|
||||||
|
'Accessible Device',
|
||||||
|
'Authorizer',
|
||||||
|
'Authorization Date & Time',
|
||||||
|
'Access Status'
|
||||||
|
],
|
||||||
|
data: filteredData.map((item) {
|
||||||
|
return [
|
||||||
|
item.passwordName,
|
||||||
|
item.passwordType.value,
|
||||||
|
accessBloc
|
||||||
|
.timestampToDate(item.effectiveTime),
|
||||||
|
accessBloc
|
||||||
|
.timestampToDate(item.invalidTime),
|
||||||
|
item.deviceName.toString(),
|
||||||
|
item.authorizerEmail.toString(),
|
||||||
|
accessBloc
|
||||||
|
.timestampToDate(item.invalidTime),
|
||||||
|
item.passwordStatus.value,
|
||||||
|
];
|
||||||
|
}).toList(),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrap _buildVisitorAdminPasswords(
|
||||||
|
BuildContext context, AccessBloc accessBloc) {
|
||||||
|
return Wrap(
|
||||||
|
spacing: 10,
|
||||||
|
runSpacing: 10,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 205,
|
||||||
|
height: 42,
|
||||||
|
decoration: containerDecoration,
|
||||||
|
child: DefaultButton(
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return const VisitorPasswordDialog();
|
||||||
|
},
|
||||||
|
).then((v) {
|
||||||
|
if (v != null) {
|
||||||
|
accessBloc.add(FetchTableData());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
borderRadius: 8,
|
||||||
|
child: Text(
|
||||||
|
'Create Visitor Password ',
|
||||||
|
style: context.textTheme.titleSmall!
|
||||||
|
.copyWith(color: Colors.white, fontSize: 12),
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
),
|
// Container(
|
||||||
|
// width: 133,
|
||||||
|
// height: 42,
|
||||||
|
// decoration: containerDecoration,
|
||||||
|
// child: DefaultButton(
|
||||||
|
// borderRadius: 8,
|
||||||
|
// backgroundColor: ColorsManager.whiteColors,
|
||||||
|
// child: Text(
|
||||||
|
// 'Admin Password',
|
||||||
|
// style: context.textTheme.titleSmall!
|
||||||
|
// .copyWith(color: Colors.black, fontSize: 12),
|
||||||
|
// )),
|
||||||
|
// ),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _switchPage(int index) {
|
Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) {
|
||||||
setState(() => _currentPageIndex = index);
|
// TimeOfDay _selectedTime = TimeOfDay.now();
|
||||||
_pageController.jumpToPage(index);
|
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
textBaseline: TextBaseline.ideographic,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 250,
|
||||||
|
child: CustomWebTextField(
|
||||||
|
controller: accessBloc.passwordName,
|
||||||
|
height: 43,
|
||||||
|
isRequired: false,
|
||||||
|
textFieldName: 'Name',
|
||||||
|
description: '',
|
||||||
|
onSubmitted: (value) {
|
||||||
|
accessBloc.add(FilterDataEvent(
|
||||||
|
emailAuthorizer:
|
||||||
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
SizedBox(
|
||||||
|
width: 250,
|
||||||
|
child: CustomWebTextField(
|
||||||
|
controller: accessBloc.emailAuthorizer,
|
||||||
|
height: 43,
|
||||||
|
isRequired: false,
|
||||||
|
textFieldName: 'Authorizer',
|
||||||
|
description: '',
|
||||||
|
onSubmitted: (value) {
|
||||||
|
accessBloc.add(FilterDataEvent(
|
||||||
|
emailAuthorizer:
|
||||||
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
SizedBox(
|
||||||
|
child: DateTimeWebWidget(
|
||||||
|
icon: Assets.calendarIcon,
|
||||||
|
isRequired: false,
|
||||||
|
title: 'Access Time',
|
||||||
|
size: MediaQuery.of(context).size,
|
||||||
|
endTime: () {
|
||||||
|
accessBloc.add(SelectTime(context: context, isStart: false));
|
||||||
|
},
|
||||||
|
startTime: () {
|
||||||
|
accessBloc.add(SelectTime(context: context, isStart: true));
|
||||||
|
},
|
||||||
|
firstString: BlocProvider.of<AccessBloc>(context).startTime,
|
||||||
|
secondString: BlocProvider.of<AccessBloc>(context).endTime,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
SearchResetButtons(
|
||||||
|
onSearch: () {
|
||||||
|
accessBloc.add(FilterDataEvent(
|
||||||
|
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
},
|
||||||
|
onReset: () {
|
||||||
|
accessBloc.add(ResetSearch());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSmallSearchFilters(BuildContext context, AccessBloc accessBloc) {
|
||||||
|
return Wrap(
|
||||||
|
spacing: 20,
|
||||||
|
runSpacing: 10,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 300,
|
||||||
|
child: CustomWebTextField(
|
||||||
|
controller: accessBloc.passwordName,
|
||||||
|
isRequired: true,
|
||||||
|
height: 40,
|
||||||
|
textFieldName: 'Name',
|
||||||
|
description: '',
|
||||||
|
onSubmitted: (value) {
|
||||||
|
accessBloc.add(FilterDataEvent(
|
||||||
|
emailAuthorizer:
|
||||||
|
accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
DateTimeWebWidget(
|
||||||
|
icon: Assets.calendarIcon,
|
||||||
|
isRequired: false,
|
||||||
|
title: 'Access Time',
|
||||||
|
size: MediaQuery.of(context).size,
|
||||||
|
endTime: () {
|
||||||
|
accessBloc.add(SelectTime(context: context, isStart: false));
|
||||||
|
},
|
||||||
|
startTime: () {
|
||||||
|
accessBloc.add(SelectTime(context: context, isStart: true));
|
||||||
|
},
|
||||||
|
firstString: BlocProvider.of<AccessBloc>(context).startTime,
|
||||||
|
secondString: BlocProvider.of<AccessBloc>(context).endTime,
|
||||||
|
),
|
||||||
|
SearchResetButtons(
|
||||||
|
onSearch: () {
|
||||||
|
accessBloc.add(FilterDataEvent(
|
||||||
|
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
||||||
|
selectedTabIndex:
|
||||||
|
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
||||||
|
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
||||||
|
startTime: accessBloc.effectiveTimeTimeStamp,
|
||||||
|
endTime: accessBloc.expirationTimeTimeStamp));
|
||||||
|
},
|
||||||
|
onReset: () {
|
||||||
|
accessBloc.add(ResetSearch());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,289 +0,0 @@
|
|||||||
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/custom_table.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/date_time_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/filter/filter_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
|
|
||||||
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/app_enum.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
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_event.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
|
||||||
|
|
||||||
class AccessOverviewContent extends StatelessWidget
|
|
||||||
with HelperResponsiveLayout {
|
|
||||||
const AccessOverviewContent({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final isLargeScreen = isLargeScreenSize(context);
|
|
||||||
final isSmallScreen = isSmallScreenSize(context);
|
|
||||||
final isHalfMediumScreen = isHafMediumScreenSize(context);
|
|
||||||
final padding =
|
|
||||||
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
|
|
||||||
|
|
||||||
return BlocProvider(
|
|
||||||
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
|
|
||||||
child: BlocConsumer<AccessBloc, AccessState>(
|
|
||||||
listener: (context, state) {},
|
|
||||||
builder: (context, state) {
|
|
||||||
final accessBloc = BlocProvider.of<AccessBloc>(context);
|
|
||||||
final filteredData = accessBloc.filteredData;
|
|
||||||
return state is AccessLoaded
|
|
||||||
? const Center(child: CircularProgressIndicator())
|
|
||||||
: Container(
|
|
||||||
padding: padding,
|
|
||||||
height: MediaQuery.of(context).size.height,
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
FilterWidget(
|
|
||||||
size: MediaQuery.of(context).size,
|
|
||||||
tabs: accessBloc.tabs,
|
|
||||||
selectedIndex: accessBloc.selectedIndex,
|
|
||||||
onTabChanged: (index) {
|
|
||||||
accessBloc.add(TabChangedEvent(index));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
if (isSmallScreen || isHalfMediumScreen)
|
|
||||||
_buildSmallSearchFilters(context, accessBloc)
|
|
||||||
else
|
|
||||||
_buildNormalSearchWidgets(context, accessBloc),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
_buildVisitorAdminPasswords(context, accessBloc),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Expanded(
|
|
||||||
child: DynamicTable(
|
|
||||||
tableName: 'AccessManagement',
|
|
||||||
uuidIndex: 1,
|
|
||||||
withSelectAll: true,
|
|
||||||
isEmpty: filteredData.isEmpty,
|
|
||||||
withCheckBox: false,
|
|
||||||
size: MediaQuery.of(context).size,
|
|
||||||
cellDecoration: containerDecoration,
|
|
||||||
headers: const [
|
|
||||||
'Name',
|
|
||||||
'Access Type',
|
|
||||||
'Access Start',
|
|
||||||
'Access End',
|
|
||||||
'Accessible Device',
|
|
||||||
'Authorizer',
|
|
||||||
'Authorization Date & Time',
|
|
||||||
'Access Status'
|
|
||||||
],
|
|
||||||
data: filteredData.map((item) {
|
|
||||||
return [
|
|
||||||
item.passwordName,
|
|
||||||
item.passwordType.value,
|
|
||||||
accessBloc.timestampToDate(item.effectiveTime),
|
|
||||||
accessBloc.timestampToDate(item.invalidTime),
|
|
||||||
item.deviceName.toString(),
|
|
||||||
item.authorizerEmail.toString(),
|
|
||||||
accessBloc.timestampToDate(item.invalidTime),
|
|
||||||
item.passwordStatus.value,
|
|
||||||
];
|
|
||||||
}).toList(),
|
|
||||||
)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Wrap _buildVisitorAdminPasswords(
|
|
||||||
BuildContext context, AccessBloc accessBloc) {
|
|
||||||
return Wrap(
|
|
||||||
spacing: 10,
|
|
||||||
runSpacing: 10,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: 205,
|
|
||||||
height: 42,
|
|
||||||
decoration: containerDecoration,
|
|
||||||
child: DefaultButton(
|
|
||||||
onPressed: () {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return const VisitorPasswordDialog();
|
|
||||||
},
|
|
||||||
).then((v) {
|
|
||||||
if (v != null) {
|
|
||||||
accessBloc.add(FetchTableData());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
borderRadius: 8,
|
|
||||||
child: Text(
|
|
||||||
'Create Visitor Password ',
|
|
||||||
style: context.textTheme.titleSmall!
|
|
||||||
.copyWith(color: Colors.white, fontSize: 12),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
// Container(
|
|
||||||
// width: 133,
|
|
||||||
// height: 42,
|
|
||||||
// decoration: containerDecoration,
|
|
||||||
// child: DefaultButton(
|
|
||||||
// borderRadius: 8,
|
|
||||||
// backgroundColor: ColorsManager.whiteColors,
|
|
||||||
// child: Text(
|
|
||||||
// 'Admin Password',
|
|
||||||
// style: context.textTheme.titleSmall!
|
|
||||||
// .copyWith(color: Colors.black, fontSize: 12),
|
|
||||||
// )),
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) {
|
|
||||||
// TimeOfDay _selectedTime = TimeOfDay.now();
|
|
||||||
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
textBaseline: TextBaseline.ideographic,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 250,
|
|
||||||
child: CustomWebTextField(
|
|
||||||
controller: accessBloc.passwordName,
|
|
||||||
height: 43,
|
|
||||||
isRequired: false,
|
|
||||||
textFieldName: 'Name',
|
|
||||||
description: '',
|
|
||||||
onSubmitted: (value) {
|
|
||||||
accessBloc.add(FilterDataEvent(
|
|
||||||
emailAuthorizer:
|
|
||||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
|
||||||
selectedTabIndex:
|
|
||||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 15),
|
|
||||||
SizedBox(
|
|
||||||
width: 250,
|
|
||||||
child: CustomWebTextField(
|
|
||||||
controller: accessBloc.emailAuthorizer,
|
|
||||||
height: 43,
|
|
||||||
isRequired: false,
|
|
||||||
textFieldName: 'Authorizer',
|
|
||||||
description: '',
|
|
||||||
onSubmitted: (value) {
|
|
||||||
accessBloc.add(FilterDataEvent(
|
|
||||||
emailAuthorizer:
|
|
||||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
|
||||||
selectedTabIndex:
|
|
||||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 15),
|
|
||||||
SizedBox(
|
|
||||||
child: DateTimeWebWidget(
|
|
||||||
icon: Assets.calendarIcon,
|
|
||||||
isRequired: false,
|
|
||||||
title: 'Access Time',
|
|
||||||
size: MediaQuery.of(context).size,
|
|
||||||
endTime: () {
|
|
||||||
accessBloc.add(SelectTime(context: context, isStart: false));
|
|
||||||
},
|
|
||||||
startTime: () {
|
|
||||||
accessBloc.add(SelectTime(context: context, isStart: true));
|
|
||||||
},
|
|
||||||
firstString: BlocProvider.of<AccessBloc>(context).startTime,
|
|
||||||
secondString: BlocProvider.of<AccessBloc>(context).endTime,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 15),
|
|
||||||
SearchResetButtons(
|
|
||||||
onSearch: () {
|
|
||||||
accessBloc.add(FilterDataEvent(
|
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
|
||||||
selectedTabIndex:
|
|
||||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
|
||||||
},
|
|
||||||
onReset: () {
|
|
||||||
accessBloc.add(ResetSearch());
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSmallSearchFilters(BuildContext context, AccessBloc accessBloc) {
|
|
||||||
return Wrap(
|
|
||||||
spacing: 20,
|
|
||||||
runSpacing: 10,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 300,
|
|
||||||
child: CustomWebTextField(
|
|
||||||
controller: accessBloc.passwordName,
|
|
||||||
isRequired: true,
|
|
||||||
height: 40,
|
|
||||||
textFieldName: 'Name',
|
|
||||||
description: '',
|
|
||||||
onSubmitted: (value) {
|
|
||||||
accessBloc.add(FilterDataEvent(
|
|
||||||
emailAuthorizer:
|
|
||||||
accessBloc.emailAuthorizer.text.toLowerCase(),
|
|
||||||
selectedTabIndex:
|
|
||||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
DateTimeWebWidget(
|
|
||||||
icon: Assets.calendarIcon,
|
|
||||||
isRequired: false,
|
|
||||||
title: 'Access Time',
|
|
||||||
size: MediaQuery.of(context).size,
|
|
||||||
endTime: () {
|
|
||||||
accessBloc.add(SelectTime(context: context, isStart: false));
|
|
||||||
},
|
|
||||||
startTime: () {
|
|
||||||
accessBloc.add(SelectTime(context: context, isStart: true));
|
|
||||||
},
|
|
||||||
firstString: BlocProvider.of<AccessBloc>(context).startTime,
|
|
||||||
secondString: BlocProvider.of<AccessBloc>(context).endTime,
|
|
||||||
),
|
|
||||||
SearchResetButtons(
|
|
||||||
onSearch: () {
|
|
||||||
accessBloc.add(FilterDataEvent(
|
|
||||||
emailAuthorizer: accessBloc.emailAuthorizer.text.toLowerCase(),
|
|
||||||
selectedTabIndex:
|
|
||||||
BlocProvider.of<AccessBloc>(context).selectedIndex,
|
|
||||||
passwordName: accessBloc.passwordName.text.toLowerCase(),
|
|
||||||
startTime: accessBloc.effectiveTimeTimeStamp,
|
|
||||||
endTime: accessBloc.expirationTimeTimeStamp));
|
|
||||||
},
|
|
||||||
onReset: () {
|
|
||||||
accessBloc.add(ResetSearch());
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -39,12 +39,8 @@ class AnalyticsDevice {
|
|||||||
? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>)
|
? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>)
|
||||||
: null,
|
: null,
|
||||||
spaceUuid: json['spaceUuid'] as String?,
|
spaceUuid: json['spaceUuid'] as String?,
|
||||||
latitude: json['lat'] != null && json['lat'] != ''
|
latitude: json['lat'] != null ? double.parse(json['lat'] as String? ?? '0.0') : null,
|
||||||
? double.tryParse(json['lat']?.toString() ?? '0.0')
|
longitude: json['lon'] != null ? double.parse(json['lon'] as String? ?? '0.0') : null,
|
||||||
: null,
|
|
||||||
longitude: json['lon'] != null && json['lon'] != ''
|
|
||||||
? double.tryParse(json['lon']?.toString() ?? '0.0')
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,11 +46,11 @@ class AirQualityDistributionBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onClearAirQualityDistribution(
|
Future<void> _onClearAirQualityDistribution(
|
||||||
ClearAirQualityDistribution event,
|
ClearAirQualityDistribution event,
|
||||||
Emitter<AirQualityDistributionState> emit,
|
Emitter<AirQualityDistributionState> emit,
|
||||||
) {
|
) async {
|
||||||
emit(AirQualityDistributionState(selectedAqiType: state.selectedAqiType));
|
emit(const AirQualityDistributionState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateAqiTypeEvent(
|
void _onUpdateAqiTypeEvent(
|
||||||
|
@ -75,6 +75,6 @@ class RangeOfAqiBloc extends Bloc<RangeOfAqiEvent, RangeOfAqiState> {
|
|||||||
ClearRangeOfAqiEvent event,
|
ClearRangeOfAqiEvent event,
|
||||||
Emitter<RangeOfAqiState> emit,
|
Emitter<RangeOfAqiState> emit,
|
||||||
) {
|
) {
|
||||||
emit(RangeOfAqiState(selectedAqiType: state.selectedAqiType));
|
emit(const RangeOfAqiState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ class AqiDistributionChart extends StatelessWidget {
|
|||||||
return BarChart(
|
return BarChart(
|
||||||
BarChartData(
|
BarChartData(
|
||||||
maxY: 100.1,
|
maxY: 100.1,
|
||||||
alignment: BarChartAlignment.start,
|
|
||||||
gridData: EnergyManagementChartsHelper.gridData(
|
gridData: EnergyManagementChartsHelper.gridData(
|
||||||
horizontalInterval: 20,
|
horizontalInterval: 20,
|
||||||
),
|
),
|
||||||
|
@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/air_quality_distribution/air_quality_distribution_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/air_quality_distribution/air_quality_distribution_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class AqiDistributionChartBox extends StatelessWidget {
|
class AqiDistributionChartBox extends StatelessWidget {
|
||||||
@ -34,20 +32,8 @@ class AqiDistributionChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Visibility(
|
Expanded(
|
||||||
visible: state.chartData.isNotEmpty,
|
child: AqiDistributionChart(chartData: state.chartData),
|
||||||
replacement: AnalyticsChartEmptyStateWidget(
|
|
||||||
isLoading: state.status == AirQualityDistributionStatus.loading,
|
|
||||||
isError: state.status == AirQualityDistributionStatus.failure,
|
|
||||||
isInitial: state.status == AirQualityDistributionStatus.initial,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
iconPath: Assets.emptyBarredChart,
|
|
||||||
),
|
|
||||||
child: Expanded(
|
|
||||||
child: AqiDistributionChart(
|
|
||||||
chartData: state.chartData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -34,7 +34,6 @@ class AqiDistributionChartTitle extends StatelessWidget {
|
|||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: AqiTypeDropdown(
|
child: AqiTypeDropdown(
|
||||||
selectedAqiType: context.watch<AirQualityDistributionBloc>().state.selectedAqiType,
|
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
final bloc = context.read<AirQualityDistributionBloc>();
|
final bloc = context.read<AirQualityDistributionBloc>();
|
||||||
|
@ -18,20 +18,19 @@ enum AqiType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AqiTypeDropdown extends StatefulWidget {
|
class AqiTypeDropdown extends StatefulWidget {
|
||||||
const AqiTypeDropdown({
|
const AqiTypeDropdown({super.key, required this.onChanged});
|
||||||
required this.onChanged,
|
|
||||||
this.selectedAqiType,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final ValueChanged<AqiType?> onChanged;
|
final ValueChanged<AqiType?> onChanged;
|
||||||
final AqiType? selectedAqiType;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AqiTypeDropdown> createState() => _AqiTypeDropdownState();
|
State<AqiTypeDropdown> createState() => _AqiTypeDropdownState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
||||||
|
AqiType? _selectedItem = AqiType.aqi;
|
||||||
|
|
||||||
|
void _updateSelectedItem(AqiType? item) => setState(() => _selectedItem = item);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -42,8 +41,8 @@ class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
|||||||
width: 1,
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: DropdownButton<AqiType>(
|
child: DropdownButton<AqiType?>(
|
||||||
value: widget.selectedAqiType,
|
value: _selectedItem,
|
||||||
isDense: true,
|
isDense: true,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
dropdownColor: ColorsManager.whiteColors,
|
dropdownColor: ColorsManager.whiteColors,
|
||||||
@ -60,7 +59,10 @@ class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
|||||||
items: AqiType.values
|
items: AqiType.values
|
||||||
.map((e) => DropdownMenuItem(value: e, child: Text(e.value)))
|
.map((e) => DropdownMenuItem(value: e, child: Text(e.value)))
|
||||||
.toList(),
|
.toList(),
|
||||||
onChanged: widget.onChanged,
|
onChanged: (value) {
|
||||||
|
_updateSelectedItem(value);
|
||||||
|
widget.onChanged(value);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/range_of_aqi/range_of_aqi_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/range_of_aqi/range_of_aqi_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_title.dart';
|
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_title.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class RangeOfAqiChartBox extends StatelessWidget {
|
class RangeOfAqiChartBox extends StatelessWidget {
|
||||||
@ -34,20 +32,10 @@ class RangeOfAqiChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Visibility(
|
Expanded(
|
||||||
visible: state.filteredRangeOfAqi.isNotEmpty,
|
child: RangeOfAqiChart(
|
||||||
replacement: AnalyticsChartEmptyStateWidget(
|
chartData: state.filteredRangeOfAqi,
|
||||||
isLoading: state.status == RangeOfAqiStatus.loading,
|
selectedAqiType: state.selectedAqiType,
|
||||||
isError: state.status == RangeOfAqiStatus.failure,
|
|
||||||
isInitial: state.status == RangeOfAqiStatus.initial,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
iconPath: Assets.emptyRangeOfAqi,
|
|
||||||
),
|
|
||||||
child: Expanded(
|
|
||||||
child: RangeOfAqiChart(
|
|
||||||
chartData: state.filteredRangeOfAqi,
|
|
||||||
selectedAqiType: state.selectedAqiType,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -63,15 +63,15 @@ class RangeOfAqiChartTitle extends StatelessWidget {
|
|||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: AqiTypeDropdown(
|
child: AqiTypeDropdown(
|
||||||
selectedAqiType: context.watch<RangeOfAqiBloc>().state.selectedAqiType,
|
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
||||||
final spaceUuid = spaceTreeState.selectedSpaces.firstOrNull;
|
final spaceUuid = spaceTreeState.selectedSpaces.firstOrNull;
|
||||||
|
|
||||||
|
if (spaceUuid == null) return;
|
||||||
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
context.read<RangeOfAqiBloc>().add(UpdateAqiTypeEvent(value));
|
context.read<RangeOfAqiBloc>().add(UpdateAqiTypeEvent(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spaceUuid == null) return;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -38,7 +38,7 @@ class AnalyticsEnergyManagementView extends StatelessWidget {
|
|||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: _padding,
|
padding: _padding,
|
||||||
height: MediaQuery.sizeOf(context).height * 1.05,
|
height: MediaQuery.sizeOf(context).height * 1,
|
||||||
child: const Column(
|
child: const Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -5,10 +5,8 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/ener
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
||||||
@ -56,24 +54,8 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(height: 0),
|
const Divider(height: 0),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Visibility(
|
Expanded(
|
||||||
visible: state.chartData.isNotEmpty &&
|
child: EnergyConsumptionPerDeviceChart(chartData: state.chartData),
|
||||||
state.chartData
|
|
||||||
.every((e) => e.energy.every((e) => e.value != 0)),
|
|
||||||
replacement: AnalyticsChartEmptyStateWidget(
|
|
||||||
isLoading:
|
|
||||||
state.status == EnergyConsumptionPerDeviceStatus.loading,
|
|
||||||
isError: state.status == EnergyConsumptionPerDeviceStatus.failure,
|
|
||||||
isInitial:
|
|
||||||
state.status == EnergyConsumptionPerDeviceStatus.initial,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
iconPath: Assets.emptyEnergyManagementPerDevice,
|
|
||||||
),
|
|
||||||
child: Expanded(
|
|
||||||
child: EnergyConsumptionPerDeviceChart(
|
|
||||||
chartData: state.chartData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -3,10 +3,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class TotalEnergyConsumptionChartBox extends StatelessWidget {
|
class TotalEnergyConsumptionChartBox extends StatelessWidget {
|
||||||
@ -43,18 +41,7 @@ class TotalEnergyConsumptionChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Visibility(
|
TotalEnergyConsumptionChart(chartData: state.chartData),
|
||||||
visible: state.chartData.isNotEmpty &&
|
|
||||||
state.chartData.every((e) => e.value != 0),
|
|
||||||
replacement: AnalyticsChartEmptyStateWidget(
|
|
||||||
isLoading: state.status == TotalEnergyConsumptionStatus.loading,
|
|
||||||
isError: state.status == TotalEnergyConsumptionStatus.failure,
|
|
||||||
isInitial: state.status == TotalEnergyConsumptionStatus.initial,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
iconPath: Assets.emptyEnergyManagementChart,
|
|
||||||
),
|
|
||||||
child: TotalEnergyConsumptionChart(chartData: state.chartData),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -18,7 +18,6 @@ class OccupancyChart extends StatelessWidget {
|
|||||||
return BarChart(
|
return BarChart(
|
||||||
BarChartData(
|
BarChartData(
|
||||||
maxY: 100.001,
|
maxY: 100.001,
|
||||||
alignment: BarChartAlignment.start,
|
|
||||||
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
||||||
checkToShowHorizontalLine: (value) => true,
|
checkToShowHorizontalLine: (value) => true,
|
||||||
horizontalInterval: 20,
|
horizontalInterval: 20,
|
||||||
|
@ -6,10 +6,8 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/ch
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.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/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class OccupancyChartBox extends StatelessWidget {
|
class OccupancyChartBox extends StatelessWidget {
|
||||||
@ -69,24 +67,7 @@ class OccupancyChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Visibility(
|
Expanded(child: OccupancyChart(chartData: state.chartData)),
|
||||||
visible: state.chartData.isNotEmpty &&
|
|
||||||
state.chartData.every(
|
|
||||||
(e) => e.occupancy.isNotEmpty,
|
|
||||||
),
|
|
||||||
replacement: AnalyticsChartEmptyStateWidget(
|
|
||||||
isLoading: state.status == OccupancyStatus.loading,
|
|
||||||
isError: state.status == OccupancyStatus.failure,
|
|
||||||
isInitial: state.status == OccupancyStatus.initial,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
iconPath: Assets.emptyBarredChart,
|
|
||||||
),
|
|
||||||
child: Expanded(
|
|
||||||
child: OccupancyChart(
|
|
||||||
chartData: state.chartData,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -6,10 +6,8 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/ch
|
|||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart';
|
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
|
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
|
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.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/utils/constants/assets.dart';
|
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class OccupancyHeatMapBox extends StatelessWidget {
|
class OccupancyHeatMapBox extends StatelessWidget {
|
||||||
@ -70,29 +68,16 @@ class OccupancyHeatMapBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Visibility(
|
Expanded(
|
||||||
visible: state.heatMapData.isNotEmpty &&
|
child: OccupancyHeatMap(
|
||||||
state.heatMapData.every(
|
selectedDate:
|
||||||
(e) => e.countTotalPresenceDetected != 0,
|
context.watch<AnalyticsDatePickerBloc>().state.yearlyDate,
|
||||||
),
|
heatMapData: state.heatMapData.asMap().map(
|
||||||
replacement: AnalyticsChartEmptyStateWidget(
|
(_, value) => MapEntry(
|
||||||
isLoading: state.status == OccupancyHeatMapStatus.loading,
|
value.eventDate,
|
||||||
isError: state.status == OccupancyHeatMapStatus.failure,
|
value.countTotalPresenceDetected,
|
||||||
isInitial: state.status == OccupancyHeatMapStatus.initial,
|
|
||||||
errorMessage: state.errorMessage,
|
|
||||||
iconPath: Assets.emptyHeatmap,
|
|
||||||
),
|
|
||||||
child: Expanded(
|
|
||||||
child: OccupancyHeatMap(
|
|
||||||
selectedDate:
|
|
||||||
context.watch<AnalyticsDatePickerBloc>().state.yearlyDate,
|
|
||||||
heatMapData: state.heatMapData.asMap().map(
|
|
||||||
(_, value) => MapEntry(
|
|
||||||
value.eventDate,
|
|
||||||
value.countTotalPresenceDetected,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -17,8 +17,8 @@ class DeviceLocationDetailsServiceDecorator implements DeviceLocationService {
|
|||||||
'reverse',
|
'reverse',
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'format': 'json',
|
'format': 'json',
|
||||||
'lat': 25.1880567,
|
'lat': param.latitude,
|
||||||
'lon': 55.266608,
|
'lon': param.longitude,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/common/widgets/app_loading_indicator.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class AnalyticsChartEmptyStateWidget extends StatelessWidget {
|
|
||||||
const AnalyticsChartEmptyStateWidget({
|
|
||||||
required this.iconPath,
|
|
||||||
this.isLoading = false,
|
|
||||||
this.isError = false,
|
|
||||||
this.isInitial = false,
|
|
||||||
this.errorMessage,
|
|
||||||
this.noDataMessage = 'No data to display',
|
|
||||||
this.initialMessage = 'Please select a space to see data',
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final bool isLoading;
|
|
||||||
final bool isError;
|
|
||||||
final bool isInitial;
|
|
||||||
final String? errorMessage;
|
|
||||||
final String noDataMessage;
|
|
||||||
final String initialMessage;
|
|
||||||
final String iconPath;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Expanded(
|
|
||||||
child: _buildWidgetBasedOnState(context),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildWidgetBasedOnState(BuildContext context) {
|
|
||||||
final widgetsMap = {
|
|
||||||
isLoading: const AppLoadingIndicator(),
|
|
||||||
isInitial: _buildState(context, initialMessage),
|
|
||||||
isError: _buildState(context, errorMessage ?? 'Something went wrong'),
|
|
||||||
};
|
|
||||||
|
|
||||||
return widgetsMap[true] ?? _buildState(context, noDataMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildState(BuildContext context, String message) {
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
spacing: 16,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Expanded(child: SvgPicture.asset(iconPath, fit: BoxFit.contain)),
|
|
||||||
SelectableText(
|
|
||||||
message,
|
|
||||||
style: isError
|
|
||||||
? context.textTheme.bodyMedium?.copyWith(
|
|
||||||
color: ColorsManager.red,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,9 +50,6 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
bool _selectAll = false;
|
bool _selectAll = false;
|
||||||
final ScrollController _verticalScrollController = ScrollController();
|
final ScrollController _verticalScrollController = ScrollController();
|
||||||
final ScrollController _horizontalScrollController = ScrollController();
|
final ScrollController _horizontalScrollController = ScrollController();
|
||||||
static const double _fixedRowHeight = 60;
|
|
||||||
static const double _checkboxColumnWidth = 50;
|
|
||||||
static const double _settingsColumnWidth = 100;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -70,6 +67,7 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
|
|
||||||
bool _compareListOfLists(
|
bool _compareListOfLists(
|
||||||
List<List<dynamic>> oldList, List<List<dynamic>> newList) {
|
List<List<dynamic>> oldList, List<List<dynamic>> newList) {
|
||||||
|
// Check if the old and new lists are the same
|
||||||
if (oldList.length != newList.length) return false;
|
if (oldList.length != newList.length) return false;
|
||||||
|
|
||||||
for (int i = 0; i < oldList.length; i++) {
|
for (int i = 0; i < oldList.length; i++) {
|
||||||
@ -106,130 +104,73 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
context.read<DeviceManagementBloc>().add(UpdateSelection(_selectedRows));
|
context.read<DeviceManagementBloc>().add(UpdateSelection(_selectedRows));
|
||||||
}
|
}
|
||||||
|
|
||||||
double get _totalTableWidth {
|
|
||||||
final hasSettings = widget.headers.contains('Settings');
|
|
||||||
final base = (widget.withCheckBox ? _checkboxColumnWidth : 0) +
|
|
||||||
(hasSettings ? _settingsColumnWidth : 0);
|
|
||||||
final regularCount = widget.headers.length - (hasSettings ? 1 : 0);
|
|
||||||
final regularWidth = (widget.size.width - base) / regularCount;
|
|
||||||
return base + regularCount * regularWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: widget.size.width,
|
|
||||||
height: widget.size.height,
|
|
||||||
decoration: widget.cellDecoration,
|
decoration: widget.cellDecoration,
|
||||||
child: ScrollConfiguration(
|
child: Scrollbar(
|
||||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
controller: _verticalScrollController,
|
||||||
|
thumbVisibility: true,
|
||||||
|
trackVisibility: true,
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
|
//fixed the horizontal scrollbar issue
|
||||||
controller: _horizontalScrollController,
|
controller: _horizontalScrollController,
|
||||||
thumbVisibility: true,
|
thumbVisibility: true,
|
||||||
trackVisibility: true,
|
trackVisibility: true,
|
||||||
notificationPredicate: (notif) =>
|
notificationPredicate: (notif) => notif.depth == 1,
|
||||||
notif.metrics.axis == Axis.horizontal,
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: _horizontalScrollController,
|
controller: _verticalScrollController,
|
||||||
scrollDirection: Axis.horizontal,
|
child: SingleChildScrollView(
|
||||||
child: SizedBox(
|
controller: _horizontalScrollController,
|
||||||
width: _totalTableWidth,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Column(
|
child: SizedBox(
|
||||||
children: [
|
width: widget.size.width,
|
||||||
Container(
|
child: Column(
|
||||||
height: _fixedRowHeight,
|
children: [
|
||||||
decoration: widget.headerDecoration ??
|
Container(
|
||||||
const BoxDecoration(color: ColorsManager.boxColor),
|
decoration: widget.headerDecoration ??
|
||||||
child: Row(
|
const BoxDecoration(
|
||||||
children: [
|
color: ColorsManager.boxColor,
|
||||||
if (widget.withCheckBox)
|
|
||||||
_buildSelectAllCheckbox(_checkboxColumnWidth),
|
|
||||||
for (var i = 0; i < widget.headers.length; i++)
|
|
||||||
_buildTableHeaderCell(
|
|
||||||
widget.headers[i],
|
|
||||||
widget.headers[i] == 'Settings'
|
|
||||||
? _settingsColumnWidth
|
|
||||||
: (_totalTableWidth -
|
|
||||||
(widget.withCheckBox
|
|
||||||
? _checkboxColumnWidth
|
|
||||||
: 0) -
|
|
||||||
(widget.headers.contains('Settings')
|
|
||||||
? _settingsColumnWidth
|
|
||||||
: 0)) /
|
|
||||||
(widget.headers.length -
|
|
||||||
(widget.headers.contains('Settings')
|
|
||||||
? 1
|
|
||||||
: 0)),
|
|
||||||
),
|
),
|
||||||
],
|
child: Row(
|
||||||
|
children: [
|
||||||
|
if (widget.withCheckBox) _buildSelectAllCheckbox(),
|
||||||
|
...List.generate(widget.headers.length, (index) {
|
||||||
|
return _buildTableHeaderCell(
|
||||||
|
widget.headers[index], index);
|
||||||
|
})
|
||||||
|
//...widget.headers.map((header) => _buildTableHeaderCell(header)),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(
|
||||||
|
width: widget.size.width,
|
||||||
Expanded(
|
child: widget.isEmpty
|
||||||
child: widget.isEmpty
|
? _buildEmptyState()
|
||||||
? _buildEmptyState()
|
: Column(
|
||||||
: Scrollbar(
|
children:
|
||||||
controller: _verticalScrollController,
|
List.generate(widget.data.length, (rowIndex) {
|
||||||
thumbVisibility: true,
|
|
||||||
trackVisibility: true,
|
|
||||||
notificationPredicate: (notif) =>
|
|
||||||
notif.metrics.axis == Axis.vertical,
|
|
||||||
child: ListView.builder(
|
|
||||||
controller: _verticalScrollController,
|
|
||||||
itemCount: widget.data.length,
|
|
||||||
itemBuilder: (_, rowIndex) {
|
|
||||||
final row = widget.data[rowIndex];
|
final row = widget.data[rowIndex];
|
||||||
return SizedBox(
|
return Row(
|
||||||
height: _fixedRowHeight,
|
children: [
|
||||||
child: Row(
|
if (widget.withCheckBox)
|
||||||
children: [
|
_buildRowCheckbox(
|
||||||
if (widget.withCheckBox)
|
rowIndex, widget.size.height * 0.08),
|
||||||
_buildRowCheckbox(
|
...row.asMap().entries.map((entry) {
|
||||||
rowIndex,
|
return _buildTableCell(
|
||||||
_checkboxColumnWidth,
|
entry.value.toString(),
|
||||||
),
|
widget.size.height * 0.08,
|
||||||
for (var colIndex = 0;
|
rowIndex: rowIndex,
|
||||||
colIndex < row.length;
|
columnIndex: entry.key,
|
||||||
colIndex++)
|
);
|
||||||
widget.headers[colIndex] == 'Settings'
|
}).toList(),
|
||||||
? buildSettingsIcon(
|
],
|
||||||
width: _settingsColumnWidth,
|
|
||||||
onTap: () => widget
|
|
||||||
.onSettingsPressed
|
|
||||||
?.call(rowIndex),
|
|
||||||
)
|
|
||||||
: _buildTableCell(
|
|
||||||
row[colIndex].toString(),
|
|
||||||
width: widget.headers[
|
|
||||||
colIndex] ==
|
|
||||||
'Settings'
|
|
||||||
? _settingsColumnWidth
|
|
||||||
: (_totalTableWidth -
|
|
||||||
(widget.withCheckBox
|
|
||||||
? _checkboxColumnWidth
|
|
||||||
: 0) -
|
|
||||||
(widget.headers
|
|
||||||
.contains(
|
|
||||||
'Settings')
|
|
||||||
? _settingsColumnWidth
|
|
||||||
: 0)) /
|
|
||||||
(widget.headers.length -
|
|
||||||
(widget.headers
|
|
||||||
.contains(
|
|
||||||
'Settings')
|
|
||||||
? 1
|
|
||||||
: 0)),
|
|
||||||
rowIndex: rowIndex,
|
|
||||||
columnIndex: colIndex,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -269,10 +210,9 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Widget _buildSelectAllCheckbox() {
|
||||||
Widget _buildSelectAllCheckbox(double width) {
|
|
||||||
return Container(
|
return Container(
|
||||||
width: width,
|
width: 50,
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border.symmetric(
|
border: Border.symmetric(
|
||||||
vertical: BorderSide(color: ColorsManager.boxDivider),
|
vertical: BorderSide(color: ColorsManager.boxDivider),
|
||||||
@ -287,11 +227,11 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRowCheckbox(int index, double width) {
|
Widget _buildRowCheckbox(int index, double size) {
|
||||||
return Container(
|
return Container(
|
||||||
width: width,
|
width: 50,
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
height: _fixedRowHeight,
|
height: size,
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
@ -313,47 +253,50 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTableHeaderCell(String title, double width) {
|
Widget _buildTableHeaderCell(String title, int index) {
|
||||||
return Container(
|
return Expanded(
|
||||||
width: width,
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border.symmetric(
|
border: Border.symmetric(
|
||||||
vertical: BorderSide(color: ColorsManager.boxDivider),
|
vertical: BorderSide(color: ColorsManager.boxDivider),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
constraints: BoxConstraints(minHeight: 40, maxHeight: _fixedRowHeight),
|
constraints: const BoxConstraints.expand(height: 40),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
|
padding: EdgeInsets.symmetric(
|
||||||
child: Text(
|
horizontal: index == widget.headers.length - 1 ? 12 : 8.0,
|
||||||
title,
|
vertical: 4),
|
||||||
style: context.textTheme.titleSmall!.copyWith(
|
child: Text(
|
||||||
color: ColorsManager.grayColor,
|
title,
|
||||||
fontSize: 12,
|
style: context.textTheme.titleSmall!.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
color: ColorsManager.grayColor,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTableCell(String content,
|
Widget _buildTableCell(String content, double size,
|
||||||
{required double width,
|
{required int rowIndex, required int columnIndex}) {
|
||||||
required int rowIndex,
|
|
||||||
required int columnIndex}) {
|
|
||||||
bool isBatteryLevel = content.endsWith('%');
|
bool isBatteryLevel = content.endsWith('%');
|
||||||
double? batteryLevel;
|
double? batteryLevel;
|
||||||
|
|
||||||
if (isBatteryLevel) {
|
if (isBatteryLevel) {
|
||||||
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
|
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSettingsColumn = widget.headers[columnIndex] == 'Settings';
|
bool isSettingsColumn = widget.headers[columnIndex] == 'Settings';
|
||||||
if (isSettingsColumn) {
|
if (isSettingsColumn) {
|
||||||
return buildSettingsIcon(
|
return buildSettingsIcon(
|
||||||
width: width, onTap: () => widget.onSettingsPressed?.call(rowIndex));
|
width: 120,
|
||||||
|
height: 60,
|
||||||
|
iconSize: 40,
|
||||||
|
onTap: () => widget.onSettingsPressed?.call(rowIndex),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color? statusColor;
|
Color? statusColor;
|
||||||
@ -377,82 +320,92 @@ class _DynamicTableState extends State<DynamicTable> {
|
|||||||
statusColor = Colors.black;
|
statusColor = Colors.black;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Expanded(
|
||||||
width: width,
|
child: Container(
|
||||||
height: _fixedRowHeight,
|
height: size,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
|
padding: const EdgeInsets.all(5.0),
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
color: ColorsManager.boxDivider,
|
color: ColorsManager.boxDivider,
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
color: Colors.white,
|
alignment: Alignment.centerLeft,
|
||||||
),
|
child: Text(
|
||||||
alignment: Alignment.centerLeft,
|
content,
|
||||||
child: Text(
|
style: TextStyle(
|
||||||
content,
|
color: (batteryLevel != null && batteryLevel < 20)
|
||||||
style: TextStyle(
|
? ColorsManager.red
|
||||||
color: (batteryLevel != null && batteryLevel < 20)
|
: (batteryLevel != null && batteryLevel > 20)
|
||||||
? ColorsManager.red
|
? ColorsManager.green
|
||||||
: (batteryLevel != null && batteryLevel > 20)
|
: statusColor,
|
||||||
? ColorsManager.green
|
fontSize: 13,
|
||||||
: statusColor,
|
fontWeight: FontWeight.w400),
|
||||||
fontSize: 13,
|
maxLines: 2,
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildSettingsIcon({required double width, VoidCallback? onTap}) {
|
Widget buildSettingsIcon(
|
||||||
return Container(
|
{double width = 120,
|
||||||
width: width,
|
double height = 60,
|
||||||
height: _fixedRowHeight,
|
double iconSize = 40,
|
||||||
padding: const EdgeInsets.only(left: 15, top: 10, bottom: 10),
|
VoidCallback? onTap}) {
|
||||||
decoration: const BoxDecoration(
|
return Column(
|
||||||
color: ColorsManager.whiteColors,
|
children: [
|
||||||
border: Border(
|
Container(
|
||||||
bottom: BorderSide(
|
padding: const EdgeInsets.only(top: 10, bottom: 15, left: 10),
|
||||||
color: ColorsManager.boxDivider,
|
margin: const EdgeInsets.only(right: 15),
|
||||||
width: 1.0,
|
decoration: const BoxDecoration(
|
||||||
),
|
color: ColorsManager.whiteColors,
|
||||||
),
|
border: Border(
|
||||||
),
|
bottom: BorderSide(
|
||||||
child: Align(
|
color: ColorsManager.boxDivider,
|
||||||
alignment: Alignment.centerLeft,
|
width: 1.0,
|
||||||
child: Container(
|
|
||||||
width: 50,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color(0xFFF7F8FA),
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withOpacity(0.17),
|
|
||||||
blurRadius: 14,
|
|
||||||
offset: const Offset(0, 4),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
child: InkWell(
|
width: width,
|
||||||
onTap: onTap,
|
child: Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.only(
|
||||||
padding: EdgeInsets.all(8.0),
|
right: 16.0,
|
||||||
child: Center(
|
left: 17.0,
|
||||||
child: SvgPicture.asset(
|
),
|
||||||
Assets.settings,
|
child: Container(
|
||||||
width: 40,
|
width: 50,
|
||||||
height: 20,
|
decoration: BoxDecoration(
|
||||||
color: ColorsManager.primaryColor,
|
color: const Color(0xFFF7F8FA),
|
||||||
|
borderRadius: BorderRadius.circular(height / 2),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.17),
|
||||||
|
blurRadius: 14,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Center(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.settings,
|
||||||
|
width: 40,
|
||||||
|
height: 22,
|
||||||
|
color: ColorsManager.primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,7 @@ import 'package:syncrow_web/utils/constants/assets.dart';
|
|||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class AcDeviceBatchControlView extends StatelessWidget
|
class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayout {
|
||||||
with HelperResponsiveLayout {
|
|
||||||
const AcDeviceBatchControlView({super.key, required this.devicesIds});
|
const AcDeviceBatchControlView({super.key, required this.devicesIds});
|
||||||
|
|
||||||
final List<String> devicesIds;
|
final List<String> devicesIds;
|
||||||
@ -52,7 +51,7 @@ class AcDeviceBatchControlView extends StatelessWidget
|
|||||||
deviceId: devicesIds.first,
|
deviceId: devicesIds.first,
|
||||||
code: 'switch',
|
code: 'switch',
|
||||||
value: state.status.acSwitch,
|
value: state.status.acSwitch,
|
||||||
label: 'Thermostat',
|
label: 'ThermoState',
|
||||||
icon: Assets.ac,
|
icon: Assets.ac,
|
||||||
onChange: (value) {
|
onChange: (value) {
|
||||||
context.read<AcBloc>().add(AcBatchControlEvent(
|
context.read<AcBloc>().add(AcBatchControlEvent(
|
||||||
@ -101,8 +100,8 @@ class AcDeviceBatchControlView extends StatelessWidget
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'h',
|
'h',
|
||||||
style: context.textTheme.bodySmall!
|
style:
|
||||||
.copyWith(color: ColorsManager.blackColor),
|
context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'30',
|
'30',
|
||||||
@ -149,8 +148,7 @@ class AcDeviceBatchControlView extends StatelessWidget
|
|||||||
callFactoryReset: () {
|
callFactoryReset: () {
|
||||||
context.read<AcBloc>().add(AcFactoryResetEvent(
|
context.read<AcBloc>().add(AcFactoryResetEvent(
|
||||||
deviceId: state.status.uuid,
|
deviceId: state.status.uuid,
|
||||||
factoryResetModel:
|
factoryResetModel: FactoryResetModel(devicesUuid: devicesIds),
|
||||||
FactoryResetModel(devicesUuid: devicesIds),
|
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -16,12 +16,11 @@ class DeviceManagementBloc
|
|||||||
int _onlineCount = 0;
|
int _onlineCount = 0;
|
||||||
int _offlineCount = 0;
|
int _offlineCount = 0;
|
||||||
int _lowBatteryCount = 0;
|
int _lowBatteryCount = 0;
|
||||||
final List<AllDevicesModel> _selectedDevices = [];
|
List<AllDevicesModel> _selectedDevices = [];
|
||||||
List<AllDevicesModel> _filteredDevices = [];
|
List<AllDevicesModel> _filteredDevices = [];
|
||||||
String currentProductName = '';
|
String currentProductName = '';
|
||||||
String? currentCommunity;
|
String? currentCommunity;
|
||||||
String? currentUnitName;
|
String? currentUnitName;
|
||||||
String subSpaceName = '';
|
|
||||||
|
|
||||||
DeviceManagementBloc() : super(DeviceManagementInitial()) {
|
DeviceManagementBloc() : super(DeviceManagementInitial()) {
|
||||||
on<FetchDevices>(_onFetchDevices);
|
on<FetchDevices>(_onFetchDevices);
|
||||||
@ -32,29 +31,27 @@ class DeviceManagementBloc
|
|||||||
on<ResetFilters>(_onResetFilters);
|
on<ResetFilters>(_onResetFilters);
|
||||||
on<ResetSelectedDevices>(_onResetSelectedDevices);
|
on<ResetSelectedDevices>(_onResetSelectedDevices);
|
||||||
on<UpdateSelection>(_onUpdateSelection);
|
on<UpdateSelection>(_onUpdateSelection);
|
||||||
on<UpdateDeviceName>(_onUpdateDeviceName);
|
|
||||||
on<UpdateSubSpaceName>(_onUpdateSubSpaceName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDevices(
|
Future<void> _onFetchDevices(
|
||||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
emit(DeviceManagementLoading());
|
emit(DeviceManagementLoading());
|
||||||
try {
|
try {
|
||||||
var devices = <AllDevicesModel>[];
|
List<AllDevicesModel> devices = [];
|
||||||
_devices.clear();
|
_devices.clear();
|
||||||
final spaceBloc = event.context.read<SpaceTreeBloc>();
|
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||||
devices = await DevicesManagementApi().fetchDevices('', '', projectUuid);
|
devices = await DevicesManagementApi().fetchDevices(
|
||||||
|
projectUuid,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
for (final community in spaceBloc.state.selectedCommunities) {
|
for (var community in spaceBloc.state.selectedCommunities) {
|
||||||
final spacesList =
|
final spacesList =
|
||||||
spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||||
for (final space in spacesList) {
|
devices.addAll(await DevicesManagementApi()
|
||||||
devices.addAll(await DevicesManagementApi()
|
.fetchDevices(projectUuid, spacesId: spacesList));
|
||||||
.fetchDevices(community, space, projectUuid));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +73,7 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFilterDevices(
|
void _onFilterDevices(
|
||||||
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
if (_devices.isNotEmpty) {
|
if (_devices.isNotEmpty) {
|
||||||
_filteredDevices = List.from(_devices.where((device) {
|
_filteredDevices = List.from(_devices.where((device) {
|
||||||
@ -158,7 +155,8 @@ class DeviceManagementBloc
|
|||||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
|
void _onSelectDevice(
|
||||||
|
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||||
final selectedUuid = event.selectedDevice.uuid;
|
final selectedUuid = event.selectedDevice.uuid;
|
||||||
|
|
||||||
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||||
@ -167,9 +165,9 @@ class DeviceManagementBloc
|
|||||||
_selectedDevices.add(event.selectedDevice);
|
_selectedDevices.add(event.selectedDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
final clonedSelectedDevices = List<AllDevicesModel>.from(_selectedDevices);
|
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
||||||
|
|
||||||
final isControlButtonEnabled =
|
bool isControlButtonEnabled =
|
||||||
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
@ -199,8 +197,8 @@ class DeviceManagementBloc
|
|||||||
|
|
||||||
void _onUpdateSelection(
|
void _onUpdateSelection(
|
||||||
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||||
final selectedDevices = <AllDevicesModel>[];
|
List<AllDevicesModel> selectedDevices = [];
|
||||||
var devicesToSelectFrom = <AllDevicesModel>[];
|
List<AllDevicesModel> devicesToSelectFrom = [];
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
devicesToSelectFrom = (state as DeviceManagementLoaded).devices;
|
devicesToSelectFrom = (state as DeviceManagementLoaded).devices;
|
||||||
@ -208,7 +206,7 @@ class DeviceManagementBloc
|
|||||||
devicesToSelectFrom = (state as DeviceManagementFiltered).filteredDevices;
|
devicesToSelectFrom = (state as DeviceManagementFiltered).filteredDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < event.selectedRows.length; i++) {
|
for (int i = 0; i < event.selectedRows.length; i++) {
|
||||||
if (event.selectedRows[i]) {
|
if (event.selectedRows[i]) {
|
||||||
selectedDevices.add(devicesToSelectFrom[i]);
|
selectedDevices.add(devicesToSelectFrom[i]);
|
||||||
}
|
}
|
||||||
@ -254,7 +252,8 @@ class DeviceManagementBloc
|
|||||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||||
_lowBatteryCount = _devices
|
_lowBatteryCount = _devices
|
||||||
.where((device) => device.batteryLevel != null && device.batteryLevel! < 20)
|
.where((device) =>
|
||||||
|
device.batteryLevel != null && device.batteryLevel! < 20)
|
||||||
.length;
|
.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +270,8 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
|
void _onSearchDevices(
|
||||||
|
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||||
if ((event.community == null || event.community!.isEmpty) &&
|
if ((event.community == null || event.community!.isEmpty) &&
|
||||||
(event.unitName == null || event.unitName!.isEmpty) &&
|
(event.unitName == null || event.unitName!.isEmpty) &&
|
||||||
(event.deviceNameOrProductName == null ||
|
(event.deviceNameOrProductName == null ||
|
||||||
@ -300,7 +300,7 @@ class DeviceManagementBloc
|
|||||||
currentCommunity = event.community;
|
currentCommunity = event.community;
|
||||||
currentUnitName = event.unitName;
|
currentUnitName = event.unitName;
|
||||||
|
|
||||||
final devicesToSearch = _devices;
|
List<AllDevicesModel> devicesToSearch = _devices;
|
||||||
|
|
||||||
if (devicesToSearch.isNotEmpty) {
|
if (devicesToSearch.isNotEmpty) {
|
||||||
final searchText = event.deviceNameOrProductName?.toLowerCase() ?? '';
|
final searchText = event.deviceNameOrProductName?.toLowerCase() ?? '';
|
||||||
@ -343,134 +343,5 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateDeviceName(
|
|
||||||
UpdateDeviceName event, Emitter<DeviceManagementState> emit) {
|
|
||||||
final devices = _devices.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
final modifiedDevice = device.copyWith(name: event.newName);
|
|
||||||
_selectedDevices.removeWhere((device) => device.uuid == event.deviceId);
|
|
||||||
_selectedDevices.add(modifiedDevice);
|
|
||||||
return modifiedDevice;
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
final filteredDevices = _filteredDevices.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
final modifiedDevice = device.copyWith(name: event.newName);
|
|
||||||
_selectedDevices.removeWhere((device) => device.uuid == event.deviceId);
|
|
||||||
_selectedDevices.add(modifiedDevice);
|
|
||||||
return modifiedDevice;
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
_devices = devices;
|
|
||||||
_filteredDevices = filteredDevices;
|
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
|
||||||
final loaded = state as DeviceManagementLoaded;
|
|
||||||
final selectedDevices01 = _selectedDevices.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
final modifiedDevice = device.copyWith(name: event.newName);
|
|
||||||
return modifiedDevice;
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
emit(DeviceManagementLoaded(
|
|
||||||
devices: devices,
|
|
||||||
selectedIndex: loaded.selectedIndex,
|
|
||||||
onlineCount: loaded.onlineCount,
|
|
||||||
offlineCount: loaded.offlineCount,
|
|
||||||
lowBatteryCount: loaded.lowBatteryCount,
|
|
||||||
selectedDevice: selectedDevices01,
|
|
||||||
isControlButtonEnabled: loaded.isControlButtonEnabled,
|
|
||||||
));
|
|
||||||
} else if (state is DeviceManagementFiltered) {
|
|
||||||
final filtered = state as DeviceManagementFiltered;
|
|
||||||
final selectedDevices01 = filtered.selectedDevice?.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
final modifiedDevice = device.copyWith(name: event.newName);
|
|
||||||
return modifiedDevice;
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
emit(DeviceManagementFiltered(
|
|
||||||
filteredDevices: filteredDevices,
|
|
||||||
selectedIndex: filtered.selectedIndex,
|
|
||||||
onlineCount: filtered.onlineCount,
|
|
||||||
offlineCount: filtered.offlineCount,
|
|
||||||
lowBatteryCount: filtered.lowBatteryCount,
|
|
||||||
selectedDevice: selectedDevices01,
|
|
||||||
isControlButtonEnabled: filtered.isControlButtonEnabled,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onUpdateSubSpaceName(
|
|
||||||
UpdateSubSpaceName event, Emitter<DeviceManagementState> emit) {
|
|
||||||
final devices = _devices.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
return device.copyWith(
|
|
||||||
subspace:
|
|
||||||
device.subspace?.copyWith(subspaceName: event.newSubSpaceName));
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
final filteredDevices = _filteredDevices.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
return device.copyWith(
|
|
||||||
subspace:
|
|
||||||
device.subspace?.copyWith(subspaceName: event.newSubSpaceName));
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
_devices = devices;
|
|
||||||
_filteredDevices = filteredDevices;
|
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
|
||||||
final loaded = state as DeviceManagementLoaded;
|
|
||||||
final selectedDevices = loaded.selectedDevice?.map((device) {
|
|
||||||
if (device.uuid == event.deviceId) {
|
|
||||||
return device.copyWith(
|
|
||||||
subspace:
|
|
||||||
device.subspace?.copyWith(subspaceName: event.newSubSpaceName));
|
|
||||||
}
|
|
||||||
return device;
|
|
||||||
}).toList();
|
|
||||||
emit(DeviceManagementLoaded(
|
|
||||||
devices: _devices,
|
|
||||||
selectedIndex: loaded.selectedIndex,
|
|
||||||
onlineCount: loaded.onlineCount,
|
|
||||||
offlineCount: loaded.offlineCount,
|
|
||||||
lowBatteryCount: loaded.lowBatteryCount,
|
|
||||||
selectedDevice: selectedDevices,
|
|
||||||
isControlButtonEnabled: loaded.isControlButtonEnabled,
|
|
||||||
));
|
|
||||||
} else if (state is DeviceManagementFiltered) {
|
|
||||||
// final filtered = state as DeviceManagementFiltered;
|
|
||||||
// emit(DeviceManagementFiltered(
|
|
||||||
// filteredDevices: _filteredDevices,
|
|
||||||
// selectedIndex: filtered.selectedIndex,
|
|
||||||
// onlineCount: filtered.onlineCount,
|
|
||||||
// offlineCount: filtered.offlineCount,
|
|
||||||
// lowBatteryCount: filtered.lowBatteryCount,
|
|
||||||
// selectedDevice: filtered.selectedDevice,
|
|
||||||
// isControlButtonEnabled: filtered.isControlButtonEnabled,
|
|
||||||
// ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeSubspaceName(
|
|
||||||
String deviceId, String newSubSpaceName, String subspaceId) {
|
|
||||||
add(UpdateSubSpaceName(
|
|
||||||
deviceId: deviceId,
|
|
||||||
newSubSpaceName: newSubSpaceName,
|
|
||||||
subspaceId: subspaceId,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<AllDevicesModel> get selectedDevices => _selectedDevices;
|
List<AllDevicesModel> get selectedDevices => _selectedDevices;
|
||||||
}
|
}
|
||||||
|
@ -70,21 +70,3 @@ class UpdateSelection extends DeviceManagementEvent {
|
|||||||
|
|
||||||
const UpdateSelection(this.selectedRows);
|
const UpdateSelection(this.selectedRows);
|
||||||
}
|
}
|
||||||
|
|
||||||
class UpdateDeviceName extends DeviceManagementEvent {
|
|
||||||
final String deviceId;
|
|
||||||
final String newName;
|
|
||||||
|
|
||||||
const UpdateDeviceName({required this.deviceId, required this.newName});
|
|
||||||
}
|
|
||||||
|
|
||||||
class UpdateSubSpaceName extends DeviceManagementEvent {
|
|
||||||
final String deviceId;
|
|
||||||
final String newSubSpaceName;
|
|
||||||
final String subspaceId;
|
|
||||||
|
|
||||||
const UpdateSubSpaceName(
|
|
||||||
{required this.deviceId,
|
|
||||||
required this.newSubSpaceName,
|
|
||||||
required this.subspaceId});
|
|
||||||
}
|
|
||||||
|
@ -60,13 +60,4 @@ class Status {
|
|||||||
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
|
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
|
||||||
|
|
||||||
String toJson() => json.encode(toMap());
|
String toJson() => json.encode(toMap());
|
||||||
Status copyWith({
|
|
||||||
String? code,
|
|
||||||
dynamic value,
|
|
||||||
}) {
|
|
||||||
return Status(
|
|
||||||
code: code ?? this.code,
|
|
||||||
value: value ?? this.value,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -44,20 +44,4 @@ class DeviceSubspace {
|
|||||||
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
||||||
return subspaces.map((subspace) => subspace.toJson()).toList();
|
return subspaces.map((subspace) => subspace.toJson()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceSubspace copyWith({
|
|
||||||
String? uuid,
|
|
||||||
DateTime? createdAt,
|
|
||||||
DateTime? updatedAt,
|
|
||||||
String? subspaceName,
|
|
||||||
bool? disabled,
|
|
||||||
}) {
|
|
||||||
return DeviceSubspace(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
createdAt: createdAt ?? this.createdAt,
|
|
||||||
updatedAt: updatedAt ?? this.updatedAt,
|
|
||||||
subspaceName: subspaceName ?? this.subspaceName,
|
|
||||||
disabled: disabled ?? this.disabled,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -588,72 +588,4 @@ SOS
|
|||||||
"NCPS": DeviceType.NCPS,
|
"NCPS": DeviceType.NCPS,
|
||||||
"PC": DeviceType.PC,
|
"PC": DeviceType.PC,
|
||||||
};
|
};
|
||||||
|
|
||||||
AllDevicesModel copyWith({
|
|
||||||
DevicesModelRoom? room,
|
|
||||||
DeviceSubspace? subspace,
|
|
||||||
DevicesModelUnit? unit,
|
|
||||||
DeviceCommunityModel? community,
|
|
||||||
String? productUuid,
|
|
||||||
String? productType,
|
|
||||||
String? permissionType,
|
|
||||||
int? activeTime,
|
|
||||||
String? category,
|
|
||||||
String? categoryName,
|
|
||||||
int? createTime,
|
|
||||||
String? gatewayId,
|
|
||||||
String? icon,
|
|
||||||
String? ip,
|
|
||||||
String? lat,
|
|
||||||
String? localKey,
|
|
||||||
String? lon,
|
|
||||||
String? model,
|
|
||||||
String? name,
|
|
||||||
String? nodeId,
|
|
||||||
bool? online,
|
|
||||||
String? ownerId,
|
|
||||||
bool? sub,
|
|
||||||
String? timeZone,
|
|
||||||
int? updateTime,
|
|
||||||
String? uuid,
|
|
||||||
int? batteryLevel,
|
|
||||||
String? productName,
|
|
||||||
List<DeviceSpaceModel>? spaces,
|
|
||||||
List<DeviceTagModel>? deviceTags,
|
|
||||||
DeviceSubSpace? deviceSubSpace,
|
|
||||||
}) {
|
|
||||||
return AllDevicesModel(
|
|
||||||
room: room ?? this.room,
|
|
||||||
subspace: subspace ?? this.subspace,
|
|
||||||
unit: unit ?? this.unit,
|
|
||||||
community: community ?? this.community,
|
|
||||||
productUuid: productUuid ?? this.productUuid,
|
|
||||||
productType: productType ?? this.productType,
|
|
||||||
permissionType: permissionType ?? this.permissionType,
|
|
||||||
activeTime: activeTime ?? this.activeTime,
|
|
||||||
category: category ?? this.category,
|
|
||||||
categoryName: categoryName ?? this.categoryName,
|
|
||||||
createTime: createTime ?? this.createTime,
|
|
||||||
gatewayId: gatewayId ?? this.gatewayId,
|
|
||||||
icon: icon ?? this.icon,
|
|
||||||
ip: ip ?? this.ip,
|
|
||||||
lat: lat ?? this.lat,
|
|
||||||
localKey: localKey ?? this.localKey,
|
|
||||||
lon: lon ?? this.lon,
|
|
||||||
model: model ?? this.model,
|
|
||||||
name: name ?? this.name,
|
|
||||||
nodeId: nodeId ?? this.nodeId,
|
|
||||||
online: online ?? this.online,
|
|
||||||
ownerId: ownerId ?? this.ownerId,
|
|
||||||
sub: sub ?? this.sub,
|
|
||||||
timeZone: timeZone ?? this.timeZone,
|
|
||||||
updateTime: updateTime ?? this.updateTime,
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
batteryLevel: batteryLevel ?? this.batteryLevel,
|
|
||||||
productName: productName ?? this.productName,
|
|
||||||
spaces: spaces ?? this.spaces,
|
|
||||||
deviceTags: deviceTags ?? this.deviceTags,
|
|
||||||
deviceSubSpace: deviceSubSpace ?? this.deviceSubSpace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||||
buildWhen: (previous, current) => previous != current,
|
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
List<AllDevicesModel> devicesToShow = [];
|
List<AllDevicesModel> devicesToShow = [];
|
||||||
int selectedIndex = 0;
|
int selectedIndex = 0;
|
||||||
@ -32,6 +31,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
int lowBatteryCount = 0;
|
int lowBatteryCount = 0;
|
||||||
bool isControlButtonEnabled = false;
|
bool isControlButtonEnabled = false;
|
||||||
List<AllDevicesModel> selectedDevices = [];
|
List<AllDevicesModel> selectedDevices = [];
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
devicesToShow = state.devices;
|
devicesToShow = state.devices;
|
||||||
selectedIndex = state.selectedIndex;
|
selectedIndex = state.selectedIndex;
|
||||||
@ -68,7 +68,6 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(child: SpaceTreeView(
|
Expanded(child: SpaceTreeView(
|
||||||
onSelect: () {
|
onSelect: () {
|
||||||
context.read<DeviceManagementBloc>().add(ResetFilters());
|
|
||||||
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
@ -112,8 +111,6 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
onPressed: isControlButtonEnabled
|
onPressed: isControlButtonEnabled
|
||||||
? () {
|
? () {
|
||||||
if (isAnyDeviceOffline) {
|
if (isAnyDeviceOffline) {
|
||||||
ScaffoldMessenger.of(context)
|
|
||||||
.clearSnackBars();
|
|
||||||
ScaffoldMessenger.of(context)
|
ScaffoldMessenger.of(context)
|
||||||
.showSnackBar(
|
.showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
@ -193,7 +190,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
'Product Name',
|
'Product Name',
|
||||||
'Device ID',
|
'Device ID',
|
||||||
'Space Name',
|
'Space Name',
|
||||||
'Location',
|
'location',
|
||||||
'Battery Level',
|
'Battery Level',
|
||||||
'Installation Date and Time',
|
'Installation Date and Time',
|
||||||
'Status',
|
'Status',
|
||||||
@ -245,7 +242,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
.map((device) => device.uuid!)
|
.map((device) => device.uuid!)
|
||||||
.toList(),
|
.toList(),
|
||||||
isEmpty: devicesToShow.isEmpty,
|
isEmpty: devicesToShow.isEmpty,
|
||||||
onSettingsPressed: (rowIndex) async {
|
onSettingsPressed: (rowIndex) {
|
||||||
final device = devicesToShow[rowIndex];
|
final device = devicesToShow[rowIndex];
|
||||||
showDeviceSettingsSidebar(context, device);
|
showDeviceSettingsSidebar(context, device);
|
||||||
},
|
},
|
||||||
@ -267,7 +264,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierLabel: "Device Settings",
|
barrierLabel: "Device Settings",
|
||||||
transitionDuration: const Duration(milliseconds: 300),
|
transitionDuration: const Duration(milliseconds: 300),
|
||||||
pageBuilder: (_, anim1, anim2) {
|
pageBuilder: (context, anim1, anim2) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: Material(
|
child: Material(
|
||||||
@ -277,7 +274,6 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
child: DeviceSettingsPanel(
|
child: DeviceSettingsPanel(
|
||||||
device: device,
|
device: device,
|
||||||
onClose: () => Navigator.of(context).pop(),
|
onClose: () => Navigator.of(context).pop(),
|
||||||
deviceManagementBloc: context.read<DeviceManagementBloc>(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -62,10 +62,9 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
BlocProvider.of<CurtainModuleBloc>(context),
|
BlocProvider.of<CurtainModuleBloc>(context),
|
||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'Timer',
|
category: 'CUR_2',
|
||||||
code: 'control',
|
code: 'control',
|
||||||
countdownCode: 'Timer',
|
|
||||||
deviceType: 'CUR_2',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,6 @@ import 'package:syncrow_web/pages/device_managment/curtain_module/bloc/curtain_m
|
|||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_dialog_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_dialog_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/calibrate_completed_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/calibrate_completed_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/normal_text_body_for_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/normal_text_body_for_dialog.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class AccurteCalibratingDialog extends StatelessWidget {
|
class AccurteCalibratingDialog extends StatelessWidget {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
@ -18,15 +17,14 @@ class AccurteCalibratingDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: AccurateDialogWidget(
|
content: AccurateDialogWidget(
|
||||||
title: 'Calibrating',
|
title: 'Calibrating',
|
||||||
body: const NormalTextBodyForDialog(
|
body: const NormalTextBodyForDialog(
|
||||||
title: '',
|
title: '',
|
||||||
step1:
|
step1:
|
||||||
'Click Close Button to make the Curtain run to Full Close and Position.',
|
'1. Click Close Button to make the Curtain run to Full Close and Position.',
|
||||||
step2: 'click Next to complete the Calibration.',
|
step2: '2. click Next to complete the Calibration.',
|
||||||
),
|
),
|
||||||
leftOnTap: () => Navigator.of(parentContext).pop(),
|
leftOnTap: () => Navigator.of(parentContext).pop(),
|
||||||
rightOnTap: () {
|
rightOnTap: () {
|
||||||
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_calibrating_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_calibrating_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_dialog_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_dialog_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/normal_text_body_for_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/normal_text_body_for_dialog.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class AccurateCalibrationDialog extends StatelessWidget {
|
class AccurateCalibrationDialog extends StatelessWidget {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
@ -16,14 +15,13 @@ class AccurateCalibrationDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: AccurateDialogWidget(
|
content: AccurateDialogWidget(
|
||||||
title: 'Accurate Calibration',
|
title: 'Accurate Calibration',
|
||||||
body: const NormalTextBodyForDialog(
|
body: const NormalTextBodyForDialog(
|
||||||
title: 'Prepare Calibration:',
|
title: 'Prepare Calibration:',
|
||||||
step1: 'Run The Curtain to the Fully Open Position,and pause.',
|
step1: '1. Run The Curtain to the Fully Open Position,and pause.',
|
||||||
step2: 'click Next to Start accurate calibration.',
|
step2: '2. click Next to Start accurate calibration.',
|
||||||
),
|
),
|
||||||
leftOnTap: () => Navigator.of(parentContext).pop(),
|
leftOnTap: () => Navigator.of(parentContext).pop(),
|
||||||
rightOnTap: () {
|
rightOnTap: () {
|
||||||
|
@ -17,102 +17,78 @@ class AccurateDialogWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 250,
|
height: 300,
|
||||||
width: 500,
|
width: 400,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Padding(
|
||||||
flex: 3,
|
padding: const EdgeInsets.all(10),
|
||||||
child: Column(
|
child: Text(
|
||||||
children: [
|
title,
|
||||||
Padding(
|
style: const TextStyle(
|
||||||
padding: const EdgeInsets.all(10),
|
fontSize: 24,
|
||||||
child: Text(
|
fontWeight: FontWeight.bold,
|
||||||
title,
|
color: ColorsManager.blueColor,
|
||||||
style: TextStyle(
|
),
|
||||||
fontSize: 24,
|
),
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
color: ColorsManager.dialogBlueTitle,
|
const SizedBox(height: 5),
|
||||||
|
const Divider(
|
||||||
|
indent: 10,
|
||||||
|
endIndent: 10,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
child: body,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
const Spacer(),
|
||||||
|
const Divider(),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: leftOnTap,
|
||||||
|
child: Container(
|
||||||
|
height: 60,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
right: BorderSide(
|
||||||
|
color: ColorsManager.grayBorder,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Cancel',
|
||||||
|
style: TextStyle(color: ColorsManager.grayBorder),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(
|
),
|
||||||
indent: 60,
|
Expanded(
|
||||||
endIndent: 60,
|
child: InkWell(
|
||||||
),
|
onTap: rightOnTap,
|
||||||
],
|
child: Container(
|
||||||
),
|
height: 60,
|
||||||
),
|
alignment: Alignment.center,
|
||||||
Expanded(
|
decoration: const BoxDecoration(
|
||||||
flex: 5,
|
border: Border(
|
||||||
child: body,
|
right: BorderSide(
|
||||||
),
|
color: ColorsManager.grayBorder,
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
const Expanded(child: Divider()),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(26),
|
|
||||||
),
|
|
||||||
onTap: leftOnTap,
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
right: BorderSide(
|
|
||||||
color: ColorsManager.grayBorder,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(26),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'Cancel',
|
|
||||||
style: TextStyle(color: ColorsManager.grayBorder),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
child: const Text(
|
||||||
child: InkWell(
|
'Next',
|
||||||
borderRadius: const BorderRadius.only(
|
style: TextStyle(
|
||||||
bottomRight: Radius.circular(26),
|
color: ColorsManager.blueColor,
|
||||||
),
|
|
||||||
onTap: rightOnTap,
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
right: BorderSide(
|
|
||||||
color: ColorsManager.grayBorder,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomRight: Radius.circular(26),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Text(
|
|
||||||
'Next',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorsManager.blueColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
),
|
||||||
)
|
),
|
||||||
],
|
)
|
||||||
),
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -1,9 +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:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/bloc/curtain_module_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/bloc/curtain_module_bloc.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';
|
|
||||||
|
|
||||||
class CalibrateCompletedDialog extends StatelessWidget {
|
class CalibrateCompletedDialog extends StatelessWidget {
|
||||||
final BuildContext parentContext;
|
final BuildContext parentContext;
|
||||||
@ -17,69 +15,58 @@ class CalibrateCompletedDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
height: 250,
|
height: 250,
|
||||||
width: 400,
|
width: 400,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
const Padding(
|
||||||
child: Column(
|
padding: EdgeInsets.all(10),
|
||||||
children: [
|
child: Text(
|
||||||
Padding(
|
'Calibration Completed',
|
||||||
padding: const EdgeInsets.all(10),
|
style: TextStyle(
|
||||||
child: Text(
|
fontSize: 24,
|
||||||
'Calibration Completed',
|
fontWeight: FontWeight.bold,
|
||||||
style: TextStyle(
|
color: ColorsManager.blueColor,
|
||||||
fontSize: 24,
|
),
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: ColorsManager.dialogBlueTitle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
const Divider(
|
|
||||||
indent: 10,
|
|
||||||
endIndent: 10,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
const SizedBox(height: 5),
|
||||||
child: SvgPicture.asset(Assets.completedDoneIcon),
|
const Divider(
|
||||||
|
indent: 10,
|
||||||
|
endIndent: 10,
|
||||||
),
|
),
|
||||||
Expanded(
|
const Icon(
|
||||||
child: Column(
|
Icons.check_circle,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
size: 100,
|
||||||
children: [
|
color: ColorsManager.blueColor,
|
||||||
const Divider(
|
),
|
||||||
indent: 10,
|
const Spacer(),
|
||||||
endIndent: 10,
|
const Divider(
|
||||||
),
|
indent: 10,
|
||||||
InkWell(
|
endIndent: 10,
|
||||||
onTap: () {
|
),
|
||||||
parentContext.read<CurtainModuleBloc>().add(
|
InkWell(
|
||||||
FetchCurtainModuleStatusEvent(
|
onTap: () {
|
||||||
deviceId: deviceId,
|
parentContext.read<CurtainModuleBloc>().add(
|
||||||
),
|
FetchCurtainModuleStatusEvent(
|
||||||
);
|
deviceId: deviceId,
|
||||||
Navigator.of(parentContext).pop();
|
|
||||||
Navigator.of(parentContext).pop();
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
width: double.infinity,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: const Text(
|
|
||||||
'Close',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorsManager.grayBorder,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
)
|
Navigator.of(parentContext).pop();
|
||||||
],
|
Navigator.of(parentContext).pop();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
width: double.infinity,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: const Text(
|
||||||
|
'Close',
|
||||||
|
style: TextStyle(
|
||||||
|
color: ColorsManager.grayBorder,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -15,72 +15,28 @@ class NormalTextBodyForDialog extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Column(
|
||||||
padding: EdgeInsetsGeometry.only(left: 15),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Text(
|
||||||
children: [
|
title,
|
||||||
if (title.isEmpty)
|
style: const TextStyle(
|
||||||
const SizedBox()
|
color: ColorsManager.grayColor,
|
||||||
else
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
title,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 15,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
width: 10,
|
|
||||||
),
|
|
||||||
const Text('1. ',
|
|
||||||
style: TextStyle(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 15,
|
|
||||||
)),
|
|
||||||
SizedBox(
|
|
||||||
width: 450,
|
|
||||||
child: Text(
|
|
||||||
step1,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 15,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
child: Row(
|
Text(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
step1,
|
||||||
children: [
|
style: const TextStyle(
|
||||||
const SizedBox(
|
color: ColorsManager.grayColor,
|
||||||
width: 10,
|
),
|
||||||
),
|
),
|
||||||
const Text('2. ',
|
Text(
|
||||||
style: TextStyle(
|
step2,
|
||||||
color: ColorsManager.grayColor,
|
style: const TextStyle(
|
||||||
fontSize: 15,
|
color: ColorsManager.grayColor,
|
||||||
)),
|
),
|
||||||
Text(
|
)
|
||||||
step2,
|
],
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontSize: 15,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class NumberInputField extends StatelessWidget {
|
|||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 20,
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -18,7 +18,7 @@ class PrefReversCardWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DefaultContainer(
|
return DefaultContainer(
|
||||||
padding: const EdgeInsets.all(18),
|
padding: const EdgeInsets.all(12),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -23,12 +23,12 @@ class CurtainModulePrefrencesDialog extends StatelessWidget {
|
|||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.CircleImageBackground,
|
backgroundColor: ColorsManager.CircleImageBackground,
|
||||||
contentPadding: const EdgeInsets.all(20),
|
contentPadding: const EdgeInsets.all(30),
|
||||||
title: Center(
|
title: const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Preferences',
|
'Preferences',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: ColorsManager.dialogBlueTitle,
|
color: ColorsManager.blueColor,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
@ -63,82 +63,55 @@ class _QuickCalibratingDialogState extends State<QuickCalibratingDialog> {
|
|||||||
@override
|
@override
|
||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: AccurateDialogWidget(
|
content: AccurateDialogWidget(
|
||||||
title: 'Calibrating',
|
title: 'Calibrating',
|
||||||
body: Column(
|
body: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Expanded(
|
const Text(
|
||||||
child: Align(
|
'1. please Enter the Travel Time:',
|
||||||
alignment: Alignment.topCenter,
|
style: TextStyle(color: ColorsManager.grayBorder),
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(right: 75),
|
|
||||||
child: Text(
|
|
||||||
'1.please Enter the Travel Time:',
|
|
||||||
style: TextStyle(color: ColorsManager.lightGrayColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
const SizedBox(height: 10),
|
||||||
child: Align(
|
Container(
|
||||||
alignment: Alignment.center,
|
width: 150,
|
||||||
child: Container(
|
height: 40,
|
||||||
width: 130,
|
padding: const EdgeInsets.all(5),
|
||||||
padding: const EdgeInsets.all(5),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: ColorsManager.whiteColors,
|
||||||
color: ColorsManager.neutralGray.withValues(
|
borderRadius: BorderRadius.circular(12),
|
||||||
alpha: 0.5,
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: NumberInputField(controller: _controller),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Text(
|
||||||
|
'seconds',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: ColorsManager.blueColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
),
|
||||||
child: Row(
|
],
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsGeometry.only(left: 5),
|
|
||||||
child: NumberInputField(controller: _controller)),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
'seconds',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: ColorsManager.dialogBlueTitle,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_errorText != null)
|
if (_errorText != null)
|
||||||
Expanded(
|
Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
child: Text(
|
||||||
child: Text(
|
_errorText!,
|
||||||
_errorText!,
|
style: const TextStyle(
|
||||||
style: const TextStyle(
|
color: ColorsManager.red,
|
||||||
color: ColorsManager.red,
|
fontSize: 14,
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: Text(
|
|
||||||
'2.click Next to Complete the calibration',
|
|
||||||
style: TextStyle(color: ColorsManager.lightGrayColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
leftOnTap: () => Navigator.of(widget.parentContext).pop(),
|
leftOnTap: () => Navigator.of(widget.parentContext).pop(),
|
||||||
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_dialog_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/accurate_dialog_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/normal_text_body_for_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/normal_text_body_for_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/quick_calibrating_dialog.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/quick_calibrating_dialog.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
|
|
||||||
class QuickCalibrationDialog extends StatelessWidget {
|
class QuickCalibrationDialog extends StatelessWidget {
|
||||||
final int timControl;
|
final int timControl;
|
||||||
@ -18,15 +17,14 @@ class QuickCalibrationDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: AccurateDialogWidget(
|
content: AccurateDialogWidget(
|
||||||
title: 'Quick Calibration',
|
title: 'Quick Calibration',
|
||||||
body: const NormalTextBodyForDialog(
|
body: const NormalTextBodyForDialog(
|
||||||
title: 'Prepare Calibration:',
|
title: 'Prepare Calibration:',
|
||||||
step1:
|
step1:
|
||||||
'Confirm that the curtain is in the fully closed and suspended state.',
|
'1. Confirm that the curtain is in the fully closed and suspended state.',
|
||||||
step2: 'click Next to Start calibration.',
|
step2: '2. click Next to Start calibration.',
|
||||||
),
|
),
|
||||||
leftOnTap: () => Navigator.of(parentContext).pop(),
|
leftOnTap: () => Navigator.of(parentContext).pop(),
|
||||||
rightOnTap: () {
|
rightOnTap: () {
|
||||||
|
@ -19,14 +19,11 @@ class DeviceManagementContent extends StatelessWidget {
|
|||||||
required this.device,
|
required this.device,
|
||||||
required this.subSpaces,
|
required this.subSpaces,
|
||||||
required this.deviceInfo,
|
required this.deviceInfo,
|
||||||
required this.deviceManagementBloc,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
final List<SubSpaceModel> subSpaces;
|
final List<SubSpaceModel> subSpaces;
|
||||||
final DeviceInfoModel deviceInfo;
|
final DeviceInfoModel deviceInfo;
|
||||||
final DeviceManagementBloc deviceManagementBloc;
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -90,11 +87,6 @@ class DeviceManagementContent extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
deviceManagementBloc.add(UpdateSubSpaceName(
|
|
||||||
subspaceId: selectedSubSpace.id!,
|
|
||||||
deviceId: device.uuid!,
|
|
||||||
newSubSpaceName: selectedSubSpace.name ?? ''));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: infoRow(
|
child: infoRow(
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.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/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_state.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/device_icon_type_helper.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/device_icon_type_helper.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/device_management_content.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/device_management_content.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/remove_device_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/remove_device_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_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/constants/assets.dart';
|
||||||
@ -19,13 +17,7 @@ import 'package:syncrow_web/web_layout/default_container.dart';
|
|||||||
class DeviceSettingsPanel extends StatelessWidget {
|
class DeviceSettingsPanel extends StatelessWidget {
|
||||||
final VoidCallback? onClose;
|
final VoidCallback? onClose;
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
final DeviceManagementBloc deviceManagementBloc;
|
const DeviceSettingsPanel({super.key, this.onClose, required this.device});
|
||||||
const DeviceSettingsPanel({
|
|
||||||
super.key,
|
|
||||||
this.onClose,
|
|
||||||
required this.device,
|
|
||||||
required this.deviceManagementBloc,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -79,10 +71,10 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
'Device Settings',
|
'Device Settings',
|
||||||
style: context.theme.textTheme.titleLarge!
|
style: context.theme.textTheme.titleLarge!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: ColorsManager.vividBlue
|
color: ColorsManager.vividBlue
|
||||||
.withOpacity(0.7),
|
.withOpacity(0.7),
|
||||||
fontSize: 24),
|
fontSize: 24),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -142,14 +134,8 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
onFieldSubmitted: (value) {
|
onFieldSubmitted: (value) {
|
||||||
_bloc.add(const ChangeNameEvent(
|
_bloc.add(const ChangeNameEvent(
|
||||||
value: false));
|
value: false));
|
||||||
deviceManagementBloc
|
|
||||||
..add(UpdateDeviceName(
|
|
||||||
deviceId: device.uuid!,
|
|
||||||
newName: _bloc
|
|
||||||
.nameController
|
|
||||||
.text))..add(ResetSelectedDevices());
|
|
||||||
},
|
},
|
||||||
decoration:const InputDecoration(
|
decoration: InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
@ -171,7 +157,7 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
_bloc.add(
|
_bloc.add(
|
||||||
const ChangeNameEvent(
|
const ChangeNameEvent(
|
||||||
value: true));
|
value: true));
|
||||||
},
|
},
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
Assets
|
Assets
|
||||||
@ -204,7 +190,6 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
device: device,
|
device: device,
|
||||||
subSpaces: subSpaces.cast<SubSpaceModel>(),
|
subSpaces: subSpaces.cast<SubSpaceModel>(),
|
||||||
deviceInfo: deviceInfo,
|
deviceInfo: deviceInfo,
|
||||||
deviceManagementBloc: deviceManagementBloc,
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
RemoveDeviceWidget(bloc: _bloc),
|
RemoveDeviceWidget(bloc: _bloc),
|
||||||
|
@ -40,7 +40,7 @@ class OneGangGlassSwitchBloc
|
|||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId, emit);
|
||||||
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -48,28 +48,42 @@ class OneGangGlassSwitchBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
|
void _listenToChanges(
|
||||||
|
String deviceId,
|
||||||
void _listenToChanges(String deviceId) {
|
Emitter<OneGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
|
final stream = ref.onValue;
|
||||||
if (event.snapshot.value == null) return;
|
|
||||||
|
|
||||||
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
|
stream.listen((DatabaseEvent event) {
|
||||||
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
final statusList = <Status>[];
|
final statusList = <Status>[];
|
||||||
|
if (data['status'] != null) {
|
||||||
usersMap['status'].forEach((element) {
|
for (var element in data['status']) {
|
||||||
statusList.add(Status(code: element['code'], value: element['value']));
|
statusList.add(
|
||||||
});
|
Status(
|
||||||
|
code: element['code'].toString(),
|
||||||
deviceStatus =
|
value: element['value'].toString(),
|
||||||
OneGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
|
),
|
||||||
|
);
|
||||||
add(StatusUpdated(deviceStatus));
|
}
|
||||||
|
}
|
||||||
|
if (statusList.isNotEmpty) {
|
||||||
|
final newStatus = OneGangGlassStatusModel.fromJson(deviceId, statusList);
|
||||||
|
if (newStatus != deviceStatus) {
|
||||||
|
deviceStatus = newStatus;
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (e) {
|
||||||
|
emit(OneGangGlassSwitchError('Failed to listen to changes: $e'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(
|
void _onStatusUpdated(
|
||||||
@ -160,10 +174,4 @@ class OneGangGlassSwitchBloc
|
|||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_deviceStatusSubscription?.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,6 @@ class OneGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: '1GT',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -80,8 +80,6 @@ class WallLightDeviceControl extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: '1G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -277,32 +277,6 @@ class SmartPowerDeviceControl extends StatelessWidget
|
|||||||
totalConsumption: 10000,
|
totalConsumption: 10000,
|
||||||
date: blocProvider.formattedDate,
|
date: blocProvider.formattedDate,
|
||||||
),
|
),
|
||||||
EnergyConsumptionPage(
|
|
||||||
formattedDate:
|
|
||||||
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
|
|
||||||
onTap: () {
|
|
||||||
blocProvider.add(SelectDateEvent(context: context));
|
|
||||||
},
|
|
||||||
widget: blocProvider.dateSwitcher(),
|
|
||||||
chartData: blocProvider.energyDataList.isNotEmpty
|
|
||||||
? blocProvider.energyDataList
|
|
||||||
: [
|
|
||||||
EnergyData('12:00 AM', 4.0),
|
|
||||||
EnergyData('01:00 AM', 6.5),
|
|
||||||
EnergyData('02:00 AM', 3.8),
|
|
||||||
EnergyData('03:00 AM', 3.2),
|
|
||||||
EnergyData('04:00 AM', 6.0),
|
|
||||||
EnergyData('05:00 AM', 3.4),
|
|
||||||
EnergyData('06:00 AM', 5.2),
|
|
||||||
EnergyData('07:00 AM', 3.5),
|
|
||||||
EnergyData('08:00 AM', 6.8),
|
|
||||||
EnergyData('09:00 AM', 5.6),
|
|
||||||
EnergyData('10:00 AM', 3.9),
|
|
||||||
EnergyData('11:00 AM', 4.0),
|
|
||||||
],
|
|
||||||
totalConsumption: 10000,
|
|
||||||
date: blocProvider.formattedDate,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -47,7 +47,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
final success = await RemoteControlDeviceService().controlDevice(
|
final success = await RemoteControlDeviceService().controlDevice(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
status: Status(
|
status: Status(
|
||||||
code: event.countdownCode,
|
code: 'countdown_1',
|
||||||
value: 0,
|
value: 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -80,18 +80,15 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
) {
|
) {
|
||||||
if (state is ScheduleLoaded) {
|
if (state is ScheduleLoaded) {
|
||||||
final currentState = state as ScheduleLoaded;
|
final currentState = state as ScheduleLoaded;
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
countdownSeconds: currentState.countdownSeconds,
|
|
||||||
selectedTime: currentState.selectedTime,
|
|
||||||
deviceId: deviceId,
|
|
||||||
scheduleMode: event.scheduleMode,
|
scheduleMode: event.scheduleMode,
|
||||||
countdownHours: currentState.countdownHours,
|
countdownRemaining: Duration.zero,
|
||||||
countdownMinutes: currentState.countdownMinutes,
|
countdownHours: 0,
|
||||||
inchingHours: currentState.inchingHours,
|
countdownMinutes: 0,
|
||||||
inchingMinutes: currentState.inchingMinutes,
|
inchingHours: 0,
|
||||||
|
inchingMinutes: 0,
|
||||||
|
isCountdownActive: false,
|
||||||
isInchingActive: false,
|
isInchingActive: false,
|
||||||
isCountdownActive: currentState.countdownRemaining > Duration.zero,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,6 +221,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
deviceId,
|
deviceId,
|
||||||
event.category,
|
event.category,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (state is ScheduleLoaded) {
|
if (state is ScheduleLoaded) {
|
||||||
final currentState = state as ScheduleLoaded;
|
final currentState = state as ScheduleLoaded;
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
@ -232,6 +230,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
selectedDays: List.filled(7, false),
|
selectedDays: List.filled(7, false),
|
||||||
functionOn: false,
|
functionOn: false,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
|
countdownRemaining: Duration.zero,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
emit(ScheduleLoaded(
|
emit(ScheduleLoaded(
|
||||||
@ -286,22 +285,12 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
if (state is ScheduleLoaded) {
|
if (state is ScheduleLoaded) {
|
||||||
Status status = Status(code: '', value: '');
|
|
||||||
if (event.deviceType == 'CUR_2') {
|
|
||||||
status = status.copyWith(
|
|
||||||
code: 'control',
|
|
||||||
value: event.functionOn == true ? 'open' : 'close');
|
|
||||||
} else {
|
|
||||||
status =
|
|
||||||
status.copyWith(code: event.category, value: event.functionOn);
|
|
||||||
}
|
|
||||||
|
|
||||||
final dateTime = DateTime.parse(event.time);
|
final dateTime = DateTime.parse(event.time);
|
||||||
final updatedSchedule = ScheduleEntry(
|
final updatedSchedule = ScheduleEntry(
|
||||||
scheduleId: event.scheduleId,
|
scheduleId: event.scheduleId,
|
||||||
category: event.category,
|
category: event.category,
|
||||||
time: getTimeStampWithoutSeconds(dateTime).toString(),
|
time: getTimeStampWithoutSeconds(dateTime).toString(),
|
||||||
function: status,
|
function: Status(code: event.category, value: event.functionOn),
|
||||||
days: event.selectedDays,
|
days: event.selectedDays,
|
||||||
);
|
);
|
||||||
final success = await DevicesManagementApi().editScheduleRecord(
|
final success = await DevicesManagementApi().editScheduleRecord(
|
||||||
@ -407,7 +396,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
final totalSeconds =
|
final totalSeconds =
|
||||||
Duration(hours: event.hours, minutes: event.minutes).inSeconds;
|
Duration(hours: event.hours, minutes: event.minutes).inSeconds;
|
||||||
final code = event.mode == ScheduleModes.countdown
|
final code = event.mode == ScheduleModes.countdown
|
||||||
? event.countDownCode
|
? 'countdown_1'
|
||||||
: 'switch_inching';
|
: 'switch_inching';
|
||||||
final currentState = state as ScheduleLoaded;
|
final currentState = state as ScheduleLoaded;
|
||||||
final duration = Duration(seconds: totalSeconds);
|
final duration = Duration(seconds: totalSeconds);
|
||||||
@ -434,7 +423,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (code == event.countDownCode) {
|
if (code == 'countdown_1') {
|
||||||
final countdownDuration = Duration(seconds: totalSeconds);
|
final countdownDuration = Duration(seconds: totalSeconds);
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
@ -448,7 +437,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (countdownDuration.inSeconds > 0) {
|
if (countdownDuration.inSeconds > 0) {
|
||||||
_startCountdownTimer(emit, countdownDuration, event.countDownCode);
|
_startCountdownTimer(emit, countdownDuration);
|
||||||
} else {
|
} else {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
emit(
|
emit(
|
||||||
@ -478,7 +467,9 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _startCountdownTimer(
|
void _startCountdownTimer(
|
||||||
Emitter<ScheduleState> emit, Duration duration, String countdownCode) {
|
Emitter<ScheduleState> emit,
|
||||||
|
Duration duration,
|
||||||
|
) {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
if (_currentCountdown != null && _currentCountdown! > Duration.zero) {
|
if (_currentCountdown != null && _currentCountdown! > Duration.zero) {
|
||||||
@ -488,7 +479,6 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
} else {
|
} else {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
add(StopScheduleEvent(
|
add(StopScheduleEvent(
|
||||||
countdownCode: countdownCode,
|
|
||||||
mode: _currentCountdown == null
|
mode: _currentCountdown == null
|
||||||
? ScheduleModes.countdown
|
? ScheduleModes.countdown
|
||||||
: ScheduleModes.inching,
|
: ScheduleModes.inching,
|
||||||
@ -525,75 +515,70 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
try {
|
try {
|
||||||
final status =
|
final status =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
int totalSeconds = 0;
|
print(status.status);
|
||||||
final countdownItem = status.status.firstWhere(
|
|
||||||
(item) => item.code == event.countdownCode,
|
|
||||||
orElse: () => Status(code: '', value: 0),
|
|
||||||
);
|
|
||||||
totalSeconds = (countdownItem.value as int?) ?? 0;
|
|
||||||
final countdownHours = totalSeconds ~/ 3600;
|
|
||||||
final countdownMinutes = (totalSeconds % 3600) ~/ 60;
|
|
||||||
final countdownSeconds = totalSeconds % 60;
|
|
||||||
|
|
||||||
final deviceStatus =
|
final deviceStatus =
|
||||||
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||||
final isCountdownActive = totalSeconds > 0;
|
|
||||||
final isInchingActive = !isCountdownActive &&
|
|
||||||
(deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0);
|
|
||||||
|
|
||||||
final newState = state is ScheduleLoaded
|
final scheduleMode =
|
||||||
? (state as ScheduleLoaded).copyWith(
|
deviceStatus.countdownHours > 0 || deviceStatus.countdownMinutes > 0
|
||||||
scheduleMode: ScheduleModes.schedule,
|
? ScheduleModes.countdown
|
||||||
countdownHours: countdownHours,
|
: deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0
|
||||||
countdownMinutes: countdownMinutes,
|
? ScheduleModes.inching
|
||||||
countdownSeconds: countdownSeconds,
|
: ScheduleModes.schedule;
|
||||||
inchingHours: deviceStatus.inchingHours,
|
final isCountdown = scheduleMode == ScheduleModes.countdown;
|
||||||
inchingMinutes: deviceStatus.inchingMinutes,
|
final isInching = scheduleMode == ScheduleModes.inching;
|
||||||
isCountdownActive: isCountdownActive,
|
|
||||||
isInchingActive: isInchingActive,
|
|
||||||
countdownRemaining: isCountdownActive
|
|
||||||
? Duration(seconds: totalSeconds)
|
|
||||||
: Duration.zero,
|
|
||||||
)
|
|
||||||
: ScheduleLoaded(
|
|
||||||
scheduleMode: ScheduleModes.schedule,
|
|
||||||
schedules: const [],
|
|
||||||
selectedTime: null,
|
|
||||||
selectedDays: List.filled(7, false),
|
|
||||||
functionOn: false,
|
|
||||||
isEditing: false,
|
|
||||||
deviceId: event.deviceId,
|
|
||||||
countdownHours: countdownHours,
|
|
||||||
countdownMinutes: countdownMinutes,
|
|
||||||
countdownSeconds: countdownSeconds,
|
|
||||||
inchingHours: deviceStatus.inchingHours,
|
|
||||||
inchingMinutes: deviceStatus.inchingMinutes,
|
|
||||||
isCountdownActive: isCountdownActive,
|
|
||||||
isInchingActive: isInchingActive,
|
|
||||||
countdownRemaining: isCountdownActive
|
|
||||||
? Duration(seconds: totalSeconds)
|
|
||||||
: Duration.zero,
|
|
||||||
);
|
|
||||||
emit(newState);
|
|
||||||
|
|
||||||
if (isCountdownActive) {
|
Duration? countdownRemaining;
|
||||||
_countdownTimer?.cancel();
|
var isCountdownActive = false;
|
||||||
_currentCountdown = Duration(seconds: totalSeconds);
|
var isInchingActive = false;
|
||||||
countdownRemaining = _currentCountdown!;
|
|
||||||
|
|
||||||
if (totalSeconds > 0) {
|
if (isCountdown) {
|
||||||
_startCountdownTimer(
|
countdownRemaining = Duration(
|
||||||
emit, Duration(seconds: totalSeconds), event.countdownCode);
|
hours: deviceStatus.countdownHours,
|
||||||
} else {
|
minutes: deviceStatus.countdownMinutes,
|
||||||
add(StopScheduleEvent(
|
);
|
||||||
countdownCode: event.countdownCode,
|
isCountdownActive = countdownRemaining > Duration.zero;
|
||||||
mode: ScheduleModes.countdown,
|
} else if (isInching) {
|
||||||
deviceId: event.deviceId,
|
isInchingActive = Duration(
|
||||||
));
|
hours: deviceStatus.inchingHours,
|
||||||
}
|
minutes: deviceStatus.inchingMinutes,
|
||||||
} else {
|
) >
|
||||||
_countdownTimer?.cancel();
|
Duration.zero;
|
||||||
}
|
}
|
||||||
|
if (state is ScheduleLoaded) {
|
||||||
|
final currentState = state as ScheduleLoaded;
|
||||||
|
emit(currentState.copyWith(
|
||||||
|
scheduleMode: scheduleMode,
|
||||||
|
countdownHours: deviceStatus.countdownHours,
|
||||||
|
countdownMinutes: deviceStatus.countdownMinutes,
|
||||||
|
inchingHours: deviceStatus.inchingHours,
|
||||||
|
inchingMinutes: deviceStatus.inchingMinutes,
|
||||||
|
isCountdownActive: isCountdownActive,
|
||||||
|
isInchingActive: isInchingActive,
|
||||||
|
countdownRemaining: countdownRemaining ?? Duration.zero,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
emit(ScheduleLoaded(
|
||||||
|
schedules: const [],
|
||||||
|
selectedTime: null,
|
||||||
|
selectedDays: List.filled(7, false),
|
||||||
|
functionOn: false,
|
||||||
|
isEditing: false,
|
||||||
|
deviceId: deviceId,
|
||||||
|
scheduleMode: scheduleMode,
|
||||||
|
countdownHours: deviceStatus.countdownHours,
|
||||||
|
countdownMinutes: deviceStatus.countdownMinutes,
|
||||||
|
inchingHours: deviceStatus.inchingHours,
|
||||||
|
inchingMinutes: deviceStatus.inchingMinutes,
|
||||||
|
isCountdownActive: isCountdownActive,
|
||||||
|
isInchingActive: isInchingActive,
|
||||||
|
countdownRemaining: countdownRemaining ?? Duration.zero,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (isCountdownActive && countdownRemaining != null) {
|
||||||
|
// _startCountdownTimer(emit, countdownRemaining);
|
||||||
|
// }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ScheduleError('Failed to fetch device status: $e'));
|
emit(ScheduleError('Failed to fetch device status: $e'));
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,6 @@ class ScheduleEditEvent extends ScheduleEvent {
|
|||||||
final String time;
|
final String time;
|
||||||
final List<String> selectedDays;
|
final List<String> selectedDays;
|
||||||
final bool functionOn;
|
final bool functionOn;
|
||||||
final String deviceType;
|
|
||||||
|
|
||||||
const ScheduleEditEvent({
|
const ScheduleEditEvent({
|
||||||
required this.scheduleId,
|
required this.scheduleId,
|
||||||
@ -99,7 +98,6 @@ class ScheduleEditEvent extends ScheduleEvent {
|
|||||||
required this.time,
|
required this.time,
|
||||||
required this.selectedDays,
|
required this.selectedDays,
|
||||||
required this.functionOn,
|
required this.functionOn,
|
||||||
required this.deviceType,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -109,7 +107,6 @@ class ScheduleEditEvent extends ScheduleEvent {
|
|||||||
time,
|
time,
|
||||||
selectedDays,
|
selectedDays,
|
||||||
functionOn,
|
functionOn,
|
||||||
deviceType,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,13 +138,11 @@ class ScheduleUpdateEntryEvent extends ScheduleEvent {
|
|||||||
|
|
||||||
class UpdateScheduleModeEvent extends ScheduleEvent {
|
class UpdateScheduleModeEvent extends ScheduleEvent {
|
||||||
final ScheduleModes scheduleMode;
|
final ScheduleModes scheduleMode;
|
||||||
final String countdownCode;
|
|
||||||
|
|
||||||
const UpdateScheduleModeEvent(
|
const UpdateScheduleModeEvent({required this.scheduleMode});
|
||||||
{required this.scheduleMode, required this.countdownCode});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [scheduleMode, countdownCode!];
|
List<Object> get props => [scheduleMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
class UpdateCountdownTimeEvent extends ScheduleEvent {
|
class UpdateCountdownTimeEvent extends ScheduleEvent {
|
||||||
@ -182,32 +177,28 @@ class StartScheduleEvent extends ScheduleEvent {
|
|||||||
final ScheduleModes mode;
|
final ScheduleModes mode;
|
||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
final String countDownCode;
|
|
||||||
|
|
||||||
const StartScheduleEvent({
|
const StartScheduleEvent({
|
||||||
required this.mode,
|
required this.mode,
|
||||||
required this.hours,
|
required this.hours,
|
||||||
required this.minutes,
|
required this.minutes,
|
||||||
required this.countDownCode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [mode, hours, minutes, countDownCode];
|
List<Object?> get props => [mode, hours, minutes];
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopScheduleEvent extends ScheduleEvent {
|
class StopScheduleEvent extends ScheduleEvent {
|
||||||
final ScheduleModes mode;
|
final ScheduleModes mode;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final String countdownCode;
|
|
||||||
|
|
||||||
const StopScheduleEvent({
|
const StopScheduleEvent({
|
||||||
required this.mode,
|
required this.mode,
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.countdownCode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [mode, deviceId, countdownCode];
|
List<Object?> get props => [mode, deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScheduleDecrementCountdownEvent extends ScheduleEvent {
|
class ScheduleDecrementCountdownEvent extends ScheduleEvent {
|
||||||
@ -219,13 +210,11 @@ class ScheduleDecrementCountdownEvent extends ScheduleEvent {
|
|||||||
|
|
||||||
class ScheduleFetchStatusEvent extends ScheduleEvent {
|
class ScheduleFetchStatusEvent extends ScheduleEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final String countdownCode;
|
|
||||||
|
|
||||||
const ScheduleFetchStatusEvent(
|
const ScheduleFetchStatusEvent(this.deviceId);
|
||||||
{required this.deviceId, required this.countdownCode});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId, countdownCode];
|
List<Object> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteScheduleEvent extends ScheduleEvent {
|
class DeleteScheduleEvent extends ScheduleEvent {
|
||||||
|
@ -29,7 +29,7 @@ class ScheduleLoaded extends ScheduleState {
|
|||||||
final int inchingSeconds;
|
final int inchingSeconds;
|
||||||
final bool isInchingActive;
|
final bool isInchingActive;
|
||||||
final ScheduleModes scheduleMode;
|
final ScheduleModes scheduleMode;
|
||||||
final Duration countdownRemaining;
|
final Duration? countdownRemaining;
|
||||||
final int? countdownSeconds;
|
final int? countdownSeconds;
|
||||||
|
|
||||||
const ScheduleLoaded({
|
const ScheduleLoaded({
|
||||||
@ -48,7 +48,7 @@ class ScheduleLoaded extends ScheduleState {
|
|||||||
this.inchingMinutes = 0,
|
this.inchingMinutes = 0,
|
||||||
this.isInchingActive = false,
|
this.isInchingActive = false,
|
||||||
this.scheduleMode = ScheduleModes.countdown,
|
this.scheduleMode = ScheduleModes.countdown,
|
||||||
this.countdownRemaining = Duration.zero,
|
this.countdownRemaining,
|
||||||
});
|
});
|
||||||
|
|
||||||
ScheduleLoaded copyWith({
|
ScheduleLoaded copyWith({
|
||||||
|
@ -11,7 +11,6 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
final String deviceId;
|
final String deviceId;
|
||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
final String countDownCode;
|
|
||||||
|
|
||||||
const CountdownModeButtons({
|
const CountdownModeButtons({
|
||||||
super.key,
|
super.key,
|
||||||
@ -19,7 +18,6 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.hours,
|
required this.hours,
|
||||||
required this.minutes,
|
required this.minutes,
|
||||||
required this.countDownCode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -45,7 +43,6 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
StopScheduleEvent(
|
StopScheduleEvent(
|
||||||
mode: ScheduleModes.countdown,
|
mode: ScheduleModes.countdown,
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
countdownCode: countDownCode,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -57,10 +54,10 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
StartScheduleEvent(
|
StartScheduleEvent(
|
||||||
mode: ScheduleModes.countdown,
|
mode: ScheduleModes.countdown,
|
||||||
hours: hours,
|
hours: hours,
|
||||||
minutes: minutes,
|
minutes: minutes,
|
||||||
countDownCode: countDownCode),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
backgroundColor: ColorsManager.primaryColor,
|
backgroundColor: ColorsManager.primaryColor,
|
||||||
|
@ -75,33 +75,23 @@ class _CountdownInchingViewState extends State<CountdownInchingView> {
|
|||||||
final isCountDown = state.scheduleMode == ScheduleModes.countdown;
|
final isCountDown = state.scheduleMode == ScheduleModes.countdown;
|
||||||
final isActive =
|
final isActive =
|
||||||
isCountDown ? state.isCountdownActive : state.isInchingActive;
|
isCountDown ? state.isCountdownActive : state.isInchingActive;
|
||||||
|
final displayHours = isActive && state.countdownRemaining != null
|
||||||
|
? state.countdownRemaining!.inHours
|
||||||
|
: (isCountDown ? state.countdownHours : state.inchingHours);
|
||||||
|
final displayMinutes = isActive && state.countdownRemaining != null
|
||||||
|
? state.countdownRemaining!.inMinutes.remainder(60)
|
||||||
|
: (isCountDown ? state.countdownMinutes : state.inchingMinutes);
|
||||||
|
final displaySeconds = isActive && state.countdownRemaining != null
|
||||||
|
? state.countdownRemaining!.inSeconds.remainder(60)
|
||||||
|
: (isCountDown ? state.countdownSeconds : state.inchingSeconds);
|
||||||
|
|
||||||
final displayHours =
|
_updateControllers(displayHours, displayMinutes, displaySeconds!);
|
||||||
isActive && state.countdownRemaining != Duration.zero
|
|
||||||
? state.countdownRemaining.inHours
|
|
||||||
: (isCountDown ? state.countdownHours : state.inchingHours);
|
|
||||||
|
|
||||||
final displayMinutes =
|
if (displayHours == 0 && displayMinutes == 0 && displaySeconds == 0) {
|
||||||
isActive && state.countdownRemaining != Duration.zero
|
|
||||||
? state.countdownRemaining.inMinutes.remainder(60)
|
|
||||||
: (isCountDown ? state.countdownMinutes : state.inchingMinutes);
|
|
||||||
|
|
||||||
final displaySeconds =
|
|
||||||
isActive && state.countdownRemaining != Duration.zero
|
|
||||||
? state.countdownRemaining.inSeconds.remainder(60)
|
|
||||||
: (isCountDown ? (state.countdownSeconds ?? 0) : 0);
|
|
||||||
|
|
||||||
_updateControllers(displayHours, displayMinutes, displaySeconds);
|
|
||||||
|
|
||||||
if (isActive &&
|
|
||||||
displayHours == 0 &&
|
|
||||||
displayMinutes == 0 &&
|
|
||||||
displaySeconds == 0) {
|
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
StopScheduleEvent(
|
StopScheduleEvent(
|
||||||
mode: ScheduleModes.countdown,
|
mode: ScheduleModes.countdown,
|
||||||
deviceId: widget.deviceId,
|
deviceId: widget.deviceId,
|
||||||
countdownCode: '',
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,7 @@ class InchingModeButtons extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
StopScheduleEvent(
|
StopScheduleEvent(
|
||||||
deviceId: deviceId,
|
deviceId: deviceId, mode: ScheduleModes.inching),
|
||||||
mode: ScheduleModes.inching,
|
|
||||||
countdownCode: ''),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
|
@ -18,15 +18,11 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.deviceUuid,
|
required this.deviceUuid,
|
||||||
required this.category,
|
required this.category,
|
||||||
required this.countdownCode,
|
|
||||||
this.code,
|
this.code,
|
||||||
required this.deviceType,
|
|
||||||
});
|
});
|
||||||
final String deviceUuid;
|
final String deviceUuid;
|
||||||
final String category;
|
final String category;
|
||||||
final String? code;
|
final String? code;
|
||||||
final String? countdownCode;
|
|
||||||
final String deviceType;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -35,8 +31,7 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
deviceId: deviceUuid,
|
deviceId: deviceUuid,
|
||||||
)
|
)
|
||||||
..add(ScheduleGetEvent(category: category))
|
..add(ScheduleGetEvent(category: category))
|
||||||
..add(ScheduleFetchStatusEvent(
|
..add(ScheduleFetchStatusEvent(deviceUuid)),
|
||||||
deviceId: deviceUuid, countdownCode: countdownCode ?? '')),
|
|
||||||
child: Dialog(
|
child: Dialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
insetPadding: const EdgeInsets.all(20),
|
insetPadding: const EdgeInsets.all(20),
|
||||||
@ -57,32 +52,28 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const ScheduleHeader(),
|
const ScheduleHeader(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (deviceType == 'CUR_2')
|
ScheduleModeSelector(
|
||||||
const SizedBox()
|
currentMode: state.scheduleMode,
|
||||||
else
|
),
|
||||||
ScheduleModeSelector(
|
|
||||||
countdownCode: countdownCode ?? '',
|
|
||||||
currentMode: state.scheduleMode,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (state.scheduleMode == ScheduleModes.schedule)
|
if (state.scheduleMode == ScheduleModes.schedule)
|
||||||
ScheduleManagementUI(
|
ScheduleManagementUI(
|
||||||
deviceType: deviceType,
|
|
||||||
category: category,
|
category: category,
|
||||||
deviceUuid: deviceUuid,
|
deviceUuid: deviceUuid,
|
||||||
onAddSchedule: () async {
|
onAddSchedule: () async {
|
||||||
final entry = await ScheduleDialogHelper
|
final entry = await ScheduleDialogHelper
|
||||||
.showAddScheduleDialog(context,
|
.showAddScheduleDialog(
|
||||||
schedule: ScheduleEntry(
|
context,
|
||||||
category: category,
|
schedule: ScheduleEntry(
|
||||||
time: '',
|
category: category,
|
||||||
function: Status(
|
time: '',
|
||||||
code: code.toString(), value: null),
|
function: Status(
|
||||||
days: [],
|
code: code.toString(), value: null),
|
||||||
),
|
days: [],
|
||||||
isEdit: false,
|
),
|
||||||
code: code,
|
isEdit: false,
|
||||||
deviceType: deviceType);
|
code: code,
|
||||||
|
);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
ScheduleAddEvent(
|
ScheduleAddEvent(
|
||||||
@ -96,16 +87,14 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (deviceType != 'CUR_2')
|
if (state.scheduleMode == ScheduleModes.countdown ||
|
||||||
if (state.scheduleMode == ScheduleModes.countdown ||
|
state.scheduleMode == ScheduleModes.inching)
|
||||||
state.scheduleMode == ScheduleModes.inching)
|
CountdownInchingView(
|
||||||
CountdownInchingView(
|
deviceId: deviceUuid,
|
||||||
deviceId: deviceUuid,
|
),
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (state.scheduleMode == ScheduleModes.countdown)
|
if (state.scheduleMode == ScheduleModes.countdown)
|
||||||
CountdownModeButtons(
|
CountdownModeButtons(
|
||||||
countDownCode: countdownCode ?? '',
|
|
||||||
isActive: state.isCountdownActive,
|
isActive: state.isCountdownActive,
|
||||||
deviceId: deviceUuid,
|
deviceId: deviceUuid,
|
||||||
hours: state.countdownHours,
|
hours: state.countdownHours,
|
||||||
|
@ -5,16 +5,14 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
|||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
class ScheduleManagementUI extends StatelessWidget {
|
class ScheduleManagementUI extends StatelessWidget {
|
||||||
final String deviceUuid;
|
final String deviceUuid;
|
||||||
final VoidCallback onAddSchedule;
|
final VoidCallback onAddSchedule;
|
||||||
final String category;
|
final String category;
|
||||||
final String deviceType;
|
|
||||||
|
|
||||||
const ScheduleManagementUI({
|
const ScheduleManagementUI({
|
||||||
super.key,
|
super.key,
|
||||||
required this.deviceUuid,
|
required this.deviceUuid,
|
||||||
required this.onAddSchedule,
|
required this.onAddSchedule,
|
||||||
required this.deviceType,
|
|
||||||
this.category = 'switch_1',
|
this.category = 'switch_1',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,11 +44,7 @@ class ScheduleManagementUI extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
ScheduleTableWidget(
|
ScheduleTableWidget(deviceUuid: deviceUuid, category: category),
|
||||||
deviceUuid: deviceUuid,
|
|
||||||
category: category,
|
|
||||||
deviceType: deviceType,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,10 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|||||||
|
|
||||||
class ScheduleModeSelector extends StatelessWidget {
|
class ScheduleModeSelector extends StatelessWidget {
|
||||||
final ScheduleModes currentMode;
|
final ScheduleModes currentMode;
|
||||||
final String countdownCode;
|
|
||||||
|
|
||||||
const ScheduleModeSelector({
|
const ScheduleModeSelector({
|
||||||
super.key,
|
super.key,
|
||||||
required this.currentMode,
|
required this.currentMode,
|
||||||
required this.countdownCode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -73,8 +71,7 @@ class ScheduleModeSelector extends StatelessWidget {
|
|||||||
onChanged: (ScheduleModes? value) {
|
onChanged: (ScheduleModes? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
UpdateScheduleModeEvent(
|
UpdateScheduleModeEvent(scheduleMode: value),
|
||||||
scheduleMode: value, countdownCode: countdownCode),
|
|
||||||
);
|
);
|
||||||
if (value == ScheduleModes.schedule) {
|
if (value == ScheduleModes.schedule) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
|
@ -12,13 +12,11 @@ import 'package:syncrow_web/utils/format_date_time.dart';
|
|||||||
class ScheduleTableWidget extends StatelessWidget {
|
class ScheduleTableWidget extends StatelessWidget {
|
||||||
final String deviceUuid;
|
final String deviceUuid;
|
||||||
final String category;
|
final String category;
|
||||||
final String deviceType;
|
|
||||||
|
|
||||||
const ScheduleTableWidget({
|
const ScheduleTableWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.deviceUuid,
|
required this.deviceUuid,
|
||||||
this.category = 'switch_1',
|
this.category = 'switch_1',
|
||||||
required this.deviceType,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -27,14 +25,13 @@ class ScheduleTableWidget extends StatelessWidget {
|
|||||||
create: (_) => ScheduleBloc(
|
create: (_) => ScheduleBloc(
|
||||||
deviceId: deviceUuid,
|
deviceId: deviceUuid,
|
||||||
)..add(ScheduleGetEvent(category: category)),
|
)..add(ScheduleGetEvent(category: category)),
|
||||||
child: _ScheduleTableView(deviceType),
|
child: _ScheduleTableView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ScheduleTableView extends StatelessWidget {
|
class _ScheduleTableView extends StatelessWidget {
|
||||||
final String deviceType;
|
const _ScheduleTableView();
|
||||||
const _ScheduleTableView(this.deviceType);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -84,7 +81,7 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
bottomLeft: Radius.circular(20),
|
bottomLeft: Radius.circular(20),
|
||||||
bottomRight: Radius.circular(20)),
|
bottomRight: Radius.circular(20)),
|
||||||
),
|
),
|
||||||
child: _buildTableBody(state.schedules, context, deviceType));
|
child: _buildTableBody(state.schedules, context));
|
||||||
}
|
}
|
||||||
if (state is ScheduleError) {
|
if (state is ScheduleError) {
|
||||||
return Center(child: Text(state.error));
|
return Center(child: Text(state.error));
|
||||||
@ -126,8 +123,7 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTableBody(
|
Widget _buildTableBody(List<ScheduleModel> schedules, BuildContext context) {
|
||||||
List<ScheduleModel> schedules, BuildContext context, String deviceType) {
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@ -136,8 +132,7 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < schedules.length; i++)
|
for (int i = 0; i < schedules.length; i++)
|
||||||
_buildScheduleRow(schedules[i], i, context,
|
_buildScheduleRow(schedules[i], i, context),
|
||||||
deviceType: deviceType),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -160,19 +155,25 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TableRow _buildScheduleRow(
|
TableRow _buildScheduleRow(
|
||||||
ScheduleModel schedule, int index, BuildContext context,
|
ScheduleModel schedule, int index, BuildContext context) {
|
||||||
{required String deviceType}) {
|
|
||||||
return TableRow(
|
return TableRow(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
bool temp;
|
||||||
|
if (schedule.category == 'CUR_2') {
|
||||||
|
temp = schedule.function.value == 'open' ? true : false;
|
||||||
|
} else {
|
||||||
|
temp = schedule.function.value as bool;
|
||||||
|
}
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
ScheduleUpdateEntryEvent(
|
ScheduleUpdateEntryEvent(
|
||||||
category: schedule.category,
|
category: schedule.category,
|
||||||
scheduleId: schedule.scheduleId,
|
scheduleId: schedule.scheduleId,
|
||||||
functionOn: schedule.function.value,
|
functionOn: temp,
|
||||||
|
// schedule.function.value,
|
||||||
enable: !schedule.enable,
|
enable: !schedule.enable,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -194,11 +195,10 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
child: Text(_getSelectedDays(
|
child: Text(_getSelectedDays(
|
||||||
ScheduleModel.parseSelectedDays(schedule.days)))),
|
ScheduleModel.parseSelectedDays(schedule.days)))),
|
||||||
Center(child: Text(formatIsoStringToTime(schedule.time, context))),
|
Center(child: Text(formatIsoStringToTime(schedule.time, context))),
|
||||||
if (deviceType == 'CUR_2')
|
schedule.category == 'CUR_2'
|
||||||
Center(
|
? Center(
|
||||||
child: Text(schedule.function.value == true ? 'open' : 'close'))
|
child: Text(schedule.function.value == true ? 'open' : 'close'))
|
||||||
else
|
: Center(child: Text(schedule.function.value ? 'On' : 'Off')),
|
||||||
Center(child: Text(schedule.function.value ? 'On' : 'Off')),
|
|
||||||
Center(
|
Center(
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
runAlignment: WrapAlignment.center,
|
runAlignment: WrapAlignment.center,
|
||||||
@ -206,27 +206,18 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ScheduleDialogHelper.showAddScheduleDialog(context,
|
ScheduleDialogHelper.showAddScheduleDialog(
|
||||||
schedule: ScheduleEntry.fromScheduleModel(schedule),
|
context,
|
||||||
isEdit: true,
|
schedule: ScheduleEntry.fromScheduleModel(schedule),
|
||||||
deviceType: deviceType)
|
isEdit: true,
|
||||||
.then((updatedSchedule) {
|
).then((updatedSchedule) {
|
||||||
if (updatedSchedule != null) {
|
if (updatedSchedule != null) {
|
||||||
bool temp;
|
|
||||||
if (deviceType == 'CUR_2') {
|
|
||||||
updatedSchedule.function.value == 'open'
|
|
||||||
? temp = true
|
|
||||||
: temp = false;
|
|
||||||
} else {
|
|
||||||
temp = updatedSchedule.function.value;
|
|
||||||
}
|
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
ScheduleEditEvent(
|
ScheduleEditEvent(
|
||||||
deviceType: deviceType,
|
|
||||||
scheduleId: schedule.scheduleId,
|
scheduleId: schedule.scheduleId,
|
||||||
category: schedule.category,
|
category: schedule.category,
|
||||||
time: updatedSchedule.time,
|
time: updatedSchedule.time,
|
||||||
functionOn: temp,
|
functionOn: updatedSchedule.function.value,
|
||||||
selectedDays: updatedSchedule.days),
|
selectedDays: updatedSchedule.days),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class ThreeGangGlassSwitchBloc
|
|||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
_listenToChanges(event.deviceId);
|
_listenToChanges(event.deviceId, emit);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
@ -50,28 +50,42 @@ class ThreeGangGlassSwitchBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
|
void _listenToChanges(
|
||||||
|
String deviceId,
|
||||||
void _listenToChanges(String deviceId) {
|
Emitter<ThreeGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
|
final stream = ref.onValue;
|
||||||
if (event.snapshot.value == null) return;
|
|
||||||
|
|
||||||
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
|
stream.listen((DatabaseEvent event) {
|
||||||
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
final statusList = <Status>[];
|
final statusList = <Status>[];
|
||||||
|
if (data['status'] != null) {
|
||||||
usersMap['status'].forEach((element) {
|
for (var element in data['status']) {
|
||||||
statusList.add(Status(code: element['code'], value: element['value']));
|
statusList.add(
|
||||||
});
|
Status(
|
||||||
|
code: element['code'].toString(),
|
||||||
deviceStatus =
|
value: element['value'].toString(),
|
||||||
ThreeGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
|
),
|
||||||
|
);
|
||||||
add(StatusUpdated(deviceStatus));
|
}
|
||||||
|
}
|
||||||
|
if (statusList.isNotEmpty) {
|
||||||
|
final newStatus = ThreeGangGlassStatusModel.fromJson(deviceId, statusList);
|
||||||
|
if (newStatus != deviceStatus) {
|
||||||
|
deviceStatus = newStatus;
|
||||||
|
if (!isClosed) {
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (e) {
|
||||||
|
emit(ThreeGangGlassSwitchError('Failed to listen to changes: $e'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(
|
void _onStatusUpdated(
|
||||||
@ -170,10 +184,4 @@ class ThreeGangGlassSwitchBloc
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_deviceStatusSubscription?.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,6 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: '3GT',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -129,8 +127,6 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
countdownCode: 'countdown_2',
|
|
||||||
deviceType: '3GT',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -147,8 +143,6 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_3',
|
category: 'switch_3',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
countdownCode: 'countdown_3',
|
|
||||||
deviceType: '3GT',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -102,8 +102,6 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: '3G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -120,8 +118,6 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
countdownCode: 'countdown_2',
|
|
||||||
deviceType: '3G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -138,8 +134,6 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_3',
|
category: 'switch_3',
|
||||||
countdownCode: 'countdown_3',
|
|
||||||
deviceType: '3G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -1,177 +1,173 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
||||||
import 'package:syncrow_web/services/batch_control_devices_service.dart';
|
import 'package:syncrow_web/services/batch_control_devices_service.dart';
|
||||||
import 'package:syncrow_web/services/control_device_service.dart';
|
import 'package:syncrow_web/services/control_device_service.dart';
|
||||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'two_gang_glass_switch_event.dart';
|
part 'two_gang_glass_switch_event.dart';
|
||||||
part 'two_gang_glass_switch_state.dart';
|
part 'two_gang_glass_switch_state.dart';
|
||||||
|
|
||||||
class TwoGangGlassSwitchBloc
|
class TwoGangGlassSwitchBloc
|
||||||
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final ControlDeviceService controlDeviceService;
|
final ControlDeviceService controlDeviceService;
|
||||||
final BatchControlDevicesService batchControlDevicesService;
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
late TwoGangGlassStatusModel deviceStatus;
|
late TwoGangGlassStatusModel deviceStatus;
|
||||||
|
|
||||||
TwoGangGlassSwitchBloc({
|
TwoGangGlassSwitchBloc({
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.controlDeviceService,
|
required this.controlDeviceService,
|
||||||
required this.batchControlDevicesService,
|
required this.batchControlDevicesService,
|
||||||
}) : super(TwoGangGlassSwitchInitial()) {
|
}) : super(TwoGangGlassSwitchInitial()) {
|
||||||
on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<TwoGangGlassSwitchControl>(_onControl);
|
on<TwoGangGlassSwitchControl>(_onControl);
|
||||||
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onFetchDeviceStatus(
|
||||||
|
TwoGangGlassSwitchFetchDeviceEvent event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
try {
|
||||||
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
|
deviceStatus = TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
} catch (e) {
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(
|
void _listenToChanges(String deviceId) {
|
||||||
TwoGangGlassSwitchFetchDeviceEvent event,
|
try {
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
final ref = FirebaseDatabase.instance.ref(
|
||||||
) async {
|
'device-status/$deviceId',
|
||||||
emit(TwoGangGlassSwitchLoading());
|
);
|
||||||
try {
|
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
|
||||||
deviceStatus = TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
_listenToChanges(event.deviceId);
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
} catch (e) {
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
|
ref.onValue.listen((event) {
|
||||||
|
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
void _listenToChanges(String deviceId) {
|
List<Status> statusList = [];
|
||||||
try {
|
eventsMap['status'].forEach((element) {
|
||||||
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
statusList.add(Status(code: element['code'], value: element['value']));
|
||||||
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
|
|
||||||
if (event.snapshot.value == null) return;
|
|
||||||
|
|
||||||
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
|
|
||||||
|
|
||||||
final statusList = <Status>[];
|
|
||||||
|
|
||||||
usersMap['status'].forEach((element) {
|
|
||||||
statusList.add(Status(code: element['code'], value: element['value']));
|
|
||||||
});
|
|
||||||
|
|
||||||
deviceStatus =
|
|
||||||
TwoGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
|
|
||||||
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
|
||||||
|
deviceStatus = TwoGangGlassStatusModel.fromJson(deviceId, statusList);
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
});
|
||||||
|
} catch (_) {
|
||||||
|
log(
|
||||||
|
'Error listening to changes',
|
||||||
|
name: 'TwoGangGlassSwitchBloc._listenToChanges',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onControl(
|
Future<void> _onControl(
|
||||||
TwoGangGlassSwitchControl event,
|
TwoGangGlassSwitchControl event,
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
) async {
|
) async {
|
||||||
emit(TwoGangGlassSwitchLoading());
|
emit(TwoGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await controlDeviceService.controlDevice(
|
await controlDeviceService.controlDevice(
|
||||||
deviceUuid: event.deviceId,
|
deviceUuid: event.deviceId,
|
||||||
status: Status(code: event.code, value: event.value),
|
status: Status(code: event.code, value: event.value),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_updateLocalValue(event.code, !event.value);
|
_updateLocalValue(event.code, !event.value);
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onBatchControl(
|
Future<void> _onBatchControl(
|
||||||
TwoGangGlassSwitchBatchControl event,
|
TwoGangGlassSwitchBatchControl event,
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
) async {
|
) async {
|
||||||
emit(TwoGangGlassSwitchLoading());
|
emit(TwoGangGlassSwitchLoading());
|
||||||
_updateLocalValue(event.code, event.value);
|
_updateLocalValue(event.code, event.value);
|
||||||
|
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await batchControlDevicesService.batchControlDevices(
|
||||||
|
uuids: event.deviceIds,
|
||||||
|
code: event.code,
|
||||||
|
value: event.value,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onFetchBatchStatus(
|
||||||
|
TwoGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
try {
|
||||||
|
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
|
deviceStatus = TwoGangGlassStatusModel.fromJson(
|
||||||
|
event.deviceIds.first,
|
||||||
|
status.status,
|
||||||
|
);
|
||||||
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
|
} catch (e) {
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
Future<void> _onFactoryReset(
|
||||||
await batchControlDevicesService.batchControlDevices(
|
TwoGangGlassFactoryReset event,
|
||||||
uuids: event.deviceIds,
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
code: event.code,
|
) async {
|
||||||
value: event.value,
|
emit(TwoGangGlassSwitchLoading());
|
||||||
);
|
try {
|
||||||
} catch (e) {
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
_updateLocalValue(event.code, !event.value);
|
event.factoryReset,
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
event.deviceId,
|
||||||
|
);
|
||||||
|
if (!response) {
|
||||||
|
emit(TwoGangGlassSwitchError('Failed to reset device'));
|
||||||
|
} else {
|
||||||
|
add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
void _onStatusUpdated(
|
||||||
TwoGangGlassSwitchFetchBatchStatusEvent event,
|
StatusUpdated event,
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
) async {
|
) {
|
||||||
emit(TwoGangGlassSwitchLoading());
|
deviceStatus = event.deviceStatus;
|
||||||
try {
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
}
|
||||||
deviceStatus = TwoGangGlassStatusModel.fromJson(
|
|
||||||
event.deviceIds.first,
|
void _updateLocalValue(String code, bool value) {
|
||||||
status.status,
|
switch (code) {
|
||||||
);
|
case 'switch_1':
|
||||||
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
} catch (e) {
|
break;
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
case 'switch_2':
|
||||||
}
|
deviceStatus = deviceStatus.copyWith(switch2: value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFactoryReset(
|
|
||||||
TwoGangGlassFactoryReset event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) async {
|
|
||||||
emit(TwoGangGlassSwitchLoading());
|
|
||||||
try {
|
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
|
||||||
event.factoryReset,
|
|
||||||
event.deviceId,
|
|
||||||
);
|
|
||||||
if (!response) {
|
|
||||||
emit(TwoGangGlassSwitchError('Failed to reset device'));
|
|
||||||
} else {
|
|
||||||
add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onStatusUpdated(
|
|
||||||
StatusUpdated event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) {
|
|
||||||
deviceStatus = event.deviceStatus;
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
|
||||||
switch (code) {
|
|
||||||
case 'switch_1':
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
|
||||||
break;
|
|
||||||
case 'switch_2':
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch2: value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() {
|
|
||||||
_deviceStatusSubscription?.cancel();
|
|
||||||
return super.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,6 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
|
|||||||
builder: (ctx) => BlocProvider.value(
|
builder: (ctx) => BlocProvider.value(
|
||||||
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceType: '2GT',
|
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
),
|
),
|
||||||
@ -120,8 +118,6 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
|
|||||||
builder: (ctx) => BlocProvider.value(
|
builder: (ctx) => BlocProvider.value(
|
||||||
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceType: '2GT',
|
|
||||||
countdownCode: 'countdown_2',
|
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
),
|
),
|
||||||
|
@ -97,8 +97,6 @@ class TwoGangBatchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceIds.first,
|
deviceUuid: deviceIds.first,
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: '2G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -116,8 +114,6 @@ class TwoGangBatchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
deviceUuid: deviceIds.first,
|
deviceUuid: deviceIds.first,
|
||||||
countdownCode: 'countdown_2',
|
|
||||||
deviceType: '2G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -125,7 +121,10 @@ class TwoGangBatchControlView extends StatelessWidget
|
|||||||
subtitle: 'Scheduling',
|
subtitle: 'Scheduling',
|
||||||
iconPath: Assets.scheduling,
|
iconPath: Assets.scheduling,
|
||||||
),
|
),
|
||||||
|
// FirmwareUpdateWidget(
|
||||||
|
// deviceId: deviceIds.first,
|
||||||
|
// version: 12,
|
||||||
|
// ),
|
||||||
FactoryResetWidget(callFactoryReset: () {
|
FactoryResetWidget(callFactoryReset: () {
|
||||||
context.read<TwoGangSwitchBloc>().add(
|
context.read<TwoGangSwitchBloc>().add(
|
||||||
TwoGangFactoryReset(
|
TwoGangFactoryReset(
|
||||||
|
@ -103,8 +103,6 @@ class TwoGangDeviceControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: '2G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -127,8 +125,6 @@ class TwoGangDeviceControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
countdownCode: 'countdown_2',
|
|
||||||
deviceType: '2G',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -18,21 +18,14 @@ class ScheduleDialogHelper {
|
|||||||
ScheduleEntry? schedule,
|
ScheduleEntry? schedule,
|
||||||
bool isEdit = false,
|
bool isEdit = false,
|
||||||
String? code,
|
String? code,
|
||||||
required String deviceType,
|
|
||||||
}) {
|
}) {
|
||||||
bool temp;
|
|
||||||
if (deviceType == 'CUR_2') {
|
|
||||||
temp = schedule!.function.value == 'open' ? true : false;
|
|
||||||
} else {
|
|
||||||
temp = schedule!.function.value;
|
|
||||||
}
|
|
||||||
final initialTime = schedule != null
|
final initialTime = schedule != null
|
||||||
? _convertStringToTimeOfDay(schedule.time)
|
? _convertStringToTimeOfDay(schedule.time)
|
||||||
: TimeOfDay.now();
|
: TimeOfDay.now();
|
||||||
final initialDays = schedule != null
|
final initialDays = schedule != null
|
||||||
? _convertDaysStringToBooleans(schedule.days)
|
? _convertDaysStringToBooleans(schedule.days)
|
||||||
: List.filled(7, false);
|
: List.filled(7, false);
|
||||||
bool? functionOn = temp;
|
bool? functionOn = schedule?.function.value ?? true;
|
||||||
TimeOfDay selectedTime = initialTime;
|
TimeOfDay selectedTime = initialTime;
|
||||||
List<bool> selectedDays = List.of(initialDays);
|
List<bool> selectedDays = List.of(initialDays);
|
||||||
|
|
||||||
@ -104,7 +97,8 @@ class ScheduleDialogHelper {
|
|||||||
setState(() => selectedDays[i] = v);
|
setState(() => selectedDays[i] = v);
|
||||||
}),
|
}),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildFunctionSwitch(deviceType, ctx, functionOn!, (v) {
|
_buildFunctionSwitch(schedule!.category, ctx, functionOn!,
|
||||||
|
(v) {
|
||||||
setState(() => functionOn = v);
|
setState(() => functionOn = v);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@ -120,29 +114,32 @@ class ScheduleDialogHelper {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 100,
|
width: 100,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
dynamic temp;
|
dynamic temp;
|
||||||
if (deviceType == 'CUR_2') {
|
if (schedule?.category == 'CUR_2') {
|
||||||
temp = functionOn! ? 'open' : 'close';
|
temp = functionOn! ? 'open' : 'close';
|
||||||
} else {
|
} else {
|
||||||
temp = functionOn;
|
temp = functionOn;
|
||||||
}
|
}
|
||||||
final entry = ScheduleEntry(
|
print(temp);
|
||||||
category: schedule?.category ?? 'switch_1',
|
final entry = ScheduleEntry(
|
||||||
time: _formatTimeOfDayToISO(selectedTime),
|
category: schedule?.category ?? 'switch_1',
|
||||||
function: Status(
|
time: _formatTimeOfDayToISO(selectedTime),
|
||||||
code: code ?? 'switch_1',
|
function: Status(
|
||||||
value: temp,
|
code: code ?? 'switch_1',
|
||||||
),
|
value: temp,
|
||||||
days: _convertSelectedDaysToStrings(selectedDays),
|
// functionOn,
|
||||||
scheduleId: schedule.scheduleId,
|
),
|
||||||
);
|
days: _convertSelectedDaysToStrings(selectedDays),
|
||||||
Navigator.pop(ctx, entry);
|
scheduleId: schedule?.scheduleId,
|
||||||
},
|
);
|
||||||
child: const Text('Save'),
|
Navigator.pop(ctx, entry);
|
||||||
)),
|
},
|
||||||
|
child: const Text('Save'),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -84,8 +84,6 @@ class WaterHeaterDeviceControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: device.uuid ?? '',
|
deviceUuid: device.uuid ?? '',
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
countdownCode: 'countdown_1',
|
|
||||||
deviceType: 'WH',
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -105,7 +105,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
color: const Color(0xFF0026A2),
|
color: const Color(0xFF0026A2),
|
||||||
),
|
),
|
||||||
HomeItemModel(
|
HomeItemModel(
|
||||||
title: 'Device Management',
|
title: 'Devices Management',
|
||||||
icon: Assets.devicesIcon,
|
icon: Assets.devicesIcon,
|
||||||
active: true,
|
active: true,
|
||||||
onPress: (context) {
|
onPress: (context) {
|
||||||
|
@ -455,7 +455,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
Future<void> checkEmail(
|
Future<void> checkEmail(
|
||||||
CheckEmailEvent event, Emitter<UsersState> emit) async {
|
CheckEmailEvent event, Emitter<UsersState> emit) async {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
String? res = await UserPermissionApi().checkEmail(
|
String? res = await UserPermissionApi().checkEmail(
|
||||||
emailController.text,
|
emailController.text,
|
||||||
);
|
);
|
||||||
checkEmailValid = res!;
|
checkEmailValid = res!;
|
||||||
|
@ -34,8 +34,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
return Dialog(
|
return Dialog(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
|
||||||
width: 900,
|
width: 900,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -64,8 +63,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStep3Indicator(
|
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||||
3, "Role & Permissions", _blocRole),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -107,32 +105,18 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final isBasicsStep = currentStep == 1;
|
|
||||||
|
|
||||||
if (isBasicsStep) {
|
|
||||||
// Validate the form first
|
|
||||||
final isValid = _blocRole.formKey.currentState
|
|
||||||
?.validate() ??
|
|
||||||
false;
|
|
||||||
|
|
||||||
if (!isValid)
|
|
||||||
return; // Stop if form is not valid
|
|
||||||
}
|
|
||||||
_blocRole.add(const CheckEmailEvent());
|
_blocRole.add(const CheckEmailEvent());
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if (currentStep < 3) {
|
if (currentStep < 3) {
|
||||||
currentStep++;
|
currentStep++;
|
||||||
if (currentStep == 2) {
|
if (currentStep == 2) {
|
||||||
_blocRole.add(const CheckStepStatus(
|
_blocRole.add(const CheckStepStatus(isEditUser: false));
|
||||||
isEditUser: false));
|
|
||||||
} else if (currentStep == 3) {
|
} else if (currentStep == 3) {
|
||||||
_blocRole
|
_blocRole.add(const CheckSpacesStepStatus());
|
||||||
.add(const CheckSpacesStepStatus());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_blocRole
|
_blocRole.add(SendInviteUsers(context: context));
|
||||||
.add(SendInviteUsers(context: context));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -140,11 +124,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
currentStep < 3 ? "Next" : "Save",
|
currentStep < 3 ? "Next" : "Save",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: (_blocRole.isCompleteSpaces == false ||
|
color: (_blocRole.isCompleteSpaces == false ||
|
||||||
_blocRole.isCompleteBasics ==
|
_blocRole.isCompleteBasics == false ||
|
||||||
false ||
|
_blocRole.isCompleteRolePermissions == false) &&
|
||||||
_blocRole
|
|
||||||
.isCompleteRolePermissions ==
|
|
||||||
false) &&
|
|
||||||
currentStep == 3
|
currentStep == 3
|
||||||
? ColorsManager.grayColor
|
? ColorsManager.grayColor
|
||||||
: ColorsManager.secondaryColor),
|
: ColorsManager.secondaryColor),
|
||||||
@ -162,7 +143,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
Widget _getFormContent() {
|
Widget _getFormContent() {
|
||||||
switch (currentStep) {
|
switch (currentStep) {
|
||||||
case 1:
|
case 1:
|
||||||
return BasicsView(
|
return const BasicsView(
|
||||||
userId: '',
|
userId: '',
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
@ -215,12 +196,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -283,12 +260,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -345,12 +318,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step
|
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||||
? ColorsManager.blackColor
|
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||||
: ColorsManager.greyColor,
|
|
||||||
fontWeight: currentStep == step
|
|
||||||
? FontWeight.bold
|
|
||||||
: FontWeight.normal,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
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:intl_phone_field/countries.dart';
|
import 'package:intl_phone_field/countries.dart';
|
||||||
import 'package:intl_phone_field/country_picker_dialog.dart';
|
import 'package:intl_phone_field/country_picker_dialog.dart';
|
||||||
import 'package:intl_phone_field/intl_phone_field.dart';
|
import 'package:intl_phone_field/intl_phone_field.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@ -14,9 +11,7 @@ import 'package:syncrow_web/utils/style.dart';
|
|||||||
|
|
||||||
class BasicsView extends StatelessWidget {
|
class BasicsView extends StatelessWidget {
|
||||||
final String? userId;
|
final String? userId;
|
||||||
Timer? _debounce;
|
const BasicsView({super.key, this.userId = ''});
|
||||||
|
|
||||||
BasicsView({super.key, this.userId = ''});
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
||||||
@ -26,7 +21,6 @@ class BasicsView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
return Form(
|
return Form(
|
||||||
key: _blocRole.formKey,
|
key: _blocRole.formKey,
|
||||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
|
||||||
child: ListView(
|
child: ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
@ -214,14 +208,6 @@ class BasicsView extends StatelessWidget {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: ColorsManager.textGray),
|
color: ColorsManager.textGray),
|
||||||
),
|
),
|
||||||
|
|
||||||
onChanged: (value) {
|
|
||||||
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
|
||||||
_debounce = Timer(const Duration(milliseconds: 800), () {
|
|
||||||
_blocRole.add(const CheckEmailEvent());
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Enter Email Address';
|
return 'Enter Email Address';
|
||||||
|
@ -170,45 +170,45 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLoadScenes(
|
Future<void> _onLoadScenes(
|
||||||
LoadScenes event, Emitter<RoutineState> emit) async {
|
LoadScenes event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
List<ScenesModel> scenes = [];
|
List<ScenesModel> scenes = [];
|
||||||
try {
|
try {
|
||||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
if (createRoutineBloc.selectedSpaceId == '' &&
|
if (createRoutineBloc.selectedSpaceId == '' &&
|
||||||
createRoutineBloc.selectedCommunityId == '') {
|
createRoutineBloc.selectedCommunityId == '') {
|
||||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
List<String> spacesList =
|
List<String> spacesList =
|
||||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
for (var spaceId in spacesList) {
|
for (var spaceId in spacesList) {
|
||||||
scenes.addAll(
|
scenes.addAll(
|
||||||
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
scenes.addAll(await SceneApi.getScenes(
|
||||||
|
createRoutineBloc.selectedSpaceId,
|
||||||
|
createRoutineBloc.selectedCommunityId,
|
||||||
|
projectUuid));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
scenes.addAll(await SceneApi.getScenes(
|
|
||||||
createRoutineBloc.selectedSpaceId,
|
|
||||||
createRoutineBloc.selectedCommunityId,
|
|
||||||
projectUuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
scenes: scenes,
|
scenes: scenes,
|
||||||
isLoading: false,
|
|
||||||
));
|
|
||||||
} catch (e) {
|
|
||||||
emit(state.copyWith(
|
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
loadScenesErrorMessage: 'Failed to load scenes',
|
));
|
||||||
errorMessage: '',
|
} catch (e) {
|
||||||
loadAutomationErrorMessage: '',
|
emit(state.copyWith(
|
||||||
scenes: scenes));
|
isLoading: false,
|
||||||
|
loadScenesErrorMessage: 'Failed to load scenes',
|
||||||
|
errorMessage: '',
|
||||||
|
loadAutomationErrorMessage: '',
|
||||||
|
scenes: scenes));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onLoadAutomation(
|
Future<void> _onLoadAutomation(
|
||||||
LoadAutomation event, Emitter<RoutineState> emit) async {
|
LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||||
@ -936,16 +936,15 @@ Future<void> _onLoadScenes(
|
|||||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
List<String> spacesList =
|
List<String> spacesList =
|
||||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
for (var spaceId in spacesList) {
|
|
||||||
devices.addAll(await DevicesManagementApi()
|
devices.addAll(await DevicesManagementApi()
|
||||||
.fetchDevices(communityId, spaceId, projectUuid));
|
.fetchDevices(projectUuid, spacesId: spacesList));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
devices.addAll(await DevicesManagementApi().fetchDevices(
|
devices.addAll(await DevicesManagementApi().fetchDevices(
|
||||||
createRoutineBloc.selectedCommunityId,
|
projectUuid,
|
||||||
createRoutineBloc.selectedSpaceId,
|
spacesId: [createRoutineBloc.selectedSpaceId],
|
||||||
projectUuid));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(state.copyWith(isLoading: false, devices: devices));
|
emit(state.copyWith(isLoading: false, devices: devices));
|
||||||
|
@ -32,114 +32,113 @@ class SpaceDropdown extends StatelessWidget {
|
|||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
DropdownButton2<String>(
|
SizedBox(
|
||||||
underline: const SizedBox(),
|
child: Container(
|
||||||
buttonStyleData: ButtonStyleData(
|
|
||||||
decoration:
|
|
||||||
BoxDecoration(borderRadius: BorderRadius.circular(12)),
|
|
||||||
),
|
|
||||||
value: selectedValue,
|
|
||||||
items: spaces.map((space) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: space.uuid,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
' ${space.name}',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: selectedValue == space.uuid
|
|
||||||
? ColorsManager.dialogBlueTitle
|
|
||||||
: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
' ${space.lastThreeParents}',
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
color: selectedValue == space.uuid
|
|
||||||
? ColorsManager.dialogBlueTitle
|
|
||||||
: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: onChanged,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 13,
|
|
||||||
),
|
|
||||||
hint: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
hintMessage,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
customButton: Container(
|
|
||||||
height: 40,
|
height: 40,
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(color: ColorsManager.textGray, width: 1.0),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: 8,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 10),
|
|
||||||
child: Text(
|
|
||||||
selectedValue != null
|
|
||||||
? spaces
|
|
||||||
.firstWhere((e) => e.uuid == selectedValue)
|
|
||||||
.name
|
|
||||||
: hintMessage,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
fontSize: 13,
|
|
||||||
color: selectedValue != null
|
|
||||||
? Colors.black
|
|
||||||
: ColorsManager.textGray,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.grey[200],
|
|
||||||
borderRadius: const BorderRadius.only(
|
|
||||||
topRight: Radius.circular(10),
|
|
||||||
bottomRight: Radius.circular(10),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
height: 45,
|
|
||||||
child: const Icon(
|
|
||||||
Icons.keyboard_arrow_down,
|
|
||||||
color: ColorsManager.textGray,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
dropdownStyleData: DropdownStyleData(
|
|
||||||
maxHeight: MediaQuery.of(context).size.height * 0.4,
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: ColorsManager.whiteColors,
|
color: ColorsManager.whiteColors,
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
),
|
child: DropdownButton2<String>(
|
||||||
menuItemStyleData: const MenuItemStyleData(
|
underline: const SizedBox(),
|
||||||
height: 60,
|
value: selectedValue,
|
||||||
|
items: spaces.map((space) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: space.uuid,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
' ${space.name}',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: ColorsManager.blackColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
' ${space.lastThreeParents}',
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: onChanged,
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
hint: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
hintMessage,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
customButton: Container(
|
||||||
|
height: 45,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border:
|
||||||
|
Border.all(color: ColorsManager.textGray, width: 1.0),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 8,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10),
|
||||||
|
child: Text(
|
||||||
|
selectedValue != null
|
||||||
|
? spaces
|
||||||
|
.firstWhere((e) => e.uuid == selectedValue)
|
||||||
|
.name
|
||||||
|
: hintMessage,
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: selectedValue != null
|
||||||
|
? Colors.black
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topRight: Radius.circular(10),
|
||||||
|
bottomRight: Radius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 45,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.keyboard_arrow_down,
|
||||||
|
color: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dropdownStyleData: DropdownStyleData(
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: ColorsManager.whiteColors,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 60,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -121,8 +121,7 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
|||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
height: 16,
|
height: 16,
|
||||||
child:
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
CircularProgressIndicator(strokeWidth: 2),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -160,9 +159,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
|||||||
height: iconSize,
|
height: iconSize,
|
||||||
width: iconSize,
|
width: iconSize,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder:
|
errorBuilder: (context, error, stackTrace) =>
|
||||||
(context, error, stackTrace) =>
|
Image.asset(
|
||||||
Image.asset(
|
|
||||||
Assets.logo,
|
Assets.logo,
|
||||||
height: iconSize,
|
height: iconSize,
|
||||||
width: iconSize,
|
width: iconSize,
|
||||||
@ -205,8 +203,7 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
fontSize:
|
fontSize: widget.isSmallScreenSize(context) ? 10 : 12,
|
||||||
widget.isSmallScreenSize(context) ? 10 : 12,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.spaceName != '')
|
if (widget.spaceName != '')
|
||||||
@ -225,9 +222,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: context.textTheme.bodySmall?.copyWith(
|
style: context.textTheme.bodySmall?.copyWith(
|
||||||
color: ColorsManager.blackColor,
|
color: ColorsManager.blackColor,
|
||||||
fontSize: widget.isSmallScreenSize(context)
|
fontSize:
|
||||||
? 10
|
widget.isSmallScreenSize(context) ? 10 : 12,
|
||||||
: 12,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -58,9 +58,7 @@ class CurtainHelper {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
DialogHeader(dialogType == 'THEN'
|
const DialogHeader('AC Functions'),
|
||||||
? 'Curtain Functions'
|
|
||||||
: 'Curtain Conditions'),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
@ -1,39 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_dialog.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/presentation/edit_community_dialog.dart';
|
|
||||||
|
|
||||||
abstract final class SpaceManagementCommunityDialogHelper {
|
abstract final class SpaceManagementCommunityDialogHelper {
|
||||||
static void showCreateDialog(BuildContext context) => showDialog<void>(
|
static void showCreateDialog(BuildContext context) {
|
||||||
context: context,
|
|
||||||
builder: (_) => const CreateCommunityDialog(),
|
|
||||||
);
|
|
||||||
|
|
||||||
static void showEditDialog(
|
|
||||||
BuildContext context,
|
|
||||||
CommunityModel community,
|
|
||||||
) {
|
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => EditCommunityDialog(
|
builder: (_) => CreateCommunityDialog(
|
||||||
community: community,
|
title: const SelectableText('Community Name'),
|
||||||
parentContext: context,
|
onCreateCommunity: (community) {
|
||||||
|
context.read<CommunitiesBloc>().add(
|
||||||
|
InsertCommunity(community),
|
||||||
|
);
|
||||||
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
|
SelectCommunityEvent(community: community),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void showLoadingDialog(BuildContext context) => showDialog<void>(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (context) => const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
static void showSuccessSnackBar(BuildContext context, String message) =>
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(message),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,6 @@ import 'package:syncrow_web/pages/space_management_v2/modules/communities/data/s
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/remote_space_details_service.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/unique_subspaces_decorator.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||||
@ -29,13 +26,6 @@ class SpaceManagementPage extends StatelessWidget {
|
|||||||
)..add(const LoadCommunities(LoadCommunitiesParam())),
|
)..add(const LoadCommunities(LoadCommunitiesParam())),
|
||||||
),
|
),
|
||||||
BlocProvider(create: (context) => CommunitiesTreeSelectionBloc()),
|
BlocProvider(create: (context) => CommunitiesTreeSelectionBloc()),
|
||||||
BlocProvider(
|
|
||||||
create: (context) => SpaceDetailsBloc(
|
|
||||||
UniqueSubspacesDecorator(
|
|
||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: WebScaffold(
|
child: WebScaffold(
|
||||||
appBarTitle: Text(
|
appBarTitle: Text(
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/helpers/space_management_community_dialog_helper.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header_action_buttons.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class CommunityStructureHeader extends StatelessWidget {
|
|
||||||
const CommunityStructureHeader({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final theme = Theme.of(context);
|
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: ColorsManager.whiteColors,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: ColorsManager.shadowBlackColor,
|
|
||||||
blurRadius: 8,
|
|
||||||
offset: const Offset(0, 4),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: _buildCommunityInfo(context, theme, screenWidth),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildCommunityInfo(
|
|
||||||
BuildContext context, ThemeData theme, double screenWidth) {
|
|
||||||
final selectedCommunity =
|
|
||||||
context.watch<CommunitiesTreeSelectionBloc>().state.selectedCommunity;
|
|
||||||
final selectedSpace =
|
|
||||||
context.watch<CommunitiesTreeSelectionBloc>().state.selectedSpace;
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Community Structure',
|
|
||||||
style: theme.textTheme.headlineLarge
|
|
||||||
?.copyWith(color: ColorsManager.blackColor),
|
|
||||||
),
|
|
||||||
if (selectedCommunity != null)
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: SelectableText(
|
|
||||||
selectedCommunity.name,
|
|
||||||
style: theme.textTheme.bodyLarge
|
|
||||||
?.copyWith(color: ColorsManager.blackColor),
|
|
||||||
maxLines: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 2),
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
SpaceManagementCommunityDialogHelper.showEditDialog(
|
|
||||||
context,
|
|
||||||
selectedCommunity,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
Assets.iconEdit,
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
CommunityStructureHeaderActionButtons(
|
|
||||||
onDelete: (space) {},
|
|
||||||
onDuplicate: (space) {},
|
|
||||||
onEdit: (space) {
|
|
||||||
SpaceDetailsDialogHelper.showEdit(
|
|
||||||
context,
|
|
||||||
spaceModel: selectedSpace!,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
selectedSpace: selectedSpace,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header_button.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class CommunityStructureHeaderActionButtons extends StatelessWidget {
|
|
||||||
const CommunityStructureHeaderActionButtons({
|
|
||||||
super.key,
|
|
||||||
required this.onDelete,
|
|
||||||
required this.selectedSpace,
|
|
||||||
required this.onDuplicate,
|
|
||||||
required this.onEdit,
|
|
||||||
});
|
|
||||||
|
|
||||||
final void Function(SpaceModel space) onDelete;
|
|
||||||
final void Function(SpaceModel space) onDuplicate;
|
|
||||||
final void Function(SpaceModel space) onEdit;
|
|
||||||
final SpaceModel? selectedSpace;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Wrap(
|
|
||||||
alignment: WrapAlignment.end,
|
|
||||||
spacing: 10,
|
|
||||||
children: [
|
|
||||||
if (selectedSpace != null) ...[
|
|
||||||
CommunityStructureHeaderButton(
|
|
||||||
label: 'Edit',
|
|
||||||
svgAsset: Assets.editSpace,
|
|
||||||
onPressed: () => onEdit(selectedSpace!),
|
|
||||||
),
|
|
||||||
CommunityStructureHeaderButton(
|
|
||||||
label: 'Duplicate',
|
|
||||||
svgAsset: Assets.duplicate,
|
|
||||||
onPressed: () => onDuplicate(selectedSpace!),
|
|
||||||
),
|
|
||||||
CommunityStructureHeaderButton(
|
|
||||||
label: 'Delete',
|
|
||||||
svgAsset: Assets.spaceDelete,
|
|
||||||
onPressed: () => onDelete(selectedSpace!),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class CommunityStructureHeaderButton extends StatelessWidget {
|
|
||||||
const CommunityStructureHeaderButton({
|
|
||||||
super.key,
|
|
||||||
required this.label,
|
|
||||||
required this.onPressed,
|
|
||||||
this.svgAsset,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String label;
|
|
||||||
final VoidCallback onPressed;
|
|
||||||
final String? svgAsset;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
const double buttonHeight = 40;
|
|
||||||
return ConstrainedBox(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: 130,
|
|
||||||
minHeight: buttonHeight,
|
|
||||||
),
|
|
||||||
child: DefaultButton(
|
|
||||||
onPressed: onPressed,
|
|
||||||
borderWidth: 2,
|
|
||||||
backgroundColor: ColorsManager.textFieldGreyColor,
|
|
||||||
foregroundColor: ColorsManager.blackColor,
|
|
||||||
borderRadius: 12.0,
|
|
||||||
padding: 2.0,
|
|
||||||
height: buttonHeight,
|
|
||||||
elevation: 0,
|
|
||||||
borderColor: ColorsManager.lightGrayColor,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
if (svgAsset != null)
|
|
||||||
SvgPicture.asset(
|
|
||||||
svgAsset!,
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
label,
|
|
||||||
style: context.textTheme.bodySmall
|
|
||||||
?.copyWith(color: ColorsManager.blackColor, fontSize: 14),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +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:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_canvas.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_canvas.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/community_structure_header.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
|
|
||||||
@ -19,17 +18,9 @@ class SpaceManagementCommunityStructure extends StatelessWidget {
|
|||||||
replacement: const Row(
|
replacement: const Row(
|
||||||
children: [spacer, Expanded(child: CreateSpaceButton()), spacer],
|
children: [spacer, Expanded(child: CreateSpaceButton()), spacer],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: CommunityStructureCanvas(
|
||||||
mainAxisSize: MainAxisSize.min,
|
community: selectedCommunity,
|
||||||
children: [
|
selectedSpace: selectedSpace,
|
||||||
const CommunityStructureHeader(),
|
|
||||||
Expanded(
|
|
||||||
child: CommunityStructureCanvas(
|
|
||||||
community: selectedCommunity,
|
|
||||||
selectedSpace: selectedSpace,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,26 +39,6 @@ class CommunityModel extends Equatable {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunityModel copyWith({
|
|
||||||
String? uuid,
|
|
||||||
String? name,
|
|
||||||
DateTime? createdAt,
|
|
||||||
DateTime? updatedAt,
|
|
||||||
String? description,
|
|
||||||
String? externalId,
|
|
||||||
List<SpaceModel>? spaces,
|
|
||||||
}) {
|
|
||||||
return CommunityModel(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
name: name ?? this.name,
|
|
||||||
createdAt: createdAt ?? this.createdAt,
|
|
||||||
updatedAt: updatedAt ?? this.updatedAt,
|
|
||||||
description: description ?? this.description,
|
|
||||||
externalId: externalId ?? this.externalId,
|
|
||||||
spaces: spaces ?? this.spaces,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, name, spaces];
|
List<Object?> get props => [uuid, name, spaces];
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,6 @@ class SpaceModel extends Equatable {
|
|||||||
required this.parent,
|
required this.parent,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SpaceModel.empty() => const SpaceModel(
|
|
||||||
uuid: '',
|
|
||||||
createdAt: null,
|
|
||||||
updatedAt: null,
|
|
||||||
spaceName: '',
|
|
||||||
icon: '',
|
|
||||||
children: [],
|
|
||||||
parent: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
factory SpaceModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceModel.fromJson(Map<String, dynamic> json) {
|
||||||
return SpaceModel(
|
return SpaceModel(
|
||||||
uuid: json['uuid'] as String? ?? '',
|
uuid: json['uuid'] as String? ?? '',
|
||||||
|
@ -16,7 +16,6 @@ class CommunitiesBloc extends Bloc<CommunitiesEvent, CommunitiesState> {
|
|||||||
on<LoadCommunities>(_onLoadCommunities);
|
on<LoadCommunities>(_onLoadCommunities);
|
||||||
on<LoadMoreCommunities>(_onLoadMoreCommunities);
|
on<LoadMoreCommunities>(_onLoadMoreCommunities);
|
||||||
on<InsertCommunity>(_onInsertCommunity);
|
on<InsertCommunity>(_onInsertCommunity);
|
||||||
on<CommunitiesUpdateCommunity>(_onCommunitiesUpdateCommunity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final CommunitiesService _communitiesService;
|
final CommunitiesService _communitiesService;
|
||||||
@ -115,18 +114,4 @@ class CommunitiesBloc extends Bloc<CommunitiesEvent, CommunitiesState> {
|
|||||||
) {
|
) {
|
||||||
emit(state.copyWith(communities: [event.community, ...state.communities]));
|
emit(state.copyWith(communities: [event.community, ...state.communities]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onCommunitiesUpdateCommunity(
|
|
||||||
CommunitiesUpdateCommunity event,
|
|
||||||
Emitter<CommunitiesState> emit,
|
|
||||||
) {
|
|
||||||
final updatedCommunities = state.communities
|
|
||||||
.map((e) => e.uuid == event.community.uuid ? event.community : e)
|
|
||||||
.toList();
|
|
||||||
emit(
|
|
||||||
state.copyWith(
|
|
||||||
communities: updatedCommunities,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -31,12 +31,3 @@ final class InsertCommunity extends CommunitiesEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [community];
|
List<Object?> get props => [community];
|
||||||
}
|
}
|
||||||
|
|
||||||
final class CommunitiesUpdateCommunity extends CommunitiesEvent {
|
|
||||||
const CommunitiesUpdateCommunity(this.community);
|
|
||||||
|
|
||||||
final CommunityModel community;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [community];
|
|
||||||
}
|
|
||||||
|
@ -1,58 +1,57 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/helpers/space_management_community_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/widgets/community_dialog.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/data/services/remote_create_community_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/data/services/remote_create_community_service.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/domain/param/create_community_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/bloc/create_community_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/bloc/create_community_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_dialog_widget.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
class CreateCommunityDialog extends StatelessWidget {
|
class CreateCommunityDialog extends StatelessWidget {
|
||||||
const CreateCommunityDialog({super.key});
|
final void Function(CommunityModel community) onCreateCommunity;
|
||||||
|
final String? initialName;
|
||||||
|
final Widget title;
|
||||||
|
|
||||||
|
const CreateCommunityDialog({
|
||||||
|
super.key,
|
||||||
|
required this.onCreateCommunity,
|
||||||
|
required this.title,
|
||||||
|
this.initialName,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => CreateCommunityBloc(
|
create: (_) => CreateCommunityBloc(RemoteCreateCommunityService(HTTPService())),
|
||||||
RemoteCreateCommunityService(HTTPService()),
|
child: BlocListener<CreateCommunityBloc, CreateCommunityState>(
|
||||||
),
|
|
||||||
child: BlocConsumer<CreateCommunityBloc, CreateCommunityState>(
|
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case CreateCommunityLoading() || CreateCommunityInitial():
|
case CreateCommunityLoading():
|
||||||
SpaceManagementCommunityDialogHelper.showLoadingDialog(context);
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case CreateCommunitySuccess(:final community):
|
case CreateCommunitySuccess(:final community):
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
SpaceManagementCommunityDialogHelper.showSuccessSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
context,
|
const SnackBar(content: Text('Community created successfully')),
|
||||||
'${community.name} community created successfully',
|
|
||||||
);
|
);
|
||||||
context.read<CommunitiesBloc>().add(
|
onCreateCommunity.call(community);
|
||||||
InsertCommunity(community),
|
|
||||||
);
|
|
||||||
context.read<CommunitiesTreeSelectionBloc>().add(
|
|
||||||
SelectCommunityEvent(community: community),
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case CreateCommunityFailure():
|
case CreateCommunityFailure():
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder: (BuildContext context, CreateCommunityState state) {
|
child: CreateCommunityDialogWidget(
|
||||||
return CommunityDialog(
|
title: title,
|
||||||
title: const Text('Create Community'),
|
initialName: initialName,
|
||||||
initialName: null,
|
),
|
||||||
onSubmit: (name) => context.read<CreateCommunityBloc>().add(
|
|
||||||
CreateCommunity(CreateCommunityParam(name: name)),
|
|
||||||
),
|
|
||||||
errorMessage: state is CreateCommunityFailure ? state.message : null,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/space_management_v2/modules/create_community/domain/param/create_community_param.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/bloc/create_community_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_name_text_field.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_name_text_field.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|
||||||
|
|
||||||
class CommunityDialog extends StatefulWidget {
|
class CreateCommunityDialogWidget extends StatefulWidget {
|
||||||
final String? initialName;
|
final String? initialName;
|
||||||
final Widget title;
|
final Widget title;
|
||||||
final void Function(String name) onSubmit;
|
|
||||||
final String? errorMessage;
|
|
||||||
|
|
||||||
const CommunityDialog({
|
const CreateCommunityDialogWidget({
|
||||||
required this.title,
|
|
||||||
required this.onSubmit,
|
|
||||||
this.initialName,
|
|
||||||
this.errorMessage,
|
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
this.initialName,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CommunityDialog> createState() => _CommunityDialogState();
|
State<CreateCommunityDialogWidget> createState() =>
|
||||||
|
_CreateCommunityDialogWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CommunityDialogState extends State<CommunityDialog> {
|
class _CreateCommunityDialogWidgetState extends State<CreateCommunityDialogWidget> {
|
||||||
late final TextEditingController _nameController;
|
late final TextEditingController _nameController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -64,20 +63,35 @@ class _CommunityDialogState extends State<CommunityDialog> {
|
|||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: BlocBuilder<CreateCommunityBloc, CreateCommunityState>(
|
||||||
mainAxisSize: MainAxisSize.min,
|
builder: (context, state) {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
return Column(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
DefaultTextStyle(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: Theme.of(context).textTheme.headlineMedium!,
|
children: [
|
||||||
child: widget.title,
|
DefaultTextStyle(
|
||||||
),
|
style: Theme.of(context).textTheme.headlineMedium!,
|
||||||
const SizedBox(height: 18),
|
child: widget.title,
|
||||||
CreateCommunityNameTextField(nameController: _nameController),
|
),
|
||||||
_buildErrorMessage(),
|
const SizedBox(height: 18),
|
||||||
const SizedBox(height: 24),
|
CreateCommunityNameTextField(
|
||||||
_buildActionButtons(context),
|
nameController: _nameController,
|
||||||
],
|
),
|
||||||
|
if (state case CreateCommunityFailure(:final message))
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 18),
|
||||||
|
child: SelectableText(
|
||||||
|
'* $message',
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.error,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
_buildActionButtons(context),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -118,22 +132,13 @@ class _CommunityDialogState extends State<CommunityDialog> {
|
|||||||
|
|
||||||
void _onSubmit(BuildContext context) {
|
void _onSubmit(BuildContext context) {
|
||||||
if (_formKey.currentState?.validate() ?? false) {
|
if (_formKey.currentState?.validate() ?? false) {
|
||||||
widget.onSubmit.call(_nameController.text.trim());
|
context.read<CreateCommunityBloc>().add(
|
||||||
|
CreateCommunity(
|
||||||
|
CreateCommunityParam(
|
||||||
|
name: _nameController.text.trim(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildErrorMessage() {
|
|
||||||
return Visibility(
|
|
||||||
visible: widget.errorMessage != null,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.symmetric(vertical: 18),
|
|
||||||
child: SelectableText(
|
|
||||||
'* ${widget.errorMessage}',
|
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
|
||||||
color: context.theme.colorScheme.error,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_spaces_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
import 'package:syncrow_web/services/api/http_service.dart';
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
@ -16,15 +15,12 @@ class RemoteSpaceDetailsService implements SpaceDetailsService {
|
|||||||
static const _defaultErrorMessage = 'Failed to load space details';
|
static const _defaultErrorMessage = 'Failed to load space details';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<SpaceDetailsModel> getSpaceDetails(LoadSpaceDetailsParam param) async {
|
Future<SpaceDetailsModel> getSpaceDetails(LoadSpacesParam param) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
path: await _makeEndpoint(param),
|
path: 'endpoint',
|
||||||
expectedResponseModel: (data) {
|
expectedResponseModel: (data) {
|
||||||
final response = data as Map<String, dynamic>;
|
return SpaceDetailsModel.fromJson(data as Map<String, dynamic>);
|
||||||
return SpaceDetailsModel.fromJson(
|
|
||||||
response['data'] as Map<String, dynamic>,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
@ -41,13 +37,4 @@ class RemoteSpaceDetailsService implements SpaceDetailsService {
|
|||||||
throw APIException(formattedErrorMessage);
|
throw APIException(formattedErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _makeEndpoint(LoadSpaceDetailsParam param) async {
|
|
||||||
final projectUuid = await ProjectManager.getProjectUUID();
|
|
||||||
if (projectUuid == null || projectUuid.isEmpty) {
|
|
||||||
throw APIException('Project UUID is not set');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '/projects/$projectUuid/communities/${param.communityUuid}/spaces/${param.spaceUuid}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
|
||||||
|
|
||||||
class UniqueSubspacesDecorator implements SpaceDetailsService {
|
|
||||||
final SpaceDetailsService _decoratee;
|
|
||||||
|
|
||||||
const UniqueSubspacesDecorator(this._decoratee);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<SpaceDetailsModel> getSpaceDetails(LoadSpaceDetailsParam param) async {
|
|
||||||
final response = await _decoratee.getSpaceDetails(param);
|
|
||||||
|
|
||||||
final uniqueSubspaces = <String, Subspace>{};
|
|
||||||
|
|
||||||
for (final subspace in response.subspaces) {
|
|
||||||
final normalizedName = subspace.name.trim().toLowerCase();
|
|
||||||
if (!uniqueSubspaces.containsKey(normalizedName)) {
|
|
||||||
uniqueSubspaces[normalizedName] = subspace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.copyWith(
|
|
||||||
subspaces: uniqueSubspaces.values.toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsModel extends Equatable {
|
class SpaceDetailsModel extends Equatable {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
@ -18,21 +17,14 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
required this.subspaces,
|
required this.subspaces,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SpaceDetailsModel.empty() => const SpaceDetailsModel(
|
|
||||||
uuid: '',
|
|
||||||
spaceName: '',
|
|
||||||
icon: Assets.villa,
|
|
||||||
productAllocations: [],
|
|
||||||
subspaces: [],
|
|
||||||
);
|
|
||||||
factory SpaceDetailsModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceDetailsModel.fromJson(Map<String, dynamic> json) {
|
||||||
return SpaceDetailsModel(
|
return SpaceDetailsModel(
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
spaceName: json['spaceName'] as String,
|
spaceName: json['spaceName'] as String,
|
||||||
icon: json['icon'] as String,
|
icon: json['icon'] as String,
|
||||||
productAllocations: (json['productAllocations'] as List)
|
productAllocations: (json['productAllocations'] as List)
|
||||||
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
subspaces: (json['subspaces'] as List)
|
subspaces: (json['subspaces'] as List)
|
||||||
.map((e) => Subspace.fromJson(e as Map<String, dynamic>))
|
.map((e) => Subspace.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -49,22 +41,6 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceDetailsModel copyWith({
|
|
||||||
String? uuid,
|
|
||||||
String? spaceName,
|
|
||||||
String? icon,
|
|
||||||
List<ProductAllocation>? productAllocations,
|
|
||||||
List<Subspace>? subspaces,
|
|
||||||
}) {
|
|
||||||
return SpaceDetailsModel(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
spaceName: spaceName ?? this.spaceName,
|
|
||||||
icon: icon ?? this.icon,
|
|
||||||
productAllocations: productAllocations ?? this.productAllocations,
|
|
||||||
subspaces: subspaces ?? this.subspaces,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, spaceName, icon, productAllocations, subspaces];
|
List<Object?> get props => [uuid, spaceName, icon, productAllocations, subspaces];
|
||||||
}
|
}
|
||||||
@ -72,10 +48,12 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
class ProductAllocation extends Equatable {
|
class ProductAllocation extends Equatable {
|
||||||
final Product product;
|
final Product product;
|
||||||
final Tag tag;
|
final Tag tag;
|
||||||
|
final String? location;
|
||||||
|
|
||||||
const ProductAllocation({
|
const ProductAllocation({
|
||||||
required this.product,
|
required this.product,
|
||||||
required this.tag,
|
required this.tag,
|
||||||
|
this.location,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ProductAllocation.fromJson(Map<String, dynamic> json) {
|
factory ProductAllocation.fromJson(Map<String, dynamic> json) {
|
||||||
@ -92,16 +70,6 @@ class ProductAllocation extends Equatable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ProductAllocation copyWith({
|
|
||||||
Product? product,
|
|
||||||
Tag? tag,
|
|
||||||
}) {
|
|
||||||
return ProductAllocation(
|
|
||||||
product: product ?? this.product,
|
|
||||||
tag: tag ?? this.tag,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [product, tag];
|
List<Object?> get props => [product, tag];
|
||||||
}
|
}
|
||||||
@ -120,7 +88,7 @@ class Subspace extends Equatable {
|
|||||||
factory Subspace.fromJson(Map<String, dynamic> json) {
|
factory Subspace.fromJson(Map<String, dynamic> json) {
|
||||||
return Subspace(
|
return Subspace(
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
name: json['subspaceName'] as String,
|
name: json['name'] as String,
|
||||||
productAllocations: (json['productAllocations'] as List)
|
productAllocations: (json['productAllocations'] as List)
|
||||||
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -135,18 +103,6 @@ class Subspace extends Equatable {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Subspace copyWith({
|
|
||||||
String? uuid,
|
|
||||||
String? name,
|
|
||||||
List<ProductAllocation>? productAllocations,
|
|
||||||
}) {
|
|
||||||
return Subspace(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
name: name ?? this.name,
|
|
||||||
productAllocations: productAllocations ?? this.productAllocations,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, name, productAllocations];
|
List<Object?> get props => [uuid, name, productAllocations];
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
class LoadSpaceDetailsParam {
|
|
||||||
const LoadSpaceDetailsParam({
|
|
||||||
required this.spaceUuid,
|
|
||||||
required this.communityUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
final String spaceUuid;
|
|
||||||
final String communityUuid;
|
|
||||||
}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
class LoadSpacesParam {
|
||||||
|
const LoadSpacesParam();
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_spaces_param.dart';
|
||||||
|
|
||||||
abstract class SpaceDetailsService {
|
abstract class SpaceDetailsService {
|
||||||
Future<SpaceDetailsModel> getSpaceDetails(LoadSpaceDetailsParam param);
|
Future<SpaceDetailsModel> getSpaceDetails(LoadSpacesParam param);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_spaces_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
@ -9,13 +9,12 @@ part 'space_details_event.dart';
|
|||||||
part 'space_details_state.dart';
|
part 'space_details_state.dart';
|
||||||
|
|
||||||
class SpaceDetailsBloc extends Bloc<SpaceDetailsEvent, SpaceDetailsState> {
|
class SpaceDetailsBloc extends Bloc<SpaceDetailsEvent, SpaceDetailsState> {
|
||||||
|
final SpaceDetailsService _spaceDetailsService;
|
||||||
|
|
||||||
SpaceDetailsBloc(this._spaceDetailsService) : super(SpaceDetailsInitial()) {
|
SpaceDetailsBloc(this._spaceDetailsService) : super(SpaceDetailsInitial()) {
|
||||||
on<LoadSpaceDetails>(_onLoadSpaceDetails);
|
on<LoadSpaceDetails>(_onLoadSpaceDetails);
|
||||||
on<ClearSpaceDetails>(_onClearSpaceDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final SpaceDetailsService _spaceDetailsService;
|
|
||||||
|
|
||||||
Future<void> _onLoadSpaceDetails(
|
Future<void> _onLoadSpaceDetails(
|
||||||
LoadSpaceDetails event,
|
LoadSpaceDetails event,
|
||||||
Emitter<SpaceDetailsState> emit,
|
Emitter<SpaceDetailsState> emit,
|
||||||
@ -32,11 +31,4 @@ class SpaceDetailsBloc extends Bloc<SpaceDetailsEvent, SpaceDetailsState> {
|
|||||||
emit(SpaceDetailsFailure(e.toString()));
|
emit(SpaceDetailsFailure(e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onClearSpaceDetails(
|
|
||||||
ClearSpaceDetails event,
|
|
||||||
Emitter<SpaceDetailsState> emit,
|
|
||||||
) {
|
|
||||||
emit(SpaceDetailsInitial());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|