Merge pull request #435 from AppFlowy-IO/grid_field_operation
Grid field operation
@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.2304 4.2561H10.0184L8.02638 7.9401H8.00238L5.99838 4.2561H4.78638L7.06638 8.2401H5.43438V8.9601H7.47438L7.48638 8.9841V9.8241H5.43438V10.5321H7.48638V12.5001H8.53038V10.5321H10.4984V9.8241H8.53038V8.9841L8.54238 8.9601H10.4984V8.2401H8.95038L11.2304 4.2561Z" fill="#333333"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 392 B |
3
frontend/app_flowy/assets/images/grid/checkmark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 5.2L2.84615 7L9 1" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 198 B |
6
frontend/app_flowy/assets/images/grid/delete.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 4.3999H4.11111H13" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.77775 4.4V3.2C5.77775 2.88174 5.89481 2.57652 6.10319 2.35147C6.31156 2.12643 6.59418 2 6.88886 2H9.11108C9.40577 2 9.68838 2.12643 9.89676 2.35147C10.1051 2.57652 10.2222 2.88174 10.2222 3.2V4.4M11.8889 4.4V12.8C11.8889 13.1183 11.7718 13.4235 11.5634 13.6485C11.3551 13.8736 11.0724 14 10.7778 14H5.2222C4.92751 14 4.64489 13.8736 4.43652 13.6485C4.22815 13.4235 4.11108 13.1183 4.11108 12.8V4.4H11.8889Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.88892 7.3999V10.9999" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.11108 7.3999V10.9999" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 886 B |
4
frontend/app_flowy/assets/images/grid/details.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="8" cy="6" r="1" fill="#333333"/>
|
||||
<circle cx="8" cy="10" r="1" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 194 B |
4
frontend/app_flowy/assets/images/grid/duplicate.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.9743 6.33301H7.35889C6.79245 6.33301 6.33325 6.7922 6.33325 7.35865V11.974C6.33325 12.5405 6.79245 12.9997 7.35889 12.9997H11.9743C12.5407 12.9997 12.9999 12.5405 12.9999 11.974V7.35865C12.9999 6.7922 12.5407 6.33301 11.9743 6.33301Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4.53846 9.66667H4.02564C3.75362 9.66667 3.49275 9.55861 3.3004 9.36626C3.10806 9.17392 3 8.91304 3 8.64103V4.02564C3 3.75362 3.10806 3.49275 3.3004 3.3004C3.49275 3.10806 3.75362 3 4.02564 3H8.64103C8.91304 3 9.17392 3.10806 9.36626 3.3004C9.55861 3.49275 9.66667 3.75362 9.66667 4.02564V4.53846" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 790 B |
4
frontend/app_flowy/assets/images/grid/field/checkbox.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.5 8L8.11538 9.5L13.5 4.5" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13 8.5V11.8889C13 12.1836 12.8829 12.4662 12.6746 12.6746C12.4662 12.8829 12.1836 13 11.8889 13H4.11111C3.81643 13 3.53381 12.8829 3.32544 12.6746C3.11706 12.4662 3 12.1836 3 11.8889V4.11111C3 3.81643 3.11706 3.53381 3.32544 3.32544C3.53381 3.11706 3.81643 3 4.11111 3H10.2222" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 561 B |
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.5 8L8.11538 9.5L13.5 4.5" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13.5 8C13.5 11.0376 11.0376 13.5 8 13.5C4.96243 13.5 2.5 11.0376 2.5 8C2.5 4.96243 4.96243 2.5 8 2.5C8.81896 2.5 9.59612 2.679 10.2945 3" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 421 B |
6
frontend/app_flowy/assets/images/grid/field/date.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.8889 3.5H4.11111C3.49746 3.5 3 3.94772 3 4.5V11.5C3 12.0523 3.49746 12.5 4.11111 12.5H11.8889C12.5025 12.5 13 12.0523 13 11.5V4.5C13 3.94772 12.5025 3.5 11.8889 3.5Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 2.5V4.58181" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 2.5V4.58181" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 6.5H13" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 618 B |
3
frontend/app_flowy/assets/images/grid/field/euro.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.9083 10.9011C10.4173 11.2751 9.83813 11.4814 9.09532 11.4814C7.93705 11.4814 6.82914 10.8367 6.45144 9.2765H10.027V8.50287H6.32554C6.31295 8.34814 6.31295 8.19341 6.31295 8.02579C6.31295 7.84527 6.32554 7.67765 6.33813 7.51003H10.027V6.73639H6.45144C6.81655 5.25358 7.82374 4.50573 9.09532 4.50573C9.72482 4.50573 10.304 4.69914 10.8201 5.06017L11.4371 4.24785C10.7194 3.73209 9.91367 3.5 9.09532 3.5C7.10612 3.5 5.72122 4.69914 5.31835 6.73639H4.5V7.51003H5.21763C5.20504 7.67765 5.20504 7.84527 5.20504 8.02579C5.20504 8.19341 5.20504 8.34814 5.21763 8.50287H4.5V9.2765H5.31835C5.7464 11.5716 7.40827 12.5 9.09532 12.5C10.0773 12.5 10.8705 12.1777 11.5 11.7264L10.9083 10.9011Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 814 B |
@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.5 4L12.5 4" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.5 8H12.5" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.5 12H12.5" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="4" cy="4" r="0.5" fill="#333333"/>
|
||||
<circle cx="4" cy="8" r="0.5" fill="#333333"/>
|
||||
<circle cx="4" cy="12" r="0.5" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 512 B |
3
frontend/app_flowy/assets/images/grid/field/number.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.201 6.4H3.001V12H2.081V7.384L0.953 7.704L0.729 6.92L2.201 6.4ZM3.91156 12V11.1L6.35156 8.61C6.9449 8.01667 7.24156 7.50333 7.24156 7.07C7.24156 6.73 7.13823 6.46667 6.93156 6.28C6.73156 6.08667 6.4749 5.99 6.16156 5.99C5.5749 5.99 5.14156 6.28 4.86156 6.86L3.89156 6.29C4.11156 5.82333 4.42156 5.47 4.82156 5.23C5.22156 4.99 5.6649 4.87 6.15156 4.87C6.7649 4.87 7.29156 5.06333 7.73156 5.45C8.17156 5.83667 8.39156 6.36333 8.39156 7.03C8.39156 7.74333 7.9949 8.50333 7.20156 9.31L5.62156 10.89H8.52156V12H3.91156ZM12.9025 7.032C13.5105 7.176 14.0025 7.46 14.3785 7.884C14.7625 8.3 14.9545 8.824 14.9545 9.456C14.9545 10.296 14.6705 10.956 14.1025 11.436C13.5345 11.916 12.8385 12.156 12.0145 12.156C11.3745 12.156 10.7985 12.008 10.2865 11.712C9.78253 11.416 9.41853 10.984 9.19453 10.416L10.3705 9.732C10.6185 10.452 11.1665 10.812 12.0145 10.812C12.4945 10.812 12.8745 10.692 13.1545 10.452C13.4345 10.204 13.5745 9.872 13.5745 9.456C13.5745 9.04 13.4345 8.712 13.1545 8.472C12.8745 8.232 12.4945 8.112 12.0145 8.112H11.7025L11.1505 7.284L12.9625 4.896H9.44653V3.6H14.6065V4.776L12.9025 7.032Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
3
frontend/app_flowy/assets/images/grid/field/numbers.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.201 6.4H3.001V12H2.081V7.384L0.953 7.704L0.729 6.92L2.201 6.4ZM3.91156 12V11.1L6.35156 8.61C6.9449 8.01667 7.24156 7.50333 7.24156 7.07C7.24156 6.73 7.13823 6.46667 6.93156 6.28C6.73156 6.08667 6.4749 5.99 6.16156 5.99C5.5749 5.99 5.14156 6.28 4.86156 6.86L3.89156 6.29C4.11156 5.82333 4.42156 5.47 4.82156 5.23C5.22156 4.99 5.6649 4.87 6.15156 4.87C6.7649 4.87 7.29156 5.06333 7.73156 5.45C8.17156 5.83667 8.39156 6.36333 8.39156 7.03C8.39156 7.74333 7.9949 8.50333 7.20156 9.31L5.62156 10.89H8.52156V12H3.91156ZM12.9025 7.032C13.5105 7.176 14.0025 7.46 14.3785 7.884C14.7625 8.3 14.9545 8.824 14.9545 9.456C14.9545 10.296 14.6705 10.956 14.1025 11.436C13.5345 11.916 12.8385 12.156 12.0145 12.156C11.3745 12.156 10.7985 12.008 10.2865 11.712C9.78253 11.416 9.41853 10.984 9.19453 10.416L10.3705 9.732C10.6185 10.452 11.1665 10.812 12.0145 10.812C12.4945 10.812 12.8745 10.692 13.1545 10.452C13.4345 10.204 13.5745 9.872 13.5745 9.456C13.5745 9.04 13.4345 8.712 13.1545 8.472C12.8745 8.232 12.4945 8.112 12.0145 8.112H11.7025L11.1505 7.284L12.9625 4.896H9.44653V3.6H14.6065V4.776L12.9025 7.032Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.78787 8.78787L6.51213 7.51213C6.32314 7.32314 6.45699 7 6.72426 7H9.27574C9.54301 7 9.67686 7.32314 9.48787 7.51213L8.21213 8.78787C8.09497 8.90503 7.90503 8.90503 7.78787 8.78787Z" fill="#333333"/>
|
||||
<path d="M8 13C10.7614 13 13 10.7614 13 8C13 5.23858 10.7614 3 8 3C5.23858 3 3 5.23858 3 8C3 10.7614 5.23858 13 8 13Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 499 B |
4
frontend/app_flowy/assets/images/grid/field/text.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.15625 11.8359L6.43768 9.85414H2.46662L1.74805 11.8359H0.5L3.7903 3H5.11399L8.4043 11.8359H7.15625ZM2.87003 8.75596H6.03427L4.44584 4.40112L2.87003 8.75596Z" fill="#333333"/>
|
||||
<path d="M14.4032 5.52454H15.5V11.8359H14.4032V10.7504C13.8569 11.5835 13.0627 12 12.0206 12C11.1381 12 10.386 11.6802 9.76403 11.0407C9.14211 10.3927 8.83114 9.60589 8.83114 8.68022C8.83114 7.75456 9.14211 6.97195 9.76403 6.3324C10.386 5.68443 11.1381 5.36045 12.0206 5.36045C13.0627 5.36045 13.8569 5.777 14.4032 6.6101V5.52454ZM12.1593 10.9397C12.798 10.9397 13.3317 10.7251 13.7603 10.2959C14.1889 9.85835 14.4032 9.31978 14.4032 8.68022C14.4032 8.04067 14.1889 7.50631 13.7603 7.07714C13.3317 6.63955 12.798 6.42076 12.1593 6.42076C11.5289 6.42076 10.9995 6.63955 10.5708 7.07714C10.1422 7.50631 9.92791 8.04067 9.92791 8.68022C9.92791 9.31978 10.1422 9.85835 10.5708 10.2959C10.9995 10.7251 11.5289 10.9397 12.1593 10.9397Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.716 9.828C10.716 8.292 9.6 7.896 8.124 7.416C7.128 7.092 6.396 6.828 6.396 6.072C6.396 5.376 6.984 4.968 7.824 4.968C8.412 4.968 9.216 5.22 9.84 5.676L10.44 4.944C9.9 4.512 9.096 4.176 8.352 4.056V2.508H7.572V4.008C6.12 4.092 5.304 4.98 5.304 6.132C5.304 7.56 6.516 7.98 7.824 8.388C8.928 8.748 9.612 9.036 9.612 9.9C9.612 10.644 8.964 11.088 8.076 11.088C7.308 11.088 6.444 10.752 5.772 10.092L5.136 10.836C5.844 11.532 6.684 11.904 7.572 12.012V13.476H8.352V12.024C9.84 11.928 10.716 11.052 10.716 9.828Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 641 B |
3
frontend/app_flowy/assets/images/grid/field/yen.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.2301 4.25586H10.0181L8.02613 7.93986H8.00213L5.99813 4.25586H4.78613L7.06613 8.23986H5.43413V8.95986H7.47413L7.48613 8.98386V9.82386H5.43413V10.5319H7.48613V12.4999H8.53013V10.5319H10.4981V9.82386H8.53013V8.98386L8.54213 8.95986H10.4981V8.23986H8.95013L11.2301 4.25586Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 404 B |
4
frontend/app_flowy/assets/images/grid/hide.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.12265 11.5847C5.92255 12.1165 6.88538 12.5 8.00024 12.5C10.4842 12.5 12.2135 10.596 13.0675 9.39083C13.6624 8.55146 13.6624 7.44854 13.0675 6.60917C12.7341 6.13867 12.2673 5.56168 11.6743 5.03305L10.9661 5.74127C11.4908 6.20089 11.9225 6.72296 12.2516 7.18736C12.601 7.68035 12.601 8.31965 12.2516 8.81264C11.4276 9.97552 9.9599 11.5 8.00024 11.5C7.19618 11.5 6.47495 11.2434 5.84702 10.8603L5.12265 11.5847ZM5.03441 10.2587L4.32618 10.967C3.73316 10.4383 3.26636 9.86133 2.93294 9.39083C2.33811 8.55146 2.33811 7.44854 2.93294 6.60917C3.78701 5.40397 5.51627 3.5 8.00024 3.5C9.1151 3.5 10.0779 3.88354 10.8778 4.4153L10.1535 5.13966C9.52554 4.75665 8.80431 4.5 8.00024 4.5C6.04059 4.5 4.57293 6.02448 3.74884 7.18736C3.39948 7.68035 3.39948 8.31965 3.74884 8.81264C4.07794 9.27704 4.50968 9.79911 5.03441 10.2587ZM6.99269 9.71466C7.28548 9.8954 7.62952 10 8.00036 10C9.09422 10 9.95491 9.08996 9.95491 8C9.95491 7.64165 9.86187 7.30275 9.69811 7.00924L8.93118 7.77618C8.94668 7.84779 8.95491 7.92265 8.95491 8C8.95491 8.5669 8.51315 9 8.00036 9C7.91225 9 7.82623 8.98721 7.7442 8.96316L6.99269 9.71466ZM7.06951 8.22363L6.30253 8.99061C6.13882 8.69713 6.04582 8.35829 6.04582 8C6.04582 6.91005 6.9065 6 8.00036 6C8.37114 6 8.71513 6.10456 9.00789 6.28525L8.25635 7.03679C8.17436 7.01277 8.08841 7 8.00036 7C7.48757 7 7.04582 7.4331 7.04582 8C7.04582 8.07728 7.05403 8.15208 7.06951 8.22363Z" fill="#333333"/>
|
||||
<path d="M11.667 3.33398L3.33366 11.6673" stroke="#333333" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
5
frontend/app_flowy/assets/images/grid/left.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 11.7778L3 4" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.5 4.5L6 8L9.5 11.5" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 8L13 8" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 378 B |
3
frontend/app_flowy/assets/images/grid/more.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.39568 7.6963L6.91032 5.56599C6.65085 5.34358 6.25 5.52795 6.25 5.86969L6.25 10.1303C6.25 10.4721 6.65085 10.6564 6.91032 10.434L9.39568 8.3037C9.58192 8.14406 9.58192 7.85594 9.39568 7.6963Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 324 B |
5
frontend/app_flowy/assets/images/grid/right.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13 11.7778L13 4" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.5 4.5L10 8L6.5 11.5" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 8L3 8" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 281 B |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 499 B |
@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.5221 3.21932C11.4366 2.6913 12.5634 2.6913 13.4779 3.21932L18.8653 6.32972C19.7799 6.85774 20.3433 7.83356 20.3433 8.88959V15.1104C20.3433 16.1664 19.7799 17.1423 18.8653 17.6703L13.4779 20.7807C12.5634 21.3087 11.4366 21.3087 10.5221 20.7807L5.13468 17.6703C4.22012 17.1423 3.65673 16.1664 3.65673 15.1104V8.88959C3.65673 7.83356 4.22012 6.85774 5.13467 6.32972L10.5221 3.21932Z" stroke="#333333" stroke-width="1.5"/>
|
||||
<circle cx="12" cy="12" r="3.75" stroke="#333333" stroke-width="1.5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 606 B |
4
frontend/app_flowy/assets/images/grid/setting/sort.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2.5" y="3" width="4" height="10" rx="1" stroke="#333333"/>
|
||||
<rect x="9.5" y="7" width="4" height="6" rx="1" stroke="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 238 B |
@ -141,5 +141,53 @@
|
||||
"lightLabel": "Light Mode",
|
||||
"darkLabel": "Dark Mode"
|
||||
}
|
||||
},
|
||||
"grid": {
|
||||
"settings": {
|
||||
"filter": "Filter",
|
||||
"sortBy": "Sort by",
|
||||
"Properties": "Properties"
|
||||
},
|
||||
"field": {
|
||||
"hide": "Hide",
|
||||
"insertLeft": "Insert Left",
|
||||
"insertRight": "Insert Right",
|
||||
"duplicate": "Duplicate",
|
||||
"delete": "Delete",
|
||||
"textFieldName": "Text",
|
||||
"checkboxFieldName": "Checkbox",
|
||||
"dateFieldName": "Date",
|
||||
"numberFieldName": "Numbers",
|
||||
"singleSelectFieldName": "Select",
|
||||
"multiSelectFieldName": "Multiselect",
|
||||
"numberFormat": " Number format",
|
||||
"dateFormat": " Date format",
|
||||
"dateFormatFriendly": "Month Day,Year",
|
||||
"dateFormatISO": "Year-Month-Day",
|
||||
"dateFormatLocal": "Month/Month/Day",
|
||||
"dateFormatUS": "Month/Month/Day",
|
||||
"timeFormat": " Time format",
|
||||
"timeFormatTwelveHour": "12 hour",
|
||||
"timeFormatTwentyFourHour": "24 hour",
|
||||
"addSelectOption": "Add an option",
|
||||
"optionTitle": "Options",
|
||||
"addOption": "Add option",
|
||||
"editProperty": "Edit property"
|
||||
},
|
||||
"selectOption": {
|
||||
"purpleColor": "Purple",
|
||||
"pinkColor": "Pink",
|
||||
"lightPinkColor": "Light Pink",
|
||||
"orangeColor": "Orange",
|
||||
"yellowColor": "Yellow",
|
||||
"limeColor": "Lime",
|
||||
"greenColor": "Green",
|
||||
"aquaColor": "Aqua",
|
||||
"blueColor": "Blue",
|
||||
"deleteTag": "Delete tag",
|
||||
"colorPannelTitle": "Colors",
|
||||
"pannelTitle": "Select an option or create one",
|
||||
"searchOption": "Search for an option"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flowy_sdk/protobuf/dart-notify/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
|
||||
@ -5,6 +6,7 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
// User
|
||||
typedef UserNotificationCallback = void Function(UserNotification, Either<Uint8List, FlowyError>);
|
||||
@ -45,6 +47,23 @@ class GridNotificationParser extends NotificationParser<GridNotification, FlowyE
|
||||
);
|
||||
}
|
||||
|
||||
typedef GridNotificationHandler = Function(GridNotification ty, Either<Uint8List, FlowyError> result);
|
||||
|
||||
class GridNotificationListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
GridNotificationParser? _parser;
|
||||
|
||||
GridNotificationListener({required String objectId, required GridNotificationHandler handler})
|
||||
: _parser = GridNotificationParser(id: objectId, callback: handler) {
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationParser<T, E> {
|
||||
String? id;
|
||||
void Function(T, Either<Uint8List, E>) callback;
|
||||
|
@ -61,12 +61,6 @@ abstract class PluginConfig {
|
||||
}
|
||||
|
||||
abstract class PluginDisplay<T> with NavigationItem {
|
||||
@override
|
||||
Widget get leftBarItem;
|
||||
|
||||
@override
|
||||
Widget? get rightBarItem;
|
||||
|
||||
List<NavigationItem> get navigationItems;
|
||||
|
||||
PublishNotifier<T>? get notifier => null;
|
||||
|
238
frontend/app_flowy/lib/startup/deps_resolver.dart
Normal file
@ -0,0 +1,238 @@
|
||||
import 'package:app_flowy/core/network_monitor.dart';
|
||||
import 'package:app_flowy/user/application/user_listener.dart';
|
||||
import 'package:app_flowy/user/application/user_service.dart';
|
||||
import 'package:app_flowy/workspace/application/app/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/doc/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/trash/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/workspace/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/view/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/home/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/menu/prelude.dart';
|
||||
import 'package:app_flowy/user/application/prelude.dart';
|
||||
import 'package:app_flowy/user/presentation/router.dart';
|
||||
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
class DependencyResolver {
|
||||
static Future<void> resolve(GetIt getIt) async {
|
||||
_resolveUserDeps(getIt);
|
||||
|
||||
_resolveHomeDeps(getIt);
|
||||
|
||||
_resolveFolderDeps(getIt);
|
||||
|
||||
_resolveDocDeps(getIt);
|
||||
|
||||
_resolveGridDeps(getIt);
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveUserDeps(GetIt getIt) {
|
||||
getIt.registerFactory<AuthService>(() => AuthService());
|
||||
getIt.registerFactory<AuthRouter>(() => AuthRouter());
|
||||
|
||||
getIt.registerFactory<SignInBloc>(() => SignInBloc(getIt<AuthService>()));
|
||||
getIt.registerFactory<SignUpBloc>(() => SignUpBloc(getIt<AuthService>()));
|
||||
|
||||
getIt.registerFactory<SplashRoute>(() => SplashRoute());
|
||||
getIt.registerFactory<HomeBloc>(() => HomeBloc());
|
||||
getIt.registerFactory<EditPannelBloc>(() => EditPannelBloc());
|
||||
getIt.registerFactory<SplashBloc>(() => SplashBloc());
|
||||
getIt.registerLazySingleton<NetworkListener>(() => NetworkListener());
|
||||
}
|
||||
|
||||
void _resolveHomeDeps(GetIt getIt) {
|
||||
getIt.registerFactoryParam<UserListener, UserProfile, void>(
|
||||
(user, _) => UserListener(user: user),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<HomeListenBloc, UserProfile, void>(
|
||||
(user, _) => HomeListenBloc(getIt<UserListener>(param1: user)),
|
||||
);
|
||||
|
||||
//
|
||||
getIt.registerLazySingleton<HomeStackManager>(() => HomeStackManager());
|
||||
|
||||
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
|
||||
(user, _) => WelcomeBloc(
|
||||
userService: UserService(),
|
||||
userListener: getIt<UserListener>(param1: user),
|
||||
),
|
||||
);
|
||||
|
||||
// share
|
||||
getIt.registerLazySingleton<ShareService>(() => ShareService());
|
||||
getIt.registerFactoryParam<DocShareBloc, View, void>(
|
||||
(view, _) => DocShareBloc(view: view, service: getIt<ShareService>()));
|
||||
}
|
||||
|
||||
void _resolveFolderDeps(GetIt getIt) {
|
||||
//workspace
|
||||
getIt.registerFactoryParam<WorkspaceListener, UserProfile, String>((user, workspaceId) =>
|
||||
WorkspaceListener(service: WorkspaceListenerService(user: user, workspaceId: workspaceId)));
|
||||
|
||||
// View
|
||||
getIt.registerFactoryParam<ViewListener, View, void>(
|
||||
(view, _) => ViewListener(view: view),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<ViewBloc, View, void>(
|
||||
(view, _) => ViewBloc(
|
||||
view: view,
|
||||
service: ViewService(),
|
||||
listener: getIt<ViewListener>(param1: view),
|
||||
),
|
||||
);
|
||||
|
||||
//Menu
|
||||
getIt.registerFactoryParam<MenuBloc, UserProfile, String>(
|
||||
(user, workspaceId) => MenuBloc(
|
||||
workspaceId: workspaceId,
|
||||
service: WorkspaceService(),
|
||||
listener: getIt<WorkspaceListener>(param1: user, param2: workspaceId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>(
|
||||
(user, _) => MenuUserBloc(
|
||||
user,
|
||||
UserService(),
|
||||
getIt<UserListener>(param1: user),
|
||||
),
|
||||
);
|
||||
|
||||
// App
|
||||
getIt.registerFactoryParam<AppBloc, App, void>(
|
||||
(app, _) => AppBloc(
|
||||
app: app,
|
||||
service: AppService(),
|
||||
listener: AppListener(appId: app.id),
|
||||
),
|
||||
);
|
||||
|
||||
// trash
|
||||
getIt.registerLazySingleton<TrashService>(() => TrashService());
|
||||
getIt.registerLazySingleton<TrashListener>(() => TrashListener());
|
||||
getIt.registerFactory<TrashBloc>(
|
||||
() => TrashBloc(
|
||||
service: getIt<TrashService>(),
|
||||
listener: getIt<TrashListener>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _resolveDocDeps(GetIt getIt) {
|
||||
// Doc
|
||||
getIt.registerFactoryParam<DocumentBloc, View, void>(
|
||||
(view, _) => DocumentBloc(
|
||||
view: view,
|
||||
service: DocumentService(),
|
||||
listener: getIt<ViewListener>(param1: view),
|
||||
trashService: getIt<TrashService>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _resolveGridDeps(GetIt getIt) {
|
||||
// Grid
|
||||
getIt.registerFactoryParam<GridBloc, View, void>(
|
||||
(view, _) => GridBloc(view: view, service: GridService()),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<RowBloc, RowData, void>(
|
||||
(data, _) => RowBloc(
|
||||
rowData: data,
|
||||
rowlistener: RowListener(rowId: data.rowId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<GridHeaderBloc, String, List<Field>>(
|
||||
(gridId, fields) => GridHeaderBloc(
|
||||
data: GridHeaderData(gridId: gridId, fields: fields),
|
||||
service: FieldService(gridId: gridId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<FieldActionSheetBloc, GridFieldCellContext, void>(
|
||||
(data, _) => FieldActionSheetBloc(
|
||||
field: data.field,
|
||||
service: FieldService(gridId: data.gridId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<FieldEditorBloc, String, EditFieldContextLoader>(
|
||||
(gridId, fieldLoader) => FieldEditorBloc(
|
||||
service: FieldService(gridId: gridId),
|
||||
fieldLoader: fieldLoader,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<TextCellBloc, CellData, void>(
|
||||
(cellData, _) => TextCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SelectionCellBloc, CellData, void>(
|
||||
(cellData, _) => SelectionCellBloc(
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<NumberCellBloc, CellData, void>(
|
||||
(cellData, _) => NumberCellBloc(
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<DateCellBloc, CellData, void>(
|
||||
(cellData, _) => DateCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, CellData, void>(
|
||||
(cellData, _) => CheckboxCellBloc(
|
||||
service: CellService(),
|
||||
cellData: cellData,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<FieldSwitcherBloc, SwitchFieldContext, void>(
|
||||
(context, _) => FieldSwitcherBloc(context),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SingleSelectTypeOptionBloc, SingleSelectTypeOption, String>(
|
||||
(typeOption, fieldId) => SingleSelectTypeOptionBloc(typeOption, fieldId),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<MultiSelectTypeOptionBloc, MultiSelectTypeOption, String>(
|
||||
(typeOption, fieldId) => MultiSelectTypeOptionBloc(typeOption, fieldId),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<DateTypeOptionBloc, DateTypeOption, void>(
|
||||
(typeOption, _) => DateTypeOptionBloc(typeOption: typeOption),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<NumberTypeOptionBloc, NumberTypeOption, void>(
|
||||
(typeOption, _) => NumberTypeOptionBloc(typeOption: typeOption),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<GridPropertyBloc, String, List<Field>>(
|
||||
(gridId, fields) => GridPropertyBloc(gridId: gridId, fields: fields),
|
||||
);
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
import 'package:app_flowy/user/application/user_listener.dart';
|
||||
import 'package:app_flowy/user/application/user_service.dart';
|
||||
import 'package:app_flowy/workspace/application/app/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/doc/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/trash/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/workspace/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/view/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/home/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/menu/prelude.dart';
|
||||
|
||||
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
class HomeDepsResolver {
|
||||
static Future<void> resolve(GetIt getIt) async {
|
||||
getIt.registerFactoryParam<UserListener, UserProfile, void>(
|
||||
(user, _) => UserListener(user: user),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<HomeListenBloc, UserProfile, void>(
|
||||
(user, _) => HomeListenBloc(getIt<UserListener>(param1: user)),
|
||||
);
|
||||
|
||||
//
|
||||
getIt.registerLazySingleton<HomeStackManager>(() => HomeStackManager());
|
||||
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
|
||||
(user, _) => WelcomeBloc(
|
||||
userService: UserService(),
|
||||
userListener: getIt<UserListener>(param1: user),
|
||||
),
|
||||
);
|
||||
|
||||
//workspace
|
||||
getIt.registerFactoryParam<WorkspaceListener, UserProfile, String>((user, workspaceId) =>
|
||||
WorkspaceListener(service: WorkspaceListenerService(user: user, workspaceId: workspaceId)));
|
||||
|
||||
// View
|
||||
getIt.registerFactoryParam<ViewListener, View, void>(
|
||||
(view, _) => ViewListener(view: view),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<ViewBloc, View, void>(
|
||||
(view, _) => ViewBloc(
|
||||
view: view,
|
||||
service: ViewService(),
|
||||
listener: getIt<ViewListener>(param1: view),
|
||||
),
|
||||
);
|
||||
|
||||
//Menu Bloc
|
||||
getIt.registerFactoryParam<MenuBloc, UserProfile, String>(
|
||||
(user, workspaceId) => MenuBloc(
|
||||
workspaceId: workspaceId,
|
||||
service: WorkspaceService(),
|
||||
listener: getIt<WorkspaceListener>(param1: user, param2: workspaceId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>(
|
||||
(user, _) => MenuUserBloc(
|
||||
user,
|
||||
UserService(),
|
||||
getIt<UserListener>(param1: user),
|
||||
),
|
||||
);
|
||||
|
||||
// App
|
||||
getIt.registerFactoryParam<AppBloc, App, void>(
|
||||
(app, _) => AppBloc(
|
||||
app: app,
|
||||
service: AppService(),
|
||||
listener: AppListener(appId: app.id),
|
||||
),
|
||||
);
|
||||
|
||||
// Doc
|
||||
getIt.registerFactoryParam<DocumentBloc, View, void>(
|
||||
(view, _) => DocumentBloc(
|
||||
view: view,
|
||||
service: DocumentService(),
|
||||
listener: getIt<ViewListener>(param1: view),
|
||||
trashService: getIt<TrashService>(),
|
||||
),
|
||||
);
|
||||
|
||||
// Grid
|
||||
getIt.registerFactoryParam<GridBloc, View, void>(
|
||||
(view, _) => GridBloc(view: view, service: GridService()),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<RowBloc, GridRowData, void>(
|
||||
(data, _) => RowBloc(
|
||||
rowService: RowService(data),
|
||||
listener: RowListener(rowId: data.rowId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<ColumnBloc, List<Field>, void>(
|
||||
(data, _) => ColumnBloc(
|
||||
data: GridColumnData(fields: data),
|
||||
service: ColumnService(),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<TextCellBloc, GridCellData, void>(
|
||||
(context, _) => TextCellBloc(
|
||||
service: CellService(context),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SelectionCellBloc, GridCellData, void>(
|
||||
(context, _) => SelectionCellBloc(
|
||||
service: CellService(context),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<NumberCellBloc, GridCellData, void>(
|
||||
(context, _) => NumberCellBloc(
|
||||
service: CellService(context),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<DateCellBloc, GridCellData, void>(
|
||||
(context, _) => DateCellBloc(
|
||||
service: CellService(context),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, GridCellData, void>(
|
||||
(context, _) => CheckboxCellBloc(
|
||||
service: CellService(context),
|
||||
),
|
||||
);
|
||||
|
||||
// trash
|
||||
getIt.registerLazySingleton<TrashService>(() => TrashService());
|
||||
getIt.registerLazySingleton<TrashListener>(() => TrashListener());
|
||||
getIt.registerFactory<TrashBloc>(
|
||||
() => TrashBloc(
|
||||
service: getIt<TrashService>(),
|
||||
listener: getIt<TrashListener>(),
|
||||
),
|
||||
);
|
||||
|
||||
// share
|
||||
getIt.registerLazySingleton<ShareService>(() => ShareService());
|
||||
getIt.registerFactoryParam<DocShareBloc, View, void>(
|
||||
(view, _) => DocShareBloc(view: view, service: getIt<ShareService>()));
|
||||
}
|
||||
}
|
@ -2,8 +2,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:app_flowy/plugin/plugin.dart';
|
||||
import 'package:app_flowy/startup/tasks/prelude.dart';
|
||||
import 'package:app_flowy/startup/home_deps_resolver.dart';
|
||||
import 'package:app_flowy/startup/user_deps_resolver.dart';
|
||||
import 'package:app_flowy/startup/deps_resolver.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
@ -62,8 +61,7 @@ Future<void> initGetIt(
|
||||
getIt.registerLazySingleton<AppLauncher>(() => AppLauncher(env, getIt));
|
||||
getIt.registerSingleton<PluginSandbox>(PluginSandbox());
|
||||
|
||||
await UserDepsResolver.resolve(getIt);
|
||||
await HomeDepsResolver.resolve(getIt);
|
||||
await DependencyResolver.resolve(getIt);
|
||||
}
|
||||
|
||||
class LaunchContext {
|
||||
|
@ -113,7 +113,7 @@ class ApplicationBlocObserver extends BlocObserver {
|
||||
// ignore: unnecessary_overrides
|
||||
void onTransition(Bloc bloc, Transition transition) {
|
||||
// Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}");
|
||||
//Log.debug("${transition.nextState}");
|
||||
// Log.debug("${transition.nextState}");
|
||||
super.onTransition(bloc, transition);
|
||||
}
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
import 'package:app_flowy/user/application/auth_service.dart';
|
||||
import 'package:app_flowy/user/application/sign_in_bloc.dart';
|
||||
import 'package:app_flowy/user/application/sign_up_bloc.dart';
|
||||
import 'package:app_flowy/user/application/splash_bloc.dart';
|
||||
import 'package:app_flowy/user/presentation/router.dart';
|
||||
import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import '../core/network_monitor.dart';
|
||||
|
||||
class UserDepsResolver {
|
||||
static Future<void> resolve(GetIt getIt) async {
|
||||
getIt.registerFactory<AuthService>(() => AuthService());
|
||||
|
||||
//Interface implementation
|
||||
getIt.registerFactory<AuthRouter>(() => AuthRouter());
|
||||
|
||||
//Bloc
|
||||
getIt.registerFactory<SignInBloc>(() => SignInBloc(getIt<AuthService>()));
|
||||
getIt.registerFactory<SignUpBloc>(() => SignUpBloc(getIt<AuthService>()));
|
||||
|
||||
getIt.registerFactory<SplashRoute>(() => SplashRoute());
|
||||
getIt.registerFactory<HomeBloc>(() => HomeBloc());
|
||||
getIt.registerFactory<EditPannelBloc>(() => EditPannelBloc());
|
||||
getIt.registerFactory<SplashBloc>(() => SplashBloc());
|
||||
getIt.registerLazySingleton<NetworkListener>(() => NetworkListener());
|
||||
}
|
||||
}
|
4
frontend/app_flowy/lib/user/application/prelude.dart
Normal file
@ -0,0 +1,4 @@
|
||||
export './auth_service.dart';
|
||||
export './sign_in_bloc.dart';
|
||||
export './sign_up_bloc.dart';
|
||||
export './splash_bloc.dart';
|
@ -54,14 +54,14 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SignInEvent with _$SignInEvent {
|
||||
class SignInEvent with _$SignInEvent {
|
||||
const factory SignInEvent.signedInWithUserEmailAndPassword() = SignedInWithUserEmailAndPassword;
|
||||
const factory SignInEvent.emailChanged(String email) = EmailChanged;
|
||||
const factory SignInEvent.passwordChanged(String password) = PasswordChanged;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SignInState with _$SignInState {
|
||||
class SignInState with _$SignInState {
|
||||
const factory SignInState({
|
||||
String? email,
|
||||
String? password,
|
||||
|
@ -15,11 +15,11 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
|
||||
on<SignUpEvent>((event, emit) async {
|
||||
await event.map(signUpWithUserEmailAndPassword: (e) async {
|
||||
await _performActionOnSignUp(emit);
|
||||
}, emailChanged: (EmailChanged value) async {
|
||||
}, emailChanged: (_EmailChanged value) async {
|
||||
emit(state.copyWith(email: value.email, emailError: none(), successOrFail: none()));
|
||||
}, passwordChanged: (PasswordChanged value) async {
|
||||
}, passwordChanged: (_PasswordChanged value) async {
|
||||
emit(state.copyWith(password: value.password, passwordError: none(), successOrFail: none()));
|
||||
}, repeatPasswordChanged: (RepeatPasswordChanged value) async {
|
||||
}, repeatPasswordChanged: (_RepeatPasswordChanged value) async {
|
||||
emit(state.copyWith(repeatedPassword: value.password, repeatPasswordError: none(), successOrFail: none()));
|
||||
});
|
||||
});
|
||||
@ -104,9 +104,9 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
|
||||
@freezed
|
||||
class SignUpEvent with _$SignUpEvent {
|
||||
const factory SignUpEvent.signUpWithUserEmailAndPassword() = SignUpWithUserEmailAndPassword;
|
||||
const factory SignUpEvent.emailChanged(String email) = EmailChanged;
|
||||
const factory SignUpEvent.passwordChanged(String password) = PasswordChanged;
|
||||
const factory SignUpEvent.repeatPasswordChanged(String password) = RepeatPasswordChanged;
|
||||
const factory SignUpEvent.emailChanged(String email) = _EmailChanged;
|
||||
const factory SignUpEvent.passwordChanged(String password) = _PasswordChanged;
|
||||
const factory SignUpEvent.repeatPasswordChanged(String password) = _RepeatPasswordChanged;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -12,7 +12,6 @@ import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/dart_notification.pb.dart' as user;
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
|
||||
typedef UserProfileUpdatedNotifierValue = Either<UserProfile, FlowyError>;
|
||||
typedef AuthNotifierValue = Either<Unit, FlowyError>;
|
||||
typedef WorkspaceUpdatedNotifierValue = Either<List<Workspace>, FlowyError>;
|
||||
@ -23,8 +22,8 @@ class UserListener {
|
||||
final authDidChangedNotifier = PublishNotifier<AuthNotifierValue>();
|
||||
final workspaceUpdatedNotifier = PublishNotifier<WorkspaceUpdatedNotifierValue>();
|
||||
|
||||
late FolderNotificationParser _workspaceParser;
|
||||
late UserNotificationParser _userParser;
|
||||
FolderNotificationParser? _workspaceParser;
|
||||
UserNotificationParser? _userParser;
|
||||
late UserProfile _user;
|
||||
UserListener({
|
||||
required UserProfile user,
|
||||
@ -36,12 +35,14 @@ class UserListener {
|
||||
_workspaceParser = FolderNotificationParser(id: _user.token, callback: _notificationCallback);
|
||||
_userParser = UserNotificationParser(id: _user.token, callback: _userNotificationCallback);
|
||||
_subscription = RustStreamReceiver.listen((observable) {
|
||||
_workspaceParser.parse(observable);
|
||||
_userParser.parse(observable);
|
||||
_workspaceParser?.parse(observable);
|
||||
_userParser?.parse(observable);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
_workspaceParser = null;
|
||||
_userParser = null;
|
||||
await _subscription?.cancel();
|
||||
profileUpdatedNotifier.dispose();
|
||||
authDidChangedNotifier.dispose();
|
||||
|
@ -4,7 +4,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'auth_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
abstract class AuthState with _$AuthState {
|
||||
class AuthState with _$AuthState {
|
||||
const factory AuthState.authenticated(UserProfile userProfile) = Authenticated;
|
||||
const factory AuthState.unauthenticated(FlowyError error) = Unauthenticated;
|
||||
const factory AuthState.initial() = _Initial;
|
||||
|
@ -170,11 +170,11 @@ class PasswordTextField extends StatelessWidget {
|
||||
return RoundedInputField(
|
||||
obscureText: true,
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
obscureIcon: svg("home/hide"),
|
||||
obscureHideIcon: svg("home/show"),
|
||||
obscureIcon: svgWidget("home/hide"),
|
||||
obscureHideIcon: svgWidget("home/show"),
|
||||
hintText: LocaleKeys.signIn_passwordHint.tr(),
|
||||
normalBorderColor: theme.shader4,
|
||||
highlightBorderColor: theme.red,
|
||||
errorBorderColor: theme.red,
|
||||
cursorColor: theme.main1,
|
||||
errorText: context.read<SignInBloc>().state.passwordError.fold(() => "", (error) => error),
|
||||
onChanged: (value) => context.read<SignInBloc>().add(SignInEvent.passwordChanged(value)),
|
||||
@ -199,7 +199,7 @@ class EmailTextField extends StatelessWidget {
|
||||
hintText: LocaleKeys.signIn_emailHint.tr(),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
normalBorderColor: theme.shader4,
|
||||
highlightBorderColor: theme.red,
|
||||
errorBorderColor: theme.red,
|
||||
cursorColor: theme.main1,
|
||||
errorText: context.read<SignInBloc>().state.emailError.fold(() => "", (error) => error),
|
||||
onChanged: (value) => context.read<SignInBloc>().add(SignInEvent.emailChanged(value)),
|
||||
|
@ -134,12 +134,12 @@ class PasswordTextField extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
return RoundedInputField(
|
||||
obscureText: true,
|
||||
obscureIcon: svg("home/hide"),
|
||||
obscureHideIcon: svg("home/show"),
|
||||
obscureIcon: svgWidget("home/hide"),
|
||||
obscureHideIcon: svgWidget("home/show"),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
hintText: LocaleKeys.signUp_passwordHint.tr(),
|
||||
normalBorderColor: theme.shader4,
|
||||
highlightBorderColor: theme.red,
|
||||
errorBorderColor: theme.red,
|
||||
cursorColor: theme.main1,
|
||||
errorText: context.read<SignUpBloc>().state.passwordError.fold(() => "", (error) => error),
|
||||
onChanged: (value) => context.read<SignUpBloc>().add(SignUpEvent.passwordChanged(value)),
|
||||
@ -162,12 +162,12 @@ class RepeatPasswordTextField extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
return RoundedInputField(
|
||||
obscureText: true,
|
||||
obscureIcon: svg("home/hide"),
|
||||
obscureHideIcon: svg("home/show"),
|
||||
obscureIcon: svgWidget("home/hide"),
|
||||
obscureHideIcon: svgWidget("home/show"),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
hintText: LocaleKeys.signUp_repeatPasswordHint.tr(),
|
||||
normalBorderColor: theme.shader4,
|
||||
highlightBorderColor: theme.red,
|
||||
errorBorderColor: theme.red,
|
||||
cursorColor: theme.main1,
|
||||
errorText: context.read<SignUpBloc>().state.repeatPasswordError.fold(() => "", (error) => error),
|
||||
onChanged: (value) => context.read<SignUpBloc>().add(SignUpEvent.repeatPasswordChanged(value)),
|
||||
@ -192,7 +192,7 @@ class EmailTextField extends StatelessWidget {
|
||||
hintText: LocaleKeys.signUp_emailHint.tr(),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
normalBorderColor: theme.shader4,
|
||||
highlightBorderColor: theme.red,
|
||||
errorBorderColor: theme.red,
|
||||
cursorColor: theme.main1,
|
||||
errorText: context.read<SignUpBloc>().state.emailError.fold(() => "", (error) => error),
|
||||
onChanged: (value) => context.read<SignUpBloc>().add(SignUpEvent.emailChanged(value)),
|
||||
|
@ -4,7 +4,7 @@ import 'package:app_flowy/user/domain/auth_state.dart';
|
||||
import 'package:app_flowy/user/presentation/router.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/error-code/error_code.pbenum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
|
@ -44,7 +44,7 @@ class FlowyLogoTitle extends StatelessWidget {
|
||||
children: [
|
||||
SizedBox.fromSize(
|
||||
size: logoSize,
|
||||
child: svg("flowy_logo"),
|
||||
child: svgWidget("flowy_logo"),
|
||||
),
|
||||
const VSpace(30),
|
||||
Text(
|
||||
|
@ -19,7 +19,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
AppBloc({required this.app, required this.service, required this.listener}) : super(AppState.initial(app)) {
|
||||
on<AppEvent>((event, emit) async {
|
||||
await event.map(initial: (e) async {
|
||||
listener.startListening(
|
||||
listener.start(
|
||||
viewsChanged: _handleViewsChanged,
|
||||
appUpdated: (app) => add(AppEvent.appDidUpdate(app)),
|
||||
);
|
||||
|
@ -17,18 +17,18 @@ class AppListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
ViewsDidChangeCallback? _viewsChanged;
|
||||
AppDidUpdateCallback? _updated;
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
String appId;
|
||||
|
||||
AppListener({
|
||||
required this.appId,
|
||||
});
|
||||
|
||||
void startListening({ViewsDidChangeCallback? viewsChanged, AppDidUpdateCallback? appUpdated}) {
|
||||
void start({ViewsDidChangeCallback? viewsChanged, AppDidUpdateCallback? appUpdated}) {
|
||||
_viewsChanged = viewsChanged;
|
||||
_updated = appUpdated;
|
||||
_parser = FolderNotificationParser(id: appId, callback: _bservableCallback);
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _bservableCallback(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -61,6 +61,7 @@ class AppListener {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
_viewsChanged = null;
|
||||
_updated = null;
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:app_flowy/user/application/user_settings_service.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
@ -5,13 +7,12 @@ import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_setting.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:async/async.dart';
|
||||
|
||||
class AppearanceSettingModel extends ChangeNotifier with EquatableMixin {
|
||||
AppearanceSettings setting;
|
||||
AppTheme _theme;
|
||||
Locale _locale;
|
||||
CancelableOperation? _saveOperation;
|
||||
Timer? _saveOperation;
|
||||
|
||||
AppearanceSettingModel(this.setting)
|
||||
: _theme = AppTheme.fromName(name: setting.theme),
|
||||
@ -21,12 +22,10 @@ class AppearanceSettingModel extends ChangeNotifier with EquatableMixin {
|
||||
Locale get locale => _locale;
|
||||
|
||||
Future<void> save() async {
|
||||
_saveOperation?.cancel;
|
||||
_saveOperation = CancelableOperation.fromFuture(
|
||||
Future.delayed(const Duration(seconds: 1), () async {
|
||||
await UserSettingsService().setAppearanceSettings(setting);
|
||||
}),
|
||||
);
|
||||
_saveOperation?.cancel();
|
||||
_saveOperation = Timer(const Duration(seconds: 2), () async {
|
||||
await UserSettingsService().setAppearanceSettings(setting);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -5,19 +5,8 @@ abstract class EditPannelContext extends Equatable {
|
||||
final String identifier;
|
||||
final String title;
|
||||
final Widget child;
|
||||
const EditPannelContext(
|
||||
{required this.child, required this.identifier, required this.title});
|
||||
const EditPannelContext({required this.child, required this.identifier, required this.title});
|
||||
|
||||
@override
|
||||
List<Object> get props => [identifier];
|
||||
}
|
||||
|
||||
class BlankEditPannelContext extends EditPannelContext {
|
||||
const BlankEditPannelContext()
|
||||
: super(child: const Text('Blank'), identifier: '1', title: '');
|
||||
}
|
||||
|
||||
class CellEditPannelContext extends EditPannelContext {
|
||||
const CellEditPannelContext()
|
||||
: super(child: const Text('shit'), identifier: 'test', title: 'test');
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:app_flowy/workspace/application/edit_pannel/edit_context.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
// ignore: import_of_legacy_library_into_null_safe
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
part 'edit_pannel_bloc.freezed.dart';
|
||||
|
@ -0,0 +1,40 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<CellNotificationData, FlowyError>;
|
||||
|
||||
class CellListener {
|
||||
final String rowId;
|
||||
final String fieldId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue> updateCellNotifier = PublishNotifier();
|
||||
GridNotificationListener? _listener;
|
||||
CellListener({required this.rowId, required this.fieldId});
|
||||
|
||||
void start() {
|
||||
_listener = GridNotificationListener(objectId: "$rowId:$fieldId", handler: _handler);
|
||||
}
|
||||
|
||||
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateCell:
|
||||
result.fold(
|
||||
(payload) => updateCellNotifier.value = left(CellNotificationData.fromBuffer(payload)),
|
||||
(error) => updateCellNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
updateCellNotifier.dispose();
|
||||
}
|
||||
}
|
@ -1,20 +1,36 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
|
||||
class CellService {
|
||||
final GridCellData context;
|
||||
CellService();
|
||||
|
||||
CellService(this.context);
|
||||
|
||||
Future<Either<void, FlowyError>> updateCell({required String data}) {
|
||||
Future<Either<void, FlowyError>> updateCell({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String data,
|
||||
}) {
|
||||
final payload = CellMetaChangeset.create()
|
||||
..gridId = context.gridId
|
||||
..fieldId = context.field.id
|
||||
..rowId = context.rowId
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId
|
||||
..data = data;
|
||||
return GridEventUpdateCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Cell, FlowyError>> getCell({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
}) {
|
||||
final payload = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
return GridEventGetCell(payload).send();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -7,15 +10,32 @@ import 'cell_service.dart';
|
||||
part 'checkbox_cell_bloc.freezed.dart';
|
||||
|
||||
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
final CellService service;
|
||||
final CellService _service;
|
||||
final CellListener _listener;
|
||||
|
||||
CheckboxCellBloc({
|
||||
required this.service,
|
||||
}) : super(CheckboxCellState.initial(service.context.cell)) {
|
||||
required CellService service,
|
||||
required CellData cellData,
|
||||
}) : _service = service,
|
||||
_listener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(CheckboxCellState.initial(cellData)) {
|
||||
on<CheckboxCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialCell value) async {},
|
||||
initial: (_Initial value) {
|
||||
_startListening();
|
||||
},
|
||||
select: (_Selected value) async {
|
||||
_service.updateCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
data: !state.isSelected ? "Yes" : "No",
|
||||
);
|
||||
},
|
||||
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
|
||||
emit(state.copyWith(isSelected: isSelected(value.cell)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -23,20 +43,51 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _listener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_listener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
result.fold(
|
||||
(cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_listener.start();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class CheckboxCellEvent with _$CheckboxCellEvent {
|
||||
const factory CheckboxCellEvent.initial() = _InitialCell;
|
||||
class CheckboxCellEvent with _$CheckboxCellEvent {
|
||||
const factory CheckboxCellEvent.initial() = _Initial;
|
||||
const factory CheckboxCellEvent.select() = _Selected;
|
||||
const factory CheckboxCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class CheckboxCellState with _$CheckboxCellState {
|
||||
class CheckboxCellState with _$CheckboxCellState {
|
||||
const factory CheckboxCellState({
|
||||
required Cell? cell,
|
||||
required CellData cellData,
|
||||
required bool isSelected,
|
||||
}) = _CheckboxCellState;
|
||||
|
||||
factory CheckboxCellState.initial(Cell? cell) => CheckboxCellState(cell: cell);
|
||||
factory CheckboxCellState.initial(CellData cellData) {
|
||||
return CheckboxCellState(cellData: cellData, isSelected: isSelected(cellData.cell));
|
||||
}
|
||||
}
|
||||
|
||||
bool isSelected(Cell? cell) {
|
||||
final content = cell?.content ?? "";
|
||||
return content == "Yes";
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -8,10 +9,12 @@ part 'date_cell_bloc.freezed.dart';
|
||||
|
||||
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
final CellService service;
|
||||
final CellData cellData;
|
||||
|
||||
DateCellBloc({
|
||||
required this.service,
|
||||
}) : super(DateCellState.initial(service.context.cell)) {
|
||||
required this.cellData,
|
||||
}) : super(DateCellState.initial()) {
|
||||
on<DateCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -28,15 +31,15 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class DateCellEvent with _$DateCellEvent {
|
||||
class DateCellEvent with _$DateCellEvent {
|
||||
const factory DateCellEvent.initial() = _InitialCell;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class DateCellState with _$DateCellState {
|
||||
class DateCellState with _$DateCellState {
|
||||
const factory DateCellState({
|
||||
required Cell? cell,
|
||||
Cell? cell,
|
||||
}) = _DateCellState;
|
||||
|
||||
factory DateCellState.initial(Cell? cell) => DateCellState(cell: cell);
|
||||
factory DateCellState.initial() => const DateCellState();
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -7,36 +10,87 @@ import 'cell_service.dart';
|
||||
part 'number_cell_bloc.freezed.dart';
|
||||
|
||||
class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
final CellService service;
|
||||
final CellService _service;
|
||||
final CellListener _listener;
|
||||
|
||||
NumberCellBloc({
|
||||
required this.service,
|
||||
}) : super(NumberCellState.initial(service.context.cell)) {
|
||||
required CellData cellData,
|
||||
}) : _service = CellService(),
|
||||
_listener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(NumberCellState.initial(cellData)) {
|
||||
on<NumberCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialCell value) async {},
|
||||
initial: (_Initial value) async {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
|
||||
emit(state.copyWith(content: value.cell.content));
|
||||
},
|
||||
updateCell: (_UpdateCell value) {
|
||||
_updateCellValue(value, emit);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _updateCellValue(_UpdateCell value, Emitter<NumberCellState> emit) {
|
||||
final number = num.tryParse(value.text);
|
||||
if (number == null) {
|
||||
emit(state.copyWith(content: ""));
|
||||
} else {
|
||||
_service.updateCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
data: value.text,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _listener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_listener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
result.fold(
|
||||
(cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_listener.start();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class NumberCellEvent with _$NumberCellEvent {
|
||||
const factory NumberCellEvent.initial() = _InitialCell;
|
||||
class NumberCellEvent with _$NumberCellEvent {
|
||||
const factory NumberCellEvent.initial() = _Initial;
|
||||
const factory NumberCellEvent.updateCell(String text) = _UpdateCell;
|
||||
const factory NumberCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class NumberCellState with _$NumberCellState {
|
||||
class NumberCellState with _$NumberCellState {
|
||||
const factory NumberCellState({
|
||||
required Cell? cell,
|
||||
required CellData cellData,
|
||||
required String content,
|
||||
}) = _NumberCellState;
|
||||
|
||||
factory NumberCellState.initial(Cell? cell) => NumberCellState(cell: cell);
|
||||
factory NumberCellState.initial(CellData cellData) {
|
||||
return NumberCellState(cellData: cellData, content: cellData.cell?.content ?? "");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,109 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
|
||||
class SelectOptionService {
|
||||
SelectOptionService();
|
||||
|
||||
Future<Either<Unit, FlowyError>> create({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String name,
|
||||
}) {
|
||||
return GridEventNewSelectOption(SelectOptionName.create()..name = name).send().then(
|
||||
(result) {
|
||||
return result.fold(
|
||||
(option) {
|
||||
final cellIdentifier = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
final payload = SelectOptionChangesetPayload.create()
|
||||
..insertOption = option
|
||||
..cellIdentifier = cellIdentifier;
|
||||
return GridEventApplySelectOptionChangeset(payload).send();
|
||||
},
|
||||
(r) => right(r),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> insert({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required SelectOption option,
|
||||
}) {
|
||||
final cellIdentifier = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
final payload = SelectOptionChangesetPayload.create()
|
||||
..insertOption = option
|
||||
..cellIdentifier = cellIdentifier;
|
||||
return GridEventApplySelectOptionChangeset(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> delete({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required SelectOption option,
|
||||
}) {
|
||||
final cellIdentifier = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
|
||||
final payload = SelectOptionChangesetPayload.create()
|
||||
..deleteOption = option
|
||||
..cellIdentifier = cellIdentifier;
|
||||
|
||||
return GridEventApplySelectOptionChangeset(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<SelectOptionContext, FlowyError>> getOpitonContext({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
}) {
|
||||
final payload = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
|
||||
return GridEventGetSelectOptionContext(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<void, FlowyError>> select({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String optionId,
|
||||
}) {
|
||||
final payload = SelectOptionCellChangesetPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId
|
||||
..insertOptionId = optionId;
|
||||
return GridEventApplySelectOptionCellChangeset(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<void, FlowyError>> remove({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required String optionId,
|
||||
}) {
|
||||
final payload = SelectOptionCellChangesetPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId
|
||||
..deleteOptionId = optionId;
|
||||
return GridEventApplySelectOptionCellChangeset(payload).send();
|
||||
}
|
||||
}
|
@ -1,21 +1,33 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell_bloc/select_option_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'cell_service.dart';
|
||||
|
||||
part 'selection_cell_bloc.freezed.dart';
|
||||
|
||||
class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||
final CellService service;
|
||||
final SelectOptionService _service;
|
||||
final CellListener _listener;
|
||||
|
||||
SelectionCellBloc({
|
||||
required this.service,
|
||||
}) : super(SelectionCellState.initial(service.context.cell)) {
|
||||
required CellData cellData,
|
||||
}) : _service = SelectOptionService(),
|
||||
_listener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(SelectionCellState.initial(cellData)) {
|
||||
on<SelectionCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialCell value) async {},
|
||||
initial: (_InitialCell value) async {
|
||||
_loadOptions();
|
||||
_startListening();
|
||||
},
|
||||
didReceiveOptions: (_DidReceiveOptions value) {
|
||||
emit(state.copyWith(options: value.options, selectedOptions: value.selectedOptions));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -23,20 +35,57 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _listener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _loadOptions() async {
|
||||
final result = await _service.getOpitonContext(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
|
||||
result.fold(
|
||||
(selectOptionContext) => add(SelectionCellEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_listener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) => _loadOptions(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_listener.start();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SelectionCellEvent with _$SelectionCellEvent {
|
||||
class SelectionCellEvent with _$SelectionCellEvent {
|
||||
const factory SelectionCellEvent.initial() = _InitialCell;
|
||||
const factory SelectionCellEvent.didReceiveOptions(
|
||||
List<SelectOption> options,
|
||||
List<SelectOption> selectedOptions,
|
||||
) = _DidReceiveOptions;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SelectionCellState with _$SelectionCellState {
|
||||
class SelectionCellState with _$SelectionCellState {
|
||||
const factory SelectionCellState({
|
||||
required Cell? cell,
|
||||
required CellData cellData,
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> selectedOptions,
|
||||
}) = _SelectionCellState;
|
||||
|
||||
factory SelectionCellState.initial(Cell? cell) => SelectionCellState(cell: cell);
|
||||
factory SelectionCellState.initial(CellData cellData) => SelectionCellState(
|
||||
cellData: cellData,
|
||||
options: [],
|
||||
selectedOptions: [],
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,186 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'select_option_service.dart';
|
||||
|
||||
part 'selection_editor_bloc.freezed.dart';
|
||||
|
||||
class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
|
||||
final SelectOptionService _selectOptionService;
|
||||
final FieldListener _fieldListener;
|
||||
final CellListener _cellListener;
|
||||
Timer? _delayOperation;
|
||||
|
||||
SelectOptionEditorBloc({
|
||||
required CellData cellData,
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> selectedOptions,
|
||||
}) : _selectOptionService = SelectOptionService(),
|
||||
_fieldListener = FieldListener(fieldId: cellData.field.id),
|
||||
_cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id),
|
||||
super(SelectOptionEditorState.initial(cellData, options, selectedOptions)) {
|
||||
on<SelectOptionEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_Initial value) async {
|
||||
_startListening();
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(field: value.field));
|
||||
_loadOptions();
|
||||
},
|
||||
didReceiveOptions: (_DidReceiveOptions value) {
|
||||
emit(state.copyWith(
|
||||
options: value.options,
|
||||
selectedOptions: value.selectedOptions,
|
||||
));
|
||||
},
|
||||
newOption: (_NewOption value) {
|
||||
_createOption(value.optionName);
|
||||
},
|
||||
deleteOption: (_DeleteOption value) {
|
||||
_deleteOption(value.option);
|
||||
},
|
||||
updateOption: (_UpdateOption value) {
|
||||
_updateOption(value.option);
|
||||
},
|
||||
selectOption: (_SelectOption value) {
|
||||
_makeOptionAsSelected(value.optionId);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
_delayOperation?.cancel();
|
||||
await _fieldListener.stop();
|
||||
await _cellListener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _createOption(String name) async {
|
||||
final result = await _selectOptionService.create(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
name: name,
|
||||
);
|
||||
result.fold((l) => _loadOptions(), (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _deleteOption(SelectOption option) async {
|
||||
final result = await _selectOptionService.delete(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
option: option,
|
||||
);
|
||||
|
||||
result.fold((l) => null, (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _updateOption(SelectOption option) async {
|
||||
final result = await _selectOptionService.insert(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
option: option,
|
||||
);
|
||||
|
||||
result.fold((l) => null, (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _makeOptionAsSelected(String optionId) {
|
||||
_selectOptionService.select(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
optionId: optionId,
|
||||
);
|
||||
}
|
||||
|
||||
void _loadOptions() async {
|
||||
_delayOperation?.cancel();
|
||||
_delayOperation = Timer(
|
||||
const Duration(milliseconds: 300),
|
||||
() async {
|
||||
final result = await _selectOptionService.getOpitonContext(
|
||||
gridId: state.gridId,
|
||||
fieldId: state.field.id,
|
||||
rowId: state.rowId,
|
||||
);
|
||||
|
||||
result.fold(
|
||||
(selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_cellListener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) => _loadOptions(),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_cellListener.start();
|
||||
|
||||
_fieldListener.updateFieldNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(field) => add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionEditorEvent with _$SelectOptionEditorEvent {
|
||||
const factory SelectOptionEditorEvent.initial() = _Initial;
|
||||
const factory SelectOptionEditorEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||
const factory SelectOptionEditorEvent.didReceiveOptions(
|
||||
List<SelectOption> options, List<SelectOption> selectedOptions) = _DidReceiveOptions;
|
||||
const factory SelectOptionEditorEvent.newOption(String optionName) = _NewOption;
|
||||
const factory SelectOptionEditorEvent.selectOption(String optionId) = _SelectOption;
|
||||
const factory SelectOptionEditorEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory SelectOptionEditorEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionEditorState with _$SelectOptionEditorState {
|
||||
const factory SelectOptionEditorState({
|
||||
required String gridId,
|
||||
required Field field,
|
||||
required String rowId,
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> selectedOptions,
|
||||
}) = _SelectOptionEditorState;
|
||||
|
||||
factory SelectOptionEditorState.initial(
|
||||
CellData cellData,
|
||||
List<SelectOption> options,
|
||||
List<SelectOption> selectedOptions,
|
||||
) {
|
||||
return SelectOptionEditorState(
|
||||
gridId: cellData.gridId,
|
||||
field: cellData.field,
|
||||
rowId: cellData.rowId,
|
||||
options: options,
|
||||
selectedOptions: selectedOptions,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -10,19 +11,39 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
|
||||
TextCellBloc({
|
||||
required this.service,
|
||||
}) : super(TextCellState.initial(service.context.cell?.content ?? "")) {
|
||||
required CellData cellData,
|
||||
}) : super(TextCellState.initial(cellData)) {
|
||||
on<TextCellEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialCell value) async {},
|
||||
updateText: (_UpdateText value) {
|
||||
service.updateCell(data: value.text);
|
||||
updateCellContent(value.text);
|
||||
emit(state.copyWith(content: value.text));
|
||||
},
|
||||
didReceiveCellData: (_DidReceiveCellData value) {
|
||||
emit(state.copyWith(
|
||||
cellData: value.cellData,
|
||||
content: value.cellData.cell?.content ?? "",
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void updateCellContent(String content) {
|
||||
final fieldId = state.cellData.field.id;
|
||||
final gridId = state.cellData.gridId;
|
||||
final rowId = state.cellData.rowId;
|
||||
service.updateCell(
|
||||
data: content,
|
||||
fieldId: fieldId,
|
||||
gridId: gridId,
|
||||
rowId: rowId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
@ -30,16 +51,21 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class TextCellEvent with _$TextCellEvent {
|
||||
class TextCellEvent with _$TextCellEvent {
|
||||
const factory TextCellEvent.initial() = _InitialCell;
|
||||
const factory TextCellEvent.didReceiveCellData(CellData cellData) = _DidReceiveCellData;
|
||||
const factory TextCellEvent.updateText(String text) = _UpdateText;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class TextCellState with _$TextCellState {
|
||||
class TextCellState with _$TextCellState {
|
||||
const factory TextCellState({
|
||||
required String content,
|
||||
required CellData cellData,
|
||||
}) = _TextCellState;
|
||||
|
||||
factory TextCellState.initial(String content) => TextCellState(content: content);
|
||||
factory TextCellState.initial(CellData cellData) => TextCellState(
|
||||
content: cellData.cell?.content ?? "",
|
||||
cellData: cellData,
|
||||
);
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'column_service.dart';
|
||||
import 'data.dart';
|
||||
|
||||
part 'column_bloc.freezed.dart';
|
||||
|
||||
class ColumnBloc extends Bloc<ColumnEvent, ColumnState> {
|
||||
final ColumnService service;
|
||||
final GridColumnData data;
|
||||
|
||||
ColumnBloc({required this.data, required this.service}) : super(ColumnState.initial(data.fields)) {
|
||||
on<ColumnEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialColumn value) async {},
|
||||
createColumn: (_CreateColumn value) {},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ColumnEvent with _$ColumnEvent {
|
||||
const factory ColumnEvent.initial() = _InitialColumn;
|
||||
const factory ColumnEvent.createColumn() = _CreateColumn;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ColumnState with _$ColumnState {
|
||||
const factory ColumnState({required List<Field> fields}) = _ColumnState;
|
||||
|
||||
factory ColumnState.initial(List<Field> fields) => ColumnState(fields: fields);
|
||||
}
|
@ -1 +0,0 @@
|
||||
class ColumnService {}
|
@ -1,7 +1,8 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
|
||||
class GridColumnData {
|
||||
class GridHeaderData {
|
||||
final String gridId;
|
||||
final List<Field> fields;
|
||||
|
||||
GridColumnData({required this.fields});
|
||||
GridHeaderData({required this.gridId, required this.fields});
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'field_service.dart';
|
||||
|
||||
part 'action_sheet_bloc.freezed.dart';
|
||||
|
||||
class FieldActionSheetBloc extends Bloc<ActionSheetEvent, ActionSheetState> {
|
||||
final FieldService service;
|
||||
|
||||
FieldActionSheetBloc({required Field field, required this.service})
|
||||
: super(ActionSheetState.initial(EditFieldContext.create()..gridField = field)) {
|
||||
on<ActionSheetEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
updateFieldName: (_UpdateFieldName value) async {
|
||||
final result = await service.updateField(fieldId: field.id, name: value.name);
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
hideField: (_HideField value) async {
|
||||
final result = await service.updateField(fieldId: field.id, visibility: false);
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
deleteField: (_DeleteField value) async {
|
||||
final result = await service.deleteField(fieldId: field.id);
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
duplicateField: (_DuplicateField value) async {
|
||||
final result = await service.duplicateField(fieldId: field.id);
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
saveField: (_SaveField value) {},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ActionSheetEvent with _$ActionSheetEvent {
|
||||
const factory ActionSheetEvent.updateFieldName(String name) = _UpdateFieldName;
|
||||
const factory ActionSheetEvent.hideField() = _HideField;
|
||||
const factory ActionSheetEvent.duplicateField() = _DuplicateField;
|
||||
const factory ActionSheetEvent.deleteField() = _DeleteField;
|
||||
const factory ActionSheetEvent.saveField() = _SaveField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ActionSheetState with _$ActionSheetState {
|
||||
const factory ActionSheetState({
|
||||
required EditFieldContext editContext,
|
||||
required String errorText,
|
||||
required String fieldName,
|
||||
}) = _ActionSheetState;
|
||||
|
||||
factory ActionSheetState.initial(EditFieldContext editContext) => ActionSheetState(
|
||||
editContext: editContext,
|
||||
errorText: '',
|
||||
fieldName: editContext.gridField.name,
|
||||
);
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'field_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'field_editor_bloc.freezed.dart';
|
||||
|
||||
class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
final FieldService service;
|
||||
final EditFieldContextLoader _loader;
|
||||
|
||||
FieldEditorBloc({
|
||||
required this.service,
|
||||
required EditFieldContextLoader fieldLoader,
|
||||
}) : _loader = fieldLoader,
|
||||
super(FieldEditorState.initial(service.gridId)) {
|
||||
on<FieldEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialField value) async {
|
||||
await _getEditFieldContext(emit);
|
||||
},
|
||||
updateName: (_UpdateName value) {
|
||||
emit(state.copyWith(fieldName: value.name));
|
||||
},
|
||||
switchField: (_SwitchField value) {
|
||||
emit(state.copyWith(field: Some(value.field), typeOptionData: value.typeOptionData));
|
||||
},
|
||||
done: (_Done value) async {
|
||||
await _saveField(emit);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _saveField(Emitter<FieldEditorState> emit) async {
|
||||
await state.field.fold(
|
||||
() async => null,
|
||||
(field) async {
|
||||
field.name = state.fieldName;
|
||||
final result = await service.insertField(
|
||||
field: field,
|
||||
typeOptionData: state.typeOptionData,
|
||||
);
|
||||
result.fold((l) => null, (r) => null);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _getEditFieldContext(Emitter<FieldEditorState> emit) async {
|
||||
final result = await _loader.load();
|
||||
result.fold(
|
||||
(editContext) {
|
||||
emit(state.copyWith(
|
||||
field: Some(editContext.gridField),
|
||||
typeOptionData: editContext.typeOptionData,
|
||||
fieldName: editContext.gridField.name,
|
||||
));
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldEditorEvent with _$FieldEditorEvent {
|
||||
const factory FieldEditorEvent.initial() = _InitialField;
|
||||
const factory FieldEditorEvent.updateName(String name) = _UpdateName;
|
||||
const factory FieldEditorEvent.switchField(Field field, Uint8List typeOptionData) = _SwitchField;
|
||||
const factory FieldEditorEvent.done() = _Done;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldEditorState with _$FieldEditorState {
|
||||
const factory FieldEditorState({
|
||||
required String fieldName,
|
||||
required String gridId,
|
||||
required String errorText,
|
||||
required Option<Field> field,
|
||||
required List<int> typeOptionData,
|
||||
}) = _FieldEditorState;
|
||||
|
||||
factory FieldEditorState.initial(String gridId) => FieldEditorState(
|
||||
gridId: gridId,
|
||||
fieldName: '',
|
||||
field: none(),
|
||||
errorText: '',
|
||||
typeOptionData: List<int>.empty(),
|
||||
);
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<Field, FlowyError>;
|
||||
|
||||
class FieldListener {
|
||||
final String fieldId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue> updateFieldNotifier = PublishNotifier();
|
||||
GridNotificationListener? _listener;
|
||||
|
||||
FieldListener({required this.fieldId});
|
||||
|
||||
void start() {
|
||||
_listener = GridNotificationListener(
|
||||
objectId: fieldId,
|
||||
handler: _handler,
|
||||
);
|
||||
}
|
||||
|
||||
void _handler(
|
||||
GridNotification ty,
|
||||
Either<Uint8List, FlowyError> result,
|
||||
) {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateField:
|
||||
result.fold(
|
||||
(payload) => updateFieldNotifier.value = left(Field.fromBuffer(payload)),
|
||||
(error) => updateFieldNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
updateFieldNotifier.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
class FieldService {
|
||||
final String gridId;
|
||||
|
||||
FieldService({required this.gridId});
|
||||
|
||||
Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
|
||||
final payload = EditFieldPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..fieldType = fieldType;
|
||||
|
||||
return GridEventSwitchToField(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> updateField({
|
||||
required String fieldId,
|
||||
String? name,
|
||||
FieldType? fieldType,
|
||||
bool? frozen,
|
||||
bool? visibility,
|
||||
double? width,
|
||||
List<int>? typeOptionData,
|
||||
}) {
|
||||
var payload = FieldChangesetPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
if (name != null) {
|
||||
payload.name = name;
|
||||
}
|
||||
|
||||
if (fieldType != null) {
|
||||
payload.fieldType = fieldType;
|
||||
}
|
||||
|
||||
if (frozen != null) {
|
||||
payload.frozen = frozen;
|
||||
}
|
||||
|
||||
if (visibility != null) {
|
||||
payload.visibility = visibility;
|
||||
}
|
||||
|
||||
if (width != null) {
|
||||
payload.width = width.toInt();
|
||||
}
|
||||
|
||||
if (typeOptionData != null) {
|
||||
payload.typeOptionData = typeOptionData;
|
||||
}
|
||||
|
||||
return GridEventUpdateField(payload).send();
|
||||
}
|
||||
|
||||
// Create the field if it does not exist. Otherwise, update the field.
|
||||
Future<Either<Unit, FlowyError>> insertField({
|
||||
required Field field,
|
||||
List<int>? typeOptionData,
|
||||
String? startFieldId,
|
||||
}) {
|
||||
var payload = CreateFieldPayload.create()
|
||||
..gridId = gridId
|
||||
..field_2 = field
|
||||
..typeOptionData = typeOptionData ?? [];
|
||||
|
||||
if (startFieldId != null) {
|
||||
payload.startFieldId = startFieldId;
|
||||
}
|
||||
|
||||
return GridEventCreateField(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> deleteField({
|
||||
required String fieldId,
|
||||
}) {
|
||||
final payload = FieldIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
return GridEventDeleteField(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> duplicateField({
|
||||
required String fieldId,
|
||||
}) {
|
||||
final payload = FieldIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
return GridEventDuplicateField(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldCellContext extends Equatable {
|
||||
final String gridId;
|
||||
final Field field;
|
||||
|
||||
const GridFieldCellContext({
|
||||
required this.gridId,
|
||||
required this.field,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [field.id];
|
||||
}
|
||||
|
||||
abstract class EditFieldContextLoader {
|
||||
Future<Either<EditFieldContext, FlowyError>> load();
|
||||
|
||||
Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType);
|
||||
}
|
||||
|
||||
class NewFieldContextLoader extends EditFieldContextLoader {
|
||||
final String gridId;
|
||||
NewFieldContextLoader({
|
||||
required this.gridId,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<EditFieldContext, FlowyError>> load() {
|
||||
final payload = GetEditFieldContextPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldType = FieldType.RichText;
|
||||
|
||||
return GridEventGetEditFieldContext(payload).send();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
|
||||
final payload = GetEditFieldContextPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldType = fieldType;
|
||||
|
||||
return GridEventGetEditFieldContext(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
class FieldContextLoaderAdaptor extends EditFieldContextLoader {
|
||||
final String gridId;
|
||||
final Field field;
|
||||
|
||||
FieldContextLoaderAdaptor({
|
||||
required this.gridId,
|
||||
required this.field,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<EditFieldContext, FlowyError>> load() {
|
||||
final payload = GetEditFieldContextPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = field.id
|
||||
..fieldType = field.fieldType;
|
||||
|
||||
return GridEventGetEditFieldContext(payload).send();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType) async {
|
||||
final fieldService = FieldService(gridId: gridId);
|
||||
return fieldService.switchToField(fieldId, fieldType);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
part 'field_switch_bloc.freezed.dart';
|
||||
|
||||
class FieldSwitcherBloc extends Bloc<FieldSwitchEvent, FieldSwitchState> {
|
||||
FieldSwitcherBloc(SwitchFieldContext editContext) : super(FieldSwitchState.initial(editContext)) {
|
||||
on<FieldSwitchEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
toFieldType: (_ToFieldType value) async {
|
||||
emit(state.copyWith(
|
||||
field: value.field,
|
||||
typeOptionData: Uint8List.fromList(value.typeOptionData),
|
||||
));
|
||||
},
|
||||
didUpdateTypeOptionData: (_DidUpdateTypeOptionData value) {
|
||||
emit(state.copyWith(typeOptionData: value.typeOptionData));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldSwitchEvent with _$FieldSwitchEvent {
|
||||
const factory FieldSwitchEvent.toFieldType(Field field, List<int> typeOptionData) = _ToFieldType;
|
||||
const factory FieldSwitchEvent.didUpdateTypeOptionData(Uint8List typeOptionData) = _DidUpdateTypeOptionData;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldSwitchState with _$FieldSwitchState {
|
||||
const factory FieldSwitchState({
|
||||
required String gridId,
|
||||
required Field field,
|
||||
required Uint8List typeOptionData,
|
||||
}) = _FieldSwitchState;
|
||||
|
||||
factory FieldSwitchState.initial(SwitchFieldContext switchContext) => FieldSwitchState(
|
||||
gridId: switchContext.gridId,
|
||||
field: switchContext.field,
|
||||
typeOptionData: Uint8List.fromList(switchContext.typeOptionData),
|
||||
);
|
||||
}
|
||||
|
||||
class SwitchFieldContext {
|
||||
final String gridId;
|
||||
final Field field;
|
||||
final List<int> typeOptionData;
|
||||
|
||||
SwitchFieldContext(this.gridId, this.field, this.typeOptionData);
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
import 'package:app_flowy/workspace/application/grid/data.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'field_service.dart';
|
||||
|
||||
part 'grid_header_bloc.freezed.dart';
|
||||
|
||||
class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
|
||||
final FieldService service;
|
||||
final GridFieldsListener _fieldListener;
|
||||
|
||||
GridHeaderBloc({
|
||||
required GridHeaderData data,
|
||||
required this.service,
|
||||
}) : _fieldListener = GridFieldsListener(gridId: data.gridId),
|
||||
super(GridHeaderState.initial(data.fields)) {
|
||||
on<GridHeaderEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialHeader value) async {
|
||||
_startListening();
|
||||
},
|
||||
createField: (_CreateField value) {},
|
||||
insertField: (_InsertField value) {},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
value.fields.retainWhere((field) => field.visibility);
|
||||
emit(state.copyWith(fields: value.fields));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _startListening() async {
|
||||
_fieldListener.updateFieldsNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
_fieldListener.start();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _fieldListener.stop();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridHeaderEvent with _$GridHeaderEvent {
|
||||
const factory GridHeaderEvent.initial() = _InitialHeader;
|
||||
const factory GridHeaderEvent.createField() = _CreateField;
|
||||
const factory GridHeaderEvent.insertField({required bool onLeft}) = _InsertField;
|
||||
const factory GridHeaderEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridHeaderState with _$GridHeaderState {
|
||||
const factory GridHeaderState({required List<Field> fields}) = _GridHeaderState;
|
||||
|
||||
factory GridHeaderState.initial(List<Field> fields) {
|
||||
fields.retainWhere((field) => field.visibility);
|
||||
return GridHeaderState(fields: fields);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<List<Field>, FlowyError>;
|
||||
|
||||
class GridFieldsListener {
|
||||
final String gridId;
|
||||
PublishNotifier<UpdateFieldNotifiedValue> updateFieldsNotifier = PublishNotifier();
|
||||
GridNotificationListener? _listener;
|
||||
GridFieldsListener({required this.gridId});
|
||||
|
||||
void start() {
|
||||
_listener = GridNotificationListener(
|
||||
objectId: gridId,
|
||||
handler: _handler,
|
||||
);
|
||||
}
|
||||
|
||||
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateGrid:
|
||||
result.fold(
|
||||
(payload) => updateFieldsNotifier.value = left(RepeatedField.fromBuffer(payload).items),
|
||||
(error) => updateFieldsNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
updateFieldsNotifier.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
part 'date_bloc.freezed.dart';
|
||||
|
||||
class DateTypeOptionBloc extends Bloc<DateTypeOptionEvent, DateTypeOptionState> {
|
||||
DateTypeOptionBloc({required DateTypeOption typeOption}) : super(DateTypeOptionState.initial(typeOption)) {
|
||||
on<DateTypeOptionEvent>(
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
didSelectDateFormat: (_DidSelectDateFormat value) {
|
||||
emit(state.copyWith(typeOption: _updateDateFormat(value.format)));
|
||||
},
|
||||
didSelectTimeFormat: (_DidSelectTimeFormat value) {
|
||||
emit(state.copyWith(typeOption: _updateTimeFormat(value.format)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
DateTypeOption _updateTimeFormat(TimeFormat format) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.timeFormat = format;
|
||||
});
|
||||
}
|
||||
|
||||
DateTypeOption _updateDateFormat(DateFormat format) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.dateFormat = format;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DateTypeOptionEvent with _$DateTypeOptionEvent {
|
||||
const factory DateTypeOptionEvent.didSelectDateFormat(DateFormat format) = _DidSelectDateFormat;
|
||||
const factory DateTypeOptionEvent.didSelectTimeFormat(TimeFormat format) = _DidSelectTimeFormat;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DateTypeOptionState with _$DateTypeOptionState {
|
||||
const factory DateTypeOptionState({
|
||||
required DateTypeOption typeOption,
|
||||
}) = _DateTypeOptionState;
|
||||
|
||||
factory DateTypeOptionState.initial(DateTypeOption typeOption) => DateTypeOptionState(typeOption: typeOption);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
part 'edit_option_bloc.freezed.dart';
|
||||
|
||||
class EditOptionBloc extends Bloc<EditOptionEvent, EditOptionState> {
|
||||
EditOptionBloc({required SelectOption option}) : super(EditOptionState.initial(option)) {
|
||||
on<EditOptionEvent>(
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
updateName: (_UpdateName value) {
|
||||
emit(state.copyWith(option: _updateName(value.name)));
|
||||
},
|
||||
updateColor: (_UpdateColor value) {
|
||||
emit(state.copyWith(option: _updateColor(value.color)));
|
||||
},
|
||||
delete: (_Delete value) {
|
||||
emit(state.copyWith(deleted: const Some(true)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
SelectOption _updateColor(SelectOptionColor color) {
|
||||
state.option.freeze();
|
||||
return state.option.rebuild((option) {
|
||||
option.color = color;
|
||||
});
|
||||
}
|
||||
|
||||
SelectOption _updateName(String name) {
|
||||
state.option.freeze();
|
||||
return state.option.rebuild((option) {
|
||||
option.name = name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class EditOptionEvent with _$EditOptionEvent {
|
||||
const factory EditOptionEvent.updateName(String name) = _UpdateName;
|
||||
const factory EditOptionEvent.updateColor(SelectOptionColor color) = _UpdateColor;
|
||||
const factory EditOptionEvent.delete() = _Delete;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class EditOptionState with _$EditOptionState {
|
||||
const factory EditOptionState({
|
||||
required SelectOption option,
|
||||
required Option<bool> deleted,
|
||||
}) = _EditOptionState;
|
||||
|
||||
factory EditOptionState.initial(SelectOption option) => EditOptionState(
|
||||
option: option,
|
||||
deleted: none(),
|
||||
);
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
import 'type_option_service.dart';
|
||||
|
||||
part 'multi_select_bloc.freezed.dart';
|
||||
|
||||
class MultiSelectTypeOptionBloc extends Bloc<MultiSelectTypeOptionEvent, MultiSelectTypeOptionState> {
|
||||
final TypeOptionService service;
|
||||
|
||||
MultiSelectTypeOptionBloc(MultiSelectTypeOption typeOption, String fieldId)
|
||||
: service = TypeOptionService(fieldId: fieldId),
|
||||
super(MultiSelectTypeOptionState.initial(typeOption)) {
|
||||
on<MultiSelectTypeOptionEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
createOption: (_CreateOption value) async {
|
||||
final result = await service.newOption(value.optionName);
|
||||
result.fold(
|
||||
(option) {
|
||||
emit(state.copyWith(typeOption: _insertOption(option)));
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
updateOption: (_UpdateOption value) async {
|
||||
emit(state.copyWith(typeOption: _updateOption(value.option)));
|
||||
},
|
||||
deleteOption: (_DeleteOption value) {
|
||||
emit(state.copyWith(typeOption: _deleteOption(value.option)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
MultiSelectTypeOption _insertOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.options.insert(0, option);
|
||||
});
|
||||
}
|
||||
|
||||
MultiSelectTypeOption _updateOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
if (index != -1) {
|
||||
typeOption.options[index] = option;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MultiSelectTypeOption _deleteOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
if (index != -1) {
|
||||
typeOption.options.removeAt(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class MultiSelectTypeOptionEvent with _$MultiSelectTypeOptionEvent {
|
||||
const factory MultiSelectTypeOptionEvent.createOption(String optionName) = _CreateOption;
|
||||
const factory MultiSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory MultiSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class MultiSelectTypeOptionState with _$MultiSelectTypeOptionState {
|
||||
const factory MultiSelectTypeOptionState({
|
||||
required MultiSelectTypeOption typeOption,
|
||||
}) = _MultiSelectTypeOptionState;
|
||||
|
||||
factory MultiSelectTypeOptionState.initial(MultiSelectTypeOption typeOption) => MultiSelectTypeOptionState(
|
||||
typeOption: typeOption,
|
||||
);
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
|
||||
part 'number_bloc.freezed.dart';
|
||||
|
||||
class NumberTypeOptionBloc extends Bloc<NumberTypeOptionEvent, NumberTypeOptionState> {
|
||||
NumberTypeOptionBloc({required NumberTypeOption typeOption}) : super(NumberTypeOptionState.initial(typeOption)) {
|
||||
on<NumberTypeOptionEvent>(
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
didSelectFormat: (_DidSelectFormat value) {
|
||||
emit(state.copyWith(typeOption: _updateNumberFormat(value.format)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
NumberTypeOption _updateNumberFormat(NumberFormat format) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.format = format;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class NumberTypeOptionEvent with _$NumberTypeOptionEvent {
|
||||
const factory NumberTypeOptionEvent.didSelectFormat(NumberFormat format) = _DidSelectFormat;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class NumberTypeOptionState with _$NumberTypeOptionState {
|
||||
const factory NumberTypeOptionState({
|
||||
required NumberTypeOption typeOption,
|
||||
}) = _NumberTypeOptionState;
|
||||
|
||||
factory NumberTypeOptionState.initial(NumberTypeOption typeOption) => NumberTypeOptionState(
|
||||
typeOption: typeOption,
|
||||
);
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
part 'option_pannel_bloc.freezed.dart';
|
||||
|
||||
class OptionPannelBloc extends Bloc<OptionPannelEvent, OptionPannelState> {
|
||||
OptionPannelBloc({required List<SelectOption> options}) : super(OptionPannelState.initial(options)) {
|
||||
on<OptionPannelEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
createOption: (_CreateOption value) async {
|
||||
emit(state.copyWith(isEditingOption: false, newOptionName: Some(value.optionName)));
|
||||
},
|
||||
beginAddingOption: (_BeginAddingOption value) {
|
||||
emit(state.copyWith(isEditingOption: true, newOptionName: none()));
|
||||
},
|
||||
endAddingOption: (_EndAddingOption value) {
|
||||
emit(state.copyWith(isEditingOption: false, newOptionName: none()));
|
||||
},
|
||||
updateOption: (_UpdateOption value) {
|
||||
emit(state.copyWith(updateOption: Some(value.option)));
|
||||
},
|
||||
deleteOption: (_DeleteOption value) {
|
||||
emit(state.copyWith(deleteOption: Some(value.option)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class OptionPannelEvent with _$OptionPannelEvent {
|
||||
const factory OptionPannelEvent.createOption(String optionName) = _CreateOption;
|
||||
const factory OptionPannelEvent.beginAddingOption() = _BeginAddingOption;
|
||||
const factory OptionPannelEvent.endAddingOption() = _EndAddingOption;
|
||||
const factory OptionPannelEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory OptionPannelEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class OptionPannelState with _$OptionPannelState {
|
||||
const factory OptionPannelState({
|
||||
required List<SelectOption> options,
|
||||
required bool isEditingOption,
|
||||
required Option<String> newOptionName,
|
||||
required Option<SelectOption> updateOption,
|
||||
required Option<SelectOption> deleteOption,
|
||||
}) = _OptionPannelState;
|
||||
|
||||
factory OptionPannelState.initial(List<SelectOption> options) => OptionPannelState(
|
||||
options: options,
|
||||
isEditingOption: false,
|
||||
newOptionName: none(),
|
||||
updateOption: none(),
|
||||
deleteOption: none(),
|
||||
);
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
import 'type_option_service.dart';
|
||||
|
||||
part 'single_select_bloc.freezed.dart';
|
||||
|
||||
class SingleSelectTypeOptionBloc extends Bloc<SingleSelectTypeOptionEvent, SingleSelectTypeOptionState> {
|
||||
final TypeOptionService service;
|
||||
|
||||
SingleSelectTypeOptionBloc(
|
||||
SingleSelectTypeOption typeOption,
|
||||
String fieldId,
|
||||
) : service = TypeOptionService(fieldId: fieldId),
|
||||
super(
|
||||
SingleSelectTypeOptionState.initial(typeOption),
|
||||
) {
|
||||
on<SingleSelectTypeOptionEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
createOption: (_CreateOption value) async {
|
||||
final result = await service.newOption(value.optionName);
|
||||
result.fold(
|
||||
(option) {
|
||||
emit(state.copyWith(typeOption: _insertOption(option)));
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
updateOption: (_UpdateOption value) async {
|
||||
emit(state.copyWith(typeOption: _updateOption(value.option)));
|
||||
},
|
||||
deleteOption: (_DeleteOption value) {
|
||||
emit(state.copyWith(typeOption: _deleteOption(value.option)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
SingleSelectTypeOption _insertOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
typeOption.options.insert(0, option);
|
||||
});
|
||||
}
|
||||
|
||||
SingleSelectTypeOption _updateOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
if (index != -1) {
|
||||
typeOption.options[index] = option;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SingleSelectTypeOption _deleteOption(SelectOption option) {
|
||||
state.typeOption.freeze();
|
||||
return state.typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
if (index != -1) {
|
||||
typeOption.options.removeAt(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SingleSelectTypeOptionEvent with _$SingleSelectTypeOptionEvent {
|
||||
const factory SingleSelectTypeOptionEvent.createOption(String optionName) = _CreateOption;
|
||||
const factory SingleSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory SingleSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SingleSelectTypeOptionState with _$SingleSelectTypeOptionState {
|
||||
const factory SingleSelectTypeOptionState({
|
||||
required SingleSelectTypeOption typeOption,
|
||||
}) = _SingleSelectTypeOptionState;
|
||||
|
||||
factory SingleSelectTypeOptionState.initial(SingleSelectTypeOption typeOption) => SingleSelectTypeOptionState(
|
||||
typeOption: typeOption,
|
||||
);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
|
||||
class TypeOptionService {
|
||||
final String fieldId;
|
||||
TypeOptionService({
|
||||
required this.fieldId,
|
||||
});
|
||||
|
||||
Future<Either<SelectOption, FlowyError>> newOption(String name, {bool selected = false}) {
|
||||
final payload = SelectOptionName.create()..name = name;
|
||||
return GridEventNewSelectOption(payload).send();
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'grid_block_service.dart';
|
||||
import 'grid_listenr.dart';
|
||||
import 'field/grid_listenr.dart';
|
||||
import 'grid_service.dart';
|
||||
|
||||
part 'grid_bloc.freezed.dart';
|
||||
@ -14,17 +16,17 @@ part 'grid_bloc.freezed.dart';
|
||||
class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final View view;
|
||||
final GridService service;
|
||||
late GridListener _gridListener;
|
||||
late GridFieldsListener _fieldListener;
|
||||
late GridBlockService _blockService;
|
||||
|
||||
GridBloc({required this.view, required this.service}) : super(GridState.initial()) {
|
||||
_gridListener = GridListener();
|
||||
_fieldListener = GridFieldsListener(gridId: view.id);
|
||||
|
||||
on<GridEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (InitialGrid value) async {
|
||||
await _loadGrid(emit);
|
||||
await _initGrid(emit);
|
||||
},
|
||||
createRow: (_CreateRow value) {
|
||||
service.createRow(gridId: view.id);
|
||||
@ -32,9 +34,12 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
delete: (_Delete value) {},
|
||||
rename: (_Rename value) {},
|
||||
updateDesc: (_Desc value) {},
|
||||
didLoadRows: (_DidLoadRows value) {
|
||||
didReceiveRowUpdate: (_DidReceiveRowUpdate value) {
|
||||
emit(state.copyWith(rows: value.rows));
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(fields: value.fields));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -42,22 +47,39 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _gridListener.stop();
|
||||
await _fieldListener.stop();
|
||||
await _blockService.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _startGridListening() async {
|
||||
_blockService.didLoadRowscallback = (rows) {
|
||||
add(GridEvent.didLoadRows(rows));
|
||||
};
|
||||
Future<void> _initGrid(Emitter<GridState> emit) async {
|
||||
_fieldListener.updateFieldsNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(fields) => add(GridEvent.didReceiveFieldUpdate(fields)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start();
|
||||
|
||||
_gridListener.start();
|
||||
await _loadGrid(emit);
|
||||
}
|
||||
|
||||
Future<void> _initGridBlock(Grid grid) async {
|
||||
_blockService = GridBlockService(
|
||||
gridId: grid.id,
|
||||
blockOrders: grid.blockOrders,
|
||||
);
|
||||
|
||||
_blockService.blocksUpdateNotifier?.addPublishListener((result) {
|
||||
result.fold(
|
||||
(blockMap) => add(GridEvent.didReceiveRowUpdate(_buildRows(blockMap))),
|
||||
(err) => Log.error('$err'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadGrid(Emitter<GridState> emit) async {
|
||||
final result = await service.openGrid(gridId: view.id);
|
||||
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(grid) async => await _loadFields(grid, emit),
|
||||
@ -70,60 +92,58 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final result = await service.getFields(gridId: grid.id, fieldOrders: grid.fieldOrders);
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(fields) => _loadGridBlocks(grid, fields.items, emit),
|
||||
(fields) {
|
||||
_initGridBlock(grid);
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
fields: fields.items,
|
||||
loadingState: GridLoadingState.finish(left(unit)),
|
||||
));
|
||||
},
|
||||
(err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadGridBlocks(Grid grid, List<Field> fields, Emitter<GridState> emit) async {
|
||||
final result = await service.getGridBlocks(gridId: grid.id, blockOrders: grid.blockOrders);
|
||||
result.fold(
|
||||
(repeatedGridBlock) {
|
||||
final gridBlocks = repeatedGridBlock.items;
|
||||
final gridId = view.id;
|
||||
_blockService = GridBlockService(
|
||||
gridId: gridId,
|
||||
fields: fields,
|
||||
gridBlocks: gridBlocks,
|
||||
);
|
||||
final rows = _blockService.rows();
|
||||
|
||||
_startGridListening();
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
fields: Some(fields),
|
||||
rows: rows,
|
||||
loadingState: GridLoadingState.finish(left(unit)),
|
||||
));
|
||||
},
|
||||
(err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)), rows: [])),
|
||||
);
|
||||
List<GridBlockRow> _buildRows(GridBlockMap blockMap) {
|
||||
List<GridBlockRow> rows = [];
|
||||
blockMap.forEach((_, GridBlock gridBlock) {
|
||||
rows.addAll(gridBlock.rowOrders.map(
|
||||
(rowOrder) => GridBlockRow(
|
||||
gridId: view.id,
|
||||
blockId: gridBlock.id,
|
||||
rowId: rowOrder.rowId,
|
||||
height: rowOrder.height.toDouble(),
|
||||
),
|
||||
));
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class GridEvent with _$GridEvent {
|
||||
class GridEvent with _$GridEvent {
|
||||
const factory GridEvent.initial() = InitialGrid;
|
||||
const factory GridEvent.rename(String gridId, String name) = _Rename;
|
||||
const factory GridEvent.updateDesc(String gridId, String desc) = _Desc;
|
||||
const factory GridEvent.delete(String gridId) = _Delete;
|
||||
const factory GridEvent.createRow() = _CreateRow;
|
||||
const factory GridEvent.didLoadRows(List<GridRowData> rows) = _DidLoadRows;
|
||||
const factory GridEvent.didReceiveRowUpdate(List<GridBlockRow> rows) = _DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class GridState with _$GridState {
|
||||
class GridState with _$GridState {
|
||||
const factory GridState({
|
||||
required GridLoadingState loadingState,
|
||||
required Option<List<Field>> fields,
|
||||
required List<GridRowData> rows,
|
||||
required List<Field> fields,
|
||||
required List<GridBlockRow> rows,
|
||||
required Option<Grid> grid,
|
||||
}) = _GridState;
|
||||
|
||||
factory GridState.initial() => GridState(
|
||||
loadingState: const _Loading(),
|
||||
fields: none(),
|
||||
fields: [],
|
||||
rows: [],
|
||||
grid: none(),
|
||||
);
|
||||
@ -134,3 +154,46 @@ class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
}
|
||||
|
||||
class GridBlockRow {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final double height;
|
||||
|
||||
const GridBlockRow({
|
||||
required this.gridId,
|
||||
required this.rowId,
|
||||
required this.blockId,
|
||||
required this.height,
|
||||
});
|
||||
}
|
||||
|
||||
class RowData extends Equatable {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final List<Field> fields;
|
||||
final double height;
|
||||
|
||||
const RowData({
|
||||
required this.gridId,
|
||||
required this.rowId,
|
||||
required this.blockId,
|
||||
required this.fields,
|
||||
required this.height,
|
||||
});
|
||||
|
||||
factory RowData.fromBlockRow(GridBlockRow row, List<Field> fields) {
|
||||
return RowData(
|
||||
gridId: row.gridId,
|
||||
rowId: row.rowId,
|
||||
blockId: row.blockId,
|
||||
fields: fields,
|
||||
height: row.height,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [rowId, fields];
|
||||
}
|
||||
|
@ -1,85 +1,81 @@
|
||||
import 'dart:collection';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/dart-notify/subject.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
|
||||
import 'grid_service.dart';
|
||||
|
||||
typedef DidLoadRowsCallback = void Function(List<GridRowData>);
|
||||
typedef GridBlockUpdateNotifiedValue = Either<GridBlockId, FlowyError>;
|
||||
typedef GridBlockMap = LinkedHashMap<String, GridBlock>;
|
||||
typedef BlocksUpdateNotifierValue = Either<GridBlockMap, FlowyError>;
|
||||
|
||||
class GridBlockService {
|
||||
String gridId;
|
||||
List<Field> fields;
|
||||
LinkedHashMap<String, GridBlock> blockMap = LinkedHashMap();
|
||||
GridBlockMap blockMap = GridBlockMap();
|
||||
late GridBlockListener _blockListener;
|
||||
DidLoadRowsCallback? didLoadRowscallback;
|
||||
PublishNotifier<BlocksUpdateNotifierValue>? blocksUpdateNotifier = PublishNotifier();
|
||||
|
||||
GridBlockService({required this.gridId, required this.fields, required List<GridBlock> gridBlocks}) {
|
||||
for (final gridBlock in gridBlocks) {
|
||||
blockMap[gridBlock.blockId] = gridBlock;
|
||||
}
|
||||
GridBlockService({required this.gridId, required List<GridBlockOrder> blockOrders}) {
|
||||
_loadGridBlocks(blockOrders);
|
||||
|
||||
_blockListener = GridBlockListener(gridId: gridId);
|
||||
_blockListener.blockUpdateNotifier.addPublishListener((result) {
|
||||
result.fold((blockId) {
|
||||
//
|
||||
}, (err) => null);
|
||||
result.fold(
|
||||
(blockOrder) => _loadGridBlocks(blockOrder),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
List<GridRowData> rows() {
|
||||
List<GridRowData> rows = [];
|
||||
blockMap.forEach((_, GridBlock gridBlock) {
|
||||
rows.addAll(gridBlock.rowOrders.map(
|
||||
(rowOrder) => GridRowData(
|
||||
gridId: gridId,
|
||||
fields: fields,
|
||||
blockId: gridBlock.blockId,
|
||||
rowId: rowOrder.rowId,
|
||||
height: rowOrder.height.toDouble(),
|
||||
),
|
||||
));
|
||||
});
|
||||
return rows;
|
||||
_blockListener.start();
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _blockListener.stop();
|
||||
blocksUpdateNotifier?.dispose();
|
||||
blocksUpdateNotifier = null;
|
||||
}
|
||||
|
||||
void _loadGridBlocks(List<GridBlockOrder> blockOrders) {
|
||||
final payload = QueryGridBlocksPayload.create()
|
||||
..gridId = gridId
|
||||
..blockOrders.addAll(blockOrders);
|
||||
|
||||
GridEventGetGridBlocks(payload).send().then((result) {
|
||||
result.fold(
|
||||
(repeatedBlocks) {
|
||||
for (final gridBlock in repeatedBlocks.items) {
|
||||
blockMap[gridBlock.id] = gridBlock;
|
||||
}
|
||||
blocksUpdateNotifier?.value = left(blockMap);
|
||||
},
|
||||
(err) => blocksUpdateNotifier?.value = right(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class GridBlockListener {
|
||||
final String gridId;
|
||||
PublishNotifier<GridBlockUpdateNotifiedValue> blockUpdateNotifier = PublishNotifier<GridBlockUpdateNotifiedValue>();
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
late GridNotificationParser _parser;
|
||||
PublishNotifier<Either<List<GridBlockOrder>, FlowyError>> blockUpdateNotifier = PublishNotifier(comparable: null);
|
||||
GridNotificationListener? _listener;
|
||||
|
||||
GridBlockListener({required this.gridId});
|
||||
|
||||
void start() {
|
||||
_parser = GridNotificationParser(
|
||||
id: gridId,
|
||||
callback: (ty, result) {
|
||||
_handleObservableType(ty, result);
|
||||
},
|
||||
_listener = GridNotificationListener(
|
||||
objectId: gridId,
|
||||
handler: _handler,
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.GridDidUpdateBlock:
|
||||
case GridNotification.DidUpdateBlock:
|
||||
result.fold(
|
||||
(payload) => blockUpdateNotifier.value = left(GridBlockId.fromBuffer(payload)),
|
||||
(payload) => blockUpdateNotifier.value = left([GridBlockOrder.fromBuffer(payload)]),
|
||||
(error) => blockUpdateNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
@ -90,7 +86,7 @@ class GridBlockListener {
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _subscription?.cancel();
|
||||
await _listener?.stop();
|
||||
blockUpdateNotifier.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
class GridListener {
|
||||
void start() {}
|
||||
Future<void> stop() async {}
|
||||
}
|
@ -3,7 +3,6 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class GridService {
|
||||
Future<Either<Grid, FlowyError>> openGrid({required String gridId}) async {
|
||||
@ -13,9 +12,9 @@ class GridService {
|
||||
return GridEventGetGridData(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Row, FlowyError>> createRow({required String gridId, Option<String>? upperRowId}) {
|
||||
Future<Either<Row, FlowyError>> createRow({required String gridId, Option<String>? startRowId}) {
|
||||
CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId;
|
||||
upperRowId?.fold(() => null, (id) => payload.startRowId = id);
|
||||
startRowId?.fold(() => null, (id) => payload.startRowId = id);
|
||||
return GridEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
@ -34,22 +33,3 @@ class GridService {
|
||||
return GridEventGetFields(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
class GridRowData extends Equatable {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final List<Field> fields;
|
||||
final double height;
|
||||
|
||||
const GridRowData({
|
||||
required this.gridId,
|
||||
required this.rowId,
|
||||
required this.blockId,
|
||||
required this.fields,
|
||||
required this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [rowId];
|
||||
}
|
||||
|
@ -1,13 +1,29 @@
|
||||
export 'grid_bloc.dart';
|
||||
export 'row_bloc.dart';
|
||||
export 'row_service.dart';
|
||||
export 'row/row_bloc.dart';
|
||||
export 'row/row_service.dart';
|
||||
export 'grid_service.dart';
|
||||
export 'data.dart';
|
||||
export 'column_service.dart';
|
||||
export 'column_bloc.dart';
|
||||
|
||||
// Field
|
||||
export 'field/field_service.dart';
|
||||
export 'field/grid_header_bloc.dart';
|
||||
export 'field/action_sheet_bloc.dart';
|
||||
export 'field/field_editor_bloc.dart';
|
||||
export 'field/field_switch_bloc.dart';
|
||||
|
||||
// Field Type Option
|
||||
export 'field/type_option/date_bloc.dart';
|
||||
export 'field/type_option/number_bloc.dart';
|
||||
export 'field/type_option/single_select_bloc.dart';
|
||||
|
||||
// Cell
|
||||
export 'cell_bloc/text_cell_bloc.dart';
|
||||
export 'cell_bloc/number_cell_bloc.dart';
|
||||
export 'cell_bloc/selection_cell_bloc.dart';
|
||||
export 'cell_bloc/date_cell_bloc.dart';
|
||||
export 'cell_bloc/checkbox_cell_bloc.dart';
|
||||
export 'cell_bloc/cell_service.dart';
|
||||
|
||||
// Setting
|
||||
export 'setting/setting_bloc.dart';
|
||||
export 'setting/property_bloc.dart';
|
||||
|
@ -0,0 +1,151 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'row_listener.dart';
|
||||
import 'row_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'row_bloc.freezed.dart';
|
||||
|
||||
typedef CellDataMap = LinkedHashMap<String, CellData>;
|
||||
|
||||
class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
final RowService rowService;
|
||||
final RowListener rowlistener;
|
||||
final GridFieldsListener fieldListener;
|
||||
|
||||
RowBloc({required RowData rowData, required this.rowlistener})
|
||||
: rowService = RowService(
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
rowId: rowData.rowId,
|
||||
),
|
||||
fieldListener = GridFieldsListener(
|
||||
gridId: rowData.gridId,
|
||||
),
|
||||
super(RowState.initial(rowData)) {
|
||||
on<RowEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialRow value) async {
|
||||
_startListening();
|
||||
await _loadRow(emit);
|
||||
},
|
||||
createRow: (_CreateRow value) {
|
||||
rowService.createRow();
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) async {
|
||||
await _handleFieldUpdate(emit, value);
|
||||
},
|
||||
didUpdateRow: (_DidUpdateRow value) async {
|
||||
_handleRowUpdate(value, emit);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _handleRowUpdate(_DidUpdateRow value, Emitter<RowState> emit) {
|
||||
final CellDataMap cellDataMap = _makeCellDatas(value.row, state.fields);
|
||||
emit(state.copyWith(
|
||||
row: Future(() => Some(value.row)),
|
||||
cellDataMap: Some(cellDataMap),
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> _handleFieldUpdate(Emitter<RowState> emit, _DidReceiveFieldUpdate value) async {
|
||||
final optionRow = await state.row;
|
||||
final CellDataMap cellDataMap = optionRow.fold(
|
||||
() => CellDataMap.identity(),
|
||||
(row) => _makeCellDatas(row, value.fields),
|
||||
);
|
||||
|
||||
emit(state.copyWith(
|
||||
fields: value.fields,
|
||||
cellDataMap: Some(cellDataMap),
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await rowlistener.stop();
|
||||
await fieldListener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _startListening() async {
|
||||
rowlistener.updateRowNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(row) => add(RowEvent.didUpdateRow(row)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
fieldListener.updateFieldsNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(fields) => add(RowEvent.didReceiveFieldUpdate(fields)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
|
||||
rowlistener.start();
|
||||
fieldListener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadRow(Emitter<RowState> emit) async {
|
||||
rowService.getRow().then((result) {
|
||||
return result.fold(
|
||||
(row) => add(RowEvent.didUpdateRow(row)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
CellDataMap _makeCellDatas(Row row, List<Field> fields) {
|
||||
var map = CellDataMap.new();
|
||||
for (final field in fields) {
|
||||
if (field.visibility) {
|
||||
map[field.id] = CellData(
|
||||
rowId: row.id,
|
||||
gridId: rowService.gridId,
|
||||
cell: row.cellByFieldId[field.id],
|
||||
field: field,
|
||||
);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowEvent with _$RowEvent {
|
||||
const factory RowEvent.initial() = _InitialRow;
|
||||
const factory RowEvent.createRow() = _CreateRow;
|
||||
const factory RowEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
const factory RowEvent.didUpdateRow(Row row) = _DidUpdateRow;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowState with _$RowState {
|
||||
const factory RowState({
|
||||
required String rowId,
|
||||
required double rowHeight,
|
||||
required List<Field> fields,
|
||||
required Future<Option<Row>> row,
|
||||
required Option<CellDataMap> cellDataMap,
|
||||
}) = _RowState;
|
||||
|
||||
factory RowState.initial(RowData data) => RowState(
|
||||
rowId: data.rowId,
|
||||
rowHeight: data.height,
|
||||
fields: data.fields,
|
||||
row: Future(() => none()),
|
||||
cellDataMap: none(),
|
||||
);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef UpdateRowNotifiedValue = Either<Row, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<List<Field>, FlowyError>;
|
||||
|
||||
class RowListener {
|
||||
final String rowId;
|
||||
PublishNotifier<UpdateRowNotifiedValue> updateRowNotifier = PublishNotifier();
|
||||
GridNotificationListener? _listener;
|
||||
|
||||
RowListener({required this.rowId});
|
||||
|
||||
void start() {
|
||||
_listener = GridNotificationListener(objectId: rowId, handler: _handler);
|
||||
}
|
||||
|
||||
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateRow:
|
||||
result.fold(
|
||||
(payload) => updateRowNotifier.value = left(Row.fromBuffer(payload)),
|
||||
(error) => updateRowNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
updateRowNotifier.dispose();
|
||||
}
|
||||
}
|
@ -1,45 +1,47 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
|
||||
import 'grid_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
||||
|
||||
class RowService {
|
||||
final GridRowData rowData;
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
|
||||
RowService(this.rowData);
|
||||
RowService({required this.gridId, required this.rowId, required this.blockId});
|
||||
|
||||
Future<Either<Row, FlowyError>> createRow() {
|
||||
CreateRowPayload payload = CreateRowPayload.create()
|
||||
..gridId = rowData.gridId
|
||||
..startRowId = rowData.rowId;
|
||||
..gridId = gridId
|
||||
..startRowId = rowId;
|
||||
|
||||
return GridEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Row, FlowyError>> getRow() {
|
||||
QueryRowPayload payload = QueryRowPayload.create()
|
||||
..gridId = rowData.gridId
|
||||
..blockId = rowData.blockId
|
||||
..rowId = rowData.rowId;
|
||||
final payload = RowIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..rowId = rowId;
|
||||
|
||||
return GridEventGetRow(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
class GridCellData {
|
||||
class CellData extends Equatable {
|
||||
final String gridId;
|
||||
final String rowId;
|
||||
final String blockId;
|
||||
final Field field;
|
||||
final Cell? cell;
|
||||
|
||||
GridCellData({
|
||||
const CellData({
|
||||
required this.rowId,
|
||||
required this.gridId,
|
||||
required this.blockId,
|
||||
required this.field,
|
||||
required this.cell,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [cell, field];
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'grid_service.dart';
|
||||
import 'row_listener.dart';
|
||||
import 'row_service.dart';
|
||||
|
||||
part 'row_bloc.freezed.dart';
|
||||
|
||||
class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
final RowService rowService;
|
||||
final RowListener listener;
|
||||
|
||||
RowBloc({required this.rowService, required this.listener}) : super(RowState.initial(rowService.rowData)) {
|
||||
on<RowEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_InitialRow value) async {
|
||||
_startRowListening();
|
||||
await _loadCellDatas(emit);
|
||||
},
|
||||
createRow: (_CreateRow value) {
|
||||
rowService.createRow();
|
||||
},
|
||||
activeRow: (_ActiveRow value) {
|
||||
emit(state.copyWith(active: true));
|
||||
},
|
||||
disactiveRow: (_DisactiveRow value) {
|
||||
emit(state.copyWith(active: false));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await listener.close();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _startRowListening() async {
|
||||
listener.updateRowNotifier.addPublishListener((result) {
|
||||
result.fold((row) {
|
||||
//
|
||||
}, (err) => null);
|
||||
});
|
||||
|
||||
listener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold((repeatedCvell) {
|
||||
//
|
||||
Log.info("$repeatedCvell");
|
||||
}, (r) => null);
|
||||
});
|
||||
|
||||
listener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadCellDatas(Emitter<RowState> emit) async {
|
||||
final result = await rowService.getRow();
|
||||
result.fold(
|
||||
(row) {
|
||||
emit(state.copyWith(
|
||||
cellDatas: makeGridCellDatas(row),
|
||||
rowHeight: row.height.toDouble(),
|
||||
));
|
||||
},
|
||||
(e) => Log.error(e),
|
||||
);
|
||||
}
|
||||
|
||||
List<GridCellData> makeGridCellDatas(Row row) {
|
||||
return rowService.rowData.fields.map((field) {
|
||||
final cell = row.cellByFieldId[field.id];
|
||||
final rowData = rowService.rowData;
|
||||
|
||||
return GridCellData(
|
||||
rowId: row.id,
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
cell: cell,
|
||||
field: field,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class RowEvent with _$RowEvent {
|
||||
const factory RowEvent.initial() = _InitialRow;
|
||||
const factory RowEvent.createRow() = _CreateRow;
|
||||
const factory RowEvent.activeRow() = _ActiveRow;
|
||||
const factory RowEvent.disactiveRow() = _DisactiveRow;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class RowState with _$RowState {
|
||||
const factory RowState({
|
||||
required String rowId,
|
||||
required double rowHeight,
|
||||
required List<GridCellData> cellDatas,
|
||||
required bool active,
|
||||
}) = _RowState;
|
||||
|
||||
factory RowState.initial(GridRowData data) => RowState(
|
||||
rowId: data.rowId,
|
||||
active: false,
|
||||
rowHeight: data.height,
|
||||
cellDatas: [],
|
||||
);
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
import 'package:flowy_sdk/protobuf/dart-notify/subject.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef UpdateCellNotifiedValue = Either<RepeatedCell, FlowyError>;
|
||||
typedef UpdateRowNotifiedValue = Either<Row, FlowyError>;
|
||||
|
||||
class RowListener {
|
||||
final String rowId;
|
||||
PublishNotifier<UpdateCellNotifiedValue> updateCellNotifier = PublishNotifier<UpdateCellNotifiedValue>();
|
||||
PublishNotifier<UpdateRowNotifiedValue> updateRowNotifier = PublishNotifier<UpdateRowNotifiedValue>();
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
late GridNotificationParser _parser;
|
||||
|
||||
RowListener({required this.rowId});
|
||||
|
||||
void start() {
|
||||
_parser = GridNotificationParser(
|
||||
id: rowId,
|
||||
callback: (ty, result) {
|
||||
_handleObservableType(ty, result);
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.GridDidUpdateCells:
|
||||
result.fold(
|
||||
(payload) => updateCellNotifier.value = left(RepeatedCell.fromBuffer(payload)),
|
||||
(error) => updateCellNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
await _subscription?.cancel();
|
||||
updateCellNotifier.dispose();
|
||||
updateRowNotifier.dispose();
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
part 'property_bloc.freezed.dart';
|
||||
|
||||
class GridPropertyBloc extends Bloc<GridPropertyEvent, GridPropertyState> {
|
||||
final FieldService _service;
|
||||
final GridFieldsListener _fieldListener;
|
||||
|
||||
GridPropertyBloc({required String gridId, required List<Field> fields})
|
||||
: _service = FieldService(gridId: gridId),
|
||||
_fieldListener = GridFieldsListener(gridId: gridId),
|
||||
super(GridPropertyState.initial(gridId, fields)) {
|
||||
on<GridPropertyEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_Initial value) {
|
||||
_startListening();
|
||||
},
|
||||
setFieldVisibility: (_SetFieldVisibility value) async {
|
||||
final result = await _service.updateField(fieldId: value.fieldId, visibility: value.visibility);
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(fields: value.fields));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _fieldListener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_fieldListener.updateFieldsNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(fields) {
|
||||
add(GridPropertyEvent.didReceiveFieldUpdate(fields));
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_fieldListener.start();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridPropertyEvent with _$GridPropertyEvent {
|
||||
const factory GridPropertyEvent.initial() = _Initial;
|
||||
const factory GridPropertyEvent.setFieldVisibility(String fieldId, bool visibility) = _SetFieldVisibility;
|
||||
const factory GridPropertyEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridPropertyState with _$GridPropertyState {
|
||||
const factory GridPropertyState({
|
||||
required String gridId,
|
||||
required List<Field> fields,
|
||||
}) = _GridPropertyState;
|
||||
|
||||
factory GridPropertyState.initial(String gridId, List<Field> fields) => GridPropertyState(
|
||||
gridId: gridId,
|
||||
fields: fields,
|
||||
);
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'setting_bloc.freezed.dart';
|
||||
|
||||
class GridSettingBloc extends Bloc<GridSettingEvent, GridSettingState> {
|
||||
final String gridId;
|
||||
GridSettingBloc({required this.gridId}) : super(GridSettingState.initial()) {
|
||||
on<GridSettingEvent>(
|
||||
(event, emit) async {
|
||||
event.map(performAction: (_PerformAction value) {
|
||||
emit(state.copyWith(selectedAction: Some(value.action)));
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridSettingEvent with _$GridSettingEvent {
|
||||
const factory GridSettingEvent.performAction(GridSettingAction action) = _PerformAction;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridSettingState with _$GridSettingState {
|
||||
const factory GridSettingState({
|
||||
required Option<GridSettingAction> selectedAction,
|
||||
}) = _GridSettingState;
|
||||
|
||||
factory GridSettingState.initial() => GridSettingState(
|
||||
selectedAction: none(),
|
||||
);
|
||||
}
|
||||
|
||||
enum GridSettingAction {
|
||||
filter,
|
||||
sortBy,
|
||||
properties,
|
||||
}
|
@ -12,10 +12,10 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
emit(state.copyWith(isLoading: e.isLoading));
|
||||
},
|
||||
setEditPannel: (e) async {
|
||||
emit(state.copyWith(editContext: some(e.editContext)));
|
||||
emit(state.copyWith(pannelContext: some(e.editContext)));
|
||||
},
|
||||
dismissEditPannel: (value) async {
|
||||
emit(state.copyWith(editContext: none()));
|
||||
emit(state.copyWith(pannelContext: none()));
|
||||
},
|
||||
forceCollapse: (e) async {
|
||||
emit(state.copyWith(forceCollapse: e.forceCollapse));
|
||||
@ -43,12 +43,12 @@ class HomeState with _$HomeState {
|
||||
const factory HomeState({
|
||||
required bool isLoading,
|
||||
required bool forceCollapse,
|
||||
required Option<EditPannelContext> editContext,
|
||||
required Option<EditPannelContext> pannelContext,
|
||||
}) = _HomeState;
|
||||
|
||||
factory HomeState.initial() => HomeState(
|
||||
isLoading: false,
|
||||
forceCollapse: false,
|
||||
editContext: none(),
|
||||
pannelContext: none(),
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:app_flowy/user/application/user_listener.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/error-code/error_code.pbenum.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
@ -14,7 +14,7 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
||||
TrashBloc({required this.service, required this.listener}) : super(TrashState.init()) {
|
||||
on<TrashEvent>((event, emit) async {
|
||||
await event.map(initial: (e) async {
|
||||
listener.startListening(trashUpdated: _listenTrashUpdated);
|
||||
listener.start(trashUpdated: _listenTrashUpdated);
|
||||
final result = await service.readTrash();
|
||||
emit(result.fold(
|
||||
(object) => state.copyWith(objects: object.items, successOrFailure: left(unit)),
|
||||
|
@ -13,12 +13,12 @@ typedef TrashUpdatedCallback = void Function(Either<List<Trash>, FlowyError> tra
|
||||
class TrashListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
TrashUpdatedCallback? _trashUpdated;
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
|
||||
void startListening({TrashUpdatedCallback? trashUpdated}) {
|
||||
void start({TrashUpdatedCallback? trashUpdated}) {
|
||||
_trashUpdated = trashUpdated;
|
||||
_parser = FolderNotificationParser(callback: _bservableCallback);
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _bservableCallback(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -40,6 +40,7 @@ class TrashListener {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
_trashUpdated = null;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ extension ViewExtension on View {
|
||||
thumbnail = "file_icon";
|
||||
}
|
||||
|
||||
final Widget widget = svg(thumbnail, color: iconColor);
|
||||
final Widget widget = svgWidget(thumbnail, color: iconColor);
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ class ViewListener {
|
||||
PublishNotifier<UpdateViewNotifiedValue> updatedNotifier = PublishNotifier<UpdateViewNotifiedValue>();
|
||||
PublishNotifier<DeleteViewNotifyValue> deletedNotifier = PublishNotifier<DeleteViewNotifyValue>();
|
||||
PublishNotifier<RestoreViewNotifiedValue> restoredNotifier = PublishNotifier<RestoreViewNotifiedValue>();
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
View view;
|
||||
|
||||
ViewListener({
|
||||
@ -33,7 +33,7 @@ class ViewListener {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -62,6 +62,7 @@ class ViewListener {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
updatedNotifier.dispose();
|
||||
deletedNotifier.dispose();
|
||||
|
@ -12,7 +12,6 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
|
||||
typedef WorkspaceAppsChangedCallback = void Function(Either<List<App>, FlowyError> appsOrFail);
|
||||
typedef WorkspaceUpdatedCallback = void Function(String name, String desc);
|
||||
|
||||
@ -31,12 +30,11 @@ class WorkspaceListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class WorkspaceListenerService {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
WorkspaceAppsChangedCallback? _appsChanged;
|
||||
WorkspaceUpdatedCallback? _update;
|
||||
late FolderNotificationParser _parser;
|
||||
FolderNotificationParser? _parser;
|
||||
final UserProfile user;
|
||||
final String workspaceId;
|
||||
|
||||
@ -59,7 +57,7 @@ class WorkspaceListenerService {
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(FolderNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
@ -91,6 +89,7 @@ class WorkspaceListenerService {
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
// _appsChanged = null;
|
||||
// _update = null;
|
||||
|
@ -20,7 +20,7 @@ class HomeLayout {
|
||||
HomeLayout(BuildContext context, BoxConstraints homeScreenConstraint, bool forceCollapse) {
|
||||
final homeBlocState = context.read<HomeBloc>().state;
|
||||
|
||||
showEditPannel = homeBlocState.editContext.isSome();
|
||||
showEditPannel = homeBlocState.pannelContext.isSome();
|
||||
|
||||
menuWidth = Sizes.sideBarMed;
|
||||
if (context.widthPx >= PageBreaks.desktop) {
|
||||
|
@ -126,13 +126,22 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
|
||||
Widget _buildEditPannel({required HomeState homeState, required BuildContext context, required HomeLayout layout}) {
|
||||
final homeBloc = context.read<HomeBloc>();
|
||||
Widget editPannel = EditPannel(
|
||||
context: homeState.editContext,
|
||||
onEndEdit: () => homeBloc.add(const HomeEvent.dismissEditPannel()),
|
||||
return BlocBuilder<HomeBloc, HomeState>(
|
||||
buildWhen: (previous, current) => previous.pannelContext != current.pannelContext,
|
||||
builder: (context, state) {
|
||||
return state.pannelContext.fold(
|
||||
() => const SizedBox(),
|
||||
(pannelContext) => FocusTraversalGroup(
|
||||
child: RepaintBoundary(
|
||||
child: EditPannel(
|
||||
pannelContext: pannelContext,
|
||||
onEndEdit: () => homeBloc.add(const HomeEvent.dismissEditPannel()),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
// editPannel = RepaintBoundary(child: editPannel);
|
||||
// editPannel = FocusTraversalGroup(child: editPannel);
|
||||
return editPannel;
|
||||
}
|
||||
|
||||
Widget _layoutWidgets({
|
||||
|
@ -28,7 +28,7 @@ class AddButton extends StatelessWidget {
|
||||
onSelected: onSelected,
|
||||
).show(context);
|
||||
},
|
||||
icon: svg("home/add").padding(horizontal: 3, vertical: 3),
|
||||
icon: svgWidget("home/add").padding(horizontal: 3, vertical: 3),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,6 @@ class MenuAppHeader extends StatelessWidget {
|
||||
onSecondaryTap: () {
|
||||
final actionList = AppDisclosureActionSheet(onSelected: (action) => _handleAction(context, action));
|
||||
actionList.show(
|
||||
context,
|
||||
context,
|
||||
anchorDirection: AnchorDirection.bottomWithCenterAligned,
|
||||
);
|
||||
@ -154,9 +153,9 @@ extension AppDisclosureExtension on AppDisclosureAction {
|
||||
Widget get icon {
|
||||
switch (this) {
|
||||
case AppDisclosureAction.rename:
|
||||
return svg('editor/edit', color: const Color(0xffe5e5e5));
|
||||
return svgWidget('editor/edit', color: const Color(0xffe5e5e5));
|
||||
case AppDisclosureAction.delete:
|
||||
return svg('editor/delete', color: const Color(0xffe5e5e5));
|
||||
return svgWidget('editor/delete', color: const Color(0xffe5e5e5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'header.dart';
|
||||
|
||||
class AppDisclosureActionSheet with ActionList<DisclosureActionWrapper> implements FlowyOverlayDelegate {
|
||||
class AppDisclosureActionSheet with ActionList<DisclosureActionWrapper>, FlowyOverlayDelegate {
|
||||
final Function(dartz.Option<AppDisclosureAction>) onSelected;
|
||||
final _items = AppDisclosureAction.values.map((action) => DisclosureActionWrapper(action)).toList();
|
||||
|
||||
|
@ -11,9 +11,7 @@ import 'item.dart';
|
||||
|
||||
// [[Widget: LifeCycle]]
|
||||
// https://flutterbyexample.com/lesson/stateful-widget-lifecycle
|
||||
class ViewDisclosureButton extends StatelessWidget
|
||||
with ActionList<ViewDisclosureActionWrapper>
|
||||
implements FlowyOverlayDelegate {
|
||||
class ViewDisclosureButton extends StatelessWidget with ActionList<ViewDisclosureActionWrapper>, FlowyOverlayDelegate {
|
||||
final Function() onTap;
|
||||
final Function(dartz.Option<ViewDisclosureAction>) onSelected;
|
||||
final _items = ViewDisclosureAction.values.map((action) => ViewDisclosureActionWrapper(action)).toList();
|
||||
@ -32,9 +30,9 @@ class ViewDisclosureButton extends StatelessWidget
|
||||
width: 26,
|
||||
onPressed: () {
|
||||
onTap();
|
||||
show(context, context);
|
||||
show(context);
|
||||
},
|
||||
icon: svg("editor/details", color: theme.iconColor),
|
||||
icon: svgWidget("editor/details", color: theme.iconColor),
|
||||
);
|
||||
}
|
||||
|
||||
|