mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge remote-tracking branch 'origin/main' into feat/flowy_editor
This commit is contained in:
commit
7de2f7fa49
51
.githooks/commit-msg
Executable file
51
.githooks/commit-msg
Executable file
@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
|
||||
YELLOW="\e[93m"
|
||||
GREEN="\e[32m"
|
||||
RED="\e[31m"
|
||||
ENDCOLOR="\e[0m"
|
||||
|
||||
printMessage() {
|
||||
printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printSuccess() {
|
||||
printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printError() {
|
||||
printf "${RED}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printMessage "Running the AppFlowy commit-msg hook."
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
||||
|
||||
.githooks/gitlint \
|
||||
--msg-file=$1 \
|
||||
--subject-regex="^(build|chore|ci|docs|feat|feature|fix|perf|refactor|revert|style|test)(.*)?:\s?.*" \
|
||||
--subject-maxlen=100 \
|
||||
--subject-minlen=10 \
|
||||
--body-regex=".*" \
|
||||
--body-maxlen=200 \
|
||||
--max-parents=1
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
printError "Please fix your commit message to match AppFlowy coding standards"
|
||||
printError "https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/style-guides"
|
||||
exit 1
|
||||
fi
|
||||
|
19
.githooks/pre-commit
Normal file → Executable file
19
.githooks/pre-commit
Normal file → Executable file
@ -1,5 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
YELLOW="\e[93m"
|
||||
GREEN="\e[32m"
|
||||
RED="\e[31m"
|
||||
ENDCOLOR="\e[0m"
|
||||
|
||||
printMessage() {
|
||||
printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printSuccess() {
|
||||
printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printError() {
|
||||
printf "${RED}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printMessage "Running local AppFlowy pre-commit hook."
|
||||
|
||||
#flutter format .
|
||||
##https://gist.github.com/benmccallum/28e4f216d9d72f5965133e6c43aaff6e
|
||||
limit=$(( 1 * 2**20 )) # 1MB
|
||||
|
45
.githooks/pre-push
Normal file → Executable file
45
.githooks/pre-push
Normal file → Executable file
@ -1,21 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ `git status --porcelain` ]]; then
|
||||
printf "\e[31;1m%s\e[0m\n" 'This script needs to run against committed code only. Please commit or stash you changes.'
|
||||
exit 1
|
||||
fi
|
||||
printf "\e[33;1m%s\e[0m\n" 'Running the Flutter analyzer'
|
||||
flutter analyze
|
||||
if [ $? -ne 0 ]; then
|
||||
printf "\e[31;1m%s\e[0m\n" 'Flutter analyzer error'
|
||||
exit 1
|
||||
fi
|
||||
printf "\e[33;1m%s\e[0m\n" 'Finished running the Flutter analyzer'
|
||||
printf "\e[33;1m%s\e[0m\n" 'Running unit tests'
|
||||
YELLOW="\e[93m"
|
||||
GREEN="\e[32m"
|
||||
RED="\e[31m"
|
||||
ENDCOLOR="\e[0m"
|
||||
|
||||
#flutter test
|
||||
printMessage() {
|
||||
printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printSuccess() {
|
||||
printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printError() {
|
||||
printf "${RED}AppFlowy : $1${ENDCOLOR}\n"
|
||||
}
|
||||
|
||||
printMessage "Running local AppFlowy pre-push hook."
|
||||
|
||||
if [[ `git status --porcelain` ]]; then
|
||||
printError "This script needs to run against committed code only. Please commit or stash you changes."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
#printMessage "Running the Flutter analyzer"
|
||||
#flutter analyze
|
||||
#
|
||||
#if [ $? -ne 0 ]; then
|
||||
# printf "\e[31;1m%s\e[0m\n" 'Unit tests error'
|
||||
# printError "Flutter analyzer error"
|
||||
# exit 1
|
||||
#fi
|
||||
#printf "\e[33;1m%s\e[0m\n" 'Finished running unit tests'
|
||||
#
|
||||
#printMessage "Finished running the Flutter analyzer"
|
||||
|
4
.github/workflows/rust_lint.yml
vendored
4
.github/workflows/rust_lint.yml
vendored
@ -20,6 +20,10 @@ jobs:
|
||||
with:
|
||||
toolchain: 'stable-2022-01-20'
|
||||
override: true
|
||||
- uses: subosito/flutter-action@v1
|
||||
with:
|
||||
flutter-version: '3.0.0'
|
||||
channel: "stable"
|
||||
|
||||
- name: Rust Deps
|
||||
working-directory: frontend
|
||||
|
7
.github/workflows/translation_notify.yml
vendored
7
.github/workflows/translation_notify.yml
vendored
@ -4,15 +4,12 @@ on:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- "frontend/app_flowy/assets/translations/en.json"
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- "frontend/app_flowy/assets/translations/en.json"
|
||||
|
||||
jobs:
|
||||
Discord-Notify:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Ilshidur/action-discord@0.3.2
|
||||
- uses: Ilshidur/action-discord@master
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
with:
|
||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -28,3 +28,11 @@ frontend/.vscode/*
|
||||
!frontend/.vscode/launch.json
|
||||
!frontend/.vscode/extensions.json
|
||||
!frontend/.vscode/*.code-snippets
|
||||
|
||||
# Commit the highest level pubspec.lock, but ignore the others
|
||||
pubspec.lock
|
||||
!frontend/app_flowy/pubspec.lock
|
||||
|
||||
# ignore tool used for commit linting
|
||||
.githooks/gitlint
|
||||
.githooks/gitlint.exe
|
||||
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no -- commitlint --edit
|
@ -1,35 +0,0 @@
|
||||
[tasks.install-commitlint.mac]
|
||||
script = [
|
||||
"""
|
||||
brew install npm
|
||||
yarn install
|
||||
yarn husky install
|
||||
""",
|
||||
]
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.install-commitlint.windows]
|
||||
script = [
|
||||
"""
|
||||
echo "WIP"
|
||||
""",
|
||||
]
|
||||
script_runner = "@duckscript"
|
||||
|
||||
[tasks.install-commitlint.linux]
|
||||
script = [
|
||||
"""
|
||||
if command -v apt &> /dev/null
|
||||
then
|
||||
echo "Installing node.js and yarn (sudo apt install nodejs yarn)"
|
||||
sudo apt install nodejs yarn
|
||||
else
|
||||
echo "Installing node.js and yarn (sudo pacman -S nodejs yarn)"
|
||||
sudo pacman -S nodejs yarn
|
||||
fi
|
||||
|
||||
yarn install
|
||||
yarn husky install
|
||||
""",
|
||||
]
|
||||
script_runner = "@shell"
|
@ -38,14 +38,15 @@ Please view the [documentation](https://appflowy.gitbook.io/docs/essential-docum
|
||||
|
||||
## Stay Up-to-Date
|
||||
|
||||
<p align="center"><img src="https://github.com/AppFlowy-IO/appflowy/blob/main/doc/imgs/howtostar.gif" alt="AppFlowy Github" width="1000px" /></p>
|
||||
<p align="center"><img src="https://github.com/AppFlowy-IO/appflowy/blob/main/doc/imgs/howtostar.gif" alt="AppFlowy Github - how to star the repo" width="100%" /></p>
|
||||
|
||||
## Getting Started with development
|
||||
Please view the [documentation](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy) for OS specific development instructions
|
||||
|
||||
## Roadmap
|
||||
|
||||
[AppFlowy Roadmap](https://trello.com/b/NCyXCXXh/appflowy-roadmap)
|
||||
- [AppFlowy Roadmap ReadMe](https://appflowy.gitbook.io/docs/essential-documentation/roadmap)
|
||||
- [AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12)
|
||||
|
||||
If you'd like to propose a feature, submit an issue [here](https://github.com/AppFlowy-IO/appflowy/issues).
|
||||
|
||||
|
3
ROADMAP.md
Normal file
3
ROADMAP.md
Normal file
@ -0,0 +1,3 @@
|
||||
## Our [roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) is where you can learn about the features we’re working on, their status, when we expect to release them, and how you can help us.
|
||||
|
||||
## Find more information about how to use our official AppFlowy public roadmap on [Gitbook](https://appflowy.gitbook.io/docs/essential-documentation/roadmap).
|
@ -22,3 +22,4 @@ module.exports = {
|
||||
'footer-max-line-length': [2, 'always', 100]
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1 +1,3 @@
|
||||
https://trello.com/b/NCyXCXXh/appflowy-roadmap
|
||||
[AppFlowy Roadmap ReadMe](https://appflowy.gitbook.io/docs/essential-documentation/roadmap)
|
||||
|
||||
[AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12)
|
||||
|
@ -1,2 +0,0 @@
|
||||
brew 'sqlite3'
|
||||
brew 'rustup-init'
|
@ -1,14 +0,0 @@
|
||||
.PHONY: flowy_dev_install flowy_clean
|
||||
|
||||
flowy_dev_install:
|
||||
brew bundle
|
||||
rustup-init -y --default-toolchain=stable
|
||||
cargo install --force cargo-make
|
||||
cargo install --force duckscript_cli
|
||||
cargo make flowy_dev
|
||||
|
||||
|
||||
flowy_clean:
|
||||
sh ./scripts/clean.sh
|
||||
|
||||
|
1
frontend/app_flowy/.gitignore
vendored
1
frontend/app_flowy/.gitignore
vendored
@ -65,3 +65,4 @@ windows/flutter/dart_ffi/
|
||||
**/**/*.so
|
||||
**/**/Brewfile.lock.json
|
||||
**/.sandbox
|
||||
**/.vscode/
|
@ -141,6 +141,7 @@
|
||||
"menu": {
|
||||
"appearance": "Appearance",
|
||||
"language": "Language",
|
||||
"user": "User",
|
||||
"open": "Open Settings"
|
||||
},
|
||||
"appearance": {
|
||||
@ -172,8 +173,8 @@
|
||||
"includeTime": " Include time",
|
||||
"dateFormatFriendly": "Month Day,Year",
|
||||
"dateFormatISO": "Year-Month-Day",
|
||||
"dateFormatLocal": "Month/Month/Day",
|
||||
"dateFormatUS": "Month/Month/Day",
|
||||
"dateFormatLocal": "Year/Month/Day",
|
||||
"dateFormatUS": "Year/Month/Day",
|
||||
"timeFormat": " Time format",
|
||||
"invalidTimeFormat": "Invalid format",
|
||||
"timeFormatTwelveHour": "12 hour",
|
||||
|
@ -96,6 +96,12 @@
|
||||
"lightMode": "Cambiar a modo Claro",
|
||||
"darkMode": "Cambiar a modo Oscuro"
|
||||
},
|
||||
"notifications": {
|
||||
"export": {
|
||||
"markdown": "Nota exportada a Markdown",
|
||||
"path": "Documentos/flowy"
|
||||
}
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Contactos",
|
||||
"whatsHappening": "¿Qué está pasando esta semana?",
|
||||
@ -120,13 +126,13 @@
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Imposible conectarse con sus credenciales.",
|
||||
"failedMsg": "Por favor asegurese haber completado el proceso de ingreso en su buscador."
|
||||
"failedMsg": "Por favor asegurese haber completado el proceso de ingreso en su navegador."
|
||||
},
|
||||
"google": {
|
||||
"title": "Ingresar con Google",
|
||||
"instruction1": "Para importar sus contactos de Google, debe autorizar esta aplicación usando su buscador web.",
|
||||
"instruction1": "Para importar sus contactos de Google, debe autorizar esta aplicación usando su navegador web.",
|
||||
"instruction2": "Copie este código al presionar el icono o al seleccionar el texto:",
|
||||
"instruction3": "Navege al siguiente enlace en su buscador web, e ingrese el código anterior:",
|
||||
"instruction3": "Navege al siguiente enlace en su navegador web, e ingrese el código anterior:",
|
||||
"instruction4": "Presione el botón de abajo cuando haya completado su registro:"
|
||||
}
|
||||
},
|
||||
@ -141,5 +147,71 @@
|
||||
"lightLabel": "Modo Claro",
|
||||
"darkLabel": "Modo Oscuro"
|
||||
}
|
||||
},
|
||||
"grid": {
|
||||
"settings": {
|
||||
"filter": "Filtrar",
|
||||
"sortBy": "Ordenar por",
|
||||
"Properties": "Propiedades"
|
||||
},
|
||||
"field": {
|
||||
"hide": "Ocultar",
|
||||
"insertLeft": "Insertar a la Izquierda",
|
||||
"insertRight": "Insertar a la Derecha",
|
||||
"duplicate": "Duplicar",
|
||||
"delete": "Eliminar",
|
||||
"textFieldName": "Texto",
|
||||
"checkboxFieldName": "Casilla de verificación",
|
||||
"dateFieldName": "Fecha",
|
||||
"numberFieldName": "Números",
|
||||
"singleSelectFieldName": "Seleccionar",
|
||||
"multiSelectFieldName": "Selección múltiple",
|
||||
"urlFieldName": "URL",
|
||||
"numberFormat": " Formato numérico",
|
||||
"dateFormat": " Formato de fecha",
|
||||
"includeTime": " Incluir tiempo",
|
||||
"dateFormatFriendly": "Mes Día, Año",
|
||||
"dateFormatISO": "Año-Mes-Día",
|
||||
"dateFormatLocal": "Año/Mes/Día",
|
||||
"dateFormatUS": "Año/Mes/Día",
|
||||
"timeFormat": " Time format",
|
||||
"invalidTimeFormat": "Formato de tiempo",
|
||||
"timeFormatTwelveHour": "12 horas",
|
||||
"timeFormatTwentyFourHour": "24 horas",
|
||||
"addSelectOption": "Añadir una opción",
|
||||
"optionTitle": "Opciones",
|
||||
"addOption": "Añadir opción",
|
||||
"editProperty": "Editar propiedad"
|
||||
},
|
||||
"row": {
|
||||
"duplicate": "Duplicar",
|
||||
"delete": "Eliminar",
|
||||
"textPlaceholder": "Vacío",
|
||||
"copyProperty": "Propiedad copiada al portapapeles"
|
||||
},
|
||||
"selectOption": {
|
||||
"create": "Crear",
|
||||
"purpleColor": "Morado",
|
||||
"pinkColor": "Rosa",
|
||||
"lightPinkColor": "Rosa Claro",
|
||||
"orangeColor": "Naranja",
|
||||
"yellowColor": "Amarillo",
|
||||
"limeColor": "Lima",
|
||||
"greenColor": "Verde",
|
||||
"aquaColor": "Agua",
|
||||
"blueColor": "Azul",
|
||||
"deleteTag": "Borrar etiqueta",
|
||||
"colorPannelTitle": "Colores",
|
||||
"pannelTitle": "Selecciona una opción o crea una",
|
||||
"searchOption": "Buscar una opción"
|
||||
},
|
||||
"menuName": "Grid"
|
||||
},
|
||||
"document": {
|
||||
"menuName": "Doc",
|
||||
"date": {
|
||||
"timeHintTextInTwelveHour": "12:00 AM",
|
||||
"timeHintTextInTwentyFourHour": "12:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
218
frontend/app_flowy/assets/translations/id-ID.json
Normal file
218
frontend/app_flowy/assets/translations/id-ID.json
Normal file
@ -0,0 +1,218 @@
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Saya",
|
||||
"welcomeText": "Selamat datang di @:appName",
|
||||
"githubStarText": "Bintangi GitHub",
|
||||
"subscribeNewsletterText": "Berlangganan buletin",
|
||||
"letsGoButtonText": "Ayo",
|
||||
"title": "Judul",
|
||||
"signUp": {
|
||||
"buttonText": "Daftar",
|
||||
"title": "Daftar ke @:appName",
|
||||
"getStartedText": "Mulai",
|
||||
"emptyPasswordError": "Sandi tidak boleh kosong",
|
||||
"repeatPasswordEmptyError": "Sandi ulang tidak boleh kosong",
|
||||
"unmatchedPasswordError": "Sandi ulang tidak sama dengan sandi",
|
||||
"alreadyHaveAnAccount": "Sudah punya akun?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Sandi",
|
||||
"repeatPasswordHint": "Sandi ulang"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Masuk ke @:appName",
|
||||
"loginButtonText": "Masuk",
|
||||
"buttonText": "Masuk",
|
||||
"forgotPassword": "Lupa Sandi?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Sandi",
|
||||
"dontHaveAnAccount": "Belum punya akun?",
|
||||
"repeatPasswordEmptyError": "Sandi ulang tidak boleh kosong",
|
||||
"unmatchedPasswordError": "Sandi ulang tidak sama dengan sandi"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Buat workspace",
|
||||
"hint": "workspace",
|
||||
"notFoundError": "Workspace tidak ditemukan"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Bagikan",
|
||||
"workInProgress": "Segera",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Salin tautan"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Ganti nama",
|
||||
"delete": "Hapus",
|
||||
"duplicate": "Duplikat"
|
||||
},
|
||||
"blankPageTitle": "Halaman kosong",
|
||||
"newPageText": "Halaman baru",
|
||||
"trash": {
|
||||
"text": "Sampah",
|
||||
"restoreAll": "Pulihkan Semua",
|
||||
"deleteAll": "Hapus semua",
|
||||
"pageHeader": {
|
||||
"fileName": "Nama file",
|
||||
"lastModified": "Terakhir diubah",
|
||||
"created": "Dibuat"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Halaman ini di tempat sampah",
|
||||
"restore": "Pulihkan halaman",
|
||||
"deletePermanent": "Hapus secara permanen"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Nama halaman",
|
||||
"questionBubble": {
|
||||
"whatsNew": "Apa yang baru?",
|
||||
"help": "Bantuan & Dukungan",
|
||||
"debug": {
|
||||
"name": "Info debug",
|
||||
"success": "Info debug disalin ke papan klip!",
|
||||
"fail": "Tidak dapat menyalin info debug ke papan klip"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Menambahkan halaman di dalam dengan cepat",
|
||||
"defaultNewPageName": "Tanpa Judul",
|
||||
"renameDialog": "Ganti nama"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Undo",
|
||||
"redo": "Redo",
|
||||
"bold": "Tebal",
|
||||
"italic": "Miring",
|
||||
"underline": "Garis bawah",
|
||||
"strike": "Dicoret",
|
||||
"numList": "Daftar bernomor",
|
||||
"bulletList": "Daftar berpoin",
|
||||
"checkList": "Daftar periksa",
|
||||
"inlineCode": "Kode sebaris",
|
||||
"quote": "Blok kutipan",
|
||||
"header": "Tajuk",
|
||||
"highlight": "Sorotan"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "Ganti mode terang",
|
||||
"darkMode": "Ganti mode gelap"
|
||||
},
|
||||
"notifications": {
|
||||
"export": {
|
||||
"markdown": "Mengekspor Catatan ke Markdown",
|
||||
"path": "Documents/flowy"
|
||||
}
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Kontak",
|
||||
"whatsHappening": "Apa yang terjadi minggu ini?",
|
||||
"addContact": "Tambahkan Kontak",
|
||||
"editContact": "Ubah Kontak"
|
||||
},
|
||||
"button": {
|
||||
"OK": "Ya",
|
||||
"Cancel": "Batal",
|
||||
"signIn": "Masuk",
|
||||
"signOut": "Keluar",
|
||||
"complete": "Selesai",
|
||||
"save": "Simpan"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Selamat datang!",
|
||||
"firstName": "Nama Depan",
|
||||
"middleName": "Nama Tengah",
|
||||
"lastName": "Nama Akhir",
|
||||
"stepX": "Langkah {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Tidak dapat terhubung ke akun anda",
|
||||
"failedMsg": "Mohon pastikan anda menyelesaikan proses pendaftaran pada browser anda."
|
||||
},
|
||||
"google": {
|
||||
"title": "MASUK GOOGLE",
|
||||
"instruction1": "Untuk mengimpor kontak Google Contacts anda, anda harus mengizinkan aplikasi ini menggunakan browser web anda.",
|
||||
"instruction2": "Salin kode ini ke papan klip anda dengan cara mengklik ikon atau memilih teks:",
|
||||
"instruction3": "Arahkan ke tautan berikut di browser web Anda, dan masukkan kode di atas:",
|
||||
"instruction4": "Tekan tombol di bawah ini setelah Anda menyelesaikan pendaftaran:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Pengaturan",
|
||||
"menu": {
|
||||
"appearance": "Tampilan",
|
||||
"language": "Bahasa",
|
||||
"user": "Pengguna",
|
||||
"open": "Buka Pengaturan"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "Mode Terang",
|
||||
"darkLabel": "Mode Gelap"
|
||||
}
|
||||
},
|
||||
"grid": {
|
||||
"settings": {
|
||||
"filter": "Filter",
|
||||
"sortBy": "Sortir dengan",
|
||||
"Properties": "Properti"
|
||||
},
|
||||
"field": {
|
||||
"hide": "Sembunyikan",
|
||||
"insertLeft": "Sisipkan Kiri",
|
||||
"insertRight": "Sisipkan Kanan",
|
||||
"duplicate": "Duplikasi",
|
||||
"delete": "Hapus",
|
||||
"textFieldName": "Teks",
|
||||
"checkboxFieldName": "Kotak Centang",
|
||||
"dateFieldName": "Tanggal",
|
||||
"numberFieldName": "Angka",
|
||||
"singleSelectFieldName": "seleksi",
|
||||
"multiSelectFieldName": "Multi seleksi",
|
||||
"urlFieldName": "URL",
|
||||
"numberFormat": " Format angka",
|
||||
"dateFormat": " Format tanggal",
|
||||
"includeTime": " Sertakan waktu",
|
||||
"dateFormatFriendly": "Bulan Hari,Tahun",
|
||||
"dateFormatISO": "Tahun-Bulan-Hari",
|
||||
"dateFormatLocal": "Tahun/Bulan/Hari",
|
||||
"dateFormatUS": "Tahun/Bulan/Hari",
|
||||
"timeFormat": " Format waktu",
|
||||
"invalidTimeFormat": "Format yang tidak valid",
|
||||
"timeFormatTwelveHour": "12 jam",
|
||||
"timeFormatTwentyFourHour": "24 jam",
|
||||
"addSelectOption": "Tambahkan opsi",
|
||||
"optionTitle": "Opsi",
|
||||
"addOption": "Tambahkan opsi",
|
||||
"editProperty": "Ubah properti"
|
||||
},
|
||||
"row": {
|
||||
"duplicate": "Duplikasi",
|
||||
"delete": "Hapus",
|
||||
"textPlaceholder": "Kosong",
|
||||
"copyProperty": "Salin properti ke papan klip"
|
||||
},
|
||||
"selectOption": {
|
||||
"create": "Buat",
|
||||
"purpleColor": "Ungu",
|
||||
"pinkColor": "Merah Jambu",
|
||||
"lightPinkColor": "Merah Jambu Muda",
|
||||
"orangeColor": "Oranye",
|
||||
"yellowColor": "Kuning",
|
||||
"limeColor": "Limau",
|
||||
"greenColor": "Hijau",
|
||||
"aquaColor": "Air",
|
||||
"blueColor": "Biru",
|
||||
"deleteTag": "Hapus tag",
|
||||
"colorPannelTitle": "Warna",
|
||||
"pannelTitle": "Pilih opsi atau buat baru",
|
||||
"searchOption": "Cari opsi"
|
||||
},
|
||||
"menuName": "Grid"
|
||||
},
|
||||
"document": {
|
||||
"menuName": "Doc",
|
||||
"date": {
|
||||
"timeHintTextInTwelveHour": "12:00 AM",
|
||||
"timeHintTextInTwentyFourHour": "12:00"
|
||||
}
|
||||
}
|
||||
}
|
145
frontend/app_flowy/assets/translations/pl-PL.json
Normal file
145
frontend/app_flowy/assets/translations/pl-PL.json
Normal file
@ -0,0 +1,145 @@
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "Ja",
|
||||
"welcomeText": "Witaj w @:appName",
|
||||
"githubStarText": "Gwiazdka na GitHub-ie",
|
||||
"subscribeNewsletterText": "Zapisz się do naszego Newslettera",
|
||||
"letsGoButtonText": "Start!",
|
||||
"title": "Tytuł",
|
||||
"signUp": {
|
||||
"buttonText": "Zarejestruj",
|
||||
"title": "Zarejestruj się w @:appName",
|
||||
"getStartedText": "Zaczynamy",
|
||||
"emptyPasswordError": "Hasło nie moze być puste",
|
||||
"repeatPasswordEmptyError": "Powtórzone hasło nie moze być puste",
|
||||
"unmatchedPasswordError": "Hasła nie są takie same",
|
||||
"alreadyHaveAnAccount": "Masz juz konto?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Hasło",
|
||||
"repeatPasswordHint": "Powtórz hasło"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "Zaloguj do @:appName",
|
||||
"loginButtonText": "Logowanie",
|
||||
"buttonText": "Zaloguj",
|
||||
"forgotPassword": "Zapomniałem hasła?",
|
||||
"emailHint": "Email",
|
||||
"passwordHint": "Password",
|
||||
"dontHaveAnAccount": "Nie masz konta?",
|
||||
"repeatPasswordEmptyError": "Powtórzone hasło nie moze być puste",
|
||||
"unmatchedPasswordError": "Hasła nie są takie same"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "Utwórz przestrzeń",
|
||||
"hint": "przestrzeń robocza",
|
||||
"notFoundError": "Przestrzeni nie znaleziono"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Udostępnij",
|
||||
"workInProgress": "Wkrótce",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "Skopiuj link"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "Zmień nazwę",
|
||||
"delete": "Usuń",
|
||||
"duplicate": "Duplikuj"
|
||||
},
|
||||
"blankPageTitle": "Pusta strona",
|
||||
"newPageText": "Nowa strona",
|
||||
"trash": {
|
||||
"text": "Kosz",
|
||||
"restoreAll": "Przywróć Wszystko",
|
||||
"deleteAll": "Usuń Wszystko",
|
||||
"pageHeader": {
|
||||
"fileName": "Nazwa Pliku",
|
||||
"lastModified": "Ostatnio Zmodyfikowano",
|
||||
"created": "Utworzono"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "Ta strona jest w Koszu",
|
||||
"restore": "Przywróć strone",
|
||||
"deletePermanent": "Usuń bezpowrotnie"
|
||||
},
|
||||
"dialogCreatePageNameHint": "Nazwa Strony",
|
||||
"questionBubble": {
|
||||
"whatsNew": "What's new?",
|
||||
"help": "Pomoc & Wsparcie",
|
||||
"debug": {
|
||||
"name": "Informacje Debugowania",
|
||||
"success": "Skopiowano informacje debugowania do schowka!",
|
||||
"fail": "Nie mozna skopiować informacji debugowania do schowka"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "Szybko dodaj stronę do środka",
|
||||
"defaultNewPageName": "Brak tytułu",
|
||||
"renameDialog": "Zmień nazwę"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "Cofnij",
|
||||
"redo": "Powtórz",
|
||||
"bold": "Pogrubiony",
|
||||
"italic": "Kursywa",
|
||||
"underline": "Podkreśl",
|
||||
"strike": "Przekreśl",
|
||||
"numList": "Lista Numerowana",
|
||||
"bulletList": "Lista Punktowana",
|
||||
"checkList": "Lista Kontrolna",
|
||||
"inlineCode": "Kod Wbudowany",
|
||||
"quote": "Blok cytat",
|
||||
"header": "Nagłówek",
|
||||
"highlight": "Podświetl"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "Przełącz w Tryb Jasny",
|
||||
"darkMode": "Przełącz w Tryb Ciemny"
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "Kontakty",
|
||||
"whatsHappening": "Co się dzieje w tym tygodniu?",
|
||||
"addContact": "Dodaj Kontakt",
|
||||
"editContact": "Edytuj Kontakt"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "Anuluj",
|
||||
"signIn": "Zaloguj",
|
||||
"signOut": "Wyloguj",
|
||||
"complete": "Zakończono",
|
||||
"save": "Zapisz"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "Witaj!",
|
||||
"firstName": "Imię Pierwsze",
|
||||
"middleName": "Imię Drugie",
|
||||
"lastName": "Nazwisko",
|
||||
"stepX": "Krok {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "Nie można połączyć się z Twoim kontem.",
|
||||
"failedMsg": "Upewnij się, że zakończyłeś proces logowania w przeglądarce."
|
||||
},
|
||||
"google": {
|
||||
"title": "LOGOWANIE GOOGLE",
|
||||
"instruction1": "Aby zaimportować Kontakty Google, musisz autoryzować tę aplikację za pomocą przeglądarki internetowej.",
|
||||
"instruction2": "Skopiuj ten kod do schowka, klikając ikonę lub zaznaczając tekst:",
|
||||
"instruction3": "Przejdź do następującego linku w przeglądarce internetowej i wprowadź powyższy kod:",
|
||||
"instruction4": "Naciśnij poniższy przycisk po zakończeniu rejestracji:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Ustawienia",
|
||||
"menu": {
|
||||
"appearance": "Wygląd",
|
||||
"language": "Język",
|
||||
"open": "Otwórz Ustawienia"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "Tryb Jasny",
|
||||
"darkLabel": "Tryb Ciemny"
|
||||
}
|
||||
}
|
||||
}
|
218
frontend/app_flowy/assets/translations/zh-TW.json
Normal file
218
frontend/app_flowy/assets/translations/zh-TW.json
Normal file
@ -0,0 +1,218 @@
|
||||
{
|
||||
"appName": "AppFlowy",
|
||||
"defaultUsername": "我",
|
||||
"welcomeText": "歡迎使用 @:appName",
|
||||
"githubStarText": "在 GitHub 點星",
|
||||
"subscribeNewsletterText": "訂閱電子報",
|
||||
"letsGoButtonText": "出發吧",
|
||||
"title": "標題",
|
||||
"signUp": {
|
||||
"buttonText": "註冊",
|
||||
"title": "註冊 @:appName",
|
||||
"getStartedText": "開始使用",
|
||||
"emptyPasswordError": "密碼不能為空",
|
||||
"repeatPasswordEmptyError": "確認密碼不能為空",
|
||||
"unmatchedPasswordError": "確認密碼與密碼不符",
|
||||
"alreadyHaveAnAccount": "已經有帳號了嗎?",
|
||||
"emailHint": "電子郵件地址",
|
||||
"passwordHint": "密碼",
|
||||
"repeatPasswordHint": "確認密碼"
|
||||
},
|
||||
"signIn": {
|
||||
"loginTitle": "登入 @:appName",
|
||||
"loginButtonText": "登入",
|
||||
"buttonText": "登入",
|
||||
"forgotPassword": "忘記密碼?",
|
||||
"emailHint": "電子郵件地址",
|
||||
"passwordHint": "密碼",
|
||||
"dontHaveAnAccount": "沒有帳號?",
|
||||
"repeatPasswordEmptyError": "確認密碼不能為空",
|
||||
"unmatchedPasswordError": "確認密碼與密碼不符"
|
||||
},
|
||||
"workspace": {
|
||||
"create": "建立工作區",
|
||||
"hint": "工作區",
|
||||
"notFoundError": "找不到工作區"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "分享",
|
||||
"workInProgress": "即將推出",
|
||||
"markdown": "Markdown",
|
||||
"copyLink": "複製連結"
|
||||
},
|
||||
"disclosureAction": {
|
||||
"rename": "重新命名",
|
||||
"delete": "刪除",
|
||||
"duplicate": "複製"
|
||||
},
|
||||
"blankPageTitle": "空白頁面",
|
||||
"newPageText": "新頁面",
|
||||
"trash": {
|
||||
"text": "垃圾筒",
|
||||
"restoreAll": "全部復原",
|
||||
"deleteAll": "全部刪除",
|
||||
"pageHeader": {
|
||||
"fileName": "檔案名稱",
|
||||
"lastModified": "最後修改時間",
|
||||
"created": "建立時間"
|
||||
}
|
||||
},
|
||||
"deletePagePrompt": {
|
||||
"text": "此頁面在垃圾筒中",
|
||||
"restore": "復原頁面",
|
||||
"deletePermanent": "永久刪除"
|
||||
},
|
||||
"dialogCreatePageNameHint": "頁面名稱",
|
||||
"questionBubble": {
|
||||
"whatsNew": "新功能",
|
||||
"help": "幫助 & 支援",
|
||||
"debug": {
|
||||
"name": "除錯資訊",
|
||||
"success": "已將除錯資訊複製至剪貼簿!",
|
||||
"fail": "無法將除錯資訊複製至剪貼簿"
|
||||
}
|
||||
},
|
||||
"menuAppHeader": {
|
||||
"addPageTooltip": "快速新增頁面",
|
||||
"defaultNewPageName": "未命名",
|
||||
"renameDialog": "重新命名"
|
||||
},
|
||||
"toolbar": {
|
||||
"undo": "復原",
|
||||
"redo": "取消復原",
|
||||
"bold": "粗體",
|
||||
"italic": "斜體",
|
||||
"underline": "底線",
|
||||
"strike": "刪除線",
|
||||
"numList": "有序清單",
|
||||
"bulletList": "無序清單",
|
||||
"checkList": "核取清單",
|
||||
"inlineCode": "程式碼",
|
||||
"quote": "區塊引言",
|
||||
"header": "標題",
|
||||
"highlight": "反白"
|
||||
},
|
||||
"tooltip": {
|
||||
"lightMode": "切換至亮色模式",
|
||||
"darkMode": "切換至暗色模式"
|
||||
},
|
||||
"notifications": {
|
||||
"export": {
|
||||
"markdown": "已將筆記匯出成 Markdown",
|
||||
"path": "Documents/flowy"
|
||||
}
|
||||
},
|
||||
"contactsPage": {
|
||||
"title": "聯絡人",
|
||||
"whatsHappening": "這周有甚麼新鮮事?",
|
||||
"addContact": "新增聯絡人",
|
||||
"editContact": "編輯聯絡人"
|
||||
},
|
||||
"button": {
|
||||
"OK": "OK",
|
||||
"Cancel": "取消",
|
||||
"signIn": "登入",
|
||||
"signOut": "登出",
|
||||
"complete": "完成",
|
||||
"save": "儲存"
|
||||
},
|
||||
"label": {
|
||||
"welcome": "歡迎!",
|
||||
"firstName": "名",
|
||||
"middleName": "中間名",
|
||||
"lastName": "姓",
|
||||
"stepX": "步驟 {X}"
|
||||
},
|
||||
"oAuth": {
|
||||
"err": {
|
||||
"failedTitle": "無法連接至您的帳號。",
|
||||
"failedMsg": "請確認您已在瀏覽器中完成登入程序:"
|
||||
},
|
||||
"google": {
|
||||
"title": "GOOGLE 登入",
|
||||
"instruction1": "若要匯入您的 Google 聯絡人,您必須透過瀏覽器授權此應用程式:",
|
||||
"instruction2": "點擊圖示或選取文字以複製代碼:",
|
||||
"instruction3": "前往下列網址,並輸入上述代碼:",
|
||||
"instruction4": "完成註冊後,請點擊下方按鈕:"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "設定",
|
||||
"menu": {
|
||||
"appearance": "外觀",
|
||||
"language": "語言",
|
||||
"user": "使用者",
|
||||
"open": "開啟設定"
|
||||
},
|
||||
"appearance": {
|
||||
"lightLabel": "亮色模式",
|
||||
"darkLabel": "暗色模式"
|
||||
}
|
||||
},
|
||||
"grid": {
|
||||
"settings": {
|
||||
"filter": "篩選",
|
||||
"sortBy": "排序方式",
|
||||
"Properties": "內容"
|
||||
},
|
||||
"field": {
|
||||
"hide": "隱藏",
|
||||
"insertLeft": "插入左方欄",
|
||||
"insertRight": "插入右方欄",
|
||||
"duplicate": "複製",
|
||||
"delete": "刪除",
|
||||
"textFieldName": "文字",
|
||||
"checkboxFieldName": "核取方塊",
|
||||
"dateFieldName": "日期",
|
||||
"numberFieldName": "數字",
|
||||
"singleSelectFieldName": "單選",
|
||||
"multiSelectFieldName": "多選",
|
||||
"urlFieldName": "網址",
|
||||
"numberFormat": " 數字格式",
|
||||
"dateFormat": " 日期格式",
|
||||
"includeTime": " 包含時間",
|
||||
"dateFormatFriendly": "月 日,年",
|
||||
"dateFormatISO": "年-月-日",
|
||||
"dateFormatLocal": "年/月/日",
|
||||
"dateFormatUS": "年/月/日",
|
||||
"timeFormat": " 時間格式",
|
||||
"invalidTimeFormat": "格式無效",
|
||||
"timeFormatTwelveHour": "12 小時",
|
||||
"timeFormatTwentyFourHour": "24 小時",
|
||||
"addSelectOption": "新增選項",
|
||||
"optionTitle": "選項",
|
||||
"addOption": "新增選項",
|
||||
"editProperty": "編輯內容"
|
||||
},
|
||||
"row": {
|
||||
"duplicate": "複製",
|
||||
"delete": "刪除",
|
||||
"textPlaceholder": "空",
|
||||
"copyProperty": "已將內容複製至剪貼簿"
|
||||
},
|
||||
"selectOption": {
|
||||
"create": "建立",
|
||||
"purpleColor": "紫色",
|
||||
"pinkColor": "粉色",
|
||||
"lightPinkColor": "淡粉色",
|
||||
"orangeColor": "橘色",
|
||||
"yellowColor": "黃色",
|
||||
"limeColor": "萊姆色",
|
||||
"greenColor": "綠色",
|
||||
"aquaColor": "水藍色",
|
||||
"blueColor": "藍色",
|
||||
"deleteTag": "刪除標籤",
|
||||
"colorPannelTitle": "顏色",
|
||||
"pannelTitle": "搜尋或建立選項",
|
||||
"searchOption": "搜尋選項"
|
||||
},
|
||||
"menuName": "網格"
|
||||
},
|
||||
"document": {
|
||||
"menuName": "檔案",
|
||||
"date": {
|
||||
"timeHintTextInTwelveHour": "12:00 AM",
|
||||
"timeHintTextInTwentyFourHour": "12:00"
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
import 'notification_helper.dart';
|
||||
|
||||
// Grid
|
||||
// GridPB
|
||||
typedef GridNotificationCallback = void Function(GridNotification, Either<Uint8List, FlowyError>);
|
||||
|
||||
class GridNotificationParser extends NotificationParser<GridNotification, FlowyError> {
|
||||
|
@ -5,10 +5,12 @@ 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/trash/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/user/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/view/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/menu/prelude.dart';
|
||||
import 'package:app_flowy/workspace/application/settings/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';
|
||||
@ -51,14 +53,14 @@ void _resolveHomeDeps(GetIt getIt) {
|
||||
|
||||
getIt.registerSingleton(MenuSharedState());
|
||||
|
||||
getIt.registerFactoryParam<UserListener, UserProfile, void>(
|
||||
getIt.registerFactoryParam<UserListener, UserProfilePB, void>(
|
||||
(user, _) => UserListener(userProfile: user),
|
||||
);
|
||||
|
||||
//
|
||||
getIt.registerLazySingleton<HomeStackManager>(() => HomeStackManager());
|
||||
|
||||
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
|
||||
getIt.registerFactoryParam<WelcomeBloc, UserProfilePB, void>(
|
||||
(user, _) => WelcomeBloc(
|
||||
userService: UserService(userId: user.id),
|
||||
userWorkspaceListener: UserWorkspaceListener(userProfile: user),
|
||||
@ -67,21 +69,21 @@ void _resolveHomeDeps(GetIt getIt) {
|
||||
|
||||
// share
|
||||
getIt.registerLazySingleton<ShareService>(() => ShareService());
|
||||
getIt.registerFactoryParam<DocShareBloc, View, void>(
|
||||
getIt.registerFactoryParam<DocShareBloc, ViewPB, void>(
|
||||
(view, _) => DocShareBloc(view: view, service: getIt<ShareService>()));
|
||||
}
|
||||
|
||||
void _resolveFolderDeps(GetIt getIt) {
|
||||
//workspace
|
||||
getIt.registerFactoryParam<WorkspaceListener, UserProfile, String>(
|
||||
getIt.registerFactoryParam<WorkspaceListener, UserProfilePB, String>(
|
||||
(user, workspaceId) => WorkspaceListener(user: user, workspaceId: workspaceId));
|
||||
|
||||
// View
|
||||
getIt.registerFactoryParam<ViewListener, View, void>(
|
||||
// ViewPB
|
||||
getIt.registerFactoryParam<ViewListener, ViewPB, void>(
|
||||
(view, _) => ViewListener(view: view),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<ViewBloc, View, void>(
|
||||
getIt.registerFactoryParam<ViewBloc, ViewPB, void>(
|
||||
(view, _) => ViewBloc(
|
||||
view: view,
|
||||
service: ViewService(),
|
||||
@ -90,19 +92,29 @@ void _resolveFolderDeps(GetIt getIt) {
|
||||
);
|
||||
|
||||
//Menu
|
||||
getIt.registerFactoryParam<MenuBloc, UserProfile, String>(
|
||||
getIt.registerFactoryParam<MenuBloc, UserProfilePB, String>(
|
||||
(user, workspaceId) => MenuBloc(
|
||||
workspaceId: workspaceId,
|
||||
listener: getIt<WorkspaceListener>(param1: user, param2: workspaceId),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>(
|
||||
getIt.registerFactoryParam<MenuUserBloc, UserProfilePB, void>(
|
||||
(user, _) => MenuUserBloc(user),
|
||||
);
|
||||
|
||||
// App
|
||||
getIt.registerFactoryParam<AppBloc, App, void>(
|
||||
//Settings
|
||||
getIt.registerFactoryParam<SettingsDialogBloc, UserProfilePB, void>(
|
||||
(user, _) => SettingsDialogBloc(user),
|
||||
);
|
||||
|
||||
//User
|
||||
getIt.registerFactoryParam<SettingsUserViewBloc, UserProfilePB, void>(
|
||||
(user, _) => SettingsUserViewBloc(user),
|
||||
);
|
||||
|
||||
// AppPB
|
||||
getIt.registerFactoryParam<AppBloc, AppPB, void>(
|
||||
(app, _) => AppBloc(
|
||||
app: app,
|
||||
appService: AppService(appId: app.id),
|
||||
@ -123,7 +135,7 @@ void _resolveFolderDeps(GetIt getIt) {
|
||||
|
||||
void _resolveDocDeps(GetIt getIt) {
|
||||
// Doc
|
||||
getIt.registerFactoryParam<DocumentBloc, View, void>(
|
||||
getIt.registerFactoryParam<DocumentBloc, ViewPB, void>(
|
||||
(view, _) => DocumentBloc(
|
||||
view: view,
|
||||
service: DocumentService(),
|
||||
@ -134,8 +146,8 @@ void _resolveDocDeps(GetIt getIt) {
|
||||
}
|
||||
|
||||
void _resolveGridDeps(GetIt getIt) {
|
||||
// Grid
|
||||
getIt.registerFactoryParam<GridBloc, View, void>(
|
||||
// GridPB
|
||||
getIt.registerFactoryParam<GridBloc, ViewPB, void>(
|
||||
(view, _) => GridBloc(view: view),
|
||||
);
|
||||
|
||||
@ -153,31 +165,31 @@ void _resolveGridDeps(GetIt getIt) {
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<TextCellBloc, GridCellContext, void>(
|
||||
getIt.registerFactoryParam<TextCellBloc, GridCellController, void>(
|
||||
(context, _) => TextCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<SelectOptionCellBloc, GridSelectOptionCellContext, void>(
|
||||
getIt.registerFactoryParam<SelectOptionCellBloc, GridSelectOptionCellController, void>(
|
||||
(context, _) => SelectOptionCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<NumberCellBloc, GridCellContext, void>(
|
||||
getIt.registerFactoryParam<NumberCellBloc, GridCellController, void>(
|
||||
(context, _) => NumberCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<DateCellBloc, GridDateCellContext, void>(
|
||||
getIt.registerFactoryParam<DateCellBloc, GridDateCellController, void>(
|
||||
(context, _) => DateCellBloc(
|
||||
cellContext: context,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, GridCellContext, void>(
|
||||
getIt.registerFactoryParam<CheckboxCellBloc, GridCellController, void>(
|
||||
(cellData, _) => CheckboxCellBloc(
|
||||
service: CellService(),
|
||||
cellContext: cellData,
|
||||
|
@ -36,8 +36,10 @@ class InitAppWidgetTask extends LaunchTask {
|
||||
Locale('fr', 'FR'),
|
||||
Locale('fr', 'CA'),
|
||||
Locale('hu', 'HU'),
|
||||
Locale('id', 'ID'),
|
||||
Locale('it', 'IT'),
|
||||
Locale('ja', 'JP'),
|
||||
Locale('pl', 'PL'),
|
||||
Locale('pt', 'BR'),
|
||||
Locale('ru', 'RU'),
|
||||
Locale('tr', 'TR'),
|
||||
|
@ -1,21 +1,21 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show SignInPayload, SignUpPayload, UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show SignInPayloadPB, SignUpPayloadPB, UserProfilePB;
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
|
||||
class AuthService {
|
||||
Future<Either<UserProfile, FlowyError>> signIn({required String? email, required String? password}) {
|
||||
Future<Either<UserProfilePB, FlowyError>> signIn({required String? email, required String? password}) {
|
||||
//
|
||||
final request = SignInPayload.create()
|
||||
final request = SignInPayloadPB.create()
|
||||
..email = email ?? ''
|
||||
..password = password ?? '';
|
||||
|
||||
return UserEventSignIn(request).send();
|
||||
}
|
||||
|
||||
Future<Either<UserProfile, FlowyError>> signUp(
|
||||
Future<Either<UserProfilePB, FlowyError>> signUp(
|
||||
{required String? name, required String? password, required String? email}) {
|
||||
final request = SignUpPayload.create()
|
||||
final request = SignUpPayloadPB.create()
|
||||
..email = email ?? ''
|
||||
..name = name ?? ''
|
||||
..password = password ?? '';
|
||||
|
@ -2,7 +2,7 @@ import 'package:app_flowy/user/application/auth_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
@ -69,7 +69,7 @@ class SignInState with _$SignInState {
|
||||
required bool isSubmitting,
|
||||
required Option<String> passwordError,
|
||||
required Option<String> emailError,
|
||||
required Option<Either<UserProfile, FlowyError>> successOrFail,
|
||||
required Option<Either<UserProfilePB, FlowyError>> successOrFail,
|
||||
}) = _SignInState;
|
||||
|
||||
factory SignInState.initial() => SignInState(
|
||||
|
@ -2,7 +2,7 @@ import 'package:app_flowy/user/application/auth_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@ -120,7 +120,7 @@ class SignUpState with _$SignUpState {
|
||||
required Option<String> passwordError,
|
||||
required Option<String> repeatPasswordError,
|
||||
required Option<String> emailError,
|
||||
required Option<Either<UserProfile, FlowyError>> successOrFail,
|
||||
required Option<Either<UserProfilePB, FlowyError>> successOrFail,
|
||||
}) = _SignUpState;
|
||||
|
||||
factory SignUpState.initial() => SignUpState(
|
||||
|
@ -13,7 +13,7 @@ import 'package:flowy_sdk/protobuf/flowy-user/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 UserProfileNotifyValue = Either<UserProfile, FlowyError>;
|
||||
typedef UserProfileNotifyValue = Either<UserProfilePB, FlowyError>;
|
||||
typedef AuthNotifyValue = Either<Unit, FlowyError>;
|
||||
|
||||
class UserListener {
|
||||
@ -22,9 +22,9 @@ class UserListener {
|
||||
PublishNotifier<UserProfileNotifyValue>? _profileNotifier = PublishNotifier();
|
||||
|
||||
UserNotificationParser? _userParser;
|
||||
final UserProfile _userProfile;
|
||||
final UserProfilePB _userProfile;
|
||||
UserListener({
|
||||
required UserProfile userProfile,
|
||||
required UserProfilePB userProfile,
|
||||
}) : _userProfile = userProfile;
|
||||
|
||||
void start({
|
||||
@ -65,7 +65,7 @@ class UserListener {
|
||||
break;
|
||||
case user.UserNotification.UserProfileUpdated:
|
||||
result.fold(
|
||||
(payload) => _profileNotifier?.value = left(UserProfile.fromBuffer(payload)),
|
||||
(payload) => _profileNotifier?.value = left(UserProfilePB.fromBuffer(payload)),
|
||||
(error) => _profileNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
@ -75,8 +75,8 @@ class UserListener {
|
||||
}
|
||||
}
|
||||
|
||||
typedef WorkspaceListNotifyValue = Either<List<Workspace>, FlowyError>;
|
||||
typedef WorkspaceSettingNotifyValue = Either<CurrentWorkspaceSetting, FlowyError>;
|
||||
typedef WorkspaceListNotifyValue = Either<List<WorkspacePB>, FlowyError>;
|
||||
typedef WorkspaceSettingNotifyValue = Either<CurrentWorkspaceSettingPB, FlowyError>;
|
||||
|
||||
class UserWorkspaceListener {
|
||||
PublishNotifier<AuthNotifyValue>? _authNotifier = PublishNotifier();
|
||||
@ -84,10 +84,10 @@ class UserWorkspaceListener {
|
||||
PublishNotifier<WorkspaceSettingNotifyValue>? _settingChangedNotifier = PublishNotifier();
|
||||
|
||||
FolderNotificationListener? _listener;
|
||||
final UserProfile _userProfile;
|
||||
final UserProfilePB _userProfile;
|
||||
|
||||
UserWorkspaceListener({
|
||||
required UserProfile userProfile,
|
||||
required UserProfilePB userProfile,
|
||||
}) : _userProfile = userProfile;
|
||||
|
||||
void start({
|
||||
@ -119,13 +119,13 @@ class UserWorkspaceListener {
|
||||
case FolderNotification.UserDeleteWorkspace:
|
||||
case FolderNotification.WorkspaceListUpdated:
|
||||
result.fold(
|
||||
(payload) => _workspacesChangedNotifier?.value = left(RepeatedWorkspace.fromBuffer(payload).items),
|
||||
(payload) => _workspacesChangedNotifier?.value = left(RepeatedWorkspacePB.fromBuffer(payload).items),
|
||||
(error) => _workspacesChangedNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
case FolderNotification.WorkspaceSetting:
|
||||
result.fold(
|
||||
(payload) => _settingChangedNotifier?.value = left(CurrentWorkspaceSetting.fromBuffer(payload)),
|
||||
(payload) => _settingChangedNotifier?.value = left(CurrentWorkspaceSettingPB.fromBuffer(payload)),
|
||||
(error) => _settingChangedNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
@ -11,7 +11,7 @@ class UserService {
|
||||
UserService({
|
||||
required this.userId,
|
||||
});
|
||||
Future<Either<UserProfile, FlowyError>> getUserProfile({required String userId}) {
|
||||
Future<Either<UserProfilePB, FlowyError>> getUserProfile({required String userId}) {
|
||||
return UserEventGetUserProfile().send();
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ class UserService {
|
||||
String? password,
|
||||
String? email,
|
||||
}) {
|
||||
var payload = UpdateUserProfilePayload.create()..id = userId;
|
||||
var payload = UpdateUserProfilePayloadPB.create()..id = userId;
|
||||
|
||||
if (name != null) {
|
||||
payload.name = name;
|
||||
@ -49,8 +49,8 @@ class UserService {
|
||||
return UserEventInitUser().send();
|
||||
}
|
||||
|
||||
Future<Either<List<Workspace>, FlowyError>> getWorkspaces() {
|
||||
final request = WorkspaceId.create();
|
||||
Future<Either<List<WorkspacePB>, FlowyError>> getWorkspaces() {
|
||||
final request = WorkspaceIdPB.create();
|
||||
|
||||
return FolderEventReadWorkspaces(request).send().then((result) {
|
||||
return result.fold(
|
||||
@ -60,8 +60,8 @@ class UserService {
|
||||
});
|
||||
}
|
||||
|
||||
Future<Either<Workspace, FlowyError>> openWorkspace(String workspaceId) {
|
||||
final request = WorkspaceId.create()..value = workspaceId;
|
||||
Future<Either<WorkspacePB, FlowyError>> openWorkspace(String workspaceId) {
|
||||
final request = WorkspaceIdPB.create()..value = workspaceId;
|
||||
return FolderEventOpenWorkspace(request).send().then((result) {
|
||||
return result.fold(
|
||||
(workspace) => left(workspace),
|
||||
@ -70,8 +70,8 @@ class UserService {
|
||||
});
|
||||
}
|
||||
|
||||
Future<Either<Workspace, FlowyError>> createWorkspace(String name, String desc) {
|
||||
final request = CreateWorkspacePayload.create()
|
||||
Future<Either<WorkspacePB, FlowyError>> createWorkspace(String name, String desc) {
|
||||
final request = CreateWorkspacePayloadPB.create()
|
||||
..name = name
|
||||
..desc = desc;
|
||||
return FolderEventCreateWorkspace(request).send().then((result) {
|
||||
|
@ -5,11 +5,11 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/user_setting.pb.dart';
|
||||
|
||||
class UserSettingsService {
|
||||
Future<AppearanceSettings> getAppearanceSettings() async {
|
||||
Future<AppearanceSettingsPB> getAppearanceSettings() async {
|
||||
final result = await UserEventGetAppearanceSetting().send();
|
||||
|
||||
return result.fold(
|
||||
(AppearanceSettings setting) {
|
||||
(AppearanceSettingsPB setting) {
|
||||
return setting;
|
||||
},
|
||||
(error) {
|
||||
@ -18,7 +18,7 @@ class UserSettingsService {
|
||||
);
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> setAppearanceSettings(AppearanceSettings settings) {
|
||||
Future<Either<Unit, FlowyError>> setAppearanceSettings(AppearanceSettingsPB settings) {
|
||||
return UserEventSetAppearanceSetting(settings).send();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'auth_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class AuthState with _$AuthState {
|
||||
const factory AuthState.authenticated(UserProfile userProfile) = Authenticated;
|
||||
const factory AuthState.authenticated(UserProfilePB userProfile) = Authenticated;
|
||||
const factory AuthState.unauthenticated(FlowyError error) = Unauthenticated;
|
||||
const factory AuthState.initial() = _Initial;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import 'package:app_flowy/user/presentation/welcome_screen.dart';
|
||||
import 'package:app_flowy/workspace/presentation/home/home_screen.dart';
|
||||
import 'package:flowy_infra/time/duration.dart';
|
||||
import 'package:flowy_infra_ui/widget/route/animation.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/protobuf.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -16,7 +16,7 @@ class AuthRouter {
|
||||
// TODO: implement showForgetPasswordScreen
|
||||
}
|
||||
|
||||
void pushWelcomeScreen(BuildContext context, UserProfile userProfile) {
|
||||
void pushWelcomeScreen(BuildContext context, UserProfilePB userProfile) {
|
||||
getIt<SplashRoute>().pushWelcomeScreen(context, userProfile);
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ class AuthRouter {
|
||||
);
|
||||
}
|
||||
|
||||
void pushHomeScreen(BuildContext context, UserProfile profile, CurrentWorkspaceSetting workspaceSetting) {
|
||||
void pushHomeScreen(BuildContext context, UserProfilePB profile, CurrentWorkspaceSettingPB workspaceSetting) {
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRoutes.fade(() => HomeScreen(profile, workspaceSetting), RouteDurations.slow.inMilliseconds * .001),
|
||||
@ -37,7 +37,7 @@ class AuthRouter {
|
||||
}
|
||||
|
||||
class SplashRoute {
|
||||
Future<void> pushWelcomeScreen(BuildContext context, UserProfile userProfile) async {
|
||||
Future<void> pushWelcomeScreen(BuildContext context, UserProfilePB userProfile) async {
|
||||
final screen = WelcomeScreen(userProfile: userProfile);
|
||||
final workspaceId = await Navigator.of(context).push(
|
||||
PageRoutes.fade(
|
||||
@ -49,7 +49,7 @@ class SplashRoute {
|
||||
pushHomeScreen(context, userProfile, workspaceId);
|
||||
}
|
||||
|
||||
void pushHomeScreen(BuildContext context, UserProfile userProfile, CurrentWorkspaceSetting workspaceSetting) {
|
||||
void pushHomeScreen(BuildContext context, UserProfilePB userProfile, CurrentWorkspaceSettingPB workspaceSetting) {
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRoutes.fade(() => HomeScreen(userProfile, workspaceSetting), RouteDurations.slow.inMilliseconds * .001),
|
||||
|
@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/snap_bar.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
@ -39,7 +39,7 @@ class SignInScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSuccessOrFail(Either<UserProfile, FlowyError> result, BuildContext context) {
|
||||
void _handleSuccessOrFail(Either<UserProfilePB, FlowyError> result, BuildContext context) {
|
||||
result.fold(
|
||||
(user) => router.pushWelcomeScreen(context, user),
|
||||
(error) => showSnapBar(context, error.msg),
|
||||
|
@ -8,7 +8,7 @@ import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB;
|
||||
import 'package:flowy_infra_ui/style_widget/snap_bar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@ -36,7 +36,7 @@ class SignUpScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSuccessOrFail(BuildContext context, Either<UserProfile, FlowyError> result) {
|
||||
void _handleSuccessOrFail(BuildContext context, Either<UserProfilePB, FlowyError> result) {
|
||||
result.fold(
|
||||
(user) => router.pushWelcomeScreen(context, user),
|
||||
(error) => showSnapBar(context, error.msg),
|
||||
|
@ -116,8 +116,8 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
||||
|
||||
void _openCurrentWorkspace(
|
||||
BuildContext context,
|
||||
UserProfile user,
|
||||
dartz.Either<CurrentWorkspaceSetting, FlowyError> workspacesOrError,
|
||||
UserProfilePB user,
|
||||
dartz.Either<CurrentWorkspaceSettingPB, FlowyError> workspacesOrError,
|
||||
) {
|
||||
workspacesOrError.fold(
|
||||
(workspaceSetting) {
|
||||
|
@ -12,7 +12,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
|
||||
class WelcomeScreen extends StatelessWidget {
|
||||
final UserProfile userProfile;
|
||||
final UserProfilePB userProfile;
|
||||
const WelcomeScreen({
|
||||
Key? key,
|
||||
required this.userProfile,
|
||||
@ -65,7 +65,7 @@ class WelcomeScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _renderList(List<Workspace> workspaces) {
|
||||
Widget _renderList(List<WorkspacePB> workspaces) {
|
||||
return Expanded(
|
||||
child: StyledListView(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
@ -80,7 +80,7 @@ class WelcomeScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _handleOnPress(BuildContext context, Workspace workspace) {
|
||||
void _handleOnPress(BuildContext context, WorkspacePB workspace) {
|
||||
context.read<WelcomeBloc>().add(WelcomeEvent.openWorkspace(workspace));
|
||||
|
||||
Navigator.of(context).pop(workspace.id);
|
||||
@ -88,8 +88,8 @@ class WelcomeScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
class WorkspaceItem extends StatelessWidget {
|
||||
final Workspace workspace;
|
||||
final void Function(Workspace workspace) onPressed;
|
||||
final WorkspacePB workspace;
|
||||
final void Function(WorkspacePB workspace) onPressed;
|
||||
const WorkspaceItem({Key? key, required this.workspace, required this.onPressed}) : super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -18,7 +18,7 @@ import 'package:dartz/dartz.dart';
|
||||
part 'app_bloc.freezed.dart';
|
||||
|
||||
class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
final App app;
|
||||
final AppPB app;
|
||||
final AppService appService;
|
||||
final AppListener appListener;
|
||||
|
||||
@ -103,7 +103,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _didReceiveViewUpdated(List<View> views, Emitter<AppState> emit) async {
|
||||
Future<void> _didReceiveViewUpdated(List<ViewPB> views, Emitter<AppState> emit) async {
|
||||
final latestCreatedView = state.latestCreatedView;
|
||||
AppState newState = state.copyWith(views: views);
|
||||
if (latestCreatedView != null) {
|
||||
@ -139,20 +139,20 @@ class AppEvent with _$AppEvent {
|
||||
) = CreateView;
|
||||
const factory AppEvent.delete() = Delete;
|
||||
const factory AppEvent.rename(String newName) = Rename;
|
||||
const factory AppEvent.didReceiveViewUpdated(List<View> views) = ReceiveViews;
|
||||
const factory AppEvent.appDidUpdate(App app) = AppDidUpdate;
|
||||
const factory AppEvent.didReceiveViewUpdated(List<ViewPB> views) = ReceiveViews;
|
||||
const factory AppEvent.appDidUpdate(AppPB app) = AppDidUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class AppState with _$AppState {
|
||||
const factory AppState({
|
||||
required App app,
|
||||
required List<View> views,
|
||||
View? latestCreatedView,
|
||||
required AppPB app,
|
||||
required List<ViewPB> views,
|
||||
ViewPB? latestCreatedView,
|
||||
required Either<Unit, FlowyError> successOrFailure,
|
||||
}) = _AppState;
|
||||
|
||||
factory AppState.initial(App app) => AppState(
|
||||
factory AppState.initial(AppPB app) => AppState(
|
||||
app: app,
|
||||
views: [],
|
||||
successOrFailure: left(unit),
|
||||
@ -161,8 +161,8 @@ class AppState with _$AppState {
|
||||
|
||||
class AppViewDataContext extends ChangeNotifier {
|
||||
final String appId;
|
||||
final ValueNotifier<List<View>> _viewsNotifier = ValueNotifier([]);
|
||||
final ValueNotifier<View?> _selectedViewNotifier = ValueNotifier(null);
|
||||
final ValueNotifier<List<ViewPB>> _viewsNotifier = ValueNotifier([]);
|
||||
final ValueNotifier<ViewPB?> _selectedViewNotifier = ValueNotifier(null);
|
||||
VoidCallback? _menuSharedStateListener;
|
||||
ExpandableController expandController = ExpandableController(initialExpanded: false);
|
||||
|
||||
@ -173,7 +173,7 @@ class AppViewDataContext extends ChangeNotifier {
|
||||
});
|
||||
}
|
||||
|
||||
VoidCallback addSelectedViewChangeListener(void Function(View?) callback) {
|
||||
VoidCallback addSelectedViewChangeListener(void Function(ViewPB?) callback) {
|
||||
listener() {
|
||||
callback(_selectedViewNotifier.value);
|
||||
}
|
||||
@ -186,7 +186,7 @@ class AppViewDataContext extends ChangeNotifier {
|
||||
_selectedViewNotifier.removeListener(listener);
|
||||
}
|
||||
|
||||
void _setLatestView(View? view) {
|
||||
void _setLatestView(ViewPB? view) {
|
||||
view?.freeze();
|
||||
|
||||
if (_selectedViewNotifier.value != view) {
|
||||
@ -196,9 +196,9 @@ class AppViewDataContext extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
View? get selectedView => _selectedViewNotifier.value;
|
||||
ViewPB? get selectedView => _selectedViewNotifier.value;
|
||||
|
||||
set views(List<View> views) {
|
||||
set views(List<ViewPB> views) {
|
||||
if (_viewsNotifier.value != views) {
|
||||
_viewsNotifier.value = views;
|
||||
_expandIfNeed();
|
||||
@ -206,9 +206,9 @@ class AppViewDataContext extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
UnmodifiableListView<View> get views => UnmodifiableListView(_viewsNotifier.value);
|
||||
UnmodifiableListView<ViewPB> get views => UnmodifiableListView(_viewsNotifier.value);
|
||||
|
||||
VoidCallback addViewsChangeListener(void Function(UnmodifiableListView<View>) callback) {
|
||||
VoidCallback addViewsChangeListener(void Function(UnmodifiableListView<ViewPB>) callback) {
|
||||
listener() {
|
||||
callback(views);
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
typedef AppDidUpdateCallback = void Function(App app);
|
||||
typedef ViewsDidChangeCallback = void Function(Either<List<View>, FlowyError> viewsOrFailed);
|
||||
typedef AppDidUpdateCallback = void Function(AppPB app);
|
||||
typedef ViewsDidChangeCallback = void Function(Either<List<ViewPB>, FlowyError> viewsOrFailed);
|
||||
|
||||
class AppListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
@ -37,7 +37,7 @@ class AppListener {
|
||||
if (_viewsChanged != null) {
|
||||
result.fold(
|
||||
(payload) {
|
||||
final repeatedView = RepeatedView.fromBuffer(payload);
|
||||
final repeatedView = RepeatedViewPB.fromBuffer(payload);
|
||||
_viewsChanged!(left(repeatedView.items));
|
||||
},
|
||||
(error) => _viewsChanged!(right(error)),
|
||||
@ -48,7 +48,7 @@ class AppListener {
|
||||
if (_updated != null) {
|
||||
result.fold(
|
||||
(payload) {
|
||||
final app = App.fromBuffer(payload);
|
||||
final app = AppPB.fromBuffer(payload);
|
||||
_updated!(app);
|
||||
},
|
||||
(error) => Log.error(error),
|
||||
|
@ -14,20 +14,20 @@ class AppService {
|
||||
required this.appId,
|
||||
});
|
||||
|
||||
Future<Either<App, FlowyError>> getAppDesc({required String appId}) {
|
||||
final payload = AppId.create()..value = appId;
|
||||
Future<Either<AppPB, FlowyError>> getAppDesc({required String appId}) {
|
||||
final payload = AppIdPB.create()..value = appId;
|
||||
|
||||
return FolderEventReadApp(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<View, FlowyError>> createView({
|
||||
Future<Either<ViewPB, FlowyError>> createView({
|
||||
required String appId,
|
||||
required String name,
|
||||
required String desc,
|
||||
required PluginDataType dataType,
|
||||
required PluginType pluginType,
|
||||
}) {
|
||||
final payload = CreateViewPayload.create()
|
||||
final payload = CreateViewPayloadPB.create()
|
||||
..belongToId = appId
|
||||
..name = name
|
||||
..desc = desc
|
||||
@ -37,8 +37,8 @@ class AppService {
|
||||
return FolderEventCreateView(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<List<View>, FlowyError>> getViews({required String appId}) {
|
||||
final payload = AppId.create()..value = appId;
|
||||
Future<Either<List<ViewPB>, FlowyError>> getViews({required String appId}) {
|
||||
final payload = AppIdPB.create()..value = appId;
|
||||
|
||||
return FolderEventReadApp(payload).send().then((result) {
|
||||
return result.fold(
|
||||
@ -49,12 +49,12 @@ class AppService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> delete({required String appId}) {
|
||||
final request = AppId.create()..value = appId;
|
||||
final request = AppIdPB.create()..value = appId;
|
||||
return FolderEventDeleteApp(request).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> updateApp({required String appId, String? name}) {
|
||||
UpdateAppPayload payload = UpdateAppPayload.create()..appId = appId;
|
||||
UpdateAppPayloadPB payload = UpdateAppPayloadPB.create()..appId = appId;
|
||||
|
||||
if (name != null) {
|
||||
payload.name = name;
|
||||
@ -67,7 +67,7 @@ class AppService {
|
||||
required int fromIndex,
|
||||
required int toIndex,
|
||||
}) {
|
||||
final payload = MoveFolderItemPayload.create()
|
||||
final payload = MoveFolderItemPayloadPB.create()
|
||||
..itemId = viewId
|
||||
..from = fromIndex
|
||||
..to = toIndex
|
||||
|
@ -9,7 +9,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class AppearanceSettingModel extends ChangeNotifier with EquatableMixin {
|
||||
AppearanceSettings setting;
|
||||
AppearanceSettingsPB setting;
|
||||
AppTheme _theme;
|
||||
Locale _locale;
|
||||
Timer? _saveOperation;
|
||||
|
@ -17,7 +17,7 @@ part 'doc_bloc.freezed.dart';
|
||||
typedef FlutterQuillDocument = Document;
|
||||
|
||||
class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
|
||||
final View view;
|
||||
final ViewPB view;
|
||||
final DocumentService service;
|
||||
|
||||
final ViewListener listener;
|
||||
|
@ -6,24 +6,24 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-sync/text_block.pb.dart';
|
||||
|
||||
class DocumentService {
|
||||
Future<Either<TextBlockDelta, FlowyError>> openDocument({
|
||||
Future<Either<TextBlockDeltaPB, FlowyError>> openDocument({
|
||||
required String docId,
|
||||
}) async {
|
||||
await FolderEventSetLatestView(ViewId(value: docId)).send();
|
||||
await FolderEventSetLatestView(ViewIdPB(value: docId)).send();
|
||||
|
||||
final payload = TextBlockId(value: docId);
|
||||
final payload = TextBlockIdPB(value: docId);
|
||||
return TextBlockEventGetBlockData(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<TextBlockDelta, FlowyError>> composeDelta({required String docId, required String data}) {
|
||||
final payload = TextBlockDelta.create()
|
||||
Future<Either<TextBlockDeltaPB, FlowyError>> composeDelta({required String docId, required String data}) {
|
||||
final payload = TextBlockDeltaPB.create()
|
||||
..blockId = docId
|
||||
..deltaStr = data;
|
||||
return TextBlockEventApplyDelta(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> closeDocument({required String docId}) {
|
||||
final request = ViewId(value: docId);
|
||||
final request = ViewIdPB(value: docId);
|
||||
return FolderEventCloseView(request).send();
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ part 'share_bloc.freezed.dart';
|
||||
|
||||
class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
|
||||
ShareService service;
|
||||
View view;
|
||||
ViewPB view;
|
||||
DocShareBloc({required this.view, required this.service}) : super(const DocShareState.initial()) {
|
||||
on<DocShareEvent>((event, emit) async {
|
||||
await event.map(
|
||||
@ -33,7 +33,7 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
|
||||
});
|
||||
}
|
||||
|
||||
ExportData _convertDeltaToMarkdown(ExportData value) {
|
||||
ExportDataPB _convertDeltaToMarkdown(ExportDataPB value) {
|
||||
final result = deltaToMarkdown(value.data);
|
||||
value.data = result;
|
||||
writeFile(result);
|
||||
@ -73,5 +73,5 @@ class DocShareEvent with _$DocShareEvent {
|
||||
class DocShareState with _$DocShareState {
|
||||
const factory DocShareState.initial() = _Initial;
|
||||
const factory DocShareState.loading() = _Loading;
|
||||
const factory DocShareState.finish(Either<ExportData, FlowyError> successOrFail) = _Finish;
|
||||
const factory DocShareState.finish(Either<ExportDataPB, FlowyError> successOrFail) = _Finish;
|
||||
}
|
||||
|
@ -5,23 +5,23 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-text-block/protobuf.dart';
|
||||
|
||||
class ShareService {
|
||||
Future<Either<ExportData, FlowyError>> export(String docId, ExportType type) {
|
||||
final request = ExportPayload.create()
|
||||
Future<Either<ExportDataPB, FlowyError>> export(String docId, ExportType type) {
|
||||
final request = ExportPayloadPB.create()
|
||||
..viewId = docId
|
||||
..exportType = type;
|
||||
|
||||
return TextBlockEventExportDocument(request).send();
|
||||
}
|
||||
|
||||
Future<Either<ExportData, FlowyError>> exportText(String docId) {
|
||||
Future<Either<ExportDataPB, FlowyError>> exportText(String docId) {
|
||||
return export(docId, ExportType.Text);
|
||||
}
|
||||
|
||||
Future<Either<ExportData, FlowyError>> exportMarkdown(String docId) {
|
||||
Future<Either<ExportDataPB, FlowyError>> exportMarkdown(String docId) {
|
||||
return export(docId, ExportType.Markdown);
|
||||
}
|
||||
|
||||
Future<Either<ExportData, FlowyError>> exportURL(String docId) {
|
||||
Future<Either<ExportDataPB, FlowyError>> exportURL(String docId) {
|
||||
return export(docId, ExportType.Link);
|
||||
}
|
||||
}
|
||||
|
@ -6,24 +6,25 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
|
||||
import 'block_listener.dart';
|
||||
|
||||
class GridBlockCacheService {
|
||||
/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information
|
||||
class GridBlockCache {
|
||||
final String gridId;
|
||||
final GridBlock block;
|
||||
late GridRowCacheService _rowCache;
|
||||
final GridBlockPB block;
|
||||
late GridRowCache _rowCache;
|
||||
late GridBlockListener _listener;
|
||||
|
||||
List<GridRow> get rows => _rowCache.rows;
|
||||
GridRowCacheService get rowCache => _rowCache;
|
||||
List<GridRowInfo> get rows => _rowCache.rows;
|
||||
GridRowCache get rowCache => _rowCache;
|
||||
|
||||
GridBlockCacheService({
|
||||
GridBlockCache({
|
||||
required this.gridId,
|
||||
required this.block,
|
||||
required GridFieldCache fieldCache,
|
||||
}) {
|
||||
_rowCache = GridRowCacheService(
|
||||
_rowCache = GridRowCache(
|
||||
gridId: gridId,
|
||||
block: block,
|
||||
delegate: GridRowCacheDelegateImpl(fieldCache),
|
||||
notifier: GridRowCacheFieldNotifierImpl(fieldCache),
|
||||
);
|
||||
|
||||
_listener = GridBlockListener(blockId: block.id);
|
@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
|
||||
typedef GridBlockUpdateNotifierValue = Either<List<GridBlockChangeset>, FlowyError>;
|
||||
typedef GridBlockUpdateNotifierValue = Either<List<GridBlockChangesetPB>, FlowyError>;
|
||||
|
||||
class GridBlockListener {
|
||||
final String blockId;
|
||||
@ -33,7 +33,7 @@ class GridBlockListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateGridBlock:
|
||||
result.fold(
|
||||
(payload) => _rowsUpdateNotifier?.value = left([GridBlockChangeset.fromBuffer(payload)]),
|
||||
(payload) => _rowsUpdateNotifier?.value = left([GridBlockChangesetPB.fromBuffer(payload)]),
|
||||
(error) => _rowsUpdateNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
@ -1,109 +0,0 @@
|
||||
part of 'cell_service.dart';
|
||||
|
||||
typedef GridCellMap = LinkedHashMap<String, GridCell>;
|
||||
|
||||
class _GridCellCacheObject {
|
||||
_GridCellCacheKey key;
|
||||
dynamic object;
|
||||
_GridCellCacheObject({
|
||||
required this.key,
|
||||
required this.object,
|
||||
});
|
||||
}
|
||||
|
||||
class _GridCellCacheKey {
|
||||
final String fieldId;
|
||||
final String rowId;
|
||||
_GridCellCacheKey({
|
||||
required this.fieldId,
|
||||
required this.rowId,
|
||||
});
|
||||
}
|
||||
|
||||
abstract class GridCellCacheDelegate {
|
||||
void onFieldUpdated(void Function(Field) callback);
|
||||
}
|
||||
|
||||
class GridCellCacheService {
|
||||
final String gridId;
|
||||
final GridCellCacheDelegate delegate;
|
||||
|
||||
/// fieldId: {objectId: callback}
|
||||
final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId = {};
|
||||
|
||||
/// fieldId: {cacheKey: cacheData}
|
||||
final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
|
||||
GridCellCacheService({
|
||||
required this.gridId,
|
||||
required this.delegate,
|
||||
}) {
|
||||
delegate.onFieldUpdated((field) {
|
||||
_cellDataByFieldId.remove(field.id);
|
||||
final map = _fieldListenerByFieldId[field.id];
|
||||
if (map != null) {
|
||||
for (final callbacks in map.values) {
|
||||
for (final callback in callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void addFieldListener(_GridCellCacheKey cacheKey, VoidCallback onFieldChanged) {
|
||||
var map = _fieldListenerByFieldId[cacheKey.fieldId];
|
||||
if (map == null) {
|
||||
_fieldListenerByFieldId[cacheKey.fieldId] = {};
|
||||
map = _fieldListenerByFieldId[cacheKey.fieldId];
|
||||
map![cacheKey.rowId] = [onFieldChanged];
|
||||
} else {
|
||||
var objects = map[cacheKey.rowId];
|
||||
if (objects == null) {
|
||||
map[cacheKey.rowId] = [onFieldChanged];
|
||||
} else {
|
||||
objects.add(onFieldChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeFieldListener(_GridCellCacheKey cacheKey, VoidCallback fn) {
|
||||
var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId];
|
||||
final index = callbacks?.indexWhere((callback) => callback == fn);
|
||||
if (index != null && index != -1) {
|
||||
callbacks?.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
void insert<T extends _GridCellCacheObject>(T item) {
|
||||
var map = _cellDataByFieldId[item.key.fieldId];
|
||||
if (map == null) {
|
||||
_cellDataByFieldId[item.key.fieldId] = {};
|
||||
map = _cellDataByFieldId[item.key.fieldId];
|
||||
}
|
||||
|
||||
map![item.key.rowId] = item.object;
|
||||
}
|
||||
|
||||
T? get<T>(_GridCellCacheKey key) {
|
||||
final map = _cellDataByFieldId[key.fieldId];
|
||||
if (map == null) {
|
||||
return null;
|
||||
} else {
|
||||
final object = map[key.rowId];
|
||||
if (object is T) {
|
||||
return object;
|
||||
} else {
|
||||
if (object != null) {
|
||||
Log.error("Cache data type does not match the cache data type");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
_fieldListenerByFieldId.clear();
|
||||
_cellDataByFieldId.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
part of 'cell_service.dart';
|
||||
|
||||
typedef GridCellMap = LinkedHashMap<String, GridCellIdentifier>;
|
||||
|
||||
class GridCell {
|
||||
dynamic object;
|
||||
GridCell({
|
||||
required this.object,
|
||||
});
|
||||
}
|
||||
|
||||
/// Use to index the cell in the grid.
|
||||
/// We use [fieldId + rowId] to identify the cell.
|
||||
class GridCellCacheKey {
|
||||
final String fieldId;
|
||||
final String rowId;
|
||||
GridCellCacheKey({
|
||||
required this.fieldId,
|
||||
required this.rowId,
|
||||
});
|
||||
}
|
||||
|
||||
/// GridCellCache is used to cache cell data of each block.
|
||||
/// We use GridCellCacheKey to index the cell in the cache.
|
||||
/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid
|
||||
/// for more information
|
||||
class GridCellCache {
|
||||
final String gridId;
|
||||
|
||||
/// fieldId: {cacheKey: GridCell}
|
||||
final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
|
||||
GridCellCache({
|
||||
required this.gridId,
|
||||
});
|
||||
|
||||
void remove(String fieldId) {
|
||||
_cellDataByFieldId.remove(fieldId);
|
||||
}
|
||||
|
||||
void insert<T extends GridCell>(GridCellCacheKey key, T value) {
|
||||
var map = _cellDataByFieldId[key.fieldId];
|
||||
if (map == null) {
|
||||
_cellDataByFieldId[key.fieldId] = {};
|
||||
map = _cellDataByFieldId[key.fieldId];
|
||||
}
|
||||
|
||||
map![key.rowId] = value.object;
|
||||
}
|
||||
|
||||
T? get<T>(GridCellCacheKey key) {
|
||||
final map = _cellDataByFieldId[key.fieldId];
|
||||
if (map == null) {
|
||||
return null;
|
||||
} else {
|
||||
final value = map[key.rowId];
|
||||
if (value is T) {
|
||||
return value;
|
||||
} else {
|
||||
if (value != null) {
|
||||
Log.error("Expected value type: $T, but receive $value");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
_cellDataByFieldId.clear();
|
||||
}
|
||||
}
|
@ -3,60 +3,28 @@ part of 'cell_service.dart';
|
||||
abstract class IGridCellDataConfig {
|
||||
// The cell data will reload if it receives the field's change notification.
|
||||
bool get reloadOnFieldChanged;
|
||||
|
||||
// When the reloadOnCellChanged is true, it will load the cell data after user input.
|
||||
// For example: The number cell reload the cell data that carries the format
|
||||
// user input: 12
|
||||
// cell display: $12
|
||||
bool get reloadOnCellChanged;
|
||||
}
|
||||
|
||||
class GridCellDataConfig implements IGridCellDataConfig {
|
||||
@override
|
||||
final bool reloadOnCellChanged;
|
||||
|
||||
@override
|
||||
final bool reloadOnFieldChanged;
|
||||
|
||||
const GridCellDataConfig({
|
||||
this.reloadOnCellChanged = false,
|
||||
this.reloadOnFieldChanged = false,
|
||||
});
|
||||
}
|
||||
|
||||
abstract class IGridCellDataLoader<T> {
|
||||
Future<T?> loadData();
|
||||
|
||||
IGridCellDataConfig get config;
|
||||
}
|
||||
|
||||
abstract class ICellDataParser<T> {
|
||||
abstract class IGridCellDataParser<T> {
|
||||
T? parserData(List<int> data);
|
||||
}
|
||||
|
||||
class GridCellDataLoader<T> extends IGridCellDataLoader<T> {
|
||||
class GridCellDataLoader<T> {
|
||||
final CellService service = CellService();
|
||||
final GridCell gridCell;
|
||||
final ICellDataParser<T> parser;
|
||||
|
||||
@override
|
||||
final IGridCellDataConfig config;
|
||||
final GridCellIdentifier cellId;
|
||||
final IGridCellDataParser<T> parser;
|
||||
final bool reloadOnFieldChanged;
|
||||
|
||||
GridCellDataLoader({
|
||||
required this.gridCell,
|
||||
required this.cellId,
|
||||
required this.parser,
|
||||
this.config = const GridCellDataConfig(),
|
||||
this.reloadOnFieldChanged = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<T?> loadData() {
|
||||
final fut = service.getCell(
|
||||
gridId: gridCell.gridId,
|
||||
fieldId: gridCell.field.id,
|
||||
rowId: gridCell.rowId,
|
||||
);
|
||||
final fut = service.getCell(cellId: cellId);
|
||||
return fut.then(
|
||||
(result) => result.fold((Cell cell) {
|
||||
(result) => result.fold((GridCellPB cell) {
|
||||
try {
|
||||
return parser.parserData(cell.data);
|
||||
} catch (e, s) {
|
||||
@ -72,30 +40,7 @@ class GridCellDataLoader<T> extends IGridCellDataLoader<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class SelectOptionCellDataLoader extends IGridCellDataLoader<SelectOptionCellData> {
|
||||
final SelectOptionService service;
|
||||
final GridCell gridCell;
|
||||
SelectOptionCellDataLoader({
|
||||
required this.gridCell,
|
||||
}) : service = SelectOptionService(gridCell: gridCell);
|
||||
@override
|
||||
Future<SelectOptionCellData?> loadData() async {
|
||||
return service.getOpitonContext().then((result) {
|
||||
return result.fold(
|
||||
(data) => data,
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return null;
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
IGridCellDataConfig get config => const GridCellDataConfig(reloadOnFieldChanged: true);
|
||||
}
|
||||
|
||||
class StringCellDataParser implements ICellDataParser<String> {
|
||||
class StringCellDataParser implements IGridCellDataParser<String> {
|
||||
@override
|
||||
String? parserData(List<int> data) {
|
||||
final s = utf8.decode(data);
|
||||
@ -103,32 +48,32 @@ class StringCellDataParser implements ICellDataParser<String> {
|
||||
}
|
||||
}
|
||||
|
||||
class DateCellDataParser implements ICellDataParser<DateCellData> {
|
||||
class DateCellDataParser implements IGridCellDataParser<DateCellDataPB> {
|
||||
@override
|
||||
DateCellData? parserData(List<int> data) {
|
||||
DateCellDataPB? parserData(List<int> data) {
|
||||
if (data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return DateCellData.fromBuffer(data);
|
||||
return DateCellDataPB.fromBuffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
class SelectOptionCellDataParser implements ICellDataParser<SelectOptionCellData> {
|
||||
class SelectOptionCellDataParser implements IGridCellDataParser<SelectOptionCellDataPB> {
|
||||
@override
|
||||
SelectOptionCellData? parserData(List<int> data) {
|
||||
SelectOptionCellDataPB? parserData(List<int> data) {
|
||||
if (data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return SelectOptionCellData.fromBuffer(data);
|
||||
return SelectOptionCellDataPB.fromBuffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
class URLCellDataParser implements ICellDataParser<URLCellData> {
|
||||
class URLCellDataParser implements IGridCellDataParser<URLCellDataPB> {
|
||||
@override
|
||||
URLCellData? parserData(List<int> data) {
|
||||
URLCellDataPB? parserData(List<int> data) {
|
||||
if (data.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return URLCellData.fromBuffer(data);
|
||||
return URLCellDataPB.fromBuffer(data);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
part of 'cell_service.dart';
|
||||
|
||||
abstract class _GridCellDataPersistence<D> {
|
||||
/// Save the cell data to disk
|
||||
/// You can extend this class to do custom operations. For example, the DateCellDataPersistence.
|
||||
abstract class IGridCellDataPersistence<D> {
|
||||
Future<Option<FlowyError>> save(D data);
|
||||
}
|
||||
|
||||
class CellDataPersistence implements _GridCellDataPersistence<String> {
|
||||
final GridCell gridCell;
|
||||
class CellDataPersistence implements IGridCellDataPersistence<String> {
|
||||
final GridCellIdentifier cellId;
|
||||
|
||||
CellDataPersistence({
|
||||
required this.gridCell,
|
||||
required this.cellId,
|
||||
});
|
||||
final CellService _cellService = CellService();
|
||||
|
||||
@override
|
||||
Future<Option<FlowyError>> save(String data) async {
|
||||
final fut = _cellService.updateCell(
|
||||
gridId: gridCell.gridId,
|
||||
fieldId: gridCell.field.id,
|
||||
rowId: gridCell.rowId,
|
||||
data: data,
|
||||
);
|
||||
final fut = _cellService.updateCell(cellId: cellId, data: data);
|
||||
|
||||
return fut.then((result) {
|
||||
return result.fold(
|
||||
@ -35,15 +32,15 @@ class CalendarData with _$CalendarData {
|
||||
const factory CalendarData({required DateTime date, String? time}) = _CalendarData;
|
||||
}
|
||||
|
||||
class DateCellDataPersistence implements _GridCellDataPersistence<CalendarData> {
|
||||
final GridCell gridCell;
|
||||
class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData> {
|
||||
final GridCellIdentifier cellId;
|
||||
DateCellDataPersistence({
|
||||
required this.gridCell,
|
||||
required this.cellId,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Option<FlowyError>> save(CalendarData data) {
|
||||
var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell);
|
||||
var payload = DateChangesetPayloadPB.create()..cellIdentifier = _makeCellIdPayload(cellId);
|
||||
|
||||
final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
|
||||
payload.date = date;
|
||||
@ -61,9 +58,9 @@ class DateCellDataPersistence implements _GridCellDataPersistence<CalendarData>
|
||||
}
|
||||
}
|
||||
|
||||
CellIdentifierPayload _cellIdentifier(GridCell gridCell) {
|
||||
return CellIdentifierPayload.create()
|
||||
..gridId = gridCell.gridId
|
||||
..fieldId = gridCell.field.id
|
||||
..rowId = gridCell.rowId;
|
||||
GridCellIdPB _makeCellIdPayload(GridCellIdentifier cellId) {
|
||||
return GridCellIdPB.create()
|
||||
..gridId = cellId.gridId
|
||||
..fieldId = cellId.fieldId
|
||||
..rowId = cellId.rowId;
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'cell_service.dart';
|
||||
|
||||
abstract class GridFieldChangedNotifier {
|
||||
void onFieldChanged(void Function(GridFieldPB) callback);
|
||||
void dispose();
|
||||
}
|
||||
|
||||
/// GridPB's cell helper wrapper that enables each cell will get notified when the corresponding field was changed.
|
||||
/// You Register an onFieldChanged callback to listen to the cell changes, and unregister if you don't want to listen.
|
||||
class GridCellFieldNotifier {
|
||||
/// fieldId: {objectId: callback}
|
||||
final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId = {};
|
||||
|
||||
GridCellFieldNotifier({required GridFieldChangedNotifier notifier}) {
|
||||
notifier.onFieldChanged(
|
||||
(field) {
|
||||
final map = _fieldListenerByFieldId[field.id];
|
||||
if (map != null) {
|
||||
for (final callbacks in map.values) {
|
||||
for (final callback in callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
void register(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) {
|
||||
var map = _fieldListenerByFieldId[cacheKey.fieldId];
|
||||
if (map == null) {
|
||||
_fieldListenerByFieldId[cacheKey.fieldId] = {};
|
||||
map = _fieldListenerByFieldId[cacheKey.fieldId];
|
||||
map![cacheKey.rowId] = [onFieldChanged];
|
||||
} else {
|
||||
var objects = map[cacheKey.rowId];
|
||||
if (objects == null) {
|
||||
map[cacheKey.rowId] = [onFieldChanged];
|
||||
} else {
|
||||
objects.add(onFieldChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unregister(GridCellCacheKey cacheKey, VoidCallback fn) {
|
||||
var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId];
|
||||
final index = callbacks?.indexWhere((callback) => callback == fn);
|
||||
if (index != null && index != -1) {
|
||||
callbacks?.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
_fieldListenerByFieldId.clear();
|
||||
}
|
||||
}
|
@ -1,26 +1,29 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:app_flowy/workspace/application/grid/grid_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.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/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'dart:convert' show utf8;
|
||||
|
||||
import '../../field/type_option/type_option_service.dart';
|
||||
import 'cell_field_notifier.dart';
|
||||
part 'cell_service.freezed.dart';
|
||||
part 'cell_data_loader.dart';
|
||||
part 'context_builder.dart';
|
||||
part 'cache.dart';
|
||||
part 'cell_cache.dart';
|
||||
part 'cell_data_persistence.dart';
|
||||
|
||||
// key: rowId
|
||||
@ -29,44 +32,46 @@ class CellService {
|
||||
CellService();
|
||||
|
||||
Future<Either<void, FlowyError>> updateCell({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
required GridCellIdentifier cellId,
|
||||
required String data,
|
||||
}) {
|
||||
final payload = CellChangeset.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId
|
||||
final payload = CellChangesetPB.create()
|
||||
..gridId = cellId.gridId
|
||||
..fieldId = cellId.fieldId
|
||||
..rowId = cellId.rowId
|
||||
..content = data;
|
||||
return GridEventUpdateCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Cell, FlowyError>> getCell({
|
||||
required String gridId,
|
||||
required String fieldId,
|
||||
required String rowId,
|
||||
Future<Either<GridCellPB, FlowyError>> getCell({
|
||||
required GridCellIdentifier cellId,
|
||||
}) {
|
||||
final payload = CellIdentifierPayload.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
final payload = GridCellIdPB.create()
|
||||
..gridId = cellId.gridId
|
||||
..fieldId = cellId.fieldId
|
||||
..rowId = cellId.rowId;
|
||||
return GridEventGetCell(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
/// Id of the cell
|
||||
/// We can locate the cell by using gridId + rowId + field.id.
|
||||
@freezed
|
||||
class GridCell with _$GridCell {
|
||||
const factory GridCell({
|
||||
class GridCellIdentifier with _$GridCellIdentifier {
|
||||
const factory GridCellIdentifier({
|
||||
required String gridId,
|
||||
required String rowId,
|
||||
required Field field,
|
||||
}) = _GridCell;
|
||||
required GridFieldPB field,
|
||||
}) = _GridCellIdentifier;
|
||||
|
||||
// ignore: unused_element
|
||||
const GridCell._();
|
||||
const GridCellIdentifier._();
|
||||
|
||||
String cellId() {
|
||||
return rowId + field.id + "${field.fieldType}";
|
||||
String get fieldId => field.id;
|
||||
|
||||
FieldType get fieldType => field.fieldType;
|
||||
|
||||
ValueKey key() {
|
||||
return ValueKey(rowId + fieldId + "${field.fieldType}");
|
||||
}
|
||||
}
|
||||
|
@ -1,154 +1,183 @@
|
||||
part of 'cell_service.dart';
|
||||
|
||||
typedef GridCellContext = _GridCellContext<String, String>;
|
||||
typedef GridSelectOptionCellContext = _GridCellContext<SelectOptionCellData, String>;
|
||||
typedef GridDateCellContext = _GridCellContext<DateCellData, CalendarData>;
|
||||
typedef GridURLCellContext = _GridCellContext<URLCellData, String>;
|
||||
typedef GridCellController = IGridCellController<String, String>;
|
||||
typedef GridSelectOptionCellController = IGridCellController<SelectOptionCellDataPB, String>;
|
||||
typedef GridDateCellController = IGridCellController<DateCellDataPB, CalendarData>;
|
||||
typedef GridURLCellController = IGridCellController<URLCellDataPB, String>;
|
||||
|
||||
class GridCellContextBuilder {
|
||||
final GridCellCacheService _cellCache;
|
||||
final GridCell _gridCell;
|
||||
GridCellContextBuilder({
|
||||
required GridCellCacheService cellCache,
|
||||
required GridCell gridCell,
|
||||
class GridCellControllerBuilder {
|
||||
final GridCellIdentifier _cellId;
|
||||
final GridCellCache _cellCache;
|
||||
final GridFieldCache _fieldCache;
|
||||
|
||||
GridCellControllerBuilder({
|
||||
required GridCellIdentifier cellId,
|
||||
required GridCellCache cellCache,
|
||||
required GridFieldCache fieldCache,
|
||||
}) : _cellCache = cellCache,
|
||||
_gridCell = gridCell;
|
||||
_fieldCache = fieldCache,
|
||||
_cellId = cellId;
|
||||
|
||||
_GridCellContext build() {
|
||||
switch (_gridCell.field.fieldType) {
|
||||
IGridCellController build() {
|
||||
final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache));
|
||||
|
||||
switch (_cellId.fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
final cellDataLoader = GridCellDataLoader(
|
||||
gridCell: _gridCell,
|
||||
cellId: _cellId,
|
||||
parser: StringCellDataParser(),
|
||||
);
|
||||
return GridCellContext(
|
||||
gridCell: _gridCell,
|
||||
return GridCellController(
|
||||
cellId: _cellId,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||
fieldNotifier: cellFieldNotifier,
|
||||
cellDataPersistence: CellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
final cellDataLoader = GridCellDataLoader(
|
||||
gridCell: _gridCell,
|
||||
cellId: _cellId,
|
||||
parser: DateCellDataParser(),
|
||||
config: const GridCellDataConfig(reloadOnFieldChanged: true),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
|
||||
return GridDateCellContext(
|
||||
gridCell: _gridCell,
|
||||
return GridDateCellController(
|
||||
cellId: _cellId,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
|
||||
fieldNotifier: cellFieldNotifier,
|
||||
cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
case FieldType.Number:
|
||||
final cellDataLoader = GridCellDataLoader(
|
||||
gridCell: _gridCell,
|
||||
cellId: _cellId,
|
||||
parser: StringCellDataParser(),
|
||||
config: const GridCellDataConfig(reloadOnCellChanged: true, reloadOnFieldChanged: true),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
return GridCellContext(
|
||||
gridCell: _gridCell,
|
||||
return GridCellController(
|
||||
cellId: _cellId,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||
fieldNotifier: cellFieldNotifier,
|
||||
cellDataPersistence: CellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
case FieldType.RichText:
|
||||
final cellDataLoader = GridCellDataLoader(
|
||||
gridCell: _gridCell,
|
||||
cellId: _cellId,
|
||||
parser: StringCellDataParser(),
|
||||
);
|
||||
return GridCellContext(
|
||||
gridCell: _gridCell,
|
||||
return GridCellController(
|
||||
cellId: _cellId,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||
fieldNotifier: cellFieldNotifier,
|
||||
cellDataPersistence: CellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
case FieldType.MultiSelect:
|
||||
case FieldType.SingleSelect:
|
||||
final cellDataLoader = GridCellDataLoader(
|
||||
gridCell: _gridCell,
|
||||
cellId: _cellId,
|
||||
parser: SelectOptionCellDataParser(),
|
||||
config: const GridCellDataConfig(reloadOnFieldChanged: true),
|
||||
reloadOnFieldChanged: true,
|
||||
);
|
||||
|
||||
return GridSelectOptionCellContext(
|
||||
gridCell: _gridCell,
|
||||
return GridSelectOptionCellController(
|
||||
cellId: _cellId,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||
fieldNotifier: cellFieldNotifier,
|
||||
cellDataPersistence: CellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
|
||||
case FieldType.URL:
|
||||
final cellDataLoader = GridCellDataLoader(
|
||||
gridCell: _gridCell,
|
||||
cellId: _cellId,
|
||||
parser: URLCellDataParser(),
|
||||
);
|
||||
return GridURLCellContext(
|
||||
gridCell: _gridCell,
|
||||
return GridURLCellController(
|
||||
cellId: _cellId,
|
||||
cellCache: _cellCache,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||
fieldNotifier: cellFieldNotifier,
|
||||
cellDataPersistence: CellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
}
|
||||
throw UnimplementedError;
|
||||
}
|
||||
}
|
||||
|
||||
// T: the type of the CellData
|
||||
// D: the type of the data that will be save to disk
|
||||
/// IGridCellController is used to manipulate the cell and receive notifications.
|
||||
/// * Read/Write cell data
|
||||
/// * Listen on field/cell notifications.
|
||||
///
|
||||
/// Generic T represents the type of the cell data.
|
||||
/// Generic D represents the type of data that will be saved to the disk
|
||||
///
|
||||
// ignore: must_be_immutable
|
||||
class _GridCellContext<T, D> extends Equatable {
|
||||
final GridCell gridCell;
|
||||
final GridCellCacheService cellCache;
|
||||
final _GridCellCacheKey _cacheKey;
|
||||
final IGridCellDataLoader<T> cellDataLoader;
|
||||
final _GridCellDataPersistence<D> cellDataPersistence;
|
||||
class IGridCellController<T, D> extends Equatable {
|
||||
final GridCellIdentifier cellId;
|
||||
final GridCellCache _cellsCache;
|
||||
final GridCellCacheKey _cacheKey;
|
||||
final FieldService _fieldService;
|
||||
final GridCellFieldNotifier _fieldNotifier;
|
||||
final GridCellDataLoader<T> _cellDataLoader;
|
||||
final IGridCellDataPersistence<D> _cellDataPersistence;
|
||||
|
||||
late final CellListener _cellListener;
|
||||
late final ValueNotifier<T?>? _cellDataNotifier;
|
||||
ValueNotifier<T?>? _cellDataNotifier;
|
||||
|
||||
bool isListening = false;
|
||||
VoidCallback? _onFieldChangedFn;
|
||||
Timer? _loadDataOperation;
|
||||
Timer? _saveDataOperation;
|
||||
bool _isDispose = false;
|
||||
|
||||
_GridCellContext({
|
||||
required this.gridCell,
|
||||
required this.cellCache,
|
||||
required this.cellDataLoader,
|
||||
required this.cellDataPersistence,
|
||||
}) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
|
||||
_cacheKey = _GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id);
|
||||
IGridCellController({
|
||||
required this.cellId,
|
||||
required GridCellCache cellCache,
|
||||
required GridCellFieldNotifier fieldNotifier,
|
||||
required GridCellDataLoader<T> cellDataLoader,
|
||||
required IGridCellDataPersistence<D> cellDataPersistence,
|
||||
}) : _cellsCache = cellCache,
|
||||
_cellDataLoader = cellDataLoader,
|
||||
_cellDataPersistence = cellDataPersistence,
|
||||
_fieldNotifier = fieldNotifier,
|
||||
_fieldService = FieldService(gridId: cellId.gridId, fieldId: cellId.field.id),
|
||||
_cacheKey = GridCellCacheKey(rowId: cellId.rowId, fieldId: cellId.field.id);
|
||||
|
||||
_GridCellContext<T, D> clone() {
|
||||
return _GridCellContext(
|
||||
gridCell: gridCell,
|
||||
cellDataLoader: cellDataLoader,
|
||||
cellCache: cellCache,
|
||||
cellDataPersistence: cellDataPersistence);
|
||||
IGridCellController<T, D> clone() {
|
||||
return IGridCellController(
|
||||
cellId: cellId,
|
||||
cellDataLoader: _cellDataLoader,
|
||||
cellCache: _cellsCache,
|
||||
fieldNotifier: _fieldNotifier,
|
||||
cellDataPersistence: _cellDataPersistence);
|
||||
}
|
||||
|
||||
String get gridId => gridCell.gridId;
|
||||
String get gridId => cellId.gridId;
|
||||
|
||||
String get rowId => gridCell.rowId;
|
||||
String get rowId => cellId.rowId;
|
||||
|
||||
String get cellId => gridCell.rowId + gridCell.field.id;
|
||||
String get fieldId => cellId.field.id;
|
||||
|
||||
String get fieldId => gridCell.field.id;
|
||||
GridFieldPB get field => cellId.field;
|
||||
|
||||
Field get field => gridCell.field;
|
||||
FieldType get fieldType => cellId.field.fieldType;
|
||||
|
||||
FieldType get fieldType => gridCell.field.fieldType;
|
||||
|
||||
VoidCallback? startListening({required void Function(T?) onCellChanged}) {
|
||||
VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) {
|
||||
if (isListening) {
|
||||
Log.error("Already started. It seems like you should call clone first");
|
||||
return null;
|
||||
}
|
||||
|
||||
isListening = true;
|
||||
_cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey));
|
||||
_cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id);
|
||||
|
||||
_cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey));
|
||||
_cellListener = CellListener(rowId: cellId.rowId, fieldId: cellId.field.id);
|
||||
|
||||
/// 1.Listen on user edit event and load the new cell data if needed.
|
||||
/// For example:
|
||||
/// user input: 12
|
||||
/// cell display: $12
|
||||
_cellListener.start(onCellChanged: (result) {
|
||||
result.fold(
|
||||
(_) => _loadData(),
|
||||
@ -156,22 +185,27 @@ class _GridCellContext<T, D> extends Equatable {
|
||||
);
|
||||
});
|
||||
|
||||
if (cellDataLoader.config.reloadOnFieldChanged) {
|
||||
/// 2.Listen on the field event and load the cell data if needed.
|
||||
_onFieldChangedFn = () {
|
||||
if (onCellFieldChanged != null) {
|
||||
onCellFieldChanged();
|
||||
}
|
||||
|
||||
/// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
|
||||
/// For example:
|
||||
/// ¥12 -> $12
|
||||
if (_cellDataLoader.reloadOnFieldChanged) {
|
||||
_loadData();
|
||||
}
|
||||
};
|
||||
cellCache.addFieldListener(_cacheKey, _onFieldChangedFn!);
|
||||
}
|
||||
|
||||
onCellChangedFn() {
|
||||
onCellChanged(_cellDataNotifier?.value);
|
||||
|
||||
if (cellDataLoader.config.reloadOnCellChanged) {
|
||||
_loadData();
|
||||
}
|
||||
}
|
||||
_fieldNotifier.register(_cacheKey, _onFieldChangedFn!);
|
||||
|
||||
/// Notify the listener, the cell data was changed.
|
||||
onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
|
||||
_cellDataNotifier?.addListener(onCellChangedFn);
|
||||
|
||||
// Return the function pointer that can be used when calling removeListener.
|
||||
return onCellChangedFn;
|
||||
}
|
||||
|
||||
@ -179,29 +213,45 @@ class _GridCellContext<T, D> extends Equatable {
|
||||
_cellDataNotifier?.removeListener(fn);
|
||||
}
|
||||
|
||||
T? getCellData({bool loadIfNoCache = true}) {
|
||||
final data = cellCache.get(_cacheKey);
|
||||
if (data == null && loadIfNoCache) {
|
||||
/// Return the cell data.
|
||||
/// The cell data will be read from the Cache first, and load from disk if it does not exist.
|
||||
/// You can set [loadIfNotExist] to false (default is true) to disable loading the cell data.
|
||||
T? getCellData({bool loadIfNotExist = true}) {
|
||||
final data = _cellsCache.get(_cacheKey);
|
||||
if (data == null && loadIfNotExist) {
|
||||
_loadData();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Future<Either<FieldTypeOptionData, FlowyError>> getTypeOptionData() {
|
||||
return _fieldService.getFieldTypeOptionData(fieldType: fieldType);
|
||||
/// Return the FieldTypeOptionDataPB that can be parsed into corresponding class using the [parser].
|
||||
/// [PD] is the type that the parser return.
|
||||
Future<Either<PD, FlowyError>> getFieldTypeOption<PD, P extends TypeOptionDataParser>(P parser) {
|
||||
return _fieldService.getFieldTypeOptionData(fieldType: fieldType).then((result) {
|
||||
return result.fold(
|
||||
(data) => parser.fromBuffer(data.typeOptionData),
|
||||
(err) => right(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Save the cell data to disk
|
||||
/// You can set [dedeplicate] to true (default is false) to reduce the save operation.
|
||||
/// It's useful when you call this method when user editing the [TextField].
|
||||
/// The default debounce interval is 300 milliseconds.
|
||||
void saveCellData(D data, {bool deduplicate = false, void Function(Option<FlowyError>)? resultCallback}) async {
|
||||
if (deduplicate) {
|
||||
_loadDataOperation?.cancel();
|
||||
_loadDataOperation = Timer(const Duration(milliseconds: 300), () async {
|
||||
final result = await cellDataPersistence.save(data);
|
||||
|
||||
_saveDataOperation?.cancel();
|
||||
_saveDataOperation = Timer(const Duration(milliseconds: 300), () async {
|
||||
final result = await _cellDataPersistence.save(data);
|
||||
if (resultCallback != null) {
|
||||
resultCallback(result);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final result = await cellDataPersistence.save(data);
|
||||
final result = await _cellDataPersistence.save(data);
|
||||
if (resultCallback != null) {
|
||||
resultCallback(result);
|
||||
}
|
||||
@ -209,26 +259,59 @@ class _GridCellContext<T, D> extends Equatable {
|
||||
}
|
||||
|
||||
void _loadData() {
|
||||
_saveDataOperation?.cancel();
|
||||
|
||||
_loadDataOperation?.cancel();
|
||||
_loadDataOperation = Timer(const Duration(milliseconds: 10), () {
|
||||
cellDataLoader.loadData().then((data) {
|
||||
_cellDataLoader.loadData().then((data) {
|
||||
_cellDataNotifier?.value = data;
|
||||
cellCache.insert(_GridCellCacheObject(key: _cacheKey, object: data));
|
||||
_cellsCache.insert(_cacheKey, GridCell(object: data));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (_isDispose) {
|
||||
Log.error("$this should only dispose once");
|
||||
return;
|
||||
}
|
||||
_isDispose = true;
|
||||
_cellListener.stop();
|
||||
_loadDataOperation?.cancel();
|
||||
_saveDataOperation?.cancel();
|
||||
_cellDataNotifier = null;
|
||||
|
||||
if (_onFieldChangedFn != null) {
|
||||
cellCache.removeFieldListener(_cacheKey, _onFieldChangedFn!);
|
||||
_fieldNotifier.unregister(_cacheKey, _onFieldChangedFn!);
|
||||
_onFieldChangedFn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [cellCache.get(_cacheKey) ?? "", cellId];
|
||||
List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id];
|
||||
}
|
||||
|
||||
class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {
|
||||
final GridFieldCache _cache;
|
||||
FieldChangesetCallback? _onChangesetFn;
|
||||
|
||||
_GridFieldChangedNotifierImpl(GridFieldCache cache) : _cache = cache;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (_onChangesetFn != null) {
|
||||
_cache.removeListener(onChangsetListener: _onChangesetFn!);
|
||||
_onChangesetFn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onFieldChanged(void Function(GridFieldPB p1) callback) {
|
||||
_onChangesetFn = (GridFieldChangesetPB changeset) {
|
||||
for (final updatedField in changeset.updatedFields) {
|
||||
callback(updatedField);
|
||||
}
|
||||
};
|
||||
_cache.addListener(onChangeset: _onChangesetFn);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import 'cell_service/cell_service.dart';
|
||||
part 'checkbox_cell_bloc.freezed.dart';
|
||||
|
||||
class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
final GridCellContext cellContext;
|
||||
final GridCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
CheckboxCellBloc({
|
||||
@ -67,7 +67,7 @@ class CheckboxCellState with _$CheckboxCellState {
|
||||
required bool isSelected,
|
||||
}) = _CheckboxCellState;
|
||||
|
||||
factory CheckboxCellState.initial(GridCellContext context) {
|
||||
factory CheckboxCellState.initial(GridCellController context) {
|
||||
return CheckboxCellState(isSelected: _isSelected(context.getCellData()));
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
@ -16,12 +17,12 @@ import 'package:fixnum/fixnum.dart' as $fixnum;
|
||||
part 'date_cal_bloc.freezed.dart';
|
||||
|
||||
class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
|
||||
final GridDateCellContext cellContext;
|
||||
final GridDateCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
DateCalBloc({
|
||||
required DateTypeOption dateTypeOption,
|
||||
required DateCellData? cellData,
|
||||
required DateCellDataPB? cellData,
|
||||
required this.cellContext,
|
||||
}) : super(DateCalState.initial(dateTypeOption, cellData)) {
|
||||
on<DateCalEvent>(
|
||||
@ -37,7 +38,7 @@ class DateCalBloc extends Bloc<DateCalEvent, DateCalState> {
|
||||
setFocusedDay: (focusedDay) {
|
||||
emit(state.copyWith(focusedDay: focusedDay));
|
||||
},
|
||||
didReceiveCellUpdate: (DateCellData? cellData) {
|
||||
didReceiveCellUpdate: (DateCellDataPB? cellData) {
|
||||
final calData = calDataFromCellData(cellData);
|
||||
final time = calData.foldRight("", (dateData, previous) => dateData.time);
|
||||
emit(state.copyWith(calData: calData, time: time));
|
||||
@ -187,7 +188,7 @@ class DateCalEvent with _$DateCalEvent {
|
||||
const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat;
|
||||
const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime;
|
||||
const factory DateCalEvent.setTime(String time) = _Time;
|
||||
const factory DateCalEvent.didReceiveCellUpdate(DateCellData? data) = _DidReceiveCellUpdate;
|
||||
const factory DateCalEvent.didReceiveCellUpdate(DateCellDataPB? data) = _DidReceiveCellUpdate;
|
||||
const factory DateCalEvent.didUpdateCalData(Option<CalendarData> data, Option<String> timeFormatError) =
|
||||
_DidUpdateCalData;
|
||||
}
|
||||
@ -206,7 +207,7 @@ class DateCalState with _$DateCalState {
|
||||
|
||||
factory DateCalState.initial(
|
||||
DateTypeOption dateTypeOption,
|
||||
DateCellData? cellData,
|
||||
DateCellDataPB? cellData,
|
||||
) {
|
||||
Option<CalendarData> calData = calDataFromCellData(cellData);
|
||||
final time = calData.foldRight("", (dateData, previous) => dateData.time);
|
||||
@ -232,7 +233,7 @@ String _timeHintText(DateTypeOption typeOption) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Option<CalendarData> calDataFromCellData(DateCellData? cellData) {
|
||||
Option<CalendarData> calDataFromCellData(DateCellDataPB? cellData) {
|
||||
String? time = timeFromCellData(cellData);
|
||||
Option<CalendarData> calData = none();
|
||||
if (cellData != null) {
|
||||
@ -248,7 +249,7 @@ $fixnum.Int64 timestampFromDateTime(DateTime dateTime) {
|
||||
return $fixnum.Int64(timestamp);
|
||||
}
|
||||
|
||||
String? timeFromCellData(DateCellData? cellData) {
|
||||
String? timeFromCellData(DateCellDataPB? cellData) {
|
||||
String? time;
|
||||
if (cellData?.hasTime() ?? false) {
|
||||
time = cellData?.time;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -7,7 +7,7 @@ import 'cell_service/cell_service.dart';
|
||||
part 'date_cell_bloc.freezed.dart';
|
||||
|
||||
class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
final GridDateCellContext cellContext;
|
||||
final GridDateCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) {
|
||||
@ -15,10 +15,10 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
initial: () => _startListening(),
|
||||
didReceiveCellUpdate: (DateCellData? cellData) {
|
||||
didReceiveCellUpdate: (DateCellDataPB? cellData) {
|
||||
emit(state.copyWith(data: cellData, dateStr: _dateStrFromCellData(cellData)));
|
||||
},
|
||||
didReceiveFieldUpdate: (Field value) => emit(state.copyWith(field: value)),
|
||||
didReceiveFieldUpdate: (GridFieldPB value) => emit(state.copyWith(field: value)),
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -48,19 +48,19 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
@freezed
|
||||
class DateCellEvent with _$DateCellEvent {
|
||||
const factory DateCellEvent.initial() = _InitialCell;
|
||||
const factory DateCellEvent.didReceiveCellUpdate(DateCellData? data) = _DidReceiveCellUpdate;
|
||||
const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||
const factory DateCellEvent.didReceiveCellUpdate(DateCellDataPB? data) = _DidReceiveCellUpdate;
|
||||
const factory DateCellEvent.didReceiveFieldUpdate(GridFieldPB field) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class DateCellState with _$DateCellState {
|
||||
const factory DateCellState({
|
||||
required DateCellData? data,
|
||||
required DateCellDataPB? data,
|
||||
required String dateStr,
|
||||
required Field field,
|
||||
required GridFieldPB field,
|
||||
}) = _DateCellState;
|
||||
|
||||
factory DateCellState.initial(GridDateCellContext context) {
|
||||
factory DateCellState.initial(GridDateCellController context) {
|
||||
final cellData = context.getCellData();
|
||||
|
||||
return DateCellState(
|
||||
@ -71,7 +71,7 @@ class DateCellState with _$DateCellState {
|
||||
}
|
||||
}
|
||||
|
||||
String _dateStrFromCellData(DateCellData? cellData) {
|
||||
String _dateStrFromCellData(DateCellDataPB? cellData) {
|
||||
String dateStr = "";
|
||||
if (cellData != null) {
|
||||
dateStr = cellData.date + " " + cellData.time;
|
||||
|
@ -8,7 +8,7 @@ import 'cell_service/cell_service.dart';
|
||||
part 'number_cell_bloc.freezed.dart';
|
||||
|
||||
class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
final GridCellContext cellContext;
|
||||
final GridCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
NumberCellBloc({
|
||||
@ -72,7 +72,7 @@ class NumberCellState with _$NumberCellState {
|
||||
required Either<String, FlowyError> content,
|
||||
}) = _NumberCellState;
|
||||
|
||||
factory NumberCellState.initial(GridCellContext context) {
|
||||
factory NumberCellState.initial(GridCellController context) {
|
||||
final cellContent = context.getCellData() ?? "";
|
||||
return NumberCellState(
|
||||
content: left(cellContent),
|
||||
|
@ -7,7 +7,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_serv
|
||||
part 'select_option_cell_bloc.freezed.dart';
|
||||
|
||||
class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellState> {
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
final GridSelectOptionCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
|
||||
SelectOptionCellBloc({
|
||||
@ -56,17 +56,17 @@ class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellS
|
||||
class SelectOptionCellEvent with _$SelectOptionCellEvent {
|
||||
const factory SelectOptionCellEvent.initial() = _InitialCell;
|
||||
const factory SelectOptionCellEvent.didReceiveOptions(
|
||||
List<SelectOption> selectedOptions,
|
||||
List<SelectOptionPB> selectedOptions,
|
||||
) = _DidReceiveOptions;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionCellState with _$SelectOptionCellState {
|
||||
const factory SelectOptionCellState({
|
||||
required List<SelectOption> selectedOptions,
|
||||
required List<SelectOptionPB> selectedOptions,
|
||||
}) = _SelectOptionCellState;
|
||||
|
||||
factory SelectOptionCellState.initial(GridSelectOptionCellContext context) {
|
||||
factory SelectOptionCellState.initial(GridSelectOptionCellController context) {
|
||||
final data = context.getCellData();
|
||||
|
||||
return SelectOptionCellState(
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
|
||||
@ -13,16 +12,13 @@ part 'select_option_editor_bloc.freezed.dart';
|
||||
|
||||
class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
|
||||
final SelectOptionService _selectOptionService;
|
||||
final GridSelectOptionCellContext cellContext;
|
||||
late final GridFieldsListener _fieldListener;
|
||||
void Function()? _onCellChangedFn;
|
||||
final GridSelectOptionCellController cellController;
|
||||
Timer? _delayOperation;
|
||||
|
||||
SelectOptionCellEditorBloc({
|
||||
required this.cellContext,
|
||||
}) : _selectOptionService = SelectOptionService(gridCell: cellContext.gridCell),
|
||||
_fieldListener = GridFieldsListener(gridId: cellContext.gridId),
|
||||
super(SelectOptionEditorState.initial(cellContext)) {
|
||||
required this.cellController,
|
||||
}) : _selectOptionService = SelectOptionService(cellId: cellController.cellId),
|
||||
super(SelectOptionEditorState.initial(cellController)) {
|
||||
on<SelectOptionEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -64,13 +60,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_onCellChangedFn != null) {
|
||||
cellContext.removeListener(_onCellChangedFn!);
|
||||
_onCellChangedFn = null;
|
||||
}
|
||||
_delayOperation?.cancel();
|
||||
await _fieldListener.stop();
|
||||
cellContext.dispose();
|
||||
cellController.dispose();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@ -79,7 +70,7 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
|
||||
result.fold((l) => {}, (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _deleteOption(SelectOption option) async {
|
||||
void _deleteOption(SelectOptionPB option) async {
|
||||
final result = await _selectOptionService.delete(
|
||||
option: option,
|
||||
);
|
||||
@ -87,7 +78,7 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
|
||||
result.fold((l) => null, (err) => Log.error(err));
|
||||
}
|
||||
|
||||
void _updateOption(SelectOption option) async {
|
||||
void _updateOption(SelectOptionPB option) async {
|
||||
final result = await _selectOptionService.update(
|
||||
option: option,
|
||||
);
|
||||
@ -131,8 +122,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
|
||||
});
|
||||
}
|
||||
|
||||
_MakeOptionResult _makeOptions(Option<String> filter, List<SelectOption> allOptions) {
|
||||
final List<SelectOption> options = List.from(allOptions);
|
||||
_MakeOptionResult _makeOptions(Option<String> filter, List<SelectOptionPB> allOptions) {
|
||||
final List<SelectOptionPB> options = List.from(allOptions);
|
||||
Option<String> createOption = filter;
|
||||
|
||||
filter.foldRight(null, (filter, previous) {
|
||||
@ -157,24 +148,16 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_onCellChangedFn = cellContext.startListening(
|
||||
cellController.startListening(
|
||||
onCellChanged: ((selectOptionContext) {
|
||||
if (!isClosed) {
|
||||
_loadOptions();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
_fieldListener.start(onFieldsChanged: (result) {
|
||||
result.fold(
|
||||
(changeset) {
|
||||
if (changeset.updatedFields.isNotEmpty) {
|
||||
onCellFieldChanged: () {
|
||||
_loadOptions();
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,26 +165,26 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
|
||||
class SelectOptionEditorEvent with _$SelectOptionEditorEvent {
|
||||
const factory SelectOptionEditorEvent.initial() = _Initial;
|
||||
const factory SelectOptionEditorEvent.didReceiveOptions(
|
||||
List<SelectOption> options, List<SelectOption> selectedOptions) = _DidReceiveOptions;
|
||||
List<SelectOptionPB> options, List<SelectOptionPB> 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;
|
||||
const factory SelectOptionEditorEvent.updateOption(SelectOptionPB option) = _UpdateOption;
|
||||
const factory SelectOptionEditorEvent.deleteOption(SelectOptionPB option) = _DeleteOption;
|
||||
const factory SelectOptionEditorEvent.filterOption(String optionName) = _SelectOptionFilter;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionEditorState with _$SelectOptionEditorState {
|
||||
const factory SelectOptionEditorState({
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOption> allOptions,
|
||||
required List<SelectOption> selectedOptions,
|
||||
required List<SelectOptionPB> options,
|
||||
required List<SelectOptionPB> allOptions,
|
||||
required List<SelectOptionPB> selectedOptions,
|
||||
required Option<String> createOption,
|
||||
required Option<String> filter,
|
||||
}) = _SelectOptionEditorState;
|
||||
|
||||
factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) {
|
||||
final data = context.getCellData(loadIfNoCache: false);
|
||||
factory SelectOptionEditorState.initial(GridSelectOptionCellController context) {
|
||||
final data = context.getCellData(loadIfNotExist: false);
|
||||
return SelectOptionEditorState(
|
||||
options: data?.options ?? [],
|
||||
allOptions: data?.options ?? [],
|
||||
@ -213,7 +196,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState {
|
||||
}
|
||||
|
||||
class _MakeOptionResult {
|
||||
List<SelectOption> options;
|
||||
List<SelectOptionPB> options;
|
||||
Option<String> createOption;
|
||||
|
||||
_MakeOptionResult({
|
||||
|
@ -7,23 +7,23 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
|
||||
import 'cell_service/cell_service.dart';
|
||||
|
||||
class SelectOptionService {
|
||||
final GridCell gridCell;
|
||||
SelectOptionService({required this.gridCell});
|
||||
final GridCellIdentifier cellId;
|
||||
SelectOptionService({required this.cellId});
|
||||
|
||||
String get gridId => gridCell.gridId;
|
||||
String get fieldId => gridCell.field.id;
|
||||
String get rowId => gridCell.rowId;
|
||||
String get gridId => cellId.gridId;
|
||||
String get fieldId => cellId.field.id;
|
||||
String get rowId => cellId.rowId;
|
||||
|
||||
Future<Either<Unit, FlowyError>> create({required String name}) {
|
||||
return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then(
|
||||
(result) {
|
||||
return result.fold(
|
||||
(option) {
|
||||
final cellIdentifier = CellIdentifierPayload.create()
|
||||
final cellIdentifier = GridCellIdPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
final payload = SelectOptionChangesetPayload.create()
|
||||
final payload = SelectOptionChangesetPayloadPB.create()
|
||||
..insertOption = option
|
||||
..cellIdentifier = cellIdentifier;
|
||||
return GridEventUpdateSelectOption(payload).send();
|
||||
@ -35,26 +35,26 @@ class SelectOptionService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> update({
|
||||
required SelectOption option,
|
||||
required SelectOptionPB option,
|
||||
}) {
|
||||
final payload = SelectOptionChangesetPayload.create()
|
||||
final payload = SelectOptionChangesetPayloadPB.create()
|
||||
..updateOption = option
|
||||
..cellIdentifier = _cellIdentifier();
|
||||
return GridEventUpdateSelectOption(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> delete({
|
||||
required SelectOption option,
|
||||
required SelectOptionPB option,
|
||||
}) {
|
||||
final payload = SelectOptionChangesetPayload.create()
|
||||
final payload = SelectOptionChangesetPayloadPB.create()
|
||||
..deleteOption = option
|
||||
..cellIdentifier = _cellIdentifier();
|
||||
|
||||
return GridEventUpdateSelectOption(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<SelectOptionCellData, FlowyError>> getOpitonContext() {
|
||||
final payload = CellIdentifierPayload.create()
|
||||
Future<Either<SelectOptionCellDataPB, FlowyError>> getOpitonContext() {
|
||||
final payload = GridCellIdPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
@ -63,21 +63,21 @@ class SelectOptionService {
|
||||
}
|
||||
|
||||
Future<Either<void, FlowyError>> select({required String optionId}) {
|
||||
final payload = SelectOptionCellChangesetPayload.create()
|
||||
final payload = SelectOptionCellChangesetPayloadPB.create()
|
||||
..cellIdentifier = _cellIdentifier()
|
||||
..insertOptionId = optionId;
|
||||
return GridEventUpdateSelectOptionCell(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<void, FlowyError>> unSelect({required String optionId}) {
|
||||
final payload = SelectOptionCellChangesetPayload.create()
|
||||
final payload = SelectOptionCellChangesetPayloadPB.create()
|
||||
..cellIdentifier = _cellIdentifier()
|
||||
..deleteOptionId = optionId;
|
||||
return GridEventUpdateSelectOptionCell(payload).send();
|
||||
}
|
||||
|
||||
CellIdentifierPayload _cellIdentifier() {
|
||||
return CellIdentifierPayload.create()
|
||||
GridCellIdPB _cellIdentifier() {
|
||||
return GridCellIdPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..rowId = rowId;
|
||||
|
@ -6,7 +6,7 @@ import 'cell_service/cell_service.dart';
|
||||
part 'text_cell_bloc.freezed.dart';
|
||||
|
||||
class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
||||
final GridCellContext cellContext;
|
||||
final GridCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
TextCellBloc({
|
||||
required this.cellContext,
|
||||
@ -63,7 +63,7 @@ class TextCellState with _$TextCellState {
|
||||
required String content,
|
||||
}) = _TextCellState;
|
||||
|
||||
factory TextCellState.initial(GridCellContext context) => TextCellState(
|
||||
factory TextCellState.initial(GridCellController context) => TextCellState(
|
||||
content: context.getCellData() ?? "",
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -7,7 +7,7 @@ import 'cell_service/cell_service.dart';
|
||||
part 'url_cell_bloc.freezed.dart';
|
||||
|
||||
class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
final GridURLCellContext cellContext;
|
||||
final GridURLCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
URLCellBloc({
|
||||
required this.cellContext,
|
||||
@ -57,7 +57,7 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
||||
class URLCellEvent with _$URLCellEvent {
|
||||
const factory URLCellEvent.initial() = _InitialCell;
|
||||
const factory URLCellEvent.updateURL(String url) = _UpdateURL;
|
||||
const factory URLCellEvent.didReceiveCellUpdate(URLCellData? cell) = _DidReceiveCellUpdate;
|
||||
const factory URLCellEvent.didReceiveCellUpdate(URLCellDataPB? cell) = _DidReceiveCellUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -67,7 +67,7 @@ class URLCellState with _$URLCellState {
|
||||
required String url,
|
||||
}) = _URLCellState;
|
||||
|
||||
factory URLCellState.initial(GridURLCellContext context) {
|
||||
factory URLCellState.initial(GridURLCellController context) {
|
||||
final cellData = context.getCellData();
|
||||
return URLCellState(
|
||||
content: cellData?.content ?? "",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -7,7 +7,7 @@ import 'cell_service/cell_service.dart';
|
||||
part 'url_cell_editor_bloc.freezed.dart';
|
||||
|
||||
class URLCellEditorBloc extends Bloc<URLCellEditorEvent, URLCellEditorState> {
|
||||
final GridURLCellContext cellContext;
|
||||
final GridURLCellController cellContext;
|
||||
void Function()? _onCellChangedFn;
|
||||
URLCellEditorBloc({
|
||||
required this.cellContext,
|
||||
@ -54,7 +54,7 @@ class URLCellEditorBloc extends Bloc<URLCellEditorEvent, URLCellEditorState> {
|
||||
@freezed
|
||||
class URLCellEditorEvent with _$URLCellEditorEvent {
|
||||
const factory URLCellEditorEvent.initial() = _InitialCell;
|
||||
const factory URLCellEditorEvent.didReceiveCellUpdate(URLCellData? cell) = _DidReceiveCellUpdate;
|
||||
const factory URLCellEditorEvent.didReceiveCellUpdate(URLCellDataPB? cell) = _DidReceiveCellUpdate;
|
||||
const factory URLCellEditorEvent.updateText(String text) = _UpdateText;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ class URLCellEditorState with _$URLCellEditorState {
|
||||
required String content,
|
||||
}) = _URLCellEditorState;
|
||||
|
||||
factory URLCellEditorState.initial(GridURLCellContext context) {
|
||||
factory URLCellEditorState.initial(GridURLCellController context) {
|
||||
final cellData = context.getCellData();
|
||||
return URLCellEditorState(
|
||||
content: cellData?.content ?? "",
|
||||
|
@ -10,8 +10,8 @@ part 'field_action_sheet_bloc.freezed.dart';
|
||||
class FieldActionSheetBloc extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
|
||||
final FieldService fieldService;
|
||||
|
||||
FieldActionSheetBloc({required Field field, required this.fieldService})
|
||||
: super(FieldActionSheetState.initial(FieldTypeOptionData.create()..field_2 = field)) {
|
||||
FieldActionSheetBloc({required GridFieldPB field, required this.fieldService})
|
||||
: super(FieldActionSheetState.initial(FieldTypeOptionDataPB.create()..field_2 = field)) {
|
||||
on<FieldActionSheetEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -67,12 +67,12 @@ class FieldActionSheetEvent with _$FieldActionSheetEvent {
|
||||
@freezed
|
||||
class FieldActionSheetState with _$FieldActionSheetState {
|
||||
const factory FieldActionSheetState({
|
||||
required FieldTypeOptionData fieldTypeOptionData,
|
||||
required FieldTypeOptionDataPB fieldTypeOptionData,
|
||||
required String errorText,
|
||||
required String fieldName,
|
||||
}) = _FieldActionSheetState;
|
||||
|
||||
factory FieldActionSheetState.initial(FieldTypeOptionData data) => FieldActionSheetState(
|
||||
factory FieldActionSheetState.initial(FieldTypeOptionDataPB data) => FieldActionSheetState(
|
||||
fieldTypeOptionData: data,
|
||||
errorText: '',
|
||||
fieldName: data.field_2.name,
|
||||
|
@ -62,7 +62,7 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
|
||||
@freezed
|
||||
class FieldCellEvent with _$FieldCellEvent {
|
||||
const factory FieldCellEvent.initial() = _InitialCell;
|
||||
const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
|
||||
const factory FieldCellEvent.didReceiveFieldUpdate(GridFieldPB field) = _DidReceiveFieldUpdate;
|
||||
const factory FieldCellEvent.startUpdateWidth(double offset) = _StartUpdateWidth;
|
||||
const factory FieldCellEvent.endUpdateWidth() = _EndUpdateWidth;
|
||||
}
|
||||
@ -71,7 +71,7 @@ class FieldCellEvent with _$FieldCellEvent {
|
||||
class FieldCellState with _$FieldCellState {
|
||||
const factory FieldCellState({
|
||||
required String gridId,
|
||||
required Field field,
|
||||
required GridFieldPB field,
|
||||
required double width,
|
||||
}) = _FieldCellState;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -6,27 +7,32 @@ import 'package:dartz/dartz.dart';
|
||||
part 'field_editor_bloc.freezed.dart';
|
||||
|
||||
class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
final TypeOptionDataController dataController;
|
||||
|
||||
FieldEditorBloc({
|
||||
required String gridId,
|
||||
required String fieldName,
|
||||
required IFieldContextLoader fieldContextLoader,
|
||||
}) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) {
|
||||
required IFieldTypeOptionLoader loader,
|
||||
}) : dataController = TypeOptionDataController(gridId: gridId, loader: loader),
|
||||
super(FieldEditorState.initial(gridId, fieldName)) {
|
||||
on<FieldEditorEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
final fieldContext = GridFieldContext(gridId: gridId, loader: fieldContextLoader);
|
||||
await fieldContext.loadData().then((result) {
|
||||
result.fold(
|
||||
(l) => emit(state.copyWith(fieldContext: Some(fieldContext), name: fieldContext.field.name)),
|
||||
(r) => null,
|
||||
);
|
||||
dataController.addFieldListener((field) {
|
||||
if (!isClosed) {
|
||||
add(FieldEditorEvent.didReceiveFieldChanged(field));
|
||||
}
|
||||
});
|
||||
await dataController.loadData();
|
||||
},
|
||||
updateName: (name) {
|
||||
state.fieldContext.fold(() => null, (fieldContext) => fieldContext.fieldName = name);
|
||||
dataController.fieldName = name;
|
||||
emit(state.copyWith(name: name));
|
||||
},
|
||||
didReceiveFieldChanged: (GridFieldPB field) {
|
||||
emit(state.copyWith(field: Some(field)));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -42,6 +48,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||
class FieldEditorEvent with _$FieldEditorEvent {
|
||||
const factory FieldEditorEvent.initial() = _InitialField;
|
||||
const factory FieldEditorEvent.updateName(String name) = _UpdateName;
|
||||
const factory FieldEditorEvent.didReceiveFieldChanged(GridFieldPB field) = _DidReceiveFieldChanged;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -50,13 +57,17 @@ class FieldEditorState with _$FieldEditorState {
|
||||
required String gridId,
|
||||
required String errorText,
|
||||
required String name,
|
||||
required Option<GridFieldContext> fieldContext,
|
||||
required Option<GridFieldPB> field,
|
||||
}) = _FieldEditorState;
|
||||
|
||||
factory FieldEditorState.initial(String gridId, String fieldName, IFieldContextLoader loader) => FieldEditorState(
|
||||
factory FieldEditorState.initial(
|
||||
String gridId,
|
||||
String fieldName,
|
||||
) =>
|
||||
FieldEditorState(
|
||||
gridId: gridId,
|
||||
fieldContext: none(),
|
||||
errorText: '',
|
||||
field: none(),
|
||||
name: fieldName,
|
||||
);
|
||||
}
|
||||
|
@ -1,57 +0,0 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'field_service.dart';
|
||||
|
||||
part 'field_editor_pannel_bloc.freezed.dart';
|
||||
|
||||
class FieldEditorPannelBloc extends Bloc<FieldEditorPannelEvent, FieldEditorPannelState> {
|
||||
final GridFieldContext _fieldContext;
|
||||
void Function()? _fieldListenFn;
|
||||
|
||||
FieldEditorPannelBloc(GridFieldContext fieldContext)
|
||||
: _fieldContext = fieldContext,
|
||||
super(FieldEditorPannelState.initial(fieldContext)) {
|
||||
on<FieldEditorPannelEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
initial: () {
|
||||
_fieldListenFn = fieldContext.addFieldListener((field) {
|
||||
add(FieldEditorPannelEvent.didReceiveFieldUpdated(field));
|
||||
});
|
||||
},
|
||||
didReceiveFieldUpdated: (field) {
|
||||
emit(state.copyWith(field: field));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_fieldListenFn != null) {
|
||||
_fieldContext.removeFieldListener(_fieldListenFn!);
|
||||
}
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldEditorPannelEvent with _$FieldEditorPannelEvent {
|
||||
const factory FieldEditorPannelEvent.initial() = _Initial;
|
||||
const factory FieldEditorPannelEvent.didReceiveFieldUpdated(Field field) = _DidReceiveFieldUpdated;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldEditorPannelState with _$FieldEditorPannelState {
|
||||
const factory FieldEditorPannelState({
|
||||
required Field field,
|
||||
}) = _FieldEditorPannelState;
|
||||
|
||||
factory FieldEditorPannelState.initial(GridFieldContext fieldContext) => FieldEditorPannelState(
|
||||
field: fieldContext.field,
|
||||
);
|
||||
}
|
@ -7,7 +7,7 @@ import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<Field, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<GridFieldPB, FlowyError>;
|
||||
|
||||
class SingleFieldListener {
|
||||
final String fieldId;
|
||||
@ -31,7 +31,7 @@ class SingleFieldListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateField:
|
||||
result.fold(
|
||||
(payload) => _updateFieldNotifier?.value = left(Field.fromBuffer(payload)),
|
||||
(payload) => _updateFieldNotifier?.value = left(GridFieldPB.fromBuffer(payload)),
|
||||
(error) => _updateFieldNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
@ -9,6 +10,10 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
part 'field_service.freezed.dart';
|
||||
|
||||
/// FieldService consists of lots of event functions. We define the events in the backend(Rust),
|
||||
/// you can find the corresponding event implementation in event_map.rs of the corresponding crate.
|
||||
///
|
||||
/// You could check out the rust-lib/flowy-grid/event_map.rs for more information.
|
||||
class FieldService {
|
||||
final String gridId;
|
||||
final String fieldId;
|
||||
@ -16,10 +21,10 @@ class FieldService {
|
||||
FieldService({required this.gridId, required this.fieldId});
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveField(int fromIndex, int toIndex) {
|
||||
final payload = MoveItemPayload.create()
|
||||
final payload = MoveItemPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..itemId = fieldId
|
||||
..ty = MoveItemType.MoveField
|
||||
..ty = MoveItemTypePB.MoveField
|
||||
..fromIndex = fromIndex
|
||||
..toIndex = toIndex;
|
||||
|
||||
@ -34,7 +39,7 @@ class FieldService {
|
||||
double? width,
|
||||
List<int>? typeOptionData,
|
||||
}) {
|
||||
var payload = FieldChangesetPayload.create()
|
||||
var payload = FieldChangesetPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
@ -68,11 +73,11 @@ class FieldService {
|
||||
// Create the field if it does not exist. Otherwise, update the field.
|
||||
static Future<Either<Unit, FlowyError>> insertField({
|
||||
required String gridId,
|
||||
required Field field,
|
||||
required GridFieldPB field,
|
||||
List<int>? typeOptionData,
|
||||
String? startFieldId,
|
||||
}) {
|
||||
var payload = InsertFieldPayload.create()
|
||||
var payload = InsertFieldPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..field_2 = field
|
||||
..typeOptionData = typeOptionData ?? [];
|
||||
@ -89,7 +94,7 @@ class FieldService {
|
||||
required String fieldId,
|
||||
required List<int> typeOptionData,
|
||||
}) {
|
||||
var payload = UpdateFieldTypeOptionPayload.create()
|
||||
var payload = UpdateFieldTypeOptionPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..typeOptionData = typeOptionData;
|
||||
@ -98,7 +103,7 @@ class FieldService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> deleteField() {
|
||||
final payload = FieldIdentifierPayload.create()
|
||||
final payload = DeleteFieldPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
@ -106,17 +111,17 @@ class FieldService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> duplicateField() {
|
||||
final payload = FieldIdentifierPayload.create()
|
||||
final payload = DuplicateFieldPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
return GridEventDuplicateField(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<FieldTypeOptionData, FlowyError>> getFieldTypeOptionData({
|
||||
Future<Either<FieldTypeOptionDataPB, FlowyError>> getFieldTypeOptionData({
|
||||
required FieldType fieldType,
|
||||
}) {
|
||||
final payload = EditFieldPayload.create()
|
||||
final payload = GridFieldTypeOptionIdPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..fieldType = fieldType;
|
||||
@ -133,16 +138,16 @@ class FieldService {
|
||||
class GridFieldCellContext with _$GridFieldCellContext {
|
||||
const factory GridFieldCellContext({
|
||||
required String gridId,
|
||||
required Field field,
|
||||
required GridFieldPB field,
|
||||
}) = _GridFieldCellContext;
|
||||
}
|
||||
|
||||
abstract class IFieldContextLoader {
|
||||
abstract class IFieldTypeOptionLoader {
|
||||
String get gridId;
|
||||
Future<Either<FieldTypeOptionData, FlowyError>> load();
|
||||
Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
|
||||
|
||||
Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
|
||||
final payload = EditFieldPayload.create()
|
||||
Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
|
||||
final payload = EditFieldPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId
|
||||
..fieldType = fieldType;
|
||||
@ -151,16 +156,16 @@ abstract class IFieldContextLoader {
|
||||
}
|
||||
}
|
||||
|
||||
class NewFieldContextLoader extends IFieldContextLoader {
|
||||
class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
|
||||
@override
|
||||
final String gridId;
|
||||
NewFieldContextLoader({
|
||||
NewFieldTypeOptionLoader({
|
||||
required this.gridId,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<FieldTypeOptionData, FlowyError>> load() {
|
||||
final payload = EditFieldPayload.create()
|
||||
Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
|
||||
final payload = CreateFieldPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldType = FieldType.RichText;
|
||||
|
||||
@ -168,19 +173,19 @@ class NewFieldContextLoader extends IFieldContextLoader {
|
||||
}
|
||||
}
|
||||
|
||||
class FieldContextLoader extends IFieldContextLoader {
|
||||
class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
|
||||
@override
|
||||
final String gridId;
|
||||
final Field field;
|
||||
final GridFieldPB field;
|
||||
|
||||
FieldContextLoader({
|
||||
FieldTypeOptionLoader({
|
||||
required this.gridId,
|
||||
required this.field,
|
||||
});
|
||||
|
||||
@override
|
||||
Future<Either<FieldTypeOptionData, FlowyError>> load() {
|
||||
final payload = EditFieldPayload.create()
|
||||
Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
|
||||
final payload = GridFieldTypeOptionIdPB.create()
|
||||
..gridId = gridId
|
||||
..fieldId = field.id
|
||||
..fieldType = field.fieldType;
|
||||
@ -189,16 +194,16 @@ class FieldContextLoader extends IFieldContextLoader {
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldContext {
|
||||
class TypeOptionDataController {
|
||||
final String gridId;
|
||||
final IFieldContextLoader _loader;
|
||||
final IFieldTypeOptionLoader _loader;
|
||||
|
||||
late FieldTypeOptionData _data;
|
||||
ValueNotifier<Field>? _fieldNotifier;
|
||||
late FieldTypeOptionDataPB _data;
|
||||
final PublishNotifier<GridFieldPB> _fieldNotifier = PublishNotifier();
|
||||
|
||||
GridFieldContext({
|
||||
TypeOptionDataController({
|
||||
required this.gridId,
|
||||
required IFieldContextLoader loader,
|
||||
required IFieldTypeOptionLoader loader,
|
||||
}) : _loader = loader;
|
||||
|
||||
Future<Either<Unit, FlowyError>> loadData() async {
|
||||
@ -207,13 +212,7 @@ class GridFieldContext {
|
||||
(data) {
|
||||
data.freeze();
|
||||
_data = data;
|
||||
|
||||
if (_fieldNotifier == null) {
|
||||
_fieldNotifier = ValueNotifier(data.field_2);
|
||||
} else {
|
||||
_fieldNotifier?.value = data.field_2;
|
||||
}
|
||||
|
||||
_fieldNotifier.value = data.field_2;
|
||||
return left(unit);
|
||||
},
|
||||
(err) {
|
||||
@ -223,9 +222,9 @@ class GridFieldContext {
|
||||
);
|
||||
}
|
||||
|
||||
Field get field => _data.field_2;
|
||||
GridFieldPB get field => _data.field_2;
|
||||
|
||||
set field(Field field) {
|
||||
set field(GridFieldPB field) {
|
||||
_updateData(newField: field);
|
||||
}
|
||||
|
||||
@ -239,7 +238,7 @@ class GridFieldContext {
|
||||
_updateData(newTypeOptionData: typeOptionData);
|
||||
}
|
||||
|
||||
void _updateData({String? newName, Field? newField, List<int>? newTypeOptionData}) {
|
||||
void _updateData({String? newName, GridFieldPB? newField, List<int>? newTypeOptionData}) {
|
||||
_data = _data.rebuild((rebuildData) {
|
||||
if (newName != null) {
|
||||
rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
|
||||
@ -256,9 +255,7 @@ class GridFieldContext {
|
||||
}
|
||||
});
|
||||
|
||||
if (_data.field_2 != _fieldNotifier?.value) {
|
||||
_fieldNotifier?.value = _data.field_2;
|
||||
}
|
||||
_fieldNotifier.value = _data.field_2;
|
||||
|
||||
FieldService.insertField(
|
||||
gridId: gridId,
|
||||
@ -283,16 +280,16 @@ class GridFieldContext {
|
||||
});
|
||||
}
|
||||
|
||||
void Function() addFieldListener(void Function(Field) callback) {
|
||||
void Function() addFieldListener(void Function(GridFieldPB) callback) {
|
||||
listener() {
|
||||
callback(field);
|
||||
}
|
||||
|
||||
_fieldNotifier?.addListener(listener);
|
||||
_fieldNotifier.addListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
void removeFieldListener(void Function() listener) {
|
||||
_fieldNotifier?.removeListener(listener);
|
||||
_fieldNotifier.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'field_service.dart';
|
||||
|
||||
part 'field_type_option_edit_bloc.freezed.dart';
|
||||
|
||||
class FieldTypeOptionEditBloc extends Bloc<FieldTypeOptionEditEvent, FieldTypeOptionEditState> {
|
||||
final TypeOptionDataController _dataController;
|
||||
void Function()? _fieldListenFn;
|
||||
|
||||
FieldTypeOptionEditBloc(TypeOptionDataController dataController)
|
||||
: _dataController = dataController,
|
||||
super(FieldTypeOptionEditState.initial(dataController)) {
|
||||
on<FieldTypeOptionEditEvent>(
|
||||
(event, emit) async {
|
||||
event.when(
|
||||
initial: () {
|
||||
_fieldListenFn = dataController.addFieldListener((field) {
|
||||
add(FieldTypeOptionEditEvent.didReceiveFieldUpdated(field));
|
||||
});
|
||||
},
|
||||
didReceiveFieldUpdated: (field) {
|
||||
emit(state.copyWith(field: field));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_fieldListenFn != null) {
|
||||
_dataController.removeFieldListener(_fieldListenFn!);
|
||||
}
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldTypeOptionEditEvent with _$FieldTypeOptionEditEvent {
|
||||
const factory FieldTypeOptionEditEvent.initial() = _Initial;
|
||||
const factory FieldTypeOptionEditEvent.didReceiveFieldUpdated(GridFieldPB field) = _DidReceiveFieldUpdated;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FieldTypeOptionEditState with _$FieldTypeOptionEditState {
|
||||
const factory FieldTypeOptionEditState({
|
||||
required GridFieldPB field,
|
||||
}) = _FieldTypeOptionEditState;
|
||||
|
||||
factory FieldTypeOptionEditState.initial(TypeOptionDataController fieldContext) => FieldTypeOptionEditState(
|
||||
field: fieldContext.field,
|
||||
);
|
||||
}
|
@ -7,7 +7,7 @@ import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<GridFieldChangeset, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<GridFieldChangesetPB, FlowyError>;
|
||||
|
||||
class GridFieldsListener {
|
||||
final String gridId;
|
||||
@ -27,7 +27,7 @@ class GridFieldsListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateGridField:
|
||||
result.fold(
|
||||
(payload) => updateFieldsNotifier?.value = left(GridFieldChangeset.fromBuffer(payload)),
|
||||
(payload) => updateFieldsNotifier?.value = left(GridFieldChangesetPB.fromBuffer(payload)),
|
||||
(error) => updateFieldsNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
@ -1,14 +1,15 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.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';
|
||||
|
||||
typedef DateTypeOptionContext = TypeOptionContext<DateTypeOption>;
|
||||
typedef DateTypeOptionContext = TypeOptionWidgetContext<DateTypeOption>;
|
||||
|
||||
class DateTypeOptionDataBuilder extends TypeOptionDataBuilder<DateTypeOption> {
|
||||
class DateTypeOptionDataParser extends TypeOptionDataParser<DateTypeOption> {
|
||||
@override
|
||||
DateTypeOption fromBuffer(List<int> buffer) {
|
||||
return DateTypeOption.fromBuffer(buffer);
|
||||
|
@ -7,7 +7,7 @@ import 'package:dartz/dartz.dart';
|
||||
part 'edit_select_option_bloc.freezed.dart';
|
||||
|
||||
class EditSelectOptionBloc extends Bloc<EditSelectOptionEvent, EditSelectOptionState> {
|
||||
EditSelectOptionBloc({required SelectOption option}) : super(EditSelectOptionState.initial(option)) {
|
||||
EditSelectOptionBloc({required SelectOptionPB option}) : super(EditSelectOptionState.initial(option)) {
|
||||
on<EditSelectOptionEvent>(
|
||||
(event, emit) async {
|
||||
event.map(
|
||||
@ -30,14 +30,14 @@ class EditSelectOptionBloc extends Bloc<EditSelectOptionEvent, EditSelectOptionS
|
||||
return super.close();
|
||||
}
|
||||
|
||||
SelectOption _updateColor(SelectOptionColor color) {
|
||||
SelectOptionPB _updateColor(SelectOptionColorPB color) {
|
||||
state.option.freeze();
|
||||
return state.option.rebuild((option) {
|
||||
option.color = color;
|
||||
});
|
||||
}
|
||||
|
||||
SelectOption _updateName(String name) {
|
||||
SelectOptionPB _updateName(String name) {
|
||||
state.option.freeze();
|
||||
return state.option.rebuild((option) {
|
||||
option.name = name;
|
||||
@ -48,18 +48,18 @@ class EditSelectOptionBloc extends Bloc<EditSelectOptionEvent, EditSelectOptionS
|
||||
@freezed
|
||||
class EditSelectOptionEvent with _$EditSelectOptionEvent {
|
||||
const factory EditSelectOptionEvent.updateName(String name) = _UpdateName;
|
||||
const factory EditSelectOptionEvent.updateColor(SelectOptionColor color) = _UpdateColor;
|
||||
const factory EditSelectOptionEvent.updateColor(SelectOptionColorPB color) = _UpdateColor;
|
||||
const factory EditSelectOptionEvent.delete() = _Delete;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class EditSelectOptionState with _$EditSelectOptionState {
|
||||
const factory EditSelectOptionState({
|
||||
required SelectOption option,
|
||||
required SelectOptionPB option,
|
||||
required Option<bool> deleted,
|
||||
}) = _EditSelectOptionState;
|
||||
|
||||
factory EditSelectOptionState.initial(SelectOption option) => EditSelectOptionState(
|
||||
factory EditSelectOptionState.initial(SelectOptionPB option) => EditSelectOptionState(
|
||||
option: option,
|
||||
deleted: none(),
|
||||
);
|
||||
|
@ -7,21 +7,22 @@ import 'package:protobuf/protobuf.dart';
|
||||
import 'select_option_type_option_bloc.dart';
|
||||
import 'type_option_service.dart';
|
||||
|
||||
class MultiSelectTypeOptionContext extends TypeOptionContext<MultiSelectTypeOption> with SelectOptionTypeOptionAction {
|
||||
class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTypeOption>
|
||||
with SelectOptionTypeOptionAction {
|
||||
final TypeOptionService service;
|
||||
|
||||
MultiSelectTypeOptionContext({
|
||||
required MultiSelectTypeOptionDataBuilder dataBuilder,
|
||||
required GridFieldContext fieldContext,
|
||||
required MultiSelectTypeOptionWidgetDataParser dataBuilder,
|
||||
required TypeOptionDataController dataController,
|
||||
}) : service = TypeOptionService(
|
||||
gridId: fieldContext.gridId,
|
||||
fieldId: fieldContext.field.id,
|
||||
gridId: dataController.gridId,
|
||||
fieldId: dataController.field.id,
|
||||
),
|
||||
super(dataBuilder: dataBuilder, fieldContext: fieldContext);
|
||||
super(dataParser: dataBuilder, dataController: dataController);
|
||||
|
||||
@override
|
||||
List<SelectOption> Function(SelectOption) get deleteOption {
|
||||
return (SelectOption option) {
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get deleteOption {
|
||||
return (SelectOptionPB option) {
|
||||
typeOption.freeze();
|
||||
typeOption = typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
@ -34,7 +35,7 @@ class MultiSelectTypeOptionContext extends TypeOptionContext<MultiSelectTypeOpti
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SelectOption>> Function(String) get insertOption {
|
||||
Future<List<SelectOptionPB>> Function(String) get insertOption {
|
||||
return (String optionName) {
|
||||
return service.newOption(name: optionName).then((result) {
|
||||
return result.fold(
|
||||
@ -56,8 +57,8 @@ class MultiSelectTypeOptionContext extends TypeOptionContext<MultiSelectTypeOpti
|
||||
}
|
||||
|
||||
@override
|
||||
List<SelectOption> Function(SelectOption) get udpateOption {
|
||||
return (SelectOption option) {
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get udpateOption {
|
||||
return (SelectOptionPB option) {
|
||||
typeOption.freeze();
|
||||
typeOption = typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
@ -70,7 +71,7 @@ class MultiSelectTypeOptionContext extends TypeOptionContext<MultiSelectTypeOpti
|
||||
}
|
||||
}
|
||||
|
||||
class MultiSelectTypeOptionDataBuilder extends TypeOptionDataBuilder<MultiSelectTypeOption> {
|
||||
class MultiSelectTypeOptionWidgetDataParser extends TypeOptionDataParser<MultiSelectTypeOption> {
|
||||
@override
|
||||
MultiSelectTypeOption fromBuffer(List<int> buffer) {
|
||||
return MultiSelectTypeOption.fromBuffer(buffer);
|
||||
|
@ -8,9 +8,9 @@ import 'package:protobuf/protobuf.dart';
|
||||
|
||||
part 'number_bloc.freezed.dart';
|
||||
|
||||
typedef NumberTypeOptionContext = TypeOptionContext<NumberTypeOption>;
|
||||
typedef NumberTypeOptionContext = TypeOptionWidgetContext<NumberTypeOption>;
|
||||
|
||||
class NumberTypeOptionDataBuilder extends TypeOptionDataBuilder<NumberTypeOption> {
|
||||
class NumberTypeOptionWidgetDataParser extends TypeOptionDataParser<NumberTypeOption> {
|
||||
@override
|
||||
NumberTypeOption fromBuffer(List<int> buffer) {
|
||||
return NumberTypeOption.fromBuffer(buffer);
|
||||
|
@ -6,25 +6,25 @@ import 'package:dartz/dartz.dart';
|
||||
part 'select_option_type_option_bloc.freezed.dart';
|
||||
|
||||
abstract class SelectOptionTypeOptionAction {
|
||||
Future<List<SelectOption>> Function(String) get insertOption;
|
||||
Future<List<SelectOptionPB>> Function(String) get insertOption;
|
||||
|
||||
List<SelectOption> Function(SelectOption) get deleteOption;
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get deleteOption;
|
||||
|
||||
List<SelectOption> Function(SelectOption) get udpateOption;
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get udpateOption;
|
||||
}
|
||||
|
||||
class SelectOptionTypeOptionBloc extends Bloc<SelectOptionTypeOptionEvent, SelectOptionTypeOptionState> {
|
||||
final SelectOptionTypeOptionAction typeOptionAction;
|
||||
|
||||
SelectOptionTypeOptionBloc({
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOptionPB> options,
|
||||
required this.typeOptionAction,
|
||||
}) : super(SelectOptionTypeOptionState.initial(options)) {
|
||||
on<SelectOptionTypeOptionEvent>(
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
createOption: (optionName) async {
|
||||
final List<SelectOption> options = await typeOptionAction.insertOption(optionName);
|
||||
final List<SelectOptionPB> options = await typeOptionAction.insertOption(optionName);
|
||||
emit(state.copyWith(options: options));
|
||||
},
|
||||
addingOption: () {
|
||||
@ -34,11 +34,11 @@ class SelectOptionTypeOptionBloc extends Bloc<SelectOptionTypeOptionEvent, Selec
|
||||
emit(state.copyWith(isEditingOption: false, newOptionName: none()));
|
||||
},
|
||||
updateOption: (option) {
|
||||
final List<SelectOption> options = typeOptionAction.udpateOption(option);
|
||||
final List<SelectOptionPB> options = typeOptionAction.udpateOption(option);
|
||||
emit(state.copyWith(options: options));
|
||||
},
|
||||
deleteOption: (option) {
|
||||
final List<SelectOption> options = typeOptionAction.deleteOption(option);
|
||||
final List<SelectOptionPB> options = typeOptionAction.deleteOption(option);
|
||||
emit(state.copyWith(options: options));
|
||||
},
|
||||
);
|
||||
@ -57,19 +57,19 @@ class SelectOptionTypeOptionEvent with _$SelectOptionTypeOptionEvent {
|
||||
const factory SelectOptionTypeOptionEvent.createOption(String optionName) = _CreateOption;
|
||||
const factory SelectOptionTypeOptionEvent.addingOption() = _AddingOption;
|
||||
const factory SelectOptionTypeOptionEvent.endAddingOption() = _EndAddingOption;
|
||||
const factory SelectOptionTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
|
||||
const factory SelectOptionTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
|
||||
const factory SelectOptionTypeOptionEvent.updateOption(SelectOptionPB option) = _UpdateOption;
|
||||
const factory SelectOptionTypeOptionEvent.deleteOption(SelectOptionPB option) = _DeleteOption;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SelectOptionTypeOptionState with _$SelectOptionTypeOptionState {
|
||||
const factory SelectOptionTypeOptionState({
|
||||
required List<SelectOption> options,
|
||||
required List<SelectOptionPB> options,
|
||||
required bool isEditingOption,
|
||||
required Option<String> newOptionName,
|
||||
}) = _SelectOptionTyepOptionState;
|
||||
|
||||
factory SelectOptionTypeOptionState.initial(List<SelectOption> options) => SelectOptionTypeOptionState(
|
||||
factory SelectOptionTypeOptionState.initial(List<SelectOptionPB> options) => SelectOptionTypeOptionState(
|
||||
options: options,
|
||||
isEditingOption: false,
|
||||
newOptionName: none(),
|
||||
|
@ -7,22 +7,22 @@ import 'package:protobuf/protobuf.dart';
|
||||
import 'select_option_type_option_bloc.dart';
|
||||
import 'type_option_service.dart';
|
||||
|
||||
class SingleSelectTypeOptionContext extends TypeOptionContext<SingleSelectTypeOption>
|
||||
class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelectTypeOptionPB>
|
||||
with SelectOptionTypeOptionAction {
|
||||
final TypeOptionService service;
|
||||
|
||||
SingleSelectTypeOptionContext({
|
||||
required SingleSelectTypeOptionDataBuilder dataBuilder,
|
||||
required GridFieldContext fieldContext,
|
||||
required SingleSelectTypeOptionWidgetDataParser dataBuilder,
|
||||
required TypeOptionDataController fieldContext,
|
||||
}) : service = TypeOptionService(
|
||||
gridId: fieldContext.gridId,
|
||||
fieldId: fieldContext.field.id,
|
||||
),
|
||||
super(dataBuilder: dataBuilder, fieldContext: fieldContext);
|
||||
super(dataParser: dataBuilder, dataController: fieldContext);
|
||||
|
||||
@override
|
||||
List<SelectOption> Function(SelectOption) get deleteOption {
|
||||
return (SelectOption option) {
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get deleteOption {
|
||||
return (SelectOptionPB option) {
|
||||
typeOption.freeze();
|
||||
typeOption = typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
@ -35,7 +35,7 @@ class SingleSelectTypeOptionContext extends TypeOptionContext<SingleSelectTypeOp
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SelectOption>> Function(String) get insertOption {
|
||||
Future<List<SelectOptionPB>> Function(String) get insertOption {
|
||||
return (String optionName) {
|
||||
return service.newOption(name: optionName).then((result) {
|
||||
return result.fold(
|
||||
@ -57,8 +57,8 @@ class SingleSelectTypeOptionContext extends TypeOptionContext<SingleSelectTypeOp
|
||||
}
|
||||
|
||||
@override
|
||||
List<SelectOption> Function(SelectOption) get udpateOption {
|
||||
return (SelectOption option) {
|
||||
List<SelectOptionPB> Function(SelectOptionPB) get udpateOption {
|
||||
return (SelectOptionPB option) {
|
||||
typeOption.freeze();
|
||||
typeOption = typeOption.rebuild((typeOption) {
|
||||
final index = typeOption.options.indexWhere((element) => element.id == option.id);
|
||||
@ -71,9 +71,9 @@ class SingleSelectTypeOptionContext extends TypeOptionContext<SingleSelectTypeOp
|
||||
}
|
||||
}
|
||||
|
||||
class SingleSelectTypeOptionDataBuilder extends TypeOptionDataBuilder<SingleSelectTypeOption> {
|
||||
class SingleSelectTypeOptionWidgetDataParser extends TypeOptionDataParser<SingleSelectTypeOptionPB> {
|
||||
@override
|
||||
SingleSelectTypeOption fromBuffer(List<int> buffer) {
|
||||
return SingleSelectTypeOption.fromBuffer(buffer);
|
||||
SingleSelectTypeOptionPB fromBuffer(List<int> buffer) {
|
||||
return SingleSelectTypeOptionPB.fromBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
@ -18,51 +18,48 @@ class TypeOptionService {
|
||||
required this.fieldId,
|
||||
});
|
||||
|
||||
Future<Either<SelectOption, FlowyError>> newOption({
|
||||
Future<Either<SelectOptionPB, FlowyError>> newOption({
|
||||
required String name,
|
||||
}) {
|
||||
final fieldIdentifier = FieldIdentifierPayload.create()
|
||||
final payload = CreateSelectOptionPayloadPB.create()
|
||||
..optionName = name
|
||||
..gridId = gridId
|
||||
..fieldId = fieldId;
|
||||
|
||||
final payload = CreateSelectOptionPayload.create()
|
||||
..optionName = name
|
||||
..fieldIdentifier = fieldIdentifier;
|
||||
|
||||
return GridEventNewSelectOption(payload).send();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TypeOptionDataBuilder<T> {
|
||||
abstract class TypeOptionDataParser<T> {
|
||||
T fromBuffer(List<int> buffer);
|
||||
}
|
||||
|
||||
class TypeOptionContext<T extends GeneratedMessage> {
|
||||
class TypeOptionWidgetContext<T extends GeneratedMessage> {
|
||||
T? _typeOptionObject;
|
||||
final GridFieldContext _fieldContext;
|
||||
final TypeOptionDataBuilder<T> dataBuilder;
|
||||
final TypeOptionDataController _dataController;
|
||||
final TypeOptionDataParser<T> dataParser;
|
||||
|
||||
TypeOptionContext({
|
||||
required this.dataBuilder,
|
||||
required GridFieldContext fieldContext,
|
||||
}) : _fieldContext = fieldContext;
|
||||
TypeOptionWidgetContext({
|
||||
required this.dataParser,
|
||||
required TypeOptionDataController dataController,
|
||||
}) : _dataController = dataController;
|
||||
|
||||
String get gridId => _fieldContext.gridId;
|
||||
String get gridId => _dataController.gridId;
|
||||
|
||||
Field get field => _fieldContext.field;
|
||||
GridFieldPB get field => _dataController.field;
|
||||
|
||||
T get typeOption {
|
||||
if (_typeOptionObject != null) {
|
||||
return _typeOptionObject!;
|
||||
}
|
||||
|
||||
final T object = dataBuilder.fromBuffer(_fieldContext.typeOptionData);
|
||||
final T object = dataParser.fromBuffer(_dataController.typeOptionData);
|
||||
_typeOptionObject = object;
|
||||
return object;
|
||||
}
|
||||
|
||||
set typeOption(T typeOption) {
|
||||
_fieldContext.typeOptionData = typeOption.writeToBuffer();
|
||||
_dataController.typeOptionData = typeOption.writeToBuffer();
|
||||
_typeOptionObject = typeOption;
|
||||
}
|
||||
}
|
||||
@ -74,10 +71,10 @@ abstract class TypeOptionFieldDelegate {
|
||||
|
||||
class TypeOptionContext2<T> {
|
||||
final String gridId;
|
||||
final Field field;
|
||||
final GridFieldPB field;
|
||||
final FieldService _fieldService;
|
||||
T? _data;
|
||||
final TypeOptionDataBuilder dataBuilder;
|
||||
final TypeOptionDataParser dataBuilder;
|
||||
|
||||
TypeOptionContext2({
|
||||
required this.gridId,
|
||||
|
@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'block/block_service.dart';
|
||||
import 'block/block_cache.dart';
|
||||
import 'grid_service.dart';
|
||||
import 'row/row_service.dart';
|
||||
import 'dart:collection';
|
||||
@ -20,17 +20,17 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final GridFieldCache fieldCache;
|
||||
|
||||
// key: the block id
|
||||
final LinkedHashMap<String, GridBlockCacheService> _blocks;
|
||||
final LinkedHashMap<String, GridBlockCache> _blocks;
|
||||
|
||||
List<GridRow> get rows {
|
||||
final List<GridRow> rows = [];
|
||||
List<GridRowInfo> get rowInfos {
|
||||
final List<GridRowInfo> rows = [];
|
||||
for (var block in _blocks.values) {
|
||||
rows.addAll(block.rows);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
GridBloc({required View view})
|
||||
GridBloc({required ViewPB view})
|
||||
: gridId = view.id,
|
||||
_blocks = LinkedHashMap.identity(),
|
||||
_gridService = GridService(gridId: view.id),
|
||||
@ -46,11 +46,11 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
createRow: () {
|
||||
_gridService.createRow();
|
||||
},
|
||||
didReceiveRowUpdate: (rows, reason) {
|
||||
emit(state.copyWith(rows: rows, reason: reason));
|
||||
didReceiveRowUpdate: (newRowInfos, reason) {
|
||||
emit(state.copyWith(rowInfos: newRowInfos, reason: reason));
|
||||
},
|
||||
didReceiveFieldUpdate: (fields) {
|
||||
emit(state.copyWith(rows: rows, fields: GridFieldEquatable(fields)));
|
||||
emit(state.copyWith(rowInfos: rowInfos, fields: GridFieldEquatable(fields)));
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -68,8 +68,8 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
return super.close();
|
||||
}
|
||||
|
||||
GridRowCacheService? getRowCache(String blockId, String rowId) {
|
||||
final GridBlockCacheService? blockCache = _blocks[blockId];
|
||||
GridRowCache? getRowCache(String blockId, String rowId) {
|
||||
final GridBlockCache? blockCache = _blocks[blockId];
|
||||
return blockCache?.rowCache;
|
||||
}
|
||||
|
||||
@ -93,8 +93,8 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadFields(Grid grid, Emitter<GridState> emit) async {
|
||||
final result = await _gridService.getFields(fieldOrders: grid.fieldOrders);
|
||||
Future<void> _loadFields(GridPB grid, Emitter<GridState> emit) async {
|
||||
final result = await _gridService.getFields(fieldIds: grid.fields);
|
||||
return Future(
|
||||
() => result.fold(
|
||||
(fields) {
|
||||
@ -103,7 +103,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
fields: GridFieldEquatable(fieldCache.fields),
|
||||
rows: rows,
|
||||
rowInfos: rowInfos,
|
||||
loadingState: GridLoadingState.finish(left(unit)),
|
||||
));
|
||||
},
|
||||
@ -112,14 +112,14 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
);
|
||||
}
|
||||
|
||||
void _initialBlocks(List<GridBlock> blocks) {
|
||||
void _initialBlocks(List<GridBlockPB> blocks) {
|
||||
for (final block in blocks) {
|
||||
if (_blocks[block.id] != null) {
|
||||
Log.warn("Intial duplicate block's cache: ${block.id}");
|
||||
return;
|
||||
}
|
||||
|
||||
final cache = GridBlockCacheService(
|
||||
final cache = GridBlockCache(
|
||||
gridId: gridId,
|
||||
block: block,
|
||||
fieldCache: fieldCache,
|
||||
@ -127,7 +127,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
|
||||
cache.addListener(
|
||||
listenWhen: () => !isClosed,
|
||||
onChangeReason: (reason) => add(GridEvent.didReceiveRowUpdate(rows, reason)),
|
||||
onChangeReason: (reason) => add(GridEvent.didReceiveRowUpdate(rowInfos, reason)),
|
||||
);
|
||||
|
||||
_blocks[block.id] = cache;
|
||||
@ -139,24 +139,25 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
class GridEvent with _$GridEvent {
|
||||
const factory GridEvent.initial() = InitialGrid;
|
||||
const factory GridEvent.createRow() = _CreateRow;
|
||||
const factory GridEvent.didReceiveRowUpdate(List<GridRow> rows, GridRowChangeReason listState) = _DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
const factory GridEvent.didReceiveRowUpdate(List<GridRowInfo> rows, GridRowChangeReason listState) =
|
||||
_DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveFieldUpdate(List<GridFieldPB> fields) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridState with _$GridState {
|
||||
const factory GridState({
|
||||
required String gridId,
|
||||
required Option<Grid> grid,
|
||||
required Option<GridPB> grid,
|
||||
required GridFieldEquatable fields,
|
||||
required List<GridRow> rows,
|
||||
required List<GridRowInfo> rowInfos,
|
||||
required GridLoadingState loadingState,
|
||||
required GridRowChangeReason reason,
|
||||
}) = _GridState;
|
||||
|
||||
factory GridState.initial(String gridId) => GridState(
|
||||
fields: const GridFieldEquatable([]),
|
||||
rows: [],
|
||||
rowInfos: [],
|
||||
grid: none(),
|
||||
gridId: gridId,
|
||||
loadingState: const _Loading(),
|
||||
@ -171,8 +172,8 @@ class GridLoadingState with _$GridLoadingState {
|
||||
}
|
||||
|
||||
class GridFieldEquatable extends Equatable {
|
||||
final List<Field> _fields;
|
||||
const GridFieldEquatable(List<Field> fields) : _fields = fields;
|
||||
final List<GridFieldPB> _fields;
|
||||
const GridFieldEquatable(List<GridFieldPB> fields) : _fields = fields;
|
||||
|
||||
@override
|
||||
List<Object?> get props {
|
||||
@ -182,5 +183,5 @@ class GridFieldEquatable extends Equatable {
|
||||
];
|
||||
}
|
||||
|
||||
UnmodifiableListView<Field> get value => UnmodifiableListView(_fields);
|
||||
UnmodifiableListView<GridFieldPB> get value => UnmodifiableListView(_fields);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
|
||||
}
|
||||
|
||||
Future<void> _moveField(_MoveField value, Emitter<GridHeaderState> emit) async {
|
||||
final fields = List<Field>.from(state.fields);
|
||||
final fields = List<GridFieldPB>.from(state.fields);
|
||||
fields.insert(value.toIndex, fields.removeAt(value.fromIndex));
|
||||
emit(state.copyWith(fields: fields));
|
||||
|
||||
@ -62,16 +62,16 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
|
||||
@freezed
|
||||
class GridHeaderEvent with _$GridHeaderEvent {
|
||||
const factory GridHeaderEvent.initial() = _InitialHeader;
|
||||
const factory GridHeaderEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
const factory GridHeaderEvent.moveField(Field field, int fromIndex, int toIndex) = _MoveField;
|
||||
const factory GridHeaderEvent.didReceiveFieldUpdate(List<GridFieldPB> fields) = _DidReceiveFieldUpdate;
|
||||
const factory GridHeaderEvent.moveField(GridFieldPB field, int fromIndex, int toIndex) = _MoveField;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridHeaderState with _$GridHeaderState {
|
||||
const factory GridHeaderState({required List<Field> fields}) = _GridHeaderState;
|
||||
const factory GridHeaderState({required List<GridFieldPB> fields}) = _GridHeaderState;
|
||||
|
||||
factory GridHeaderState.initial(List<Field> fields) {
|
||||
// final List<Field> newFields = List.from(fields);
|
||||
factory GridHeaderState.initial(List<GridFieldPB> fields) {
|
||||
// final List<GridFieldPB> newFields = List.from(fields);
|
||||
// newFields.retainWhere((field) => field.visibility);
|
||||
return GridHeaderState(fields: fields);
|
||||
}
|
||||
|
@ -19,55 +19,54 @@ class GridService {
|
||||
required this.gridId,
|
||||
});
|
||||
|
||||
Future<Either<Grid, FlowyError>> loadGrid() async {
|
||||
await FolderEventSetLatestView(ViewId(value: gridId)).send();
|
||||
Future<Either<GridPB, FlowyError>> loadGrid() async {
|
||||
await FolderEventSetLatestView(ViewIdPB(value: gridId)).send();
|
||||
|
||||
final payload = GridId(value: gridId);
|
||||
final payload = GridIdPB(value: gridId);
|
||||
return GridEventGetGrid(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Row, FlowyError>> createRow({Option<String>? startRowId}) {
|
||||
CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId;
|
||||
Future<Either<GridRowPB, FlowyError>> createRow({Option<String>? startRowId}) {
|
||||
CreateRowPayloadPB payload = CreateRowPayloadPB.create()..gridId = gridId;
|
||||
startRowId?.fold(() => null, (id) => payload.startRowId = id);
|
||||
return GridEventCreateRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<RepeatedField, FlowyError>> getFields({required List<FieldOrder> fieldOrders}) {
|
||||
final payload = QueryFieldPayload.create()
|
||||
Future<Either<RepeatedGridFieldPB, FlowyError>> getFields({required List<GridFieldIdPB> fieldIds}) {
|
||||
final payload = QueryFieldPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..fieldOrders = RepeatedFieldOrder(items: fieldOrders);
|
||||
..fieldIds = RepeatedGridFieldIdPB(items: fieldIds);
|
||||
return GridEventGetFields(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> closeGrid() {
|
||||
final request = ViewId(value: gridId);
|
||||
final request = ViewIdPB(value: gridId);
|
||||
return FolderEventCloseView(request).send();
|
||||
}
|
||||
}
|
||||
|
||||
class FieldsNotifier extends ChangeNotifier {
|
||||
List<Field> _fields = [];
|
||||
List<GridFieldPB> _fields = [];
|
||||
|
||||
set fields(List<Field> fields) {
|
||||
set fields(List<GridFieldPB> fields) {
|
||||
_fields = fields;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<Field> get fields => _fields;
|
||||
List<GridFieldPB> get fields => _fields;
|
||||
}
|
||||
|
||||
typedef FieldChangesetCallback = void Function(GridFieldChangeset);
|
||||
typedef FieldsCallback = void Function(List<Field>);
|
||||
typedef FieldChangesetCallback = void Function(GridFieldChangesetPB);
|
||||
typedef FieldsCallback = void Function(List<GridFieldPB>);
|
||||
|
||||
class GridFieldCache {
|
||||
final String gridId;
|
||||
late final GridFieldsListener _fieldListener;
|
||||
final GridFieldsListener _fieldListener;
|
||||
FieldsNotifier? _fieldNotifier = FieldsNotifier();
|
||||
final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {};
|
||||
final Map<FieldChangesetCallback, FieldChangesetCallback> _changesetCallbackMap = {};
|
||||
|
||||
GridFieldCache({required this.gridId}) {
|
||||
_fieldListener = GridFieldsListener(gridId: gridId);
|
||||
GridFieldCache({required this.gridId}) : _fieldListener = GridFieldsListener(gridId: gridId) {
|
||||
_fieldListener.start(onFieldsChanged: (result) {
|
||||
result.fold(
|
||||
(changeset) {
|
||||
@ -89,11 +88,11 @@ class GridFieldCache {
|
||||
_fieldNotifier = null;
|
||||
}
|
||||
|
||||
UnmodifiableListView<Field> get unmodifiableFields => UnmodifiableListView(_fieldNotifier?.fields ?? []);
|
||||
UnmodifiableListView<GridFieldPB> get unmodifiableFields => UnmodifiableListView(_fieldNotifier?.fields ?? []);
|
||||
|
||||
List<Field> get fields => [..._fieldNotifier?.fields ?? []];
|
||||
List<GridFieldPB> get fields => [..._fieldNotifier?.fields ?? []];
|
||||
|
||||
set fields(List<Field> fields) {
|
||||
set fields(List<GridFieldPB> fields) {
|
||||
_fieldNotifier?.fields = [...fields];
|
||||
}
|
||||
|
||||
@ -142,12 +141,12 @@ class GridFieldCache {
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteFields(List<FieldOrder> deletedFields) {
|
||||
void _deleteFields(List<GridFieldIdPB> deletedFields) {
|
||||
if (deletedFields.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final List<Field> newFields = fields;
|
||||
final Map<String, FieldOrder> deletedFieldMap = {
|
||||
final List<GridFieldPB> newFields = fields;
|
||||
final Map<String, GridFieldIdPB> deletedFieldMap = {
|
||||
for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder
|
||||
};
|
||||
|
||||
@ -155,11 +154,11 @@ class GridFieldCache {
|
||||
_fieldNotifier?.fields = newFields;
|
||||
}
|
||||
|
||||
void _insertFields(List<IndexField> insertedFields) {
|
||||
void _insertFields(List<IndexFieldPB> insertedFields) {
|
||||
if (insertedFields.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final List<Field> newFields = fields;
|
||||
final List<GridFieldPB> newFields = fields;
|
||||
for (final indexField in insertedFields) {
|
||||
if (newFields.length > indexField.index) {
|
||||
newFields.insert(indexField.index, indexField.field_1);
|
||||
@ -170,11 +169,11 @@ class GridFieldCache {
|
||||
_fieldNotifier?.fields = newFields;
|
||||
}
|
||||
|
||||
void _updateFields(List<Field> updatedFields) {
|
||||
void _updateFields(List<GridFieldPB> updatedFields) {
|
||||
if (updatedFields.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final List<Field> newFields = fields;
|
||||
final List<GridFieldPB> newFields = fields;
|
||||
for (final updatedField in updatedFields) {
|
||||
final index = newFields.indexWhere((field) => field.id == updatedField.id);
|
||||
if (index != -1) {
|
||||
@ -186,14 +185,14 @@ class GridFieldCache {
|
||||
}
|
||||
}
|
||||
|
||||
class GridRowCacheDelegateImpl extends GridRowCacheDelegate {
|
||||
class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier {
|
||||
final GridFieldCache _cache;
|
||||
FieldChangesetCallback? _onChangesetFn;
|
||||
FieldsCallback? _onFieldFn;
|
||||
GridRowCacheDelegateImpl(GridFieldCache cache) : _cache = cache;
|
||||
GridRowCacheFieldNotifierImpl(GridFieldCache cache) : _cache = cache;
|
||||
|
||||
@override
|
||||
UnmodifiableListView<Field> get fields => _cache.unmodifiableFields;
|
||||
UnmodifiableListView<GridFieldPB> get fields => _cache.unmodifiableFields;
|
||||
|
||||
@override
|
||||
void onFieldsChanged(VoidCallback callback) {
|
||||
@ -202,8 +201,8 @@ class GridRowCacheDelegateImpl extends GridRowCacheDelegate {
|
||||
}
|
||||
|
||||
@override
|
||||
void onFieldUpdated(void Function(Field) callback) {
|
||||
_onChangesetFn = (GridFieldChangeset changeset) {
|
||||
void onFieldChanged(void Function(GridFieldPB) callback) {
|
||||
_onChangesetFn = (GridFieldChangesetPB changeset) {
|
||||
for (final updatedField in changeset.updatedFields) {
|
||||
callback(updatedField);
|
||||
}
|
||||
|
@ -4,18 +4,18 @@ export 'row/row_service.dart';
|
||||
export 'grid_service.dart';
|
||||
export 'grid_header_bloc.dart';
|
||||
|
||||
// Field
|
||||
// GridFieldPB
|
||||
export 'field/field_service.dart';
|
||||
export 'field/field_action_sheet_bloc.dart';
|
||||
export 'field/field_editor_bloc.dart';
|
||||
export 'field/field_editor_pannel_bloc.dart';
|
||||
export 'field/field_type_option_edit_bloc.dart';
|
||||
|
||||
// Field Type Option
|
||||
// GridFieldPB Type Option
|
||||
export 'field/type_option/date_bloc.dart';
|
||||
export 'field/type_option/number_bloc.dart';
|
||||
export 'field/type_option/single_select_type_option.dart';
|
||||
|
||||
// Cell
|
||||
// GridCellPB
|
||||
export 'cell/text_cell_bloc.dart';
|
||||
export 'cell/number_cell_bloc.dart';
|
||||
export 'cell/select_option_cell_bloc.dart';
|
||||
|
@ -11,11 +11,11 @@ part 'row_action_sheet_bloc.freezed.dart';
|
||||
class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState> {
|
||||
final RowService _rowService;
|
||||
|
||||
RowActionSheetBloc({required GridRow rowData})
|
||||
RowActionSheetBloc({required GridRowInfo rowData})
|
||||
: _rowService = RowService(
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
rowId: rowData.rowId,
|
||||
rowId: rowData.id,
|
||||
),
|
||||
super(RowActionSheetState.initial(rowData)) {
|
||||
on<RowActionSheetEvent>(
|
||||
@ -53,10 +53,10 @@ class RowActionSheetEvent with _$RowActionSheetEvent {
|
||||
@freezed
|
||||
class RowActionSheetState with _$RowActionSheetState {
|
||||
const factory RowActionSheetState({
|
||||
required GridRow rowData,
|
||||
required GridRowInfo rowData,
|
||||
}) = _RowActionSheetState;
|
||||
|
||||
factory RowActionSheetState.initial(GridRow rowData) => RowActionSheetState(
|
||||
factory RowActionSheetState.initial(GridRowInfo rowData) => RowActionSheetState(
|
||||
rowData: rowData,
|
||||
);
|
||||
}
|
||||
|
@ -11,19 +11,19 @@ part 'row_bloc.freezed.dart';
|
||||
|
||||
class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
final RowService _rowService;
|
||||
final GridRowCacheService _rowCache;
|
||||
final GridRowCache _rowCache;
|
||||
void Function()? _rowListenFn;
|
||||
|
||||
RowBloc({
|
||||
required GridRow rowData,
|
||||
required GridRowCacheService rowCache,
|
||||
required GridRowInfo rowInfo,
|
||||
required GridRowCache rowCache,
|
||||
}) : _rowService = RowService(
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
rowId: rowData.rowId,
|
||||
gridId: rowInfo.gridId,
|
||||
blockId: rowInfo.blockId,
|
||||
rowId: rowInfo.id,
|
||||
),
|
||||
_rowCache = rowCache,
|
||||
super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) {
|
||||
super(RowState.initial(rowInfo, rowCache.loadGridCells(rowInfo.id))) {
|
||||
on<RowEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
@ -58,7 +58,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
|
||||
Future<void> _startListening() async {
|
||||
_rowListenFn = _rowCache.addListener(
|
||||
rowId: state.rowData.rowId,
|
||||
rowId: state.rowInfo.id,
|
||||
onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)),
|
||||
listenWhen: () => !isClosed,
|
||||
);
|
||||
@ -76,23 +76,23 @@ class RowEvent with _$RowEvent {
|
||||
@freezed
|
||||
class RowState with _$RowState {
|
||||
const factory RowState({
|
||||
required GridRow rowData,
|
||||
required GridRowInfo rowInfo,
|
||||
required GridCellMap gridCellMap,
|
||||
required UnmodifiableListView<GridCellEquatable> snapshots,
|
||||
GridRowChangeReason? changeReason,
|
||||
}) = _RowState;
|
||||
|
||||
factory RowState.initial(GridRow rowData, GridCellMap cellDataMap) => RowState(
|
||||
rowData: rowData,
|
||||
factory RowState.initial(GridRowInfo rowInfo, GridCellMap cellDataMap) => RowState(
|
||||
rowInfo: rowInfo,
|
||||
gridCellMap: cellDataMap,
|
||||
snapshots: UnmodifiableListView(cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList()),
|
||||
);
|
||||
}
|
||||
|
||||
class GridCellEquatable extends Equatable {
|
||||
final Field _field;
|
||||
final GridFieldPB _field;
|
||||
|
||||
const GridCellEquatable(Field field) : _field = field;
|
||||
const GridCellEquatable(GridFieldPB field) : _field = field;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
|
@ -7,13 +7,13 @@ import 'row_service.dart';
|
||||
part 'row_detail_bloc.freezed.dart';
|
||||
|
||||
class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
|
||||
final GridRow rowData;
|
||||
final GridRowCacheService _rowCache;
|
||||
final GridRowInfo rowInfo;
|
||||
final GridRowCache _rowCache;
|
||||
void Function()? _rowListenFn;
|
||||
|
||||
RowDetailBloc({
|
||||
required this.rowData,
|
||||
required GridRowCacheService rowCache,
|
||||
required this.rowInfo,
|
||||
required GridRowCache rowCache,
|
||||
}) : _rowCache = rowCache,
|
||||
super(RowDetailState.initial()) {
|
||||
on<RowDetailEvent>(
|
||||
@ -41,14 +41,14 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
|
||||
|
||||
Future<void> _startListening() async {
|
||||
_rowListenFn = _rowCache.addListener(
|
||||
rowId: rowData.rowId,
|
||||
rowId: rowInfo.id,
|
||||
onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())),
|
||||
listenWhen: () => !isClosed,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadCellData() async {
|
||||
final cellDataMap = _rowCache.loadGridCells(rowData.rowId);
|
||||
final cellDataMap = _rowCache.loadGridCells(rowInfo.id);
|
||||
if (!isClosed) {
|
||||
add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList()));
|
||||
}
|
||||
@ -58,13 +58,13 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
|
||||
@freezed
|
||||
class RowDetailEvent with _$RowDetailEvent {
|
||||
const factory RowDetailEvent.initial() = _Initial;
|
||||
const factory RowDetailEvent.didReceiveCellDatas(List<GridCell> gridCells) = _DidReceiveCellDatas;
|
||||
const factory RowDetailEvent.didReceiveCellDatas(List<GridCellIdentifier> gridCells) = _DidReceiveCellDatas;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class RowDetailState with _$RowDetailState {
|
||||
const factory RowDetailState({
|
||||
required List<GridCell> gridCells,
|
||||
required List<GridCellIdentifier> gridCells,
|
||||
}) = _RowDetailState;
|
||||
|
||||
factory RowDetailState.initial() => RowDetailState(
|
||||
|
@ -8,8 +8,8 @@ import 'dart:typed_data';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateRowNotifiedValue = Either<Row, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<List<Field>, FlowyError>;
|
||||
typedef UpdateRowNotifiedValue = Either<GridRowPB, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<List<GridFieldPB>, FlowyError>;
|
||||
|
||||
class RowListener {
|
||||
final String rowId;
|
||||
@ -26,7 +26,7 @@ class RowListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateRow:
|
||||
result.fold(
|
||||
(payload) => updateRowNotifier?.value = left(Row.fromBuffer(payload)),
|
||||
(payload) => updateRowNotifier?.value = left(GridRowPB.fromBuffer(payload)),
|
||||
(error) => updateRowNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
@ -15,44 +14,57 @@ part 'row_service.freezed.dart';
|
||||
|
||||
typedef RowUpdateCallback = void Function();
|
||||
|
||||
abstract class GridRowCacheDelegate with GridCellCacheDelegate {
|
||||
UnmodifiableListView<Field> get fields;
|
||||
void onFieldsChanged(void Function() callback);
|
||||
abstract class GridRowCacheFieldNotifier {
|
||||
UnmodifiableListView<GridFieldPB> get fields;
|
||||
void onFieldsChanged(VoidCallback callback);
|
||||
void onFieldChanged(void Function(GridFieldPB) callback);
|
||||
void dispose();
|
||||
}
|
||||
|
||||
class GridRowCacheService {
|
||||
/// Cache the rows in memory
|
||||
/// Insert / delete / update row
|
||||
///
|
||||
/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information.
|
||||
|
||||
class GridRowCache {
|
||||
final String gridId;
|
||||
final GridBlock block;
|
||||
final _Notifier _notifier;
|
||||
List<GridRow> _rows = [];
|
||||
final HashMap<String, Row> _rowByRowId;
|
||||
final GridRowCacheDelegate _delegate;
|
||||
final GridCellCacheService _cellCache;
|
||||
final GridBlockPB block;
|
||||
|
||||
List<GridRow> get rows => _rows;
|
||||
GridCellCacheService get cellCache => _cellCache;
|
||||
/// _rows containers the current block's rows
|
||||
/// Use List to reverse the order of the GridRow.
|
||||
List<GridRowInfo> _rowInfos = [];
|
||||
|
||||
GridRowCacheService({
|
||||
/// Use Map for faster access the raw row data.
|
||||
final HashMap<String, GridRowPB> _rowByRowId;
|
||||
|
||||
final GridCellCache _cellCache;
|
||||
final GridRowCacheFieldNotifier _fieldNotifier;
|
||||
final _GridRowChangesetNotifier _rowChangeReasonNotifier;
|
||||
|
||||
UnmodifiableListView<GridRowInfo> get rows => UnmodifiableListView(_rowInfos);
|
||||
GridCellCache get cellCache => _cellCache;
|
||||
|
||||
GridRowCache({
|
||||
required this.gridId,
|
||||
required this.block,
|
||||
required GridRowCacheDelegate delegate,
|
||||
}) : _cellCache = GridCellCacheService(gridId: gridId, delegate: delegate),
|
||||
required GridRowCacheFieldNotifier notifier,
|
||||
}) : _cellCache = GridCellCache(gridId: gridId),
|
||||
_rowByRowId = HashMap(),
|
||||
_notifier = _Notifier(),
|
||||
_delegate = delegate {
|
||||
_rowChangeReasonNotifier = _GridRowChangesetNotifier(),
|
||||
_fieldNotifier = notifier {
|
||||
//
|
||||
delegate.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange()));
|
||||
_rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList();
|
||||
notifier.onFieldsChanged(() => _rowChangeReasonNotifier.receive(const GridRowChangeReason.fieldDidChange()));
|
||||
notifier.onFieldChanged((field) => _cellCache.remove(field.id));
|
||||
_rowInfos = block.rows.map((rowInfo) => buildGridRow(rowInfo.id, rowInfo.height.toDouble())).toList();
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
_delegate.dispose();
|
||||
_notifier.dispose();
|
||||
_fieldNotifier.dispose();
|
||||
_rowChangeReasonNotifier.dispose();
|
||||
await _cellCache.dispose();
|
||||
}
|
||||
|
||||
void applyChangesets(List<GridBlockChangeset> changesets) {
|
||||
void applyChangesets(List<GridBlockChangesetPB> changesets) {
|
||||
for (final changeset in changesets) {
|
||||
_deleteRows(changeset.deletedRows);
|
||||
_insertRows(changeset.insertedRows);
|
||||
@ -67,60 +79,59 @@ class GridRowCacheService {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<GridRow> newRows = [];
|
||||
final List<GridRowInfo> newRows = [];
|
||||
final DeletedIndexs deletedIndex = [];
|
||||
final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId};
|
||||
|
||||
_rows.asMap().forEach((index, row) {
|
||||
if (deletedRowByRowId[row.rowId] == null) {
|
||||
_rowInfos.asMap().forEach((index, row) {
|
||||
if (deletedRowByRowId[row.id] == null) {
|
||||
newRows.add(row);
|
||||
} else {
|
||||
_rowByRowId.remove(row.id);
|
||||
deletedIndex.add(DeletedIndex(index: index, row: row));
|
||||
}
|
||||
});
|
||||
_rows = newRows;
|
||||
_notifier.receive(GridRowChangeReason.delete(deletedIndex));
|
||||
_rowInfos = newRows;
|
||||
_rowChangeReasonNotifier.receive(GridRowChangeReason.delete(deletedIndex));
|
||||
}
|
||||
|
||||
void _insertRows(List<InsertedRow> insertRows) {
|
||||
void _insertRows(List<InsertedRowPB> insertRows) {
|
||||
if (insertRows.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
InsertedIndexs insertIndexs = [];
|
||||
final List<GridRow> newRows = _rows;
|
||||
for (final insertRow in insertRows) {
|
||||
final insertIndex = InsertedIndex(
|
||||
index: insertRow.index,
|
||||
rowId: insertRow.rowId,
|
||||
);
|
||||
insertIndexs.add(insertIndex);
|
||||
newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
|
||||
_rowInfos.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
|
||||
}
|
||||
|
||||
_notifier.receive(GridRowChangeReason.insert(insertIndexs));
|
||||
_rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs));
|
||||
}
|
||||
|
||||
void _updateRows(List<UpdatedRow> updatedRows) {
|
||||
void _updateRows(List<UpdatedRowPB> updatedRows) {
|
||||
if (updatedRows.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
|
||||
final List<GridRow> newRows = _rows;
|
||||
for (final updatedRow in updatedRows) {
|
||||
final rowId = updatedRow.rowId;
|
||||
final index = newRows.indexWhere((row) => row.rowId == rowId);
|
||||
final index = _rowInfos.indexWhere((row) => row.id == rowId);
|
||||
if (index != -1) {
|
||||
_rowByRowId[rowId] = updatedRow.row;
|
||||
|
||||
newRows.removeAt(index);
|
||||
newRows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble()));
|
||||
_rowInfos.removeAt(index);
|
||||
_rowInfos.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble()));
|
||||
updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId);
|
||||
}
|
||||
}
|
||||
|
||||
_notifier.receive(GridRowChangeReason.update(updatedIndexs));
|
||||
_rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs));
|
||||
}
|
||||
|
||||
void _hideRows(List<String> hideRows) {}
|
||||
@ -130,8 +141,8 @@ class GridRowCacheService {
|
||||
void onRowsChanged(
|
||||
void Function(GridRowChangeReason) onRowChanged,
|
||||
) {
|
||||
_notifier.addListener(() {
|
||||
onRowChanged(_notifier._reason);
|
||||
_rowChangeReasonNotifier.addListener(() {
|
||||
onRowChanged(_rowChangeReasonNotifier.reason);
|
||||
});
|
||||
}
|
||||
|
||||
@ -150,12 +161,12 @@ class GridRowCacheService {
|
||||
final row = _rowByRowId[rowId];
|
||||
if (row != null) {
|
||||
final GridCellMap cellDataMap = _makeGridCells(rowId, row);
|
||||
onCellUpdated(cellDataMap, _notifier._reason);
|
||||
onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_notifier._reason.whenOrNull(
|
||||
_rowChangeReasonNotifier.reason.whenOrNull(
|
||||
update: (indexs) {
|
||||
if (indexs[rowId] != null) notifyUpdate();
|
||||
},
|
||||
@ -163,16 +174,16 @@ class GridRowCacheService {
|
||||
);
|
||||
}
|
||||
|
||||
_notifier.addListener(listenrHandler);
|
||||
_rowChangeReasonNotifier.addListener(listenrHandler);
|
||||
return listenrHandler;
|
||||
}
|
||||
|
||||
void removeRowListener(VoidCallback callback) {
|
||||
_notifier.removeListener(callback);
|
||||
_rowChangeReasonNotifier.removeListener(callback);
|
||||
}
|
||||
|
||||
GridCellMap loadGridCells(String rowId) {
|
||||
final Row? data = _rowByRowId[rowId];
|
||||
final GridRowPB? data = _rowByRowId[rowId];
|
||||
if (data == null) {
|
||||
_loadRow(rowId);
|
||||
}
|
||||
@ -180,7 +191,7 @@ class GridRowCacheService {
|
||||
}
|
||||
|
||||
Future<void> _loadRow(String rowId) async {
|
||||
final payload = GridRowIdPayload.create()
|
||||
final payload = GridRowIdPB.create()
|
||||
..gridId = gridId
|
||||
..blockId = block.id
|
||||
..rowId = rowId;
|
||||
@ -192,11 +203,11 @@ class GridRowCacheService {
|
||||
);
|
||||
}
|
||||
|
||||
GridCellMap _makeGridCells(String rowId, Row? row) {
|
||||
GridCellMap _makeGridCells(String rowId, GridRowPB? row) {
|
||||
var cellDataMap = GridCellMap.new();
|
||||
for (final field in _delegate.fields) {
|
||||
for (final field in _fieldNotifier.fields) {
|
||||
if (field.visibility) {
|
||||
cellDataMap[field.id] = GridCell(
|
||||
cellDataMap[field.id] = GridCellIdentifier(
|
||||
rowId: rowId,
|
||||
gridId: gridId,
|
||||
field: field,
|
||||
@ -206,7 +217,7 @@ class GridRowCacheService {
|
||||
return cellDataMap;
|
||||
}
|
||||
|
||||
void _refreshRow(OptionalRow optionRow) {
|
||||
void _refreshRow(OptionalRowPB optionRow) {
|
||||
if (!optionRow.hasRow()) {
|
||||
return;
|
||||
}
|
||||
@ -214,41 +225,41 @@ class GridRowCacheService {
|
||||
updatedRow.freeze();
|
||||
|
||||
_rowByRowId[updatedRow.id] = updatedRow;
|
||||
final index = _rows.indexWhere((gridRow) => gridRow.rowId == updatedRow.id);
|
||||
final index = _rowInfos.indexWhere((gridRow) => gridRow.id == updatedRow.id);
|
||||
if (index != -1) {
|
||||
// update the corresponding row in _rows if they are not the same
|
||||
if (_rows[index].data != updatedRow) {
|
||||
final row = _rows.removeAt(index).copyWith(data: updatedRow);
|
||||
_rows.insert(index, row);
|
||||
if (_rowInfos[index].rawRow != updatedRow) {
|
||||
final row = _rowInfos.removeAt(index).copyWith(rawRow: updatedRow);
|
||||
_rowInfos.insert(index, row);
|
||||
|
||||
// Calculate the update index
|
||||
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
|
||||
updatedIndexs[row.rowId] = UpdatedIndex(index: index, rowId: row.rowId);
|
||||
updatedIndexs[row.id] = UpdatedIndex(index: index, rowId: row.id);
|
||||
|
||||
//
|
||||
_notifier.receive(GridRowChangeReason.update(updatedIndexs));
|
||||
_rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridRow buildGridRow(String rowId, double rowHeight) {
|
||||
return GridRow(
|
||||
GridRowInfo buildGridRow(String rowId, double rowHeight) {
|
||||
return GridRowInfo(
|
||||
gridId: gridId,
|
||||
blockId: block.id,
|
||||
fields: _delegate.fields,
|
||||
rowId: rowId,
|
||||
fields: _fieldNotifier.fields,
|
||||
id: rowId,
|
||||
height: rowHeight,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Notifier extends ChangeNotifier {
|
||||
GridRowChangeReason _reason = const InitialListState();
|
||||
class _GridRowChangesetNotifier extends ChangeNotifier {
|
||||
GridRowChangeReason reason = const InitialListState();
|
||||
|
||||
_Notifier();
|
||||
_GridRowChangesetNotifier();
|
||||
|
||||
void receive(GridRowChangeReason reason) {
|
||||
_reason = reason;
|
||||
void receive(GridRowChangeReason newReason) {
|
||||
reason = newReason;
|
||||
reason.map(
|
||||
insert: (_) => notifyListeners(),
|
||||
delete: (_) => notifyListeners(),
|
||||
@ -266,8 +277,8 @@ class RowService {
|
||||
|
||||
RowService({required this.gridId, required this.blockId, required this.rowId});
|
||||
|
||||
Future<Either<Row, FlowyError>> createRow() {
|
||||
CreateRowPayload payload = CreateRowPayload.create()
|
||||
Future<Either<GridRowPB, FlowyError>> createRow() {
|
||||
CreateRowPayloadPB payload = CreateRowPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..startRowId = rowId;
|
||||
|
||||
@ -275,18 +286,18 @@ class RowService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> moveRow(String rowId, int fromIndex, int toIndex) {
|
||||
final payload = MoveItemPayload.create()
|
||||
final payload = MoveItemPayloadPB.create()
|
||||
..gridId = gridId
|
||||
..itemId = rowId
|
||||
..ty = MoveItemType.MoveRow
|
||||
..ty = MoveItemTypePB.MoveRow
|
||||
..fromIndex = fromIndex
|
||||
..toIndex = toIndex;
|
||||
|
||||
return GridEventMoveItem(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<OptionalRow, FlowyError>> getRow() {
|
||||
final payload = GridRowIdPayload.create()
|
||||
Future<Either<OptionalRowPB, FlowyError>> getRow() {
|
||||
final payload = GridRowIdPB.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
@ -295,7 +306,7 @@ class RowService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> deleteRow() {
|
||||
final payload = GridRowIdPayload.create()
|
||||
final payload = GridRowIdPB.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
@ -304,7 +315,7 @@ class RowService {
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> duplicateRow() {
|
||||
final payload = GridRowIdPayload.create()
|
||||
final payload = GridRowIdPB.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
@ -314,15 +325,15 @@ class RowService {
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridRow with _$GridRow {
|
||||
const factory GridRow({
|
||||
class GridRowInfo with _$GridRowInfo {
|
||||
const factory GridRowInfo({
|
||||
required String gridId,
|
||||
required String blockId,
|
||||
required String rowId,
|
||||
required UnmodifiableListView<Field> fields,
|
||||
required String id,
|
||||
required UnmodifiableListView<GridFieldPB> fields,
|
||||
required double height,
|
||||
Row? data,
|
||||
}) = _GridRow;
|
||||
GridRowPB? rawRow,
|
||||
}) = _GridRowInfo;
|
||||
}
|
||||
|
||||
typedef InsertedIndexs = List<InsertedIndex>;
|
||||
@ -349,7 +360,7 @@ class InsertedIndex {
|
||||
|
||||
class DeletedIndex {
|
||||
final int index;
|
||||
final GridRow row;
|
||||
final GridRowInfo row;
|
||||
DeletedIndex({
|
||||
required this.index,
|
||||
required this.row,
|
||||
|
@ -10,7 +10,7 @@ part 'property_bloc.freezed.dart';
|
||||
|
||||
class GridPropertyBloc extends Bloc<GridPropertyEvent, GridPropertyState> {
|
||||
final GridFieldCache _fieldCache;
|
||||
Function(List<Field>)? _onFieldsFn;
|
||||
Function(List<GridFieldPB>)? _onFieldsFn;
|
||||
|
||||
GridPropertyBloc({required String gridId, required GridFieldCache fieldCache})
|
||||
: _fieldCache = fieldCache,
|
||||
@ -62,7 +62,7 @@ class GridPropertyBloc extends Bloc<GridPropertyEvent, GridPropertyState> {
|
||||
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;
|
||||
const factory GridPropertyEvent.didReceiveFieldUpdate(List<GridFieldPB> fields) = _DidReceiveFieldUpdate;
|
||||
const factory GridPropertyEvent.moveField(int fromIndex, int toIndex) = _MoveField;
|
||||
}
|
||||
|
||||
@ -70,10 +70,10 @@ class GridPropertyEvent with _$GridPropertyEvent {
|
||||
class GridPropertyState with _$GridPropertyState {
|
||||
const factory GridPropertyState({
|
||||
required String gridId,
|
||||
required List<Field> fields,
|
||||
required List<GridFieldPB> fields,
|
||||
}) = _GridPropertyState;
|
||||
|
||||
factory GridPropertyState.initial(String gridId, List<Field> fields) => GridPropertyState(
|
||||
factory GridPropertyState.initial(String gridId, List<GridFieldPB> fields) => GridPropertyState(
|
||||
gridId: gridId,
|
||||
fields: fields,
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import 'package:app_flowy/workspace/application/edit_pannel/edit_context.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart' show CurrentWorkspaceSetting;
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart' show CurrentWorkspaceSettingPB;
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -13,10 +13,11 @@ part 'home_bloc.freezed.dart';
|
||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
final UserWorkspaceListener _listener;
|
||||
|
||||
HomeBloc(UserProfile user, CurrentWorkspaceSetting workspaceSetting)
|
||||
HomeBloc(UserProfilePB user, CurrentWorkspaceSettingPB workspaceSetting)
|
||||
: _listener = UserWorkspaceListener(userProfile: user),
|
||||
super(HomeState.initial(workspaceSetting)) {
|
||||
on<HomeEvent>((event, emit) async {
|
||||
on<HomeEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (_Initial value) {
|
||||
_listener.start(
|
||||
@ -50,8 +51,13 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
collapseMenu: (e) {
|
||||
emit(state.copyWith(isMenuCollapsed: !state.isMenuCollapsed));
|
||||
},
|
||||
editPannelResized: (e) {
|
||||
final newOffset = (state.resizeOffset + e.offset).clamp(-50, 200).toDouble();
|
||||
emit(state.copyWith(resizeOffset: newOffset));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -76,9 +82,10 @@ class HomeEvent with _$HomeEvent {
|
||||
const factory HomeEvent.forceCollapse(bool forceCollapse) = _ForceCollapse;
|
||||
const factory HomeEvent.setEditPannel(EditPannelContext editContext) = _ShowEditPannel;
|
||||
const factory HomeEvent.dismissEditPannel() = _DismissEditPannel;
|
||||
const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSetting setting) = _DidReceiveWorkspaceSetting;
|
||||
const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSettingPB setting) = _DidReceiveWorkspaceSetting;
|
||||
const factory HomeEvent.unauthorized(String msg) = _Unauthorized;
|
||||
const factory HomeEvent.collapseMenu() = _CollapseMenu;
|
||||
const factory HomeEvent.editPannelResized(double offset) = _EditPannelResized;
|
||||
}
|
||||
|
||||
@freezed
|
||||
@ -87,17 +94,19 @@ class HomeState with _$HomeState {
|
||||
required bool isLoading,
|
||||
required bool forceCollapse,
|
||||
required Option<EditPannelContext> pannelContext,
|
||||
required CurrentWorkspaceSetting workspaceSetting,
|
||||
required CurrentWorkspaceSettingPB workspaceSetting,
|
||||
required bool unauthorized,
|
||||
required bool isMenuCollapsed,
|
||||
required double resizeOffset,
|
||||
}) = _HomeState;
|
||||
|
||||
factory HomeState.initial(CurrentWorkspaceSetting workspaceSetting) => HomeState(
|
||||
factory HomeState.initial(CurrentWorkspaceSettingPB workspaceSetting) => HomeState(
|
||||
isLoading: false,
|
||||
forceCollapse: false,
|
||||
pannelContext: none(),
|
||||
workspaceSetting: workspaceSetting,
|
||||
unauthorized: false,
|
||||
isMenuCollapsed: false,
|
||||
resizeOffset: 0,
|
||||
);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
||||
if (state.apps.length > value.fromIndex) {
|
||||
final app = state.apps[value.fromIndex];
|
||||
_workspaceService.moveApp(appId: app.id, fromIndex: value.fromIndex, toIndex: value.toIndex);
|
||||
final apps = List<App>.from(state.apps);
|
||||
final apps = List<AppPB>.from(state.apps);
|
||||
apps.insert(value.toIndex, apps.removeAt(value.fromIndex));
|
||||
emit(state.copyWith(apps: apps));
|
||||
}
|
||||
@ -79,7 +79,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
|
||||
));
|
||||
}
|
||||
|
||||
void _handleAppsOrFail(Either<List<App>, FlowyError> appsOrFail) {
|
||||
void _handleAppsOrFail(Either<List<AppPB>, FlowyError> appsOrFail) {
|
||||
appsOrFail.fold(
|
||||
(apps) => add(MenuEvent.didReceiveApps(left(apps))),
|
||||
(error) => add(MenuEvent.didReceiveApps(right(error))),
|
||||
@ -93,13 +93,13 @@ class MenuEvent with _$MenuEvent {
|
||||
const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
|
||||
const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
|
||||
const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
|
||||
const factory MenuEvent.didReceiveApps(Either<List<App>, FlowyError> appsOrFail) = _ReceiveApps;
|
||||
const factory MenuEvent.didReceiveApps(Either<List<AppPB>, FlowyError> appsOrFail) = _ReceiveApps;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class MenuState with _$MenuState {
|
||||
const factory MenuState({
|
||||
required List<App> apps,
|
||||
required List<AppPB> apps,
|
||||
required Either<Unit, FlowyError> successOrFailure,
|
||||
required Plugin plugin,
|
||||
}) = _MenuState;
|
||||
|
@ -14,7 +14,7 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
|
||||
final UserService _userService;
|
||||
final UserListener _userListener;
|
||||
final UserWorkspaceListener _userWorkspaceListener;
|
||||
final UserProfile userProfile;
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
MenuUserBloc(this.userProfile)
|
||||
: _userListener = UserListener(userProfile: userProfile),
|
||||
@ -31,7 +31,7 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
|
||||
fetchWorkspaces: () async {
|
||||
//
|
||||
},
|
||||
didReceiveUserProfile: (UserProfile newUserProfile) {
|
||||
didReceiveUserProfile: (UserProfilePB newUserProfile) {
|
||||
emit(state.copyWith(userProfile: newUserProfile));
|
||||
},
|
||||
updateUserName: (String name) {
|
||||
@ -58,14 +58,14 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
|
||||
result.fold((l) => null, (error) => Log.error(error));
|
||||
}
|
||||
|
||||
void _profileUpdated(Either<UserProfile, FlowyError> userProfileOrFailed) {
|
||||
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
|
||||
userProfileOrFailed.fold(
|
||||
(newUserProfile) => add(MenuUserEvent.didReceiveUserProfile(newUserProfile)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
||||
void _workspaceListUpdated(Either<List<Workspace>, FlowyError> workspacesOrFailed) {
|
||||
void _workspaceListUpdated(Either<List<WorkspacePB>, FlowyError> workspacesOrFailed) {
|
||||
// Do nothing by now
|
||||
}
|
||||
}
|
||||
@ -75,18 +75,18 @@ class MenuUserEvent with _$MenuUserEvent {
|
||||
const factory MenuUserEvent.initial() = _Initial;
|
||||
const factory MenuUserEvent.fetchWorkspaces() = _FetchWorkspaces;
|
||||
const factory MenuUserEvent.updateUserName(String name) = _UpdateUserName;
|
||||
const factory MenuUserEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile;
|
||||
const factory MenuUserEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class MenuUserState with _$MenuUserState {
|
||||
const factory MenuUserState({
|
||||
required UserProfile userProfile,
|
||||
required Option<List<Workspace>> workspaces,
|
||||
required UserProfilePB userProfile,
|
||||
required Option<List<WorkspacePB>> workspaces,
|
||||
required Either<Unit, String> successOrFailure,
|
||||
}) = _MenuUserState;
|
||||
|
||||
factory MenuUserState.initial(UserProfile userProfile) => MenuUserState(
|
||||
factory MenuUserState.initial(UserProfilePB userProfile) => MenuUserState(
|
||||
userProfile: userProfile,
|
||||
workspaces: none(),
|
||||
successOrFailure: left(unit),
|
||||
|
@ -62,7 +62,7 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
|
||||
Future<void> _moveView(_MoveView value, Emitter<ViewSectionState> emit) async {
|
||||
if (value.fromIndex < state.views.length) {
|
||||
final viewId = state.views[value.fromIndex].id;
|
||||
final views = List<View>.from(state.views);
|
||||
final views = List<ViewPB>.from(state.views);
|
||||
views.insert(value.toIndex, views.removeAt(value.fromIndex));
|
||||
emit(state.copyWith(views: views));
|
||||
|
||||
@ -92,16 +92,16 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
|
||||
@freezed
|
||||
class ViewSectionEvent with _$ViewSectionEvent {
|
||||
const factory ViewSectionEvent.initial() = _Initial;
|
||||
const factory ViewSectionEvent.setSelectedView(View? view) = _SetSelectedView;
|
||||
const factory ViewSectionEvent.setSelectedView(ViewPB? view) = _SetSelectedView;
|
||||
const factory ViewSectionEvent.moveView(int fromIndex, int toIndex) = _MoveView;
|
||||
const factory ViewSectionEvent.didReceiveViewUpdated(List<View> views) = _DidReceiveViewUpdated;
|
||||
const factory ViewSectionEvent.didReceiveViewUpdated(List<ViewPB> views) = _DidReceiveViewUpdated;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ViewSectionState with _$ViewSectionState {
|
||||
const factory ViewSectionState({
|
||||
required List<View> views,
|
||||
View? selectedView,
|
||||
required List<ViewPB> views,
|
||||
ViewPB? selectedView,
|
||||
}) = _ViewSectionState;
|
||||
|
||||
factory ViewSectionState.initial(AppViewDataContext appViewData) => ViewSectionState(
|
||||
|
@ -0,0 +1 @@
|
||||
export 'settings_dialog_bloc.dart';
|
@ -0,0 +1,67 @@
|
||||
import 'package:app_flowy/user/application/user_listener.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'settings_dialog_bloc.freezed.dart';
|
||||
|
||||
class SettingsDialogBloc extends Bloc<SettingsDialogEvent, SettingsDialogState> {
|
||||
final UserListener _userListener;
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
SettingsDialogBloc(this.userProfile)
|
||||
: _userListener = UserListener(userProfile: userProfile),
|
||||
super(SettingsDialogState.initial(userProfile)) {
|
||||
on<SettingsDialogEvent>((event, emit) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
_userListener.start(onProfileUpdated: _profileUpdated);
|
||||
},
|
||||
didReceiveUserProfile: (UserProfilePB newUserProfile) {
|
||||
emit(state.copyWith(userProfile: newUserProfile));
|
||||
},
|
||||
setViewIndex: (int viewIndex) {
|
||||
emit(state.copyWith(viewIndex: viewIndex));
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _userListener.stop();
|
||||
super.close();
|
||||
}
|
||||
|
||||
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
|
||||
userProfileOrFailed.fold(
|
||||
(newUserProfile) => add(SettingsDialogEvent.didReceiveUserProfile(newUserProfile)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SettingsDialogEvent with _$SettingsDialogEvent {
|
||||
const factory SettingsDialogEvent.initial() = _Initial;
|
||||
const factory SettingsDialogEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile;
|
||||
const factory SettingsDialogEvent.setViewIndex(int index) = _SetViewIndex;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SettingsDialogState with _$SettingsDialogState {
|
||||
const factory SettingsDialogState({
|
||||
required UserProfilePB userProfile,
|
||||
required Either<Unit, String> successOrFailure,
|
||||
required int viewIndex,
|
||||
}) = _SettingsDialogState;
|
||||
|
||||
factory SettingsDialogState.initial(UserProfilePB userProfile) => SettingsDialogState(
|
||||
userProfile: userProfile,
|
||||
successOrFailure: left(unit),
|
||||
viewIndex: 0,
|
||||
);
|
||||
}
|
@ -45,7 +45,7 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
||||
));
|
||||
}
|
||||
|
||||
void _listenTrashUpdated(Either<List<Trash>, FlowyError> trashOrFailed) {
|
||||
void _listenTrashUpdated(Either<List<TrashPB>, FlowyError> trashOrFailed) {
|
||||
trashOrFailed.fold(
|
||||
(trash) {
|
||||
add(TrashEvent.didReceiveTrash(trash));
|
||||
@ -66,9 +66,9 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
||||
@freezed
|
||||
class TrashEvent with _$TrashEvent {
|
||||
const factory TrashEvent.initial() = Initial;
|
||||
const factory TrashEvent.didReceiveTrash(List<Trash> trash) = ReceiveTrash;
|
||||
const factory TrashEvent.didReceiveTrash(List<TrashPB> trash) = ReceiveTrash;
|
||||
const factory TrashEvent.putback(String trashId) = Putback;
|
||||
const factory TrashEvent.delete(Trash trash) = Delete;
|
||||
const factory TrashEvent.delete(TrashPB trash) = Delete;
|
||||
const factory TrashEvent.restoreAll() = RestoreAll;
|
||||
const factory TrashEvent.deleteAll() = DeleteAll;
|
||||
}
|
||||
@ -76,7 +76,7 @@ class TrashEvent with _$TrashEvent {
|
||||
@freezed
|
||||
class TrashState with _$TrashState {
|
||||
const factory TrashState({
|
||||
required List<Trash> objects,
|
||||
required List<TrashPB> objects,
|
||||
required Either<Unit, FlowyError> successOrFailure,
|
||||
}) = _TrashState;
|
||||
|
||||
|
@ -8,7 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
|
||||
typedef TrashUpdatedCallback = void Function(Either<List<Trash>, FlowyError> trashOrFailed);
|
||||
typedef TrashUpdatedCallback = void Function(Either<List<TrashPB>, FlowyError> trashOrFailed);
|
||||
|
||||
class TrashListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
@ -27,7 +27,7 @@ class TrashListener {
|
||||
if (_trashUpdated != null) {
|
||||
result.fold(
|
||||
(payload) {
|
||||
final repeatedTrash = RepeatedTrash.fromBuffer(payload);
|
||||
final repeatedTrash = RepeatedTrashPB.fromBuffer(payload);
|
||||
_trashUpdated!(left(repeatedTrash.items));
|
||||
},
|
||||
(error) => _trashUpdated!(right(error)),
|
||||
|
@ -5,24 +5,24 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart';
|
||||
|
||||
class TrashService {
|
||||
Future<Either<RepeatedTrash, FlowyError>> readTrash() {
|
||||
Future<Either<RepeatedTrashPB, FlowyError>> readTrash() {
|
||||
return FolderEventReadTrash().send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> putback(String trashId) {
|
||||
final id = TrashId.create()..id = trashId;
|
||||
final id = TrashIdPB.create()..id = trashId;
|
||||
|
||||
return FolderEventPutbackTrash(id).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> deleteViews(List<Tuple2<String, TrashType>> trashList) {
|
||||
final items = trashList.map((trash) {
|
||||
return TrashId.create()
|
||||
return TrashIdPB.create()
|
||||
..id = trash.value1
|
||||
..ty = trash.value2;
|
||||
});
|
||||
|
||||
final ids = RepeatedTrashId(items: items);
|
||||
final ids = RepeatedTrashIdPB(items: items);
|
||||
return FolderEventDeleteTrash(ids).send();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
export 'settings_user_bloc.dart';
|
@ -0,0 +1,79 @@
|
||||
import 'package:app_flowy/user/application/user_listener.dart';
|
||||
import 'package:app_flowy/user/application/user_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
part 'settings_user_bloc.freezed.dart';
|
||||
|
||||
class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> {
|
||||
final UserService _userService;
|
||||
final UserListener _userListener;
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
SettingsUserViewBloc(this.userProfile)
|
||||
: _userListener = UserListener(userProfile: userProfile),
|
||||
_userService = UserService(userId: userProfile.id),
|
||||
super(SettingsUserState.initial(userProfile)) {
|
||||
on<SettingsUserEvent>((event, emit) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
_userListener.start(onProfileUpdated: _profileUpdated);
|
||||
await _initUser();
|
||||
},
|
||||
didReceiveUserProfile: (UserProfilePB newUserProfile) {
|
||||
emit(state.copyWith(userProfile: newUserProfile));
|
||||
},
|
||||
updateUserName: (String name) {
|
||||
_userService.updateUserProfile(name: name).then((result) {
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await _userListener.stop();
|
||||
super.close();
|
||||
}
|
||||
|
||||
Future<void> _initUser() async {
|
||||
final result = await _userService.initUser();
|
||||
result.fold((l) => null, (error) => Log.error(error));
|
||||
}
|
||||
|
||||
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
|
||||
userProfileOrFailed.fold(
|
||||
(newUserProfile) => add(SettingsUserEvent.didReceiveUserProfile(newUserProfile)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SettingsUserEvent with _$SettingsUserEvent {
|
||||
const factory SettingsUserEvent.initial() = _Initial;
|
||||
const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName;
|
||||
const factory SettingsUserEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SettingsUserState with _$SettingsUserState {
|
||||
const factory SettingsUserState({
|
||||
required UserProfilePB userProfile,
|
||||
required Either<Unit, String> successOrFailure,
|
||||
}) = _SettingsUserState;
|
||||
|
||||
factory SettingsUserState.initial(UserProfilePB userProfile) => SettingsUserState(
|
||||
userProfile: userProfile,
|
||||
successOrFailure: left(unit),
|
||||
);
|
||||
}
|
@ -11,7 +11,7 @@ part 'view_bloc.freezed.dart';
|
||||
class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
||||
final ViewService service;
|
||||
final ViewListener listener;
|
||||
final View view;
|
||||
final ViewPB view;
|
||||
|
||||
ViewBloc({
|
||||
required this.view,
|
||||
@ -81,18 +81,18 @@ class ViewEvent with _$ViewEvent {
|
||||
const factory ViewEvent.rename(String newName) = Rename;
|
||||
const factory ViewEvent.delete() = Delete;
|
||||
const factory ViewEvent.duplicate() = Duplicate;
|
||||
const factory ViewEvent.viewDidUpdate(Either<View, FlowyError> result) = ViewDidUpdate;
|
||||
const factory ViewEvent.viewDidUpdate(Either<ViewPB, FlowyError> result) = ViewDidUpdate;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ViewState with _$ViewState {
|
||||
const factory ViewState({
|
||||
required View view,
|
||||
required ViewPB view,
|
||||
required bool isEditing,
|
||||
required Either<Unit, FlowyError> successOrFailure,
|
||||
}) = _ViewState;
|
||||
|
||||
factory ViewState.init(View view) => ViewState(
|
||||
factory ViewState.init(ViewPB view) => ViewState(
|
||||
view: view,
|
||||
isEditing: false,
|
||||
successOrFailure: left(unit),
|
||||
|
@ -32,7 +32,7 @@ extension FlowyPluginExtension on FlowyPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewExtension on View {
|
||||
extension ViewExtension on ViewPB {
|
||||
Widget renderThumbnail({Color? iconColor}) {
|
||||
String thumbnail = "file_icon";
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user