Merge pull request #435 from AppFlowy-IO/grid_field_operation

Grid field operation
This commit is contained in:
Nathan.fooo 2022-04-07 21:26:20 +08:00 committed by GitHub
commit 65993b7205
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
318 changed files with 17012 additions and 6349 deletions

View File

@ -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

View 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

View 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

View 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

View 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

View 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

View 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.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

View 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

View 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

View File

@ -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

View 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

View 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

View 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.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

View 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

View 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.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

View 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

View 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

View 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

View 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

View 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

View File

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

View File

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

View File

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

View File

@ -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

View 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

View File

@ -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"
}
}
}

View File

@ -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;

View File

@ -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;

View 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),
);
}

View File

@ -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>()));
}
}

View File

@ -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 {

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -0,0 +1,4 @@
export './auth_service.dart';
export './sign_in_bloc.dart';
export './sign_up_bloc.dart';
export './splash_bloc.dart';

View File

@ -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,

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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)),

View File

@ -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)),

View File

@ -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';

View File

@ -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(

View File

@ -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)),
);

View File

@ -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;

View File

@ -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

View File

@ -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');
}

View File

@ -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';

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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";
}

View File

@ -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();
}

View File

@ -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 ?? "");
}
}

View File

@ -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();
}
}

View File

@ -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: [],
);
}

View File

@ -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,
);
}
}

View File

@ -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,
);
}

View File

@ -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);
}

View File

@ -1 +0,0 @@
class ColumnService {}

View File

@ -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});
}

View File

@ -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,
);
}

View File

@ -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(),
);
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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(),
);
}

View File

@ -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,
);
}

View File

@ -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,
);
}

View File

@ -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(),
);
}

View File

@ -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,
);
}

View File

@ -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();
}
}

View File

@ -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];
}

View File

@ -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();
}
}

View File

@ -1,4 +0,0 @@
class GridListener {
void start() {}
Future<void> stop() async {}
}

View File

@ -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];
}

View File

@ -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';

View File

@ -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(),
);
}

View File

@ -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();
}
}

View File

@ -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];
}

View File

@ -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: [],
);
}

View File

@ -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();
}
}

View File

@ -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,
);
}

View File

@ -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,
}

View File

@ -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(),
);
}

View File

@ -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';

View File

@ -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)),

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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) {

View File

@ -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({

View File

@ -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),
);
}
}

View File

@ -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));
}
}
}

View File

@ -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();

View File

@ -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),
);
}

Some files were not shown because too many files have changed in this diff Show More