diff --git a/.github/workflows/dart_lint.yml b/.github/workflows/dart_lint.yml index 2b4a995cce..69cf8e46c7 100644 --- a/.github/workflows/dart_lint.yml +++ b/.github/workflows/dart_lint.yml @@ -8,12 +8,8 @@ name: Flutter lint on: push: branches: [ main ] - paths: - - 'frontend/app_flowy' pull_request: branches: [ main ] - paths: - - 'frontend/app_flowy' env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69cf3ec788..93dedaa43d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,7 +66,7 @@ jobs: working-directory: frontend run: | flutter config --enable-linux-desktop - cargo make --profile production-linux-x86 appflowy + cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-linux-x86 appflowy - name: Upload Release Asset id: upload-release-asset @@ -111,7 +111,7 @@ jobs: working-directory: frontend run: | flutter config --enable-macos-desktop - cargo make --profile production-mac-x86 appflowy + cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-mac-x86 appflowy - name: Archive macOS app working-directory: ${{ env.MACOS_APP_RELEASE_PATH }} diff --git a/.github/workflows/rust_lint.yml b/.github/workflows/rust_lint.yml index 9b39f28f2d..ac650b197b 100644 --- a/.github/workflows/rust_lint.yml +++ b/.github/workflows/rust_lint.yml @@ -3,14 +3,8 @@ name: Rust lint on: push: branches: [ main ] - paths: - - 'frontend/rust-lib' - - 'shared-lib' pull_request: branches: [ main ] - paths: - - 'frontend/rust-lib' - - 'shared-lib' env: diff --git a/.github/workflows/rust_test.yml b/.github/workflows/rust_test.yml index e58db025b4..30b1f15576 100644 --- a/.github/workflows/rust_test.yml +++ b/.github/workflows/rust_test.yml @@ -4,15 +4,9 @@ on: push: branches: - 'main' - paths: - - 'frontend/rust-lib' - - 'shared-lib' pull_request: branches: - 'main' - paths: - - 'frontend/rust-lib' - - 'shared-lib' env: CARGO_TERM_COLOR: always @@ -50,8 +44,8 @@ jobs: - name: Run rust-lib tests working-directory: frontend/rust-lib - run: cargo test --no-default-features + run: RUST_LOG=info cargo test --no-default-features --features="sync" - name: Run shared-lib tests working-directory: shared-lib - run: cargo test --no-default-features \ No newline at end of file + run: RUST_LOG=info cargo test --no-default-features \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 19540b8ce6..a5ac013c35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Release Notes +## Version 0.0.4 - beta.1 - 2022-04-08 +v0.0.4 - beta.1 is pre-release + +New features +- Table-view database + - supported column types: Text, Checbox, Single-select, Multi-select, Numbers + - hide / delete columns + - insert rows + ## Version 0.0.3 - 2022-02-23 v0.0.3 is production ready, available on Linux, macOS, and Windows diff --git a/frontend/.vscode/launch.json b/frontend/.vscode/launch.json index 74249d756e..66fc02b1a1 100644 --- a/frontend/.vscode/launch.json +++ b/frontend/.vscode/launch.json @@ -11,7 +11,7 @@ "type": "dart", "preLaunchTask": "build_flowy_sdk", "env":{ - "RUST_LOG":"info", + "RUST_LOG":"info" }, "cwd": "${workspaceRoot}/app_flowy" }, @@ -22,7 +22,7 @@ "type": "dart", "preLaunchTask": "build_flowy_sdk", "env":{ - "RUST_LOG":"trace", + "RUST_LOG":"trace" }, "cwd": "${workspaceRoot}/app_flowy" }, diff --git a/frontend/Makefile.toml b/frontend/Makefile.toml index e661a425b6..7c82e17ba7 100644 --- a/frontend/Makefile.toml +++ b/frontend/Makefile.toml @@ -9,24 +9,43 @@ extend = [ { path = "scripts/makefile/flutter.toml" }, ] +[config] +on_error_task = "catch" + +[tasks.catch] +run_task = {name = ["restore-crate-type"]} + [env] RUST_LOG = "info" CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true CARGO_MAKE_CRATE_FS_NAME = "dart_ffi" CARGO_MAKE_CRATE_NAME = "dart-ffi" LIB_NAME = "dart_ffi" -VERSION = "0.0.3" +CURRENT_APP_VERSION = "0.0.4" FEATURES = "flutter" PRODUCT_NAME = "AppFlowy" -#CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html -CRATE_TYPE = "cdylib" -SDK_EXT = "dylib" +# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html +# If you update the macOS's CRATE_TYPE, don't forget to update the +# flowy_sdk.podspec +# for staticlib: +# s.static_framework = true +# s.vendored_libraries = "libdart_ffi.a" +# for cdylib: +# s.vendored_libraries = "libdart_ffi.dylib" +# +# Remember to update the ffi.dart: +# for staticlib: +# if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.a'); +# for cdylib: +# if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.dylib'); +CRATE_TYPE = "staticlib" +SDK_EXT = "a" APP_ENVIRONMENT = "local" FLUTTER_FLOWY_SDK_PATH="app_flowy/packages/flowy_sdk" PROTOBUF_DERIVE_CACHE="../shared-lib/flowy-derive/src/derive_cache/derive_cache.rs" [env.development-mac] -RUST_LOG = "trace" +RUST_LOG = "info" TARGET_OS = "macos" RUST_COMPILE_TARGET = "x86_64-apple-darwin" BUILD_FLAG = "debug" diff --git a/frontend/app_flowy/assets/images/editor/Icons 16/Yen.svg b/frontend/app_flowy/assets/images/editor/Icons 16/Yen.svg deleted file mode 100644 index b7cf1d361d..0000000000 --- a/frontend/app_flowy/assets/images/editor/Icons 16/Yen.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/app_flowy/assets/images/grid/checkmark.svg b/frontend/app_flowy/assets/images/grid/checkmark.svg new file mode 100644 index 0000000000..f9c848f713 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/checkmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/delete.svg b/frontend/app_flowy/assets/images/grid/delete.svg new file mode 100644 index 0000000000..fcfbf2f6dd --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/delete.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/app_flowy/assets/images/grid/details.svg b/frontend/app_flowy/assets/images/grid/details.svg new file mode 100644 index 0000000000..e4c9f58f27 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/details.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/duplicate.svg b/frontend/app_flowy/assets/images/grid/duplicate.svg new file mode 100644 index 0000000000..f11048fd2f --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/duplicate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/expander.svg b/frontend/app_flowy/assets/images/grid/expander.svg new file mode 100644 index 0000000000..179bdb1a9e --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/expander.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/checkbox.svg b/frontend/app_flowy/assets/images/grid/field/checkbox.svg new file mode 100644 index 0000000000..37f52c47ed --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/checkbox.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/checklist.svg b/frontend/app_flowy/assets/images/grid/field/checklist.svg new file mode 100644 index 0000000000..3a88d236a1 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/checklist.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/date.svg b/frontend/app_flowy/assets/images/grid/field/date.svg new file mode 100644 index 0000000000..78243f1e75 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/date.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/euro.svg b/frontend/app_flowy/assets/images/grid/field/euro.svg new file mode 100644 index 0000000000..95f511f687 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/euro.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/field/multi_select.svg b/frontend/app_flowy/assets/images/grid/field/multi_select.svg new file mode 100644 index 0000000000..97a2e9c434 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/multi_select.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/number.svg b/frontend/app_flowy/assets/images/grid/field/number.svg new file mode 100644 index 0000000000..9d8b98d10d --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/number.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/field/numbers.svg b/frontend/app_flowy/assets/images/grid/field/numbers.svg new file mode 100644 index 0000000000..9d8b98d10d --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/numbers.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/field/single_select.svg b/frontend/app_flowy/assets/images/grid/field/single_select.svg new file mode 100644 index 0000000000..8ccbc9a2e3 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/single_select.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/text.svg b/frontend/app_flowy/assets/images/grid/field/text.svg new file mode 100644 index 0000000000..7befa5080f --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/text.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/field/us_dollar.svg b/frontend/app_flowy/assets/images/grid/field/us_dollar.svg new file mode 100644 index 0000000000..a8485cd6a1 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/us_dollar.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/field/yen.svg b/frontend/app_flowy/assets/images/grid/field/yen.svg new file mode 100644 index 0000000000..8e9bf47c99 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/field/yen.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/hide.svg b/frontend/app_flowy/assets/images/grid/hide.svg new file mode 100644 index 0000000000..dfb6dbb90c --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/hide.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/left.svg b/frontend/app_flowy/assets/images/grid/left.svg new file mode 100644 index 0000000000..0f771a3858 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/app_flowy/assets/images/grid/more.svg b/frontend/app_flowy/assets/images/grid/more.svg new file mode 100644 index 0000000000..b191e64a10 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/more.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/app_flowy/assets/images/grid/right.svg b/frontend/app_flowy/assets/images/grid/right.svg new file mode 100644 index 0000000000..7d738f4e69 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/app_flowy/assets/images/editor/Icons 16/Sort/Ascending.svg b/frontend/app_flowy/assets/images/grid/setting/ascending.svg similarity index 100% rename from frontend/app_flowy/assets/images/editor/Icons 16/Sort/Ascending.svg rename to frontend/app_flowy/assets/images/grid/setting/ascending.svg diff --git a/frontend/app_flowy/assets/images/editor/Icons 16/Sort/Descending.svg b/frontend/app_flowy/assets/images/grid/setting/descending.svg similarity index 100% rename from frontend/app_flowy/assets/images/editor/Icons 16/Sort/Descending.svg rename to frontend/app_flowy/assets/images/grid/setting/descending.svg diff --git a/frontend/app_flowy/assets/images/editor/Icons 16/Filter.svg b/frontend/app_flowy/assets/images/grid/setting/filter.svg similarity index 100% rename from frontend/app_flowy/assets/images/editor/Icons 16/Filter.svg rename to frontend/app_flowy/assets/images/grid/setting/filter.svg diff --git a/frontend/app_flowy/assets/images/editor/Icons 16/Properties.svg b/frontend/app_flowy/assets/images/grid/setting/properties.svg similarity index 100% rename from frontend/app_flowy/assets/images/editor/Icons 16/Properties.svg rename to frontend/app_flowy/assets/images/grid/setting/properties.svg diff --git a/frontend/app_flowy/assets/images/grid/setting/setting.svg b/frontend/app_flowy/assets/images/grid/setting/setting.svg new file mode 100644 index 0000000000..3d632703ab --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/setting/setting.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/images/grid/setting/sort.svg b/frontend/app_flowy/assets/images/grid/setting/sort.svg new file mode 100644 index 0000000000..06e17d62a9 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/setting/sort.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json index 7717e71229..a051401446 100644 --- a/frontend/app_flowy/assets/translations/en.json +++ b/frontend/app_flowy/assets/translations/en.json @@ -141,5 +141,59 @@ "lightLabel": "Light Mode", "darkLabel": "Dark Mode" } + }, + "grid": { + "settings": { + "filter": "Filter", + "sortBy": "Sort by", + "Properties": "Properties" + }, + "field": { + "hide": "Hide", + "insertLeft": "Insert Left", + "insertRight": "Insert Right", + "duplicate": "Duplicate", + "delete": "Delete", + "textFieldName": "Text", + "checkboxFieldName": "Checkbox", + "dateFieldName": "Date", + "numberFieldName": "Numbers", + "singleSelectFieldName": "Select", + "multiSelectFieldName": "Multiselect", + "numberFormat": " Number format", + "dateFormat": " Date format", + "includeTime": " Include time", + "dateFormatFriendly": "Month Day,Year", + "dateFormatISO": "Year-Month-Day", + "dateFormatLocal": "Month/Month/Day", + "dateFormatUS": "Month/Month/Day", + "timeFormat": " Time format", + "timeFormatTwelveHour": "12 hour", + "timeFormatTwentyFourHour": "24 hour", + "addSelectOption": "Add an option", + "optionTitle": "Options", + "addOption": "Add option", + "editProperty": "Edit property" + }, + "row": { + "duplicate": "Duplicate", + "delete": "Delete", + "textPlaceholder": "Empty" + }, + "selectOption": { + "purpleColor": "Purple", + "pinkColor": "Pink", + "lightPinkColor": "Light Pink", + "orangeColor": "Orange", + "yellowColor": "Yellow", + "limeColor": "Lime", + "greenColor": "Green", + "aquaColor": "Aqua", + "blueColor": "Blue", + "deleteTag": "Delete tag", + "colorPannelTitle": "Colors", + "pannelTitle": "Select an option or create one", + "searchOption": "Search for an option" + } } } diff --git a/frontend/app_flowy/assets/translations/tr-TR.json b/frontend/app_flowy/assets/translations/tr-TR.json new file mode 100644 index 0000000000..c83cace0a7 --- /dev/null +++ b/frontend/app_flowy/assets/translations/tr-TR.json @@ -0,0 +1,145 @@ +{ + "appName": "AppFlowy", + "defaultUsername": "Ben", + "welcomeText": "@:appName'e Hoş Geldiniz!", + "githubStarText": "GitHub Yıldızı!", + "subscribeNewsletterText": "Bültene Abone Ol", + "letsGoButtonText": "Hadi başlayalım.", + "title": "Başlık", + "signUp": { + "buttonText": "Kayıt Ol", + "title": "@:appName'e kaydolun.", + "getStartedText": "başlayalım", + "emptyPasswordError": "Parola boş olamaz", + "repeatPasswordEmptyError": "Parola (tekrar) boş olamaz", + "unmatchedPasswordError": "Parolalar eşleşmiyor", + "alreadyHaveAnAccount": "Zaten hesabınız var mı?", + "emailHint": "E-Posta", + "passwordHint": "Parola", + "repeatPasswordHint": "Tekrar parola" + }, + "signIn": { + "loginTitle": "@:appName oturum aç", + "loginButtonText": "Giriş", + "buttonText": "Oturum Aç", + "forgotPassword": "Parolanızı mı Unuttunuz?", + "emailHint": "E-Posta", + "passwordHint": "Parola", + "dontHaveAnAccount": "Hesabınız yok mu?", + "repeatPasswordEmptyError": "Parola (tekrar) boş olamaz", + "unmatchedPasswordError": "Parolalar eşleşmiyor" + }, + "workspace": { + "create": "Çalışma alanı oluştur", + "hint": "Çalışma alanı", + "notFoundError": "Çalışma alanı bulunamadı" + }, + "shareAction": { + "buttonText": "Paylaş", + "workInProgress": "Yakında", + "markdown": "Markdown", + "copyLink": "Link'i Kopyala" + }, + "disclosureAction": { + "rename": "Yeniden adlandır", + "delete": "Sil", + "duplicate": "Çoğalt" + }, + "blankPageTitle": "Boş sayfa", + "newPageText": "Yeni sayfa", + "trash": { + "text": "Çöp", + "restoreAll": "Geri Yükle", + "deleteAll": "Sil", + "pageHeader": { + "fileName": "Dosya adı", + "lastModified": "Son Değiştirme", + "created": "Oluşturuldu" + } + }, + "deletePagePrompt": { + "text": "Bu sayfa Çöp Kutusu'nda", + "restore": "Sayfayı geri yükle", + "deletePermanent": "Kalıcı olarak sil" + }, + "dialogCreatePageNameHint": "Sayfa adı", + "questionBubble": { + "whatsNew": "Yeni ne var?", + "help": "Yardım & Destek", + "debug": { + "name": "Hata Ayıklama", + "success": "Hata ayıklama bilgileri panoya kopyalandı!", + "fail": "Hata ayıklama bilgileri panoya kopyalanamıyor" + } + }, + "menuAppHeader": { + "addPageTooltip": "Yeni bir sayfa ekleyin", + "defaultNewPageName": "Başlıksız", + "renameDialog": "Yeniden adlandır" + }, + "toolbar": { + "undo": "Geri", + "redo": "İleri", + "bold": "Kalın", + "italic": "İtalik", + "underline": "Altı Çizili", + "strike": "Üstü Çizili", + "numList": "Numaralı Liste", + "bulletList": "Madde İşaretli Liste", + "checkList": "Yapılacaklar Listesi", + "inlineCode": "Kod", + "quote": "Alıntı", + "header": "Başlık", + "highlight": "Vurgu" + }, + "tooltip": { + "lightMode": "Aydınlık Mod'a Geç", + "darkMode": "Karanlık Mod'a Geç" + }, + "contactsPage": { + "title": "İletişim", + "whatsHappening": "Bu hafta neler var?", + "addContact": "Kişi Ekle", + "editContact": "Kişiyi Düzenle" + }, + "button": { + "OK": "TAMAM", + "Cancel": "İptal", + "signIn": "Oturum Aç", + "signOut": "Oturum Kapat", + "complete": "Tamamlandı", + "save": "Kaydet" + }, + "label": { + "welcome": "Merhaba!", + "firstName": "Ad", + "middleName": "İkinci Ad", + "lastName": "Soyad", + "stepX": "Aşama {X}" + }, + "oAuth": { + "err": { + "failedTitle": "Hesabınıza bağlanılamıyor.", + "failedMsg": "Lütfen, tarayıcınızda oturum açma işlemini tamamladığınızdan emin olun." + }, + "google": { + "title": "GOOGLE OTURUM AÇMA", + "instruction1": "Google Kişilerinizi içe aktarmak için web tarayıcınızı kullanarak bu uygulamaya izin vermeniz gerekir.", + "instruction2": "Simgeyi tıklayarak veya metni seçerek bu kodu panonuza kopyalayın:", + "instruction3": "Web tarayıcınızda aşağıdaki bağlantıyı açın ve yukarıdaki kodu girin:", + "instruction4": "Kayıt işlemini tamamladığınızda aşağıdaki düğmeye basın:" + } + }, + "settings": { + "title": "Ayarlar", + "menu": { + "appearance": "Görünüm", + "language": "Dil", + "open": "Ayarları Aç" + }, + "appearance": { + "lightLabel": "Aydınlık Mod", + "darkLabel": "Karanlık Mod" + } + } +} diff --git a/frontend/app_flowy/lib/core/notification_helper.dart b/frontend/app_flowy/lib/core/notification_helper.dart index 88b299aa3a..650abc544c 100644 --- a/frontend/app_flowy/lib/core/notification_helper.dart +++ b/frontend/app_flowy/lib/core/notification_helper.dart @@ -1,10 +1,14 @@ +import 'dart:async'; import 'dart:typed_data'; import 'package:flowy_sdk/protobuf/dart-notify/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; +import 'package:flowy_sdk/rust_stream.dart'; +// User typedef UserNotificationCallback = void Function(UserNotification, Either); class UserNotificationParser extends NotificationParser { @@ -17,10 +21,11 @@ class UserNotificationParser extends NotificationParser); +// Folder +typedef FolderNotificationCallback = void Function(FolderNotification, Either); class FolderNotificationParser extends NotificationParser { - FolderNotificationParser({String? id, required NotificationCallback callback}) + FolderNotificationParser({String? id, required FolderNotificationCallback callback}) : super( id: id, callback: callback, @@ -29,6 +34,36 @@ class FolderNotificationParser extends NotificationParser); + +class GridNotificationParser extends NotificationParser { + GridNotificationParser({String? id, required GridNotificationCallback callback}) + : super( + id: id, + callback: callback, + tyParser: (ty) => GridNotification.valueOf(ty), + errorParser: (bytes) => FlowyError.fromBuffer(bytes), + ); +} + +typedef GridNotificationHandler = Function(GridNotification ty, Either result); + +class GridNotificationListener { + StreamSubscription? _subscription; + GridNotificationParser? _parser; + + GridNotificationListener({required String objectId, required GridNotificationHandler handler}) + : _parser = GridNotificationParser(id: objectId, callback: handler) { + _subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable)); + } + + Future stop() async { + _parser = null; + await _subscription?.cancel(); + } +} + class NotificationParser { String? id; void Function(T, Either) callback; diff --git a/frontend/app_flowy/lib/plugin/plugin.dart b/frontend/app_flowy/lib/plugin/plugin.dart index d46e14746f..8d30b122ad 100644 --- a/frontend/app_flowy/lib/plugin/plugin.dart +++ b/frontend/app_flowy/lib/plugin/plugin.dart @@ -3,27 +3,46 @@ library flowy_plugin; import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; +import 'package:flowy_infra/notifier.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flutter/widgets.dart'; export "./src/sandbox.dart"; +enum DefaultPlugin { + quill, + blank, + trash, + grid, +} + +extension FlowyDefaultPluginExt on DefaultPlugin { + int type() { + switch (this) { + case DefaultPlugin.quill: + return 0; + case DefaultPlugin.blank: + return 1; + case DefaultPlugin.trash: + return 2; + case DefaultPlugin.grid: + return 3; + } + } +} + typedef PluginType = int; - typedef PluginDataType = ViewDataType; - typedef PluginId = String; abstract class Plugin { - PluginId get pluginId; + PluginId get id; - PluginDisplay get pluginDisplay; + PluginDisplay get display; - PluginType get pluginType; + PluginType get ty; - ChangeNotifier? get displayNotifier => null; - - void dispose(); + void dispose() {} } abstract class PluginBuilder { @@ -33,22 +52,19 @@ abstract class PluginBuilder { PluginType get pluginType; - ViewDataType get dataType => ViewDataType.PlainText; + ViewDataType get dataType => ViewDataType.TextBlock; } abstract class PluginConfig { + // Return false will disable the user to create it. For example, a trash plugin shouldn't be created by the user, bool get creatable => true; } -abstract class PluginDisplay with NavigationItem { - @override - Widget get leftBarItem; - - @override - Widget? get rightBarItem; - +abstract class PluginDisplay with NavigationItem { List get navigationItems; + PublishNotifier? get notifier => null; + Widget buildWidget(); } diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart new file mode 100644 index 0000000000..8f239f1ece --- /dev/null +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -0,0 +1,217 @@ +import 'package:app_flowy/core/network_monitor.dart'; +import 'package:app_flowy/user/application/user_listener.dart'; +import 'package:app_flowy/user/application/user_service.dart'; +import 'package:app_flowy/workspace/application/app/prelude.dart'; +import 'package:app_flowy/workspace/application/doc/prelude.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/application/trash/prelude.dart'; +import 'package:app_flowy/workspace/application/workspace/prelude.dart'; +import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart'; +import 'package:app_flowy/workspace/application/home/home_bloc.dart'; +import 'package:app_flowy/workspace/application/view/prelude.dart'; +import 'package:app_flowy/workspace/application/home/prelude.dart'; +import 'package:app_flowy/workspace/application/menu/prelude.dart'; +import 'package:app_flowy/user/application/prelude.dart'; +import 'package:app_flowy/user/presentation/router.dart'; +import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart'; +import 'package:get_it/get_it.dart'; + +class DependencyResolver { + static Future resolve(GetIt getIt) async { + _resolveUserDeps(getIt); + + _resolveHomeDeps(getIt); + + _resolveFolderDeps(getIt); + + _resolveDocDeps(getIt); + + _resolveGridDeps(getIt); + } +} + +void _resolveUserDeps(GetIt getIt) { + getIt.registerFactory(() => AuthService()); + getIt.registerFactory(() => AuthRouter()); + + getIt.registerFactory(() => SignInBloc(getIt())); + getIt.registerFactory(() => SignUpBloc(getIt())); + + getIt.registerFactory(() => SplashRoute()); + getIt.registerFactory(() => HomeBloc()); + getIt.registerFactory(() => EditPannelBloc()); + getIt.registerFactory(() => SplashBloc()); + getIt.registerLazySingleton(() => NetworkListener()); +} + +void _resolveHomeDeps(GetIt getIt) { + getIt.registerFactoryParam( + (user, _) => UserListener(user: user), + ); + + getIt.registerFactoryParam( + (user, _) => HomeListenBloc(getIt(param1: user)), + ); + + // + getIt.registerLazySingleton(() => HomeStackManager()); + + getIt.registerFactoryParam( + (user, _) => WelcomeBloc( + userService: UserService(), + userListener: getIt(param1: user), + ), + ); + + // share + getIt.registerLazySingleton(() => ShareService()); + getIt.registerFactoryParam( + (view, _) => DocShareBloc(view: view, service: getIt())); +} + +void _resolveFolderDeps(GetIt getIt) { + //workspace + getIt.registerFactoryParam((user, workspaceId) => + WorkspaceListener(service: WorkspaceListenerService(user: user, workspaceId: workspaceId))); + + // View + getIt.registerFactoryParam( + (view, _) => ViewListener(view: view), + ); + + getIt.registerFactoryParam( + (view, _) => ViewBloc( + view: view, + service: ViewService(), + listener: getIt(param1: view), + ), + ); + + //Menu + getIt.registerFactoryParam( + (user, workspaceId) => MenuBloc( + workspaceId: workspaceId, + service: WorkspaceService(), + listener: getIt(param1: user, param2: workspaceId), + ), + ); + + getIt.registerFactoryParam( + (user, _) => MenuUserBloc( + user, + UserService(), + getIt(param1: user), + ), + ); + + // App + getIt.registerFactoryParam( + (app, _) => AppBloc( + app: app, + service: AppService(), + listener: AppListener(appId: app.id), + ), + ); + + // trash + getIt.registerLazySingleton(() => TrashService()); + getIt.registerLazySingleton(() => TrashListener()); + getIt.registerFactory( + () => TrashBloc( + service: getIt(), + listener: getIt(), + ), + ); +} + +void _resolveDocDeps(GetIt getIt) { +// Doc + getIt.registerFactoryParam( + (view, _) => DocumentBloc( + view: view, + service: DocumentService(), + listener: getIt(param1: view), + trashService: getIt(), + ), + ); +} + +void _resolveGridDeps(GetIt getIt) { + // Grid + getIt.registerFactoryParam( + (view, _) => GridBloc(view: view), + ); + + getIt.registerFactoryParam( + (gridId, fieldCache) => GridHeaderBloc( + gridId: gridId, + fieldCache: fieldCache, + ), + ); + + getIt.registerFactoryParam( + (data, _) => FieldActionSheetBloc( + field: data.field, + service: FieldService(gridId: data.gridId), + ), + ); + + getIt.registerFactoryParam( + (gridId, fieldLoader) => FieldEditorBloc( + service: FieldService(gridId: gridId), + fieldLoader: fieldLoader, + ), + ); + + getIt.registerFactoryParam( + (cellData, _) => TextCellBloc( + cellData: cellData, + ), + ); + + getIt.registerFactoryParam( + (cellData, _) => SelectionCellBloc( + cellData: cellData, + ), + ); + + getIt.registerFactoryParam( + (cellData, _) => NumberCellBloc( + cellData: cellData, + ), + ); + + getIt.registerFactoryParam( + (cellData, _) => DateCellBloc( + cellData: cellData, + ), + ); + + getIt.registerFactoryParam( + (cellData, _) => CheckboxCellBloc( + service: CellService(), + cellData: cellData, + ), + ); + + getIt.registerFactoryParam( + (context, _) => FieldSwitcherBloc(context), + ); + + getIt.registerFactoryParam( + (typeOption, _) => DateTypeOptionBloc(typeOption: typeOption), + ); + + getIt.registerFactoryParam( + (typeOption, _) => NumberTypeOptionBloc(typeOption: typeOption), + ); + + getIt.registerFactoryParam( + (gridId, cache) => GridPropertyBloc(gridId: gridId, fieldCache: cache), + ); +} diff --git a/frontend/app_flowy/lib/startup/home_deps_resolver.dart b/frontend/app_flowy/lib/startup/home_deps_resolver.dart deleted file mode 100644 index c006c9de88..0000000000 --- a/frontend/app_flowy/lib/startup/home_deps_resolver.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'package:app_flowy/user/application/user_listener.dart'; -import 'package:app_flowy/user/application/user_service.dart'; -import 'package:app_flowy/workspace/application/app/app_bloc.dart'; -import 'package:app_flowy/workspace/application/app/app_listener.dart'; -import 'package:app_flowy/workspace/application/app/app_service.dart'; -import 'package:app_flowy/workspace/application/doc/doc_bloc.dart'; -import 'package:app_flowy/workspace/application/doc/doc_service.dart'; -import 'package:app_flowy/workspace/application/doc/share_bloc.dart'; -import 'package:app_flowy/workspace/application/doc/share_service.dart'; -import 'package:app_flowy/workspace/application/home/home_listen_bloc.dart'; -import 'package:app_flowy/workspace/application/menu/menu_bloc.dart'; -import 'package:app_flowy/workspace/application/menu/menu_user_bloc.dart'; -import 'package:app_flowy/workspace/application/trash/trash_bloc.dart'; -import 'package:app_flowy/workspace/application/trash/trash_listener.dart'; -import 'package:app_flowy/workspace/application/trash/trash_service.dart'; -import 'package:app_flowy/workspace/application/view/view_bloc.dart'; -import 'package:app_flowy/workspace/application/view/view_listener.dart'; -import 'package:app_flowy/workspace/application/view/view_service.dart'; -import 'package:app_flowy/workspace/application/workspace/welcome_bloc.dart'; -import 'package:app_flowy/workspace/application/workspace/workspace_listener.dart'; -import 'package:app_flowy/workspace/application/workspace/workspace_service.dart'; -import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart'; -import 'package:get_it/get_it.dart'; - -class HomeDepsResolver { - static Future resolve(GetIt getIt) async { - getIt.registerFactoryParam( - (user, _) => UserListener(user: user), - ); - - getIt.registerFactoryParam( - (user, _) => HomeListenBloc(getIt(param1: user)), - ); - - // - getIt.registerLazySingleton(() => HomeStackManager()); - getIt.registerFactoryParam( - (user, _) => WelcomeBloc( - userService: UserService(), - userListener: getIt(param1: user), - ), - ); - - //workspace - getIt.registerFactoryParam((user, workspaceId) => - WorkspaceListener(service: WorkspaceListenerService(user: user, workspaceId: workspaceId))); - - // View - getIt.registerFactoryParam( - (view, _) => ViewListener(view: view), - ); - - getIt.registerFactoryParam( - (view, _) => ViewBloc( - view: view, - service: ViewService(), - listener: getIt(param1: view), - ), - ); - - //Menu Bloc - getIt.registerFactoryParam( - (user, workspaceId) => MenuBloc( - workspaceId: workspaceId, - service: WorkspaceService(), - listener: getIt(param1: user, param2: workspaceId), - ), - ); - - getIt.registerFactoryParam( - (user, _) => MenuUserBloc( - user, - UserService(), - getIt(param1: user), - ), - ); - - // App - getIt.registerFactoryParam( - (app, _) => AppBloc( - app: app, - service: AppService(), - listener: AppListener(appId: app.id), - ), - ); - - // Doc - getIt.registerFactoryParam( - (view, _) => DocumentBloc( - view: view, - service: DocumentService(), - listener: getIt(param1: view), - trashService: getIt(), - ), - ); - - // trash - getIt.registerLazySingleton(() => TrashService()); - getIt.registerLazySingleton(() => TrashListener()); - getIt.registerFactory( - () => TrashBloc( - service: getIt(), - listener: getIt(), - ), - ); - - // share - getIt.registerLazySingleton(() => ShareService()); - getIt.registerFactoryParam( - (view, _) => DocShareBloc(view: view, service: getIt())); - } -} diff --git a/frontend/app_flowy/lib/startup/startup.dart b/frontend/app_flowy/lib/startup/startup.dart index 0335879f5a..38243afa56 100644 --- a/frontend/app_flowy/lib/startup/startup.dart +++ b/frontend/app_flowy/lib/startup/startup.dart @@ -2,8 +2,7 @@ import 'dart:io'; import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/tasks/prelude.dart'; -import 'package:app_flowy/startup/home_deps_resolver.dart'; -import 'package:app_flowy/startup/user_deps_resolver.dart'; +import 'package:app_flowy/startup/deps_resolver.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; @@ -62,8 +61,7 @@ Future initGetIt( getIt.registerLazySingleton(() => AppLauncher(env, getIt)); getIt.registerSingleton(PluginSandbox()); - await UserDepsResolver.resolve(getIt); - await HomeDepsResolver.resolve(getIt); + await DependencyResolver.resolve(getIt); } class LaunchContext { diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index 23f4109042..1747cfd8ec 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -39,6 +39,7 @@ class InitAppWidgetTask extends LaunchTask { Locale('it', 'IT'), Locale('pt', 'BR'), Locale('ru', 'RU'), + Locale('tr', 'TR'), Locale('zh', 'CN'), ], path: 'assets/translations', @@ -112,7 +113,7 @@ class ApplicationBlocObserver extends BlocObserver { // ignore: unnecessary_overrides void onTransition(Bloc bloc, Transition transition) { // Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}"); - //Log.debug("${transition.nextState}"); + // Log.debug("${transition.nextState}"); super.onTransition(bloc, transition); } @@ -122,9 +123,9 @@ class ApplicationBlocObserver extends BlocObserver { super.onError(bloc, error, stackTrace); } - @override - void onEvent(Bloc bloc, Object? event) { - Log.debug("$event"); - super.onEvent(bloc, event); - } + // @override + // void onEvent(Bloc bloc, Object? event) { + // Log.debug("$event"); + // super.onEvent(bloc, event); + // } } diff --git a/frontend/app_flowy/lib/startup/tasks/load_plugin.dart b/frontend/app_flowy/lib/startup/tasks/load_plugin.dart index 650dd49d22..fd4bb7e2b9 100644 --- a/frontend/app_flowy/lib/startup/tasks/load_plugin.dart +++ b/frontend/app_flowy/lib/startup/tasks/load_plugin.dart @@ -2,27 +2,9 @@ import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/presentation/plugins/blank/blank.dart'; import 'package:app_flowy/workspace/presentation/plugins/doc/document.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/grid.dart'; import 'package:app_flowy/workspace/presentation/plugins/trash/trash.dart'; -enum DefaultPlugin { - quillEditor, - blank, - trash, -} - -extension FlowyDefaultPluginExt on DefaultPlugin { - int type() { - switch (this) { - case DefaultPlugin.quillEditor: - return 0; - case DefaultPlugin.blank: - return 1; - case DefaultPlugin.trash: - return 2; - } - } -} - class PluginLoadTask extends LaunchTask { @override LaunchTaskType get type => LaunchTaskType.dataProcessing; @@ -32,5 +14,6 @@ class PluginLoadTask extends LaunchTask { registerPlugin(builder: BlankPluginBuilder(), config: BlankPluginConfig()); registerPlugin(builder: TrashPluginBuilder(), config: TrashPluginConfig()); registerPlugin(builder: DocumentPluginBuilder()); + registerPlugin(builder: GridPluginBuilder(), config: GridPluginConfig()); } } diff --git a/frontend/app_flowy/lib/startup/user_deps_resolver.dart b/frontend/app_flowy/lib/startup/user_deps_resolver.dart deleted file mode 100644 index daf67a071a..0000000000 --- a/frontend/app_flowy/lib/startup/user_deps_resolver.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:app_flowy/user/application/auth_service.dart'; -import 'package:app_flowy/user/application/sign_in_bloc.dart'; -import 'package:app_flowy/user/application/sign_up_bloc.dart'; -import 'package:app_flowy/user/application/splash_bloc.dart'; -import 'package:app_flowy/user/presentation/router.dart'; -import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart'; -import 'package:app_flowy/workspace/application/home/home_bloc.dart'; -import 'package:get_it/get_it.dart'; - -import '../core/network_monitor.dart'; - -class UserDepsResolver { - static Future resolve(GetIt getIt) async { - getIt.registerFactory(() => AuthService()); - - //Interface implementation - getIt.registerFactory(() => AuthRouter()); - - //Bloc - getIt.registerFactory(() => SignInBloc(getIt())); - getIt.registerFactory(() => SignUpBloc(getIt())); - - getIt.registerFactory(() => SplashRoute()); - getIt.registerFactory(() => HomeBloc()); - getIt.registerFactory(() => EditPannelBloc()); - getIt.registerFactory(() => SplashBloc()); - getIt.registerLazySingleton(() => NetworkListener()); - } -} diff --git a/frontend/app_flowy/lib/user/application/prelude.dart b/frontend/app_flowy/lib/user/application/prelude.dart new file mode 100644 index 0000000000..74b644808e --- /dev/null +++ b/frontend/app_flowy/lib/user/application/prelude.dart @@ -0,0 +1,4 @@ +export './auth_service.dart'; +export './sign_in_bloc.dart'; +export './sign_up_bloc.dart'; +export './splash_bloc.dart'; diff --git a/frontend/app_flowy/lib/user/application/sign_in_bloc.dart b/frontend/app_flowy/lib/user/application/sign_in_bloc.dart index 25aa66cc50..e0f5bed605 100644 --- a/frontend/app_flowy/lib/user/application/sign_in_bloc.dart +++ b/frontend/app_flowy/lib/user/application/sign_in_bloc.dart @@ -54,14 +54,14 @@ class SignInBloc extends Bloc { } @freezed -abstract class SignInEvent with _$SignInEvent { +class SignInEvent with _$SignInEvent { const factory SignInEvent.signedInWithUserEmailAndPassword() = SignedInWithUserEmailAndPassword; const factory SignInEvent.emailChanged(String email) = EmailChanged; const factory SignInEvent.passwordChanged(String password) = PasswordChanged; } @freezed -abstract class SignInState with _$SignInState { +class SignInState with _$SignInState { const factory SignInState({ String? email, String? password, diff --git a/frontend/app_flowy/lib/user/application/sign_up_bloc.dart b/frontend/app_flowy/lib/user/application/sign_up_bloc.dart index 11acd1d385..2efc82d3c7 100644 --- a/frontend/app_flowy/lib/user/application/sign_up_bloc.dart +++ b/frontend/app_flowy/lib/user/application/sign_up_bloc.dart @@ -15,11 +15,11 @@ class SignUpBloc extends Bloc { on((event, emit) async { await event.map(signUpWithUserEmailAndPassword: (e) async { await _performActionOnSignUp(emit); - }, emailChanged: (EmailChanged value) async { + }, emailChanged: (_EmailChanged value) async { emit(state.copyWith(email: value.email, emailError: none(), successOrFail: none())); - }, passwordChanged: (PasswordChanged value) async { + }, passwordChanged: (_PasswordChanged value) async { emit(state.copyWith(password: value.password, passwordError: none(), successOrFail: none())); - }, repeatPasswordChanged: (RepeatPasswordChanged value) async { + }, repeatPasswordChanged: (_RepeatPasswordChanged value) async { emit(state.copyWith(repeatedPassword: value.password, repeatPasswordError: none(), successOrFail: none())); }); }); @@ -104,9 +104,9 @@ class SignUpBloc extends Bloc { @freezed class SignUpEvent with _$SignUpEvent { const factory SignUpEvent.signUpWithUserEmailAndPassword() = SignUpWithUserEmailAndPassword; - const factory SignUpEvent.emailChanged(String email) = EmailChanged; - const factory SignUpEvent.passwordChanged(String password) = PasswordChanged; - const factory SignUpEvent.repeatPasswordChanged(String password) = RepeatPasswordChanged; + const factory SignUpEvent.emailChanged(String email) = _EmailChanged; + const factory SignUpEvent.passwordChanged(String password) = _PasswordChanged; + const factory SignUpEvent.repeatPasswordChanged(String password) = _RepeatPasswordChanged; } @freezed diff --git a/frontend/app_flowy/lib/user/application/user_listener.dart b/frontend/app_flowy/lib/user/application/user_listener.dart index 993aee60e0..5b212cc2d0 100644 --- a/frontend/app_flowy/lib/user/application/user_listener.dart +++ b/frontend/app_flowy/lib/user/application/user_listener.dart @@ -12,7 +12,6 @@ import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/dart_notification.pb.dart' as user; import 'package:flowy_sdk/rust_stream.dart'; - typedef UserProfileUpdatedNotifierValue = Either; typedef AuthNotifierValue = Either; typedef WorkspaceUpdatedNotifierValue = Either, FlowyError>; @@ -23,8 +22,8 @@ class UserListener { final authDidChangedNotifier = PublishNotifier(); final workspaceUpdatedNotifier = PublishNotifier(); - late FolderNotificationParser _workspaceParser; - late UserNotificationParser _userParser; + FolderNotificationParser? _workspaceParser; + UserNotificationParser? _userParser; late UserProfile _user; UserListener({ required UserProfile user, @@ -36,12 +35,14 @@ class UserListener { _workspaceParser = FolderNotificationParser(id: _user.token, callback: _notificationCallback); _userParser = UserNotificationParser(id: _user.token, callback: _userNotificationCallback); _subscription = RustStreamReceiver.listen((observable) { - _workspaceParser.parse(observable); - _userParser.parse(observable); + _workspaceParser?.parse(observable); + _userParser?.parse(observable); }); } Future stop() async { + _workspaceParser = null; + _userParser = null; await _subscription?.cancel(); profileUpdatedNotifier.dispose(); authDidChangedNotifier.dispose(); diff --git a/frontend/app_flowy/lib/user/domain/auth_state.dart b/frontend/app_flowy/lib/user/domain/auth_state.dart index b70383c0aa..96f2036e01 100644 --- a/frontend/app_flowy/lib/user/domain/auth_state.dart +++ b/frontend/app_flowy/lib/user/domain/auth_state.dart @@ -4,7 +4,7 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'auth_state.freezed.dart'; @freezed -abstract class AuthState with _$AuthState { +class AuthState with _$AuthState { const factory AuthState.authenticated(UserProfile userProfile) = Authenticated; const factory AuthState.unauthenticated(FlowyError error) = Unauthenticated; const factory AuthState.initial() = _Initial; diff --git a/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart b/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart index f7afa0b4d3..9a02863345 100644 --- a/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart @@ -170,11 +170,11 @@ class PasswordTextField extends StatelessWidget { return RoundedInputField( obscureText: true, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), - obscureIcon: svg("home/hide"), - obscureHideIcon: svg("home/show"), + obscureIcon: svgWidget("home/hide"), + obscureHideIcon: svgWidget("home/show"), hintText: LocaleKeys.signIn_passwordHint.tr(), normalBorderColor: theme.shader4, - highlightBorderColor: theme.red, + errorBorderColor: theme.red, cursorColor: theme.main1, errorText: context.read().state.passwordError.fold(() => "", (error) => error), onChanged: (value) => context.read().add(SignInEvent.passwordChanged(value)), @@ -199,7 +199,7 @@ class EmailTextField extends StatelessWidget { hintText: LocaleKeys.signIn_emailHint.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), normalBorderColor: theme.shader4, - highlightBorderColor: theme.red, + errorBorderColor: theme.red, cursorColor: theme.main1, errorText: context.read().state.emailError.fold(() => "", (error) => error), onChanged: (value) => context.read().add(SignInEvent.emailChanged(value)), diff --git a/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart b/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart index 931ccff516..9f95a1db75 100644 --- a/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart @@ -134,12 +134,12 @@ class PasswordTextField extends StatelessWidget { builder: (context, state) { return RoundedInputField( obscureText: true, - obscureIcon: svg("home/hide"), - obscureHideIcon: svg("home/show"), + obscureIcon: svgWidget("home/hide"), + obscureHideIcon: svgWidget("home/show"), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), hintText: LocaleKeys.signUp_passwordHint.tr(), normalBorderColor: theme.shader4, - highlightBorderColor: theme.red, + errorBorderColor: theme.red, cursorColor: theme.main1, errorText: context.read().state.passwordError.fold(() => "", (error) => error), onChanged: (value) => context.read().add(SignUpEvent.passwordChanged(value)), @@ -162,12 +162,12 @@ class RepeatPasswordTextField extends StatelessWidget { builder: (context, state) { return RoundedInputField( obscureText: true, - obscureIcon: svg("home/hide"), - obscureHideIcon: svg("home/show"), + obscureIcon: svgWidget("home/hide"), + obscureHideIcon: svgWidget("home/show"), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), hintText: LocaleKeys.signUp_repeatPasswordHint.tr(), normalBorderColor: theme.shader4, - highlightBorderColor: theme.red, + errorBorderColor: theme.red, cursorColor: theme.main1, errorText: context.read().state.repeatPasswordError.fold(() => "", (error) => error), onChanged: (value) => context.read().add(SignUpEvent.repeatPasswordChanged(value)), @@ -192,7 +192,7 @@ class EmailTextField extends StatelessWidget { hintText: LocaleKeys.signUp_emailHint.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), normalBorderColor: theme.shader4, - highlightBorderColor: theme.red, + errorBorderColor: theme.red, cursorColor: theme.main1, errorText: context.read().state.emailError.fold(() => "", (error) => error), onChanged: (value) => context.read().add(SignUpEvent.emailChanged(value)), diff --git a/frontend/app_flowy/lib/user/presentation/splash_screen.dart b/frontend/app_flowy/lib/user/presentation/splash_screen.dart index 5fe302abd0..dd8fdcd180 100644 --- a/frontend/app_flowy/lib/user/presentation/splash_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/splash_screen.dart @@ -4,7 +4,7 @@ import 'package:app_flowy/user/domain/auth_state.dart'; import 'package:app_flowy/user/presentation/router.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/error-code/error_code.pbenum.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/app_flowy/lib/user/presentation/widgets/background.dart b/frontend/app_flowy/lib/user/presentation/widgets/background.dart index 86dfab7ffe..225f7f0080 100644 --- a/frontend/app_flowy/lib/user/presentation/widgets/background.dart +++ b/frontend/app_flowy/lib/user/presentation/widgets/background.dart @@ -44,7 +44,7 @@ class FlowyLogoTitle extends StatelessWidget { children: [ SizedBox.fromSize( size: logoSize, - child: svg("flowy_logo"), + child: svgWidget("flowy_logo"), ), const VSpace(30), Text( diff --git a/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart b/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart index 5175fe2396..73192436bf 100644 --- a/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart @@ -19,7 +19,7 @@ class AppBloc extends Bloc { AppBloc({required this.app, required this.service, required this.listener}) : super(AppState.initial(app)) { on((event, emit) async { await event.map(initial: (e) async { - listener.startListening( + listener.start( viewsChanged: _handleViewsChanged, appUpdated: (app) => add(AppEvent.appDidUpdate(app)), ); diff --git a/frontend/app_flowy/lib/workspace/application/app/app_listener.dart b/frontend/app_flowy/lib/workspace/application/app/app_listener.dart index 8f0ff7cb23..46b16bb080 100644 --- a/frontend/app_flowy/lib/workspace/application/app/app_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/app/app_listener.dart @@ -17,18 +17,18 @@ class AppListener { StreamSubscription? _subscription; ViewsDidChangeCallback? _viewsChanged; AppDidUpdateCallback? _updated; - late FolderNotificationParser _parser; + FolderNotificationParser? _parser; String appId; AppListener({ required this.appId, }); - void startListening({ViewsDidChangeCallback? viewsChanged, AppDidUpdateCallback? appUpdated}) { + void start({ViewsDidChangeCallback? viewsChanged, AppDidUpdateCallback? appUpdated}) { _viewsChanged = viewsChanged; _updated = appUpdated; _parser = FolderNotificationParser(id: appId, callback: _bservableCallback); - _subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable)); + _subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable)); } void _bservableCallback(FolderNotification ty, Either result) { @@ -61,6 +61,7 @@ class AppListener { } Future close() async { + _parser = null; await _subscription?.cancel(); _viewsChanged = null; _updated = null; diff --git a/frontend/app_flowy/lib/workspace/application/app/prelude.dart b/frontend/app_flowy/lib/workspace/application/app/prelude.dart new file mode 100644 index 0000000000..f8477049d3 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/app/prelude.dart @@ -0,0 +1,3 @@ +export 'app_bloc.dart'; +export 'app_listener.dart'; +export 'app_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/appearance.dart b/frontend/app_flowy/lib/workspace/application/appearance.dart index 87cd7e1af8..06473729a8 100644 --- a/frontend/app_flowy/lib/workspace/application/appearance.dart +++ b/frontend/app_flowy/lib/workspace/application/appearance.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:app_flowy/user/application/user_settings_service.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_infra/theme.dart'; @@ -5,13 +7,12 @@ import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_setting.pb.dart'; import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:async/async.dart'; class AppearanceSettingModel extends ChangeNotifier with EquatableMixin { AppearanceSettings setting; AppTheme _theme; Locale _locale; - CancelableOperation? _saveOperation; + Timer? _saveOperation; AppearanceSettingModel(this.setting) : _theme = AppTheme.fromName(name: setting.theme), @@ -21,12 +22,10 @@ class AppearanceSettingModel extends ChangeNotifier with EquatableMixin { Locale get locale => _locale; Future save() async { - _saveOperation?.cancel; - _saveOperation = CancelableOperation.fromFuture( - Future.delayed(const Duration(seconds: 1), () async { - await UserSettingsService().setAppearanceSettings(setting); - }), - ); + _saveOperation?.cancel(); + _saveOperation = Timer(const Duration(seconds: 2), () async { + await UserSettingsService().setAppearanceSettings(setting); + }); } @override diff --git a/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart b/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart index e3dc9c91aa..8d944c34ac 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart @@ -65,7 +65,7 @@ class DocumentBloc extends Bloc { await _subscription?.cancel(); } - service.closeDocument(docId: view.id); + await service.closeDocument(docId: view.id); return super.close(); } @@ -88,7 +88,7 @@ class DocumentBloc extends Bloc { final result = await service.openDocument(docId: view.id); result.fold( (block) { - document = _decodeJsonToDocument(block.deltaJson); + document = _decodeJsonToDocument(block.deltaStr); _subscription = document.changes.listen((event) { final delta = event.item2; final documentDelta = document.toDelta(); @@ -115,7 +115,7 @@ class DocumentBloc extends Bloc { result.fold((rustDoc) { // final json = utf8.decode(doc.data); - final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaJson)); + final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaStr)); if (documentDelta != rustDelta) { Log.error("Receive : $rustDelta"); Log.error("Expected : $documentDelta"); diff --git a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart index e0891ea62c..a0498491f9 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart @@ -1,20 +1,25 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/protobuf/flowy-collaboration/document_info.pb.dart'; + import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-sync/text_block_info.pb.dart'; class DocumentService { - Future> openDocument({required String docId}) { - final request = ViewId(value: docId); - return FolderEventOpenView(request).send(); + Future> openDocument({ + required String docId, + }) async { + await FolderEventSetLatestView(ViewId(value: docId)).send(); + + final payload = TextBlockId(value: docId); + return BlockEventGetBlockData(payload).send(); } - Future> composeDelta({required String docId, required String data}) { - final request = BlockDelta.create() + Future> composeDelta({required String docId, required String data}) { + final payload = TextBlockDelta.create() ..blockId = docId - ..deltaJson = data; - return FolderEventApplyDocDelta(request).send(); + ..deltaStr = data; + return BlockEventApplyDelta(payload).send(); } Future> closeDocument({required String docId}) { diff --git a/frontend/app_flowy/lib/workspace/application/doc/prelude.dart b/frontend/app_flowy/lib/workspace/application/doc/prelude.dart new file mode 100644 index 0000000000..f2befe4cf0 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/doc/prelude.dart @@ -0,0 +1,4 @@ +export 'doc_bloc.dart'; +export 'doc_service.dart'; +export 'share_bloc.dart'; +export 'share_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart b/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart index fe4b2e7f5c..c8fd8a2b96 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart @@ -1,6 +1,6 @@ import 'package:app_flowy/workspace/application/doc/share_service.dart'; import 'package:app_flowy/workspace/application/markdown/delta_markdown.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/share.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-text-block/entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/doc/share_service.dart b/frontend/app_flowy/lib/workspace/application/doc/share_service.dart index eedc0913bb..cc3afe1314 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/share_service.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/share_service.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-text-block/protobuf.dart'; class ShareService { Future> export(String docId, ExportType type) { @@ -10,7 +10,7 @@ class ShareService { ..viewId = docId ..exportType = type; - return FolderEventExportDocument(request).send(); + return BlockEventExportDocument(request).send(); } Future> exportText(String docId) { diff --git a/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_context.dart b/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_context.dart index cd52bc7f11..571461b365 100644 --- a/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_context.dart +++ b/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_context.dart @@ -5,19 +5,8 @@ abstract class EditPannelContext extends Equatable { final String identifier; final String title; final Widget child; - const EditPannelContext( - {required this.child, required this.identifier, required this.title}); + const EditPannelContext({required this.child, required this.identifier, required this.title}); @override List get props => [identifier]; } - -class BlankEditPannelContext extends EditPannelContext { - const BlankEditPannelContext() - : super(child: const Text('Blank'), identifier: '1', title: ''); -} - -class CellEditPannelContext extends EditPannelContext { - const CellEditPannelContext() - : super(child: const Text('shit'), identifier: 'test', title: 'test'); -} diff --git a/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_pannel_bloc.dart b/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_pannel_bloc.dart index 0ae2e8326a..e1f2f5835d 100644 --- a/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_pannel_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/edit_pannel/edit_pannel_bloc.dart @@ -1,7 +1,6 @@ import 'package:app_flowy/workspace/application/edit_pannel/edit_context.dart'; import 'package:dartz/dartz.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -// ignore: import_of_legacy_library_into_null_safe import 'package:flutter_bloc/flutter_bloc.dart'; part 'edit_pannel_bloc.freezed.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart new file mode 100644 index 0000000000..314345017e --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart @@ -0,0 +1,41 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'dart:async'; +import 'dart:typed_data'; +import 'package:app_flowy/core/notification_helper.dart'; + +typedef UpdateFieldNotifiedValue = Either; + +class CellListener { + final String rowId; + final String fieldId; + PublishNotifier? updateCellNotifier = PublishNotifier(); + GridNotificationListener? _listener; + CellListener({required this.rowId, required this.fieldId}); + + void start() { + _listener = GridNotificationListener(objectId: "$rowId:$fieldId", handler: _handler); + } + + void _handler(GridNotification ty, Either result) { + switch (ty) { + case GridNotification.DidUpdateCell: + result.fold( + (payload) => updateCellNotifier?.value = left(CellNotificationData.fromBuffer(payload)), + (error) => updateCellNotifier?.value = right(error), + ); + break; + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + updateCellNotifier?.dispose(); + updateCellNotifier = null; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart new file mode 100644 index 0000000000..dce064eae2 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -0,0 +1,75 @@ +import 'dart:collection'; + +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; + +class CellService { + CellService(); + + Future> updateCell({ + required String gridId, + required String fieldId, + required String rowId, + required String data, + }) { + final payload = CellChangeset.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId + ..data = data; + return GridEventUpdateCell(payload).send(); + } + + Future> getCell({ + required String gridId, + required String fieldId, + required String rowId, + }) { + final payload = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + return GridEventGetCell(payload).send(); + } +} + +class CellCache { + final CellService _cellService; + final HashMap _cellDataMap = HashMap(); + + CellCache() : _cellService = CellService(); + + Future> getCellData(GridCell identifier) async { + final cellId = _cellId(identifier); + final Cell? data = _cellDataMap[cellId]; + if (data != null) { + return Future(() => Some(data)); + } + + final result = await _cellService.getCell( + gridId: identifier.gridId, + fieldId: identifier.field.id, + rowId: identifier.rowId, + ); + + return result.fold( + (cell) { + _cellDataMap[_cellId(identifier)] = cell; + return Some(cell); + }, + (err) { + Log.error(err); + return none(); + }, + ); + } + + String _cellId(GridCell identifier) { + return "${identifier.rowId}/${identifier.field.id}"; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart new file mode 100644 index 0000000000..880267f6c9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart @@ -0,0 +1,102 @@ +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'cell_service.dart'; + +part 'checkbox_cell_bloc.freezed.dart'; + +class CheckboxCellBloc extends Bloc { + final CellService _service; + final CellListener _cellListener; + + CheckboxCellBloc({ + required CellService service, + required GridCell cellData, + }) : _service = service, + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + super(CheckboxCellState.initial(cellData)) { + on( + (event, emit) async { + await event.map( + initial: (_Initial value) { + _startListening(); + }, + select: (_Selected value) async { + _updateCellData(); + }, + didReceiveCellUpdate: (_DidReceiveCellUpdate value) { + emit(state.copyWith(isSelected: _isSelected(value.cell))); + }, + ); + }, + ); + } + + @override + Future close() async { + await _cellListener.stop(); + return super.close(); + } + + void _startListening() { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notificationData) async => await _loadCellData(), + (err) => Log.error(err), + ); + }); + _cellListener.start(); + } + + Future _loadCellData() async { + final result = await _service.getCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + ); + if (isClosed) { + return; + } + result.fold( + (cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)), + (err) => Log.error(err), + ); + } + + void _updateCellData() { + _service.updateCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + data: !state.isSelected ? "Yes" : "No", + ); + } +} + +@freezed +class CheckboxCellEvent with _$CheckboxCellEvent { + const factory CheckboxCellEvent.initial() = _Initial; + const factory CheckboxCellEvent.select() = _Selected; + const factory CheckboxCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; +} + +@freezed +class CheckboxCellState with _$CheckboxCellState { + const factory CheckboxCellState({ + required GridCell cellData, + required bool isSelected, + }) = _CheckboxCellState; + + factory CheckboxCellState.initial(GridCell cellData) { + return CheckboxCellState(cellData: cellData, isSelected: _isSelected(cellData.cell)); + } +} + +bool _isSelected(Cell? cell) { + final content = cell?.content ?? ""; + return content == "Yes"; +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart new file mode 100644 index 0000000000..cbabe6c5fe --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -0,0 +1,120 @@ +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'cell_service.dart'; + +part 'date_cell_bloc.freezed.dart'; + +class DateCellBloc extends Bloc { + final CellService _service; + final CellListener _cellListener; + final SingleFieldListener _fieldListener; + + DateCellBloc({required GridCell cellData}) + : _service = CellService(), + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), + super(DateCellState.initial(cellData)) { + on( + (event, emit) async { + event.map( + initial: (_InitialCell value) { + _startListening(); + }, + selectDay: (_SelectDay value) { + _updateCellData(value.day); + }, + didReceiveCellUpdate: (_DidReceiveCellUpdate value) { + emit(state.copyWith( + cellData: state.cellData.copyWith(cell: value.cell), + content: value.cell.content, + )); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(field: value.field)); + _loadCellData(); + }, + ); + }, + ); + } + + @override + Future close() async { + await _cellListener.stop(); + await _fieldListener.stop(); + return super.close(); + } + + void _startListening() { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notificationData) => _loadCellData(), + (err) => Log.error(err), + ); + }, listenWhen: () => !isClosed); + _cellListener.start(); + + _fieldListener.updateFieldNotifier?.addPublishListener((result) { + result.fold( + (field) => add(DateCellEvent.didReceiveFieldUpdate(field)), + (err) => Log.error(err), + ); + }, listenWhen: () => !isClosed); + _fieldListener.start(); + } + + Future _loadCellData() async { + final result = await _service.getCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + ); + if (isClosed) { + return; + } + result.fold( + (cell) => add(DateCellEvent.didReceiveCellUpdate(cell)), + (err) => Log.error(err), + ); + } + + void _updateCellData(DateTime day) { + final data = day.millisecondsSinceEpoch ~/ 1000; + _service.updateCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + data: data.toString(), + ); + } +} + +@freezed +class DateCellEvent with _$DateCellEvent { + const factory DateCellEvent.initial() = _InitialCell; + const factory DateCellEvent.selectDay(DateTime day) = _SelectDay; + const factory DateCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; + const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; +} + +@freezed +class DateCellState with _$DateCellState { + const factory DateCellState({ + required GridCell cellData, + required String content, + required Field field, + DateTime? selectedDay, + }) = _DateCellState; + + factory DateCellState.initial(GridCell cellData) => DateCellState( + cellData: cellData, + field: cellData.field, + content: cellData.cell?.content ?? "", + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart new file mode 100644 index 0000000000..27f17257e1 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart @@ -0,0 +1,115 @@ +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'cell_service.dart'; + +part 'number_cell_bloc.freezed.dart'; + +class NumberCellBloc extends Bloc { + final CellService _service; + final CellListener _cellListener; + final SingleFieldListener _fieldListener; + + NumberCellBloc({ + required GridCell cellData, + }) : _service = CellService(), + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), + super(NumberCellState.initial(cellData)) { + on( + (event, emit) async { + await event.map( + initial: (_Initial value) async { + _startListening(); + }, + didReceiveCellUpdate: (_DidReceiveCellUpdate value) { + emit(state.copyWith(content: value.cell.content)); + }, + updateCell: (_UpdateCell value) async { + await _updateCellValue(value, emit); + }, + ); + }, + ); + } + + Future _updateCellValue(_UpdateCell value, Emitter emit) async { + final result = await _service.updateCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + data: value.text, + ); + result.fold( + (field) => _getCellData(), + (err) => Log.error(err), + ); + } + + @override + Future close() async { + await _cellListener.stop(); + await _fieldListener.stop(); + return super.close(); + } + + void _startListening() { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notificationData) async { + await _getCellData(); + }, + (err) => Log.error(err), + ); + }); + _cellListener.start(); + + _fieldListener.updateFieldNotifier?.addPublishListener((result) { + result.fold( + (field) => _getCellData(), + (err) => Log.error(err), + ); + }); + _fieldListener.start(); + } + + Future _getCellData() async { + final result = await _service.getCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + ); + + if (isClosed) { + return; + } + result.fold( + (cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)), + (err) => Log.error(err), + ); + } +} + +@freezed +class NumberCellEvent with _$NumberCellEvent { + const factory NumberCellEvent.initial() = _Initial; + const factory NumberCellEvent.updateCell(String text) = _UpdateCell; + const factory NumberCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; +} + +@freezed +class NumberCellState with _$NumberCellState { + const factory NumberCellState({ + required GridCell cellData, + required String content, + }) = _NumberCellState; + + factory NumberCellState.initial(GridCell cellData) { + return NumberCellState(cellData: cellData, content: cellData.cell?.content ?? ""); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart new file mode 100644 index 0000000000..c76f06adc9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -0,0 +1,110 @@ +import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; + +class SelectOptionService { + SelectOptionService(); + + Future> create({ + required String gridId, + required String fieldId, + required String rowId, + required String name, + }) { + return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then( + (result) { + return result.fold( + (option) { + final cellIdentifier = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + final payload = SelectOptionChangesetPayload.create() + ..insertOption = option + ..cellIdentifier = cellIdentifier; + return GridEventUpdateSelectOption(payload).send(); + }, + (r) => right(r), + ); + }, + ); + } + + Future> update({ + required String gridId, + required String fieldId, + required String rowId, + required SelectOption option, + }) { + final cellIdentifier = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + final payload = SelectOptionChangesetPayload.create() + ..updateOption = option + ..cellIdentifier = cellIdentifier; + return GridEventUpdateSelectOption(payload).send(); + } + + Future> delete({ + required String gridId, + required String fieldId, + required String rowId, + required SelectOption option, + }) { + final cellIdentifier = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + + final payload = SelectOptionChangesetPayload.create() + ..deleteOption = option + ..cellIdentifier = cellIdentifier; + + return GridEventUpdateSelectOption(payload).send(); + } + + Future> getOpitonContext({ + required String gridId, + required String fieldId, + required String rowId, + }) { + final payload = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + + return GridEventGetSelectOptionContext(payload).send(); + } + + Future> select({ + required String gridId, + required String fieldId, + required String rowId, + required String optionId, + }) { + final payload = SelectOptionCellChangesetPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId + ..insertOptionId = optionId; + return GridEventUpdateCellSelectOption(payload).send(); + } + + Future> remove({ + required String gridId, + required String fieldId, + required String rowId, + required String optionId, + }) { + final payload = SelectOptionCellChangesetPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId + ..deleteOptionId = optionId; + return GridEventUpdateCellSelectOption(payload).send(); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart new file mode 100644 index 0000000000..2d7435dc7a --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -0,0 +1,106 @@ +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_listener.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; + +part 'selection_cell_bloc.freezed.dart'; + +class SelectionCellBloc extends Bloc { + final SelectOptionService _service; + final CellListener _cellListener; + final SingleFieldListener _fieldListener; + + SelectionCellBloc({ + required GridCell cellData, + }) : _service = SelectOptionService(), + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), + super(SelectionCellState.initial(cellData)) { + on( + (event, emit) async { + await event.map( + initial: (_InitialCell value) async { + _loadOptions(); + _startListening(); + }, + didReceiveOptions: (_DidReceiveOptions value) { + emit(state.copyWith(options: value.options, selectedOptions: value.selectedOptions)); + }, + ); + }, + ); + } + + @override + Future close() async { + await _cellListener.stop(); + await _fieldListener.stop(); + return super.close(); + } + + void _loadOptions() async { + final result = await _service.getOpitonContext( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + ); + if (isClosed) { + return; + } + + result.fold( + (selectOptionContext) => add(SelectionCellEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )), + (err) => Log.error(err), + ); + } + + void _startListening() { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notificationData) => _loadOptions(), + (err) => Log.error(err), + ); + }); + _cellListener.start(); + + _fieldListener.updateFieldNotifier?.addPublishListener((result) { + result.fold( + (field) => _loadOptions(), + (err) => Log.error(err), + ); + }); + _fieldListener.start(); + } +} + +@freezed +class SelectionCellEvent with _$SelectionCellEvent { + const factory SelectionCellEvent.initial() = _InitialCell; + const factory SelectionCellEvent.didReceiveOptions( + List options, + List selectedOptions, + ) = _DidReceiveOptions; +} + +@freezed +class SelectionCellState with _$SelectionCellState { + const factory SelectionCellState({ + required GridCell cellData, + required List options, + required List selectedOptions, + }) = _SelectionCellState; + + factory SelectionCellState.initial(GridCell cellData) => SelectionCellState( + cellData: cellData, + options: [], + selectedOptions: [], + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart new file mode 100644 index 0000000000..92676a0c12 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -0,0 +1,189 @@ +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'select_option_service.dart'; + +part 'selection_editor_bloc.freezed.dart'; + +class SelectOptionEditorBloc extends Bloc { + final SelectOptionService _selectOptionService; + final SingleFieldListener _fieldListener; + final CellListener _cellListener; + Timer? _delayOperation; + + SelectOptionEditorBloc({ + required GridCell cellData, + required List options, + required List selectedOptions, + }) : _selectOptionService = SelectOptionService(), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + super(SelectOptionEditorState.initial(cellData, options, selectedOptions)) { + on( + (event, emit) async { + await event.map( + initial: (_Initial value) async { + _startListening(); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(field: value.field)); + _loadOptions(); + }, + didReceiveOptions: (_DidReceiveOptions value) { + emit(state.copyWith( + options: value.options, + selectedOptions: value.selectedOptions, + )); + }, + newOption: (_NewOption value) { + _createOption(value.optionName); + }, + deleteOption: (_DeleteOption value) { + _deleteOption(value.option); + }, + updateOption: (_UpdateOption value) { + _updateOption(value.option); + }, + selectOption: (_SelectOption value) { + _makeOptionAsSelected(value.optionId); + }, + ); + }, + ); + } + + @override + Future close() async { + _delayOperation?.cancel(); + await _fieldListener.stop(); + await _cellListener.stop(); + return super.close(); + } + + void _createOption(String name) async { + final result = await _selectOptionService.create( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + name: name, + ); + result.fold((l) => _loadOptions(), (err) => Log.error(err)); + } + + void _deleteOption(SelectOption option) async { + final result = await _selectOptionService.delete( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + option: option, + ); + + result.fold((l) => null, (err) => Log.error(err)); + } + + void _updateOption(SelectOption option) async { + final result = await _selectOptionService.update( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + option: option, + ); + + result.fold((l) => null, (err) => Log.error(err)); + } + + void _makeOptionAsSelected(String optionId) { + _selectOptionService.select( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + optionId: optionId, + ); + } + + void _loadOptions() async { + _delayOperation?.cancel(); + _delayOperation = Timer( + const Duration(milliseconds: 1), + () async { + final result = await _selectOptionService.getOpitonContext( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + ); + if (isClosed) { + return; + } + + result.fold( + (selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )), + (err) => Log.error(err), + ); + }, + ); + } + + void _startListening() { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notificationData) => _loadOptions(), + (err) => Log.error(err), + ); + }); + _cellListener.start(); + + _fieldListener.updateFieldNotifier?.addPublishListener((result) { + result.fold( + (field) => add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)), + (err) => Log.error(err), + ); + }, listenWhen: () => !isClosed); + _fieldListener.start(); + } +} + +@freezed +class SelectOptionEditorEvent with _$SelectOptionEditorEvent { + const factory SelectOptionEditorEvent.initial() = _Initial; + const factory SelectOptionEditorEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; + const factory SelectOptionEditorEvent.didReceiveOptions( + List options, List selectedOptions) = _DidReceiveOptions; + const factory SelectOptionEditorEvent.newOption(String optionName) = _NewOption; + const factory SelectOptionEditorEvent.selectOption(String optionId) = _SelectOption; + const factory SelectOptionEditorEvent.updateOption(SelectOption option) = _UpdateOption; + const factory SelectOptionEditorEvent.deleteOption(SelectOption option) = _DeleteOption; +} + +@freezed +class SelectOptionEditorState with _$SelectOptionEditorState { + const factory SelectOptionEditorState({ + required String gridId, + required Field field, + required String rowId, + required List options, + required List selectedOptions, + }) = _SelectOptionEditorState; + + factory SelectOptionEditorState.initial( + GridCell cellData, + List options, + List selectedOptions, + ) { + return SelectOptionEditorState( + gridId: cellData.gridId, + field: cellData.field, + rowId: cellData.rowId, + options: options, + selectedOptions: selectedOptions, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart new file mode 100644 index 0000000000..f32c066c5e --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart @@ -0,0 +1,111 @@ +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'cell_listener.dart'; +import 'cell_service.dart'; + +part 'text_cell_bloc.freezed.dart'; + +class TextCellBloc extends Bloc { + final CellService _service; + final CellListener _cellListener; + + TextCellBloc({ + required GridCell cellData, + }) : _service = CellService(), + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + super(TextCellState.initial(cellData)) { + on( + (event, emit) async { + await event.map( + initial: (_InitialCell value) async { + _startListening(); + }, + updateText: (_UpdateText value) { + updateCellContent(value.text); + emit(state.copyWith(content: value.text)); + }, + didReceiveCellData: (_DidReceiveCellData value) { + emit(state.copyWith( + cellData: value.cellData, + content: value.cellData.cell?.content ?? "", + )); + }, + didReceiveCellUpdate: (_DidReceiveCellUpdate value) { + emit(state.copyWith( + cellData: state.cellData.copyWith(cell: value.cell), + content: value.cell.content, + )); + }, + ); + }, + ); + } + + @override + Future close() async { + await _cellListener.stop(); + return super.close(); + } + + void updateCellContent(String content) { + final fieldId = state.cellData.field.id; + final gridId = state.cellData.gridId; + final rowId = state.cellData.rowId; + _service.updateCell( + data: content, + fieldId: fieldId, + gridId: gridId, + rowId: rowId, + ); + } + + void _startListening() { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notificationData) async => await _loadCellData(), + (err) => Log.error(err), + ); + }); + _cellListener.start(); + } + + Future _loadCellData() async { + final result = await _service.getCell( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + ); + if (isClosed) { + return; + } + result.fold( + (cell) => add(TextCellEvent.didReceiveCellUpdate(cell)), + (err) => Log.error(err), + ); + } +} + +@freezed +class TextCellEvent with _$TextCellEvent { + const factory TextCellEvent.initial() = _InitialCell; + const factory TextCellEvent.didReceiveCellData(GridCell cellData) = _DidReceiveCellData; + const factory TextCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; + const factory TextCellEvent.updateText(String text) = _UpdateText; +} + +@freezed +class TextCellState with _$TextCellState { + const factory TextCellState({ + required String content, + required GridCell cellData, + }) = _TextCellState; + + factory TextCellState.initial(GridCell cellData) => TextCellState( + content: cellData.cell?.content ?? "", + cellData: cellData, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart new file mode 100644 index 0000000000..40ac699e7f --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart @@ -0,0 +1,80 @@ +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'field_service.dart'; + +part 'field_action_sheet_bloc.freezed.dart'; + +class FieldActionSheetBloc extends Bloc { + final FieldService service; + + FieldActionSheetBloc({required Field field, required this.service}) + : super(FieldActionSheetState.initial(EditFieldContext.create()..gridField = field)) { + on( + (event, emit) async { + await event.map( + updateFieldName: (_UpdateFieldName value) async { + final result = await service.updateField(fieldId: field.id, name: value.name); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + hideField: (_HideField value) async { + final result = await service.updateField(fieldId: field.id, visibility: false); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + deleteField: (_DeleteField value) async { + final result = await service.deleteField(fieldId: field.id); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + duplicateField: (_DuplicateField value) async { + final result = await service.duplicateField(fieldId: field.id); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + saveField: (_SaveField value) {}, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class FieldActionSheetEvent with _$FieldActionSheetEvent { + const factory FieldActionSheetEvent.updateFieldName(String name) = _UpdateFieldName; + const factory FieldActionSheetEvent.hideField() = _HideField; + const factory FieldActionSheetEvent.duplicateField() = _DuplicateField; + const factory FieldActionSheetEvent.deleteField() = _DeleteField; + const factory FieldActionSheetEvent.saveField() = _SaveField; +} + +@freezed +class FieldActionSheetState with _$FieldActionSheetState { + const factory FieldActionSheetState({ + required EditFieldContext editContext, + required String errorText, + required String fieldName, + }) = _FieldActionSheetState; + + factory FieldActionSheetState.initial(EditFieldContext editContext) => FieldActionSheetState( + editContext: editContext, + errorText: '', + fieldName: editContext.gridField.name, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart new file mode 100644 index 0000000000..576e62e3b1 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart @@ -0,0 +1,76 @@ +import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; + +part 'field_cell_bloc.freezed.dart'; + +class FieldCellBloc extends Bloc { + final SingleFieldListener _fieldListener; + final FieldService _fieldService; + + FieldCellBloc({ + required GridFieldCellContext cellContext, + }) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id), + _fieldService = FieldService(gridId: cellContext.gridId), + super(FieldCellState.initial(cellContext)) { + on( + (event, emit) async { + await event.map( + initial: (_InitialCell value) async { + _startListening(); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(field: value.field)); + }, + updateWidth: (_UpdateWidth value) { + final defaultWidth = state.field.width.toDouble(); + final width = defaultWidth + value.offset; + if (width > defaultWidth && width < 300) { + _fieldService.updateField(fieldId: state.field.id, width: width); + } + }, + ); + }, + ); + } + + @override + Future close() async { + await _fieldListener.stop(); + return super.close(); + } + + void _startListening() { + _fieldListener.updateFieldNotifier?.addPublishListener((result) { + result.fold( + (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)), + (err) => Log.error(err), + ); + }, listenWhen: () => !isClosed); + _fieldListener.start(); + } +} + +@freezed +class FieldCellEvent with _$FieldCellEvent { + const factory FieldCellEvent.initial() = _InitialCell; + const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; + const factory FieldCellEvent.updateWidth(double offset) = _UpdateWidth; +} + +@freezed +class FieldCellState with _$FieldCellState { + const factory FieldCellState({ + required String gridId, + required Field field, + }) = _FieldCellState; + + factory FieldCellState.initial(GridFieldCellContext cellContext) => FieldCellState( + gridId: cellContext.gridId, + field: cellContext.field, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart new file mode 100644 index 0000000000..c38713862e --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart @@ -0,0 +1,100 @@ +import 'dart:typed_data'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'field_service.dart'; +import 'package:dartz/dartz.dart'; + +part 'field_editor_bloc.freezed.dart'; + +class FieldEditorBloc extends Bloc { + final FieldService service; + final EditFieldContextLoader _loader; + + FieldEditorBloc({ + required this.service, + required EditFieldContextLoader fieldLoader, + }) : _loader = fieldLoader, + super(FieldEditorState.initial(service.gridId)) { + on( + (event, emit) async { + await event.map( + initial: (_InitialField value) async { + await _getEditFieldContext(emit); + }, + updateName: (_UpdateName value) { + emit(state.copyWith(fieldName: value.name)); + }, + switchField: (_SwitchField value) { + emit(state.copyWith(field: Some(value.field), typeOptionData: value.typeOptionData)); + }, + done: (_Done value) async { + await _saveField(emit); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } + + Future _saveField(Emitter emit) async { + await state.field.fold( + () async => null, + (field) async { + field.name = state.fieldName; + final result = await service.insertField( + field: field, + typeOptionData: state.typeOptionData, + ); + result.fold((l) => null, (r) => null); + }, + ); + } + + Future _getEditFieldContext(Emitter emit) async { + final result = await _loader.load(); + result.fold( + (editContext) { + emit(state.copyWith( + field: Some(editContext.gridField), + typeOptionData: editContext.typeOptionData, + fieldName: editContext.gridField.name, + )); + }, + (err) => Log.error(err), + ); + } +} + +@freezed +class FieldEditorEvent with _$FieldEditorEvent { + const factory FieldEditorEvent.initial() = _InitialField; + const factory FieldEditorEvent.updateName(String name) = _UpdateName; + const factory FieldEditorEvent.switchField(Field field, Uint8List typeOptionData) = _SwitchField; + const factory FieldEditorEvent.done() = _Done; +} + +@freezed +class FieldEditorState with _$FieldEditorState { + const factory FieldEditorState({ + required String fieldName, + required String gridId, + required String errorText, + required Option field, + required List typeOptionData, + }) = _FieldEditorState; + + factory FieldEditorState.initial(String gridId) => FieldEditorState( + gridId: gridId, + fieldName: '', + field: none(), + errorText: '', + typeOptionData: List.empty(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart new file mode 100644 index 0000000000..b31a9c3ff5 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart @@ -0,0 +1,47 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'dart:async'; +import 'dart:typed_data'; +import 'package:app_flowy/core/notification_helper.dart'; + +typedef UpdateFieldNotifiedValue = Either; + +class SingleFieldListener { + final String fieldId; + PublishNotifier? updateFieldNotifier = PublishNotifier(); + GridNotificationListener? _listener; + + SingleFieldListener({required this.fieldId}); + + void start() { + _listener = GridNotificationListener( + objectId: fieldId, + handler: _handler, + ); + } + + void _handler( + GridNotification ty, + Either result, + ) { + switch (ty) { + case GridNotification.DidUpdateField: + result.fold( + (payload) => updateFieldNotifier?.value = left(Field.fromBuffer(payload)), + (error) => updateFieldNotifier?.value = right(error), + ); + break; + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + updateFieldNotifier?.dispose(); + updateFieldNotifier = null; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart new file mode 100644 index 0000000000..c909bf1b31 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -0,0 +1,185 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'field_service.freezed.dart'; + +class FieldService { + final String gridId; + + FieldService({required this.gridId}); + + Future> switchToField(String fieldId, FieldType fieldType) { + final payload = EditFieldPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..fieldType = fieldType; + + return GridEventSwitchToField(payload).send(); + } + + Future> getEditFieldContext(String fieldId, FieldType fieldType) { + final payload = GetEditFieldContextPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..fieldType = fieldType; + + return GridEventGetEditFieldContext(payload).send(); + } + + Future> moveField(String fieldId, int fromIndex, int toIndex) { + final payload = MoveItemPayload.create() + ..gridId = gridId + ..itemId = fieldId + ..ty = MoveItemType.MoveField + ..fromIndex = fromIndex + ..toIndex = toIndex; + + return GridEventMoveItem(payload).send(); + } + + Future> updateField({ + required String fieldId, + String? name, + FieldType? fieldType, + bool? frozen, + bool? visibility, + double? width, + List? typeOptionData, + }) { + var payload = FieldChangesetPayload.create() + ..gridId = gridId + ..fieldId = fieldId; + + if (name != null) { + payload.name = name; + } + + if (fieldType != null) { + payload.fieldType = fieldType; + } + + if (frozen != null) { + payload.frozen = frozen; + } + + if (visibility != null) { + payload.visibility = visibility; + } + + if (width != null) { + payload.width = width.toInt(); + } + + if (typeOptionData != null) { + payload.typeOptionData = typeOptionData; + } + + return GridEventUpdateField(payload).send(); + } + + // Create the field if it does not exist. Otherwise, update the field. + Future> insertField({ + required Field field, + List? typeOptionData, + String? startFieldId, + }) { + var payload = InsertFieldPayload.create() + ..gridId = gridId + ..field_2 = field + ..typeOptionData = typeOptionData ?? []; + + if (startFieldId != null) { + payload.startFieldId = startFieldId; + } + + return GridEventInsertField(payload).send(); + } + + Future> deleteField({ + required String fieldId, + }) { + final payload = FieldIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId; + + return GridEventDeleteField(payload).send(); + } + + Future> duplicateField({ + required String fieldId, + }) { + final payload = FieldIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId; + + return GridEventDuplicateField(payload).send(); + } +} + +@freezed +class GridFieldCellContext with _$GridFieldCellContext { + const factory GridFieldCellContext({ + required String gridId, + required Field field, + }) = _GridFieldCellContext; +} + +abstract class EditFieldContextLoader { + Future> load(); + + Future> switchToField(String fieldId, FieldType fieldType); +} + +class NewFieldContextLoader extends EditFieldContextLoader { + final String gridId; + NewFieldContextLoader({ + required this.gridId, + }); + + @override + Future> load() { + final payload = GetEditFieldContextPayload.create() + ..gridId = gridId + ..fieldType = FieldType.RichText; + + return GridEventGetEditFieldContext(payload).send(); + } + + @override + Future> switchToField(String fieldId, FieldType fieldType) { + final payload = GetEditFieldContextPayload.create() + ..gridId = gridId + ..fieldType = fieldType; + + return GridEventGetEditFieldContext(payload).send(); + } +} + +class FieldContextLoaderAdaptor extends EditFieldContextLoader { + final String gridId; + final Field field; + + FieldContextLoaderAdaptor({ + required this.gridId, + required this.field, + }); + + @override + Future> load() { + final payload = GetEditFieldContextPayload.create() + ..gridId = gridId + ..fieldId = field.id + ..fieldType = field.fieldType; + + return GridEventGetEditFieldContext(payload).send(); + } + + @override + Future> switchToField(String fieldId, FieldType fieldType) async { + final fieldService = FieldService(gridId: gridId); + return fieldService.switchToField(fieldId, fieldType); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_switch_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_switch_bloc.dart new file mode 100644 index 0000000000..082c0decf4 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_switch_bloc.dart @@ -0,0 +1,61 @@ +import 'dart:typed_data'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; + +part 'field_switch_bloc.freezed.dart'; + +class FieldSwitcherBloc extends Bloc { + FieldSwitcherBloc(SwitchFieldContext editContext) : super(FieldSwitchState.initial(editContext)) { + on( + (event, emit) async { + await event.map( + toFieldType: (_ToFieldType value) async { + emit(state.copyWith( + field: value.field, + typeOptionData: Uint8List.fromList(value.typeOptionData), + )); + }, + didUpdateTypeOptionData: (_DidUpdateTypeOptionData value) { + emit(state.copyWith(typeOptionData: value.typeOptionData)); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class FieldSwitchEvent with _$FieldSwitchEvent { + const factory FieldSwitchEvent.toFieldType(Field field, List typeOptionData) = _ToFieldType; + const factory FieldSwitchEvent.didUpdateTypeOptionData(Uint8List typeOptionData) = _DidUpdateTypeOptionData; +} + +@freezed +class FieldSwitchState with _$FieldSwitchState { + const factory FieldSwitchState({ + required String gridId, + required Field field, + required Uint8List typeOptionData, + }) = _FieldSwitchState; + + factory FieldSwitchState.initial(SwitchFieldContext switchContext) => FieldSwitchState( + gridId: switchContext.gridId, + field: switchContext.field, + typeOptionData: Uint8List.fromList(switchContext.typeOptionData), + ); +} + +class SwitchFieldContext { + final String gridId; + final Field field; + final List typeOptionData; + + SwitchFieldContext(this.gridId, this.field, this.typeOptionData); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_listener.dart new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart new file mode 100644 index 0000000000..6774205a5e --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart @@ -0,0 +1,43 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'dart:async'; +import 'dart:typed_data'; +import 'package:app_flowy/core/notification_helper.dart'; + +typedef UpdateFieldNotifiedValue = Either; + +class GridFieldsListener { + final String gridId; + PublishNotifier? updateFieldsNotifier = PublishNotifier(); + GridNotificationListener? _listener; + GridFieldsListener({required this.gridId}); + + void start() { + _listener = GridNotificationListener( + objectId: gridId, + handler: _handler, + ); + } + + void _handler(GridNotification ty, Either result) { + switch (ty) { + case GridNotification.DidUpdateGridField: + result.fold( + (payload) => updateFieldsNotifier?.value = left(GridFieldChangeset.fromBuffer(payload)), + (error) => updateFieldsNotifier?.value = right(error), + ); + break; + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + updateFieldsNotifier?.dispose(); + updateFieldsNotifier = null; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart new file mode 100644 index 0000000000..c0a232a84f --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart @@ -0,0 +1,68 @@ +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:protobuf/protobuf.dart'; +part 'date_bloc.freezed.dart'; + +class DateTypeOptionBloc extends Bloc { + DateTypeOptionBloc({required DateTypeOption typeOption}) : super(DateTypeOptionState.initial(typeOption)) { + on( + (event, emit) async { + event.map( + didSelectDateFormat: (_DidSelectDateFormat value) { + emit(state.copyWith(typeOption: _updateTypeOption(dateFormat: value.format))); + }, + didSelectTimeFormat: (_DidSelectTimeFormat value) { + emit(state.copyWith(typeOption: _updateTypeOption(timeFormat: value.format))); + }, + includeTime: (_IncludeTime value) { + emit(state.copyWith(typeOption: _updateTypeOption(includeTime: value.includeTime))); + }, + ); + }, + ); + } + + DateTypeOption _updateTypeOption({ + DateFormat? dateFormat, + TimeFormat? timeFormat, + bool? includeTime, + }) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + if (dateFormat != null) { + typeOption.dateFormat = dateFormat; + } + + if (timeFormat != null) { + typeOption.timeFormat = timeFormat; + } + + if (includeTime != null) { + typeOption.includeTime = includeTime; + } + }); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class DateTypeOptionEvent with _$DateTypeOptionEvent { + const factory DateTypeOptionEvent.didSelectDateFormat(DateFormat format) = _DidSelectDateFormat; + const factory DateTypeOptionEvent.didSelectTimeFormat(TimeFormat format) = _DidSelectTimeFormat; + const factory DateTypeOptionEvent.includeTime(bool includeTime) = _IncludeTime; +} + +@freezed +class DateTypeOptionState with _$DateTypeOptionState { + const factory DateTypeOptionState({ + required DateTypeOption typeOption, + }) = _DateTypeOptionState; + + factory DateTypeOptionState.initial(DateTypeOption typeOption) => DateTypeOptionState(typeOption: typeOption); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart new file mode 100644 index 0000000000..2854fcf199 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart @@ -0,0 +1,66 @@ +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:protobuf/protobuf.dart'; +import 'package:dartz/dartz.dart'; +part 'edit_select_option_bloc.freezed.dart'; + +class EditSelectOptionBloc extends Bloc { + EditSelectOptionBloc({required SelectOption option}) : super(EditSelectOptionState.initial(option)) { + on( + (event, emit) async { + event.map( + updateName: (_UpdateName value) { + emit(state.copyWith(option: _updateName(value.name))); + }, + updateColor: (_UpdateColor value) { + emit(state.copyWith(option: _updateColor(value.color))); + }, + delete: (_Delete value) { + emit(state.copyWith(deleted: const Some(true))); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } + + SelectOption _updateColor(SelectOptionColor color) { + state.option.freeze(); + return state.option.rebuild((option) { + option.color = color; + }); + } + + SelectOption _updateName(String name) { + state.option.freeze(); + return state.option.rebuild((option) { + option.name = name; + }); + } +} + +@freezed +class EditSelectOptionEvent with _$EditSelectOptionEvent { + const factory EditSelectOptionEvent.updateName(String name) = _UpdateName; + const factory EditSelectOptionEvent.updateColor(SelectOptionColor color) = _UpdateColor; + const factory EditSelectOptionEvent.delete() = _Delete; +} + +@freezed +class EditSelectOptionState with _$EditSelectOptionState { + const factory EditSelectOptionState({ + required SelectOption option, + required Option deleted, + }) = _EditSelectOptionState; + + factory EditSelectOptionState.initial(SelectOption option) => EditSelectOptionState( + option: option, + deleted: none(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart new file mode 100644 index 0000000000..04ae02309d --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart @@ -0,0 +1,65 @@ +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:dartz/dartz.dart'; +part 'field_option_pannel_bloc.freezed.dart'; + +class FieldOptionPannelBloc extends Bloc { + FieldOptionPannelBloc({required List options}) : super(FieldOptionPannelState.initial(options)) { + on( + (event, emit) async { + await event.map( + createOption: (_CreateOption value) async { + emit(state.copyWith(isEditingOption: false, newOptionName: Some(value.optionName))); + }, + beginAddingOption: (_BeginAddingOption value) { + emit(state.copyWith(isEditingOption: true, newOptionName: none())); + }, + endAddingOption: (_EndAddingOption value) { + emit(state.copyWith(isEditingOption: false, newOptionName: none())); + }, + updateOption: (_UpdateOption value) { + emit(state.copyWith(updateOption: Some(value.option))); + }, + deleteOption: (_DeleteOption value) { + emit(state.copyWith(deleteOption: Some(value.option))); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class FieldOptionPannelEvent with _$FieldOptionPannelEvent { + const factory FieldOptionPannelEvent.createOption(String optionName) = _CreateOption; + const factory FieldOptionPannelEvent.beginAddingOption() = _BeginAddingOption; + const factory FieldOptionPannelEvent.endAddingOption() = _EndAddingOption; + const factory FieldOptionPannelEvent.updateOption(SelectOption option) = _UpdateOption; + const factory FieldOptionPannelEvent.deleteOption(SelectOption option) = _DeleteOption; +} + +@freezed +class FieldOptionPannelState with _$FieldOptionPannelState { + const factory FieldOptionPannelState({ + required List options, + required bool isEditingOption, + required Option newOptionName, + required Option updateOption, + required Option deleteOption, + }) = _FieldOptionPannelState; + + factory FieldOptionPannelState.initial(List options) => FieldOptionPannelState( + options: options, + isEditingOption: false, + newOptionName: none(), + updateOption: none(), + deleteOption: none(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart new file mode 100644 index 0000000000..0d42612595 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart @@ -0,0 +1,89 @@ +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:protobuf/protobuf.dart'; +import 'type_option_service.dart'; + +part 'multi_select_bloc.freezed.dart'; + +class MultiSelectTypeOptionBloc extends Bloc { + final TypeOptionService service; + + MultiSelectTypeOptionBloc(TypeOptionContext typeOptionContext) + : service = TypeOptionService(gridId: typeOptionContext.gridId, fieldId: typeOptionContext.field.id), + super(MultiSelectTypeOptionState.initial(MultiSelectTypeOption.fromBuffer(typeOptionContext.data))) { + on( + (event, emit) async { + await event.map( + createOption: (_CreateOption value) async { + final result = await service.newOption(name: value.optionName); + result.fold( + (option) { + emit(state.copyWith(typeOption: _insertOption(option))); + }, + (err) => Log.error(err), + ); + }, + updateOption: (_UpdateOption value) async { + emit(state.copyWith(typeOption: _updateOption(value.option))); + }, + deleteOption: (_DeleteOption value) { + emit(state.copyWith(typeOption: _deleteOption(value.option))); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } + + MultiSelectTypeOption _insertOption(SelectOption option) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + typeOption.options.insert(0, option); + }); + } + + MultiSelectTypeOption _updateOption(SelectOption option) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + final index = typeOption.options.indexWhere((element) => element.id == option.id); + if (index != -1) { + typeOption.options[index] = option; + } + }); + } + + MultiSelectTypeOption _deleteOption(SelectOption option) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + final index = typeOption.options.indexWhere((element) => element.id == option.id); + if (index != -1) { + typeOption.options.removeAt(index); + } + }); + } +} + +@freezed +class MultiSelectTypeOptionEvent with _$MultiSelectTypeOptionEvent { + const factory MultiSelectTypeOptionEvent.createOption(String optionName) = _CreateOption; + const factory MultiSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption; + const factory MultiSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption; +} + +@freezed +class MultiSelectTypeOptionState with _$MultiSelectTypeOptionState { + const factory MultiSelectTypeOptionState({ + required MultiSelectTypeOption typeOption, + }) = _MultiSelectTypeOptionState; + + factory MultiSelectTypeOptionState.initial(MultiSelectTypeOption typeOption) => MultiSelectTypeOptionState( + typeOption: typeOption, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart new file mode 100644 index 0000000000..a655ebc1e8 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart @@ -0,0 +1,49 @@ +import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:protobuf/protobuf.dart'; + +part 'number_bloc.freezed.dart'; + +class NumberTypeOptionBloc extends Bloc { + NumberTypeOptionBloc({required NumberTypeOption typeOption}) : super(NumberTypeOptionState.initial(typeOption)) { + on( + (event, emit) async { + event.map( + didSelectFormat: (_DidSelectFormat value) { + emit(state.copyWith(typeOption: _updateNumberFormat(value.format))); + }, + ); + }, + ); + } + + NumberTypeOption _updateNumberFormat(NumberFormat format) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + typeOption.format = format; + }); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class NumberTypeOptionEvent with _$NumberTypeOptionEvent { + const factory NumberTypeOptionEvent.didSelectFormat(NumberFormat format) = _DidSelectFormat; +} + +@freezed +class NumberTypeOptionState with _$NumberTypeOptionState { + const factory NumberTypeOptionState({ + required NumberTypeOption typeOption, + }) = _NumberTypeOptionState; + + factory NumberTypeOptionState.initial(NumberTypeOption typeOption) => NumberTypeOptionState( + typeOption: typeOption, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart new file mode 100644 index 0000000000..36a2f956b3 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart @@ -0,0 +1,92 @@ +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:protobuf/protobuf.dart'; +import 'type_option_service.dart'; + +part 'single_select_bloc.freezed.dart'; + +class SingleSelectTypeOptionBloc extends Bloc { + final TypeOptionService service; + + SingleSelectTypeOptionBloc( + TypeOptionContext typeOptionContext, + ) : service = TypeOptionService(gridId: typeOptionContext.gridId, fieldId: typeOptionContext.field.id), + super( + SingleSelectTypeOptionState.initial(SingleSelectTypeOption.fromBuffer(typeOptionContext.data)), + ) { + on( + (event, emit) async { + await event.map( + createOption: (_CreateOption value) async { + final result = await service.newOption(name: value.optionName); + result.fold( + (option) { + emit(state.copyWith(typeOption: _insertOption(option))); + }, + (err) => Log.error(err), + ); + }, + updateOption: (_UpdateOption value) async { + emit(state.copyWith(typeOption: _updateOption(value.option))); + }, + deleteOption: (_DeleteOption value) { + emit(state.copyWith(typeOption: _deleteOption(value.option))); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } + + SingleSelectTypeOption _insertOption(SelectOption option) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + typeOption.options.insert(0, option); + }); + } + + SingleSelectTypeOption _updateOption(SelectOption option) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + final index = typeOption.options.indexWhere((element) => element.id == option.id); + if (index != -1) { + typeOption.options[index] = option; + } + }); + } + + SingleSelectTypeOption _deleteOption(SelectOption option) { + state.typeOption.freeze(); + return state.typeOption.rebuild((typeOption) { + final index = typeOption.options.indexWhere((element) => element.id == option.id); + if (index != -1) { + typeOption.options.removeAt(index); + } + }); + } +} + +@freezed +class SingleSelectTypeOptionEvent with _$SingleSelectTypeOptionEvent { + const factory SingleSelectTypeOptionEvent.createOption(String optionName) = _CreateOption; + const factory SingleSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption; + const factory SingleSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption; +} + +@freezed +class SingleSelectTypeOptionState with _$SingleSelectTypeOptionState { + const factory SingleSelectTypeOptionState({ + required SingleSelectTypeOption typeOption, + }) = _SingleSelectTypeOptionState; + + factory SingleSelectTypeOptionState.initial(SingleSelectTypeOption typeOption) => SingleSelectTypeOptionState( + typeOption: typeOption, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart new file mode 100644 index 0000000000..92f2263c5d --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -0,0 +1,44 @@ +import 'dart:typed_data'; + +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; + +class TypeOptionService { + final String gridId; + final String fieldId; + + TypeOptionService({ + required this.gridId, + required this.fieldId, + }); + + Future> newOption({ + required String name, + }) { + final fieldIdentifier = FieldIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId; + + final payload = CreateSelectOptionPayload.create() + ..optionName = name + ..fieldIdentifier = fieldIdentifier; + + return GridEventNewSelectOption(payload).send(); + } +} + +class TypeOptionContext { + final String gridId; + final Field field; + final Uint8List data; + const TypeOptionContext({ + required this.gridId, + required this.field, + required this.data, + }); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart new file mode 100644 index 0000000000..93036082fb --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -0,0 +1,132 @@ +import 'dart:async'; +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'grid_service.dart'; +import 'row/row_service.dart'; + +part 'grid_bloc.freezed.dart'; + +class GridBloc extends Bloc { + final GridService _gridService; + final GridFieldCache fieldCache; + late final GridRowCache rowCache; + + GridBloc({required View view}) + : _gridService = GridService(gridId: view.id), + fieldCache = GridFieldCache(gridId: view.id), + super(GridState.initial(view.id)) { + rowCache = GridRowCache( + gridId: view.id, + dataDelegate: GridRowDataDelegateAdaptor(fieldCache), + ); + + on( + (event, emit) async { + await event.map( + initial: (InitialGrid value) async { + _startListening(); + await _loadGrid(emit); + }, + createRow: (_CreateRow value) { + _gridService.createRow(); + }, + didReceiveRowUpdate: (_DidReceiveRowUpdate value) { + emit(state.copyWith(rows: value.rows, listState: value.listState)); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(rows: rowCache.clonedRows, fields: value.fields)); + }, + ); + }, + ); + } + + @override + Future close() async { + await _gridService.closeGrid(); + await fieldCache.dispose(); + await rowCache.dispose(); + return super.close(); + } + + void _startListening() { + fieldCache.addListener( + listenWhen: () => !isClosed, + onChanged: (fields) => add(GridEvent.didReceiveFieldUpdate(fields)), + ); + + rowCache.addListener( + listenWhen: () => !isClosed, + onChanged: (rows, listState) => add(GridEvent.didReceiveRowUpdate(rowCache.clonedRows, listState)), + ); + } + + Future _loadGrid(Emitter emit) async { + final result = await _gridService.loadGrid(); + return Future( + () => result.fold( + (grid) async => await _loadFields(grid, emit), + (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))), + ), + ); + } + + Future _loadFields(Grid grid, Emitter emit) async { + final result = await _gridService.getFields(fieldOrders: grid.fieldOrders); + return Future( + () => result.fold( + (fields) { + fieldCache.fields = fields.items; + rowCache.updateWithBlock(grid.blockOrders); + + emit(state.copyWith( + grid: Some(grid), + fields: fieldCache.clonedFields, + rows: rowCache.clonedRows, + loadingState: GridLoadingState.finish(left(unit)), + )); + }, + (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))), + ), + ); + } +} + +@freezed +class GridEvent with _$GridEvent { + const factory GridEvent.initial() = InitialGrid; + const factory GridEvent.createRow() = _CreateRow; + const factory GridEvent.didReceiveRowUpdate(List rows, GridRowChangeReason listState) = _DidReceiveRowUpdate; + const factory GridEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; +} + +@freezed +class GridState with _$GridState { + const factory GridState({ + required String gridId, + required Option grid, + required List fields, + required List rows, + required GridLoadingState loadingState, + required GridRowChangeReason listState, + }) = _GridState; + + factory GridState.initial(String gridId) => GridState( + fields: [], + rows: [], + grid: none(), + gridId: gridId, + loadingState: const _Loading(), + listState: const InitialListState(), + ); +} + +@freezed +class GridLoadingState with _$GridLoadingState { + const factory GridLoadingState.loading() = _Loading; + const factory GridLoadingState.finish(Either successOrFail) = _Finish; +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart new file mode 100644 index 0000000000..90007ba8c2 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -0,0 +1,67 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'grid_service.dart'; + +part 'grid_header_bloc.freezed.dart'; + +class GridHeaderBloc extends Bloc { + final FieldService _fieldService; + final GridFieldCache fieldCache; + + GridHeaderBloc({ + required String gridId, + required this.fieldCache, + }) : _fieldService = FieldService(gridId: gridId), + super(GridHeaderState.initial(fieldCache.clonedFields)) { + on( + (event, emit) async { + await event.map( + initial: (_InitialHeader value) async { + _startListening(); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(fields: value.fields)); + }, + moveField: (_MoveField value) async { + final result = await _fieldService.moveField(value.field.id, value.fromIndex, value.toIndex); + result.fold((l) {}, (err) => Log.error(err)); + }, + ); + }, + ); + } + + Future _startListening() async { + fieldCache.addListener( + onChanged: (fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)), + listenWhen: () => !isClosed, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class GridHeaderEvent with _$GridHeaderEvent { + const factory GridHeaderEvent.initial() = _InitialHeader; + const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridHeaderEvent.moveField(Field field, int fromIndex, int toIndex) = _MoveField; +} + +@freezed +class GridHeaderState with _$GridHeaderState { + const factory GridHeaderState({required List fields}) = _GridHeaderState; + + factory GridHeaderState.initial(List fields) { + // final List newFields = List.from(fields); + // newFields.retainWhere((field) => field.visibility); + return GridHeaderState(fields: fields); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart new file mode 100644 index 0000000000..e6c7dc9de7 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart @@ -0,0 +1,42 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'dart:async'; +import 'dart:typed_data'; +import 'package:app_flowy/core/notification_helper.dart'; + +class GridRowListener { + final String gridId; + PublishNotifier, FlowyError>> rowsUpdateNotifier = PublishNotifier(comparable: null); + GridNotificationListener? _listener; + + GridRowListener({required this.gridId}); + + void start() { + _listener = GridNotificationListener( + objectId: gridId, + handler: _handler, + ); + } + + void _handler(GridNotification ty, Either result) { + switch (ty) { + case GridNotification.DidUpdateGridRow: + result.fold( + (payload) => rowsUpdateNotifier.value = left([GridRowsChangeset.fromBuffer(payload)]), + (error) => rowsUpdateNotifier.value = right(error), + ); + break; + + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + rowsUpdateNotifier.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart new file mode 100644 index 0000000000..aee2a82be4 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -0,0 +1,197 @@ +import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; +import 'package:dartz/dartz.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-folder-data-model/view.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import 'row/row_service.dart'; + +class GridService { + final String gridId; + GridService({ + required this.gridId, + }); + + Future> loadGrid() async { + await FolderEventSetLatestView(ViewId(value: gridId)).send(); + + final payload = GridId(value: gridId); + return GridEventGetGridData(payload).send(); + } + + Future> createRow({Option? startRowId}) { + CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId; + startRowId?.fold(() => null, (id) => payload.startRowId = id); + return GridEventCreateRow(payload).send(); + } + + Future> getFields({required List fieldOrders}) { + final payload = QueryFieldPayload.create() + ..gridId = gridId + ..fieldOrders = RepeatedFieldOrder(items: fieldOrders); + return GridEventGetFields(payload).send(); + } + + Future> closeGrid() { + final request = ViewId(value: gridId); + return FolderEventCloseView(request).send(); + } +} + +class FieldsNotifier extends ChangeNotifier { + List _fields = []; + + set fields(List fields) { + _fields = fields; + notifyListeners(); + } + + List get fields => _fields; +} + +class GridFieldCache { + final String gridId; + late final GridFieldsListener _fieldListener; + final FieldsNotifier _fieldNotifier = FieldsNotifier(); + GridFieldCache({required this.gridId}) { + _fieldListener = GridFieldsListener(gridId: gridId); + _fieldListener.updateFieldsNotifier?.addPublishListener((result) { + result.fold( + (changeset) { + _deleteFields(changeset.deletedFields); + _insertFields(changeset.insertedFields); + _updateFields(changeset.updatedFields); + }, + (err) => Log.error(err), + ); + }); + _fieldListener.start(); + } + + Future dispose() async { + await _fieldListener.stop(); + _fieldNotifier.dispose(); + } + + void applyChangeset(GridFieldChangeset changeset) {} + + UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier.fields); + + List get clonedFields => [..._fieldNotifier.fields]; + + set fields(List fields) { + _fieldNotifier.fields = [...fields]; + } + + VoidCallback addListener( + {VoidCallback? listener, void Function(List)? onChanged, bool Function()? listenWhen}) { + f() { + if (listenWhen != null && listenWhen() == false) { + return; + } + + if (onChanged != null) { + onChanged(clonedFields); + } + + if (listener != null) { + listener(); + } + } + + _fieldNotifier.addListener(f); + return f; + } + + void removeListener(VoidCallback f) { + _fieldNotifier.removeListener(f); + } + + void _deleteFields(List deletedFields) { + if (deletedFields.isEmpty) { + return; + } + final List fields = _fieldNotifier.fields; + final Map deletedFieldMap = { + for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder + }; + + fields.retainWhere((field) => (deletedFieldMap[field.id] == null)); + _fieldNotifier.fields = fields; + } + + void _insertFields(List insertedFields) { + if (insertedFields.isEmpty) { + return; + } + final List fields = _fieldNotifier.fields; + for (final indexField in insertedFields) { + if (fields.length > indexField.index) { + fields.insert(indexField.index, indexField.field_1); + } else { + fields.add(indexField.field_1); + } + } + _fieldNotifier.fields = fields; + } + + void _updateFields(List updatedFields) { + if (updatedFields.isEmpty) { + return; + } + final List fields = _fieldNotifier.fields; + for (final updatedField in updatedFields) { + final index = fields.indexWhere((field) => field.id == updatedField.id); + if (index != -1) { + fields.removeAt(index); + fields.insert(index, updatedField); + } + } + _fieldNotifier.fields = fields; + } +} + +class GridRowDataDelegateAdaptor extends GridRowDataDelegate { + final GridFieldCache _cache; + + GridRowDataDelegateAdaptor(GridFieldCache cache) : _cache = cache; + @override + UnmodifiableListView get fields => _cache.unmodifiableFields; + + @override + GridRow buildGridRow(RowOrder rowOrder) { + return GridRow( + gridId: _cache.gridId, + fields: _cache.unmodifiableFields, + rowId: rowOrder.rowId, + height: rowOrder.height.toDouble(), + ); + } + + @override + void onFieldChanged(FieldDidUpdateCallback callback) { + _cache.addListener(listener: () { + callback(); + }); + } + + @override + CellDataMap buildCellDataMap(Row rowData) { + var map = CellDataMap.new(); + for (final field in fields) { + if (field.visibility) { + map[field.id] = GridCell( + rowId: rowData.id, + gridId: _cache.gridId, + cell: rowData.cellByFieldId[field.id], + field: field, + ); + } + } + return map; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart new file mode 100644 index 0000000000..16287db6bf --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -0,0 +1,28 @@ +export 'grid_bloc.dart'; +export 'row/row_bloc.dart'; +export 'row/row_service.dart'; +export 'grid_service.dart'; +export 'grid_header_bloc.dart'; + +// Field +export 'field/field_service.dart'; +export 'field/field_action_sheet_bloc.dart'; +export 'field/field_editor_bloc.dart'; +export 'field/field_switch_bloc.dart'; + +// Field Type Option +export 'field/type_option/date_bloc.dart'; +export 'field/type_option/number_bloc.dart'; +export 'field/type_option/single_select_bloc.dart'; + +// Cell +export 'cell/text_cell_bloc.dart'; +export 'cell/number_cell_bloc.dart'; +export 'cell/selection_cell_bloc.dart'; +export 'cell/date_cell_bloc.dart'; +export 'cell/checkbox_cell_bloc.dart'; +export 'cell/cell_service.dart'; + +// Setting +export 'setting/setting_bloc.dart'; +export 'setting/property_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart new file mode 100644 index 0000000000..16f8679b2c --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart @@ -0,0 +1,58 @@ +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:dartz/dartz.dart'; + +part 'row_action_sheet_bloc.freezed.dart'; + +class RowActionSheetBloc extends Bloc { + final RowService _rowService; + + RowActionSheetBloc({required GridRow rowData}) + : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), + super(RowActionSheetState.initial(rowData)) { + on( + (event, emit) async { + await event.map( + deleteRow: (_DeleteRow value) async { + final result = await _rowService.deleteRow(); + logResult(result); + }, + duplicateRow: (_DuplicateRow value) async { + final result = await _rowService.duplicateRow(); + logResult(result); + }, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } + + void logResult(Either result) { + result.fold((l) => null, (err) => Log.error(err)); + } +} + +@freezed +class RowActionSheetEvent with _$RowActionSheetEvent { + const factory RowActionSheetEvent.duplicateRow() = _DuplicateRow; + const factory RowActionSheetEvent.deleteRow() = _DeleteRow; +} + +@freezed +class RowActionSheetState with _$RowActionSheetState { + const factory RowActionSheetState({ + required GridRow rowData, + }) = _RowActionSheetState; + + factory RowActionSheetState.initial(GridRow rowData) => RowActionSheetState( + rowData: rowData, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart new file mode 100644 index 0000000000..b49485c16b --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -0,0 +1,83 @@ +import 'dart:collection'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'row_service.dart'; +import 'package:dartz/dartz.dart'; + +part 'row_bloc.freezed.dart'; + +class RowBloc extends Bloc { + final RowService _rowService; + final GridRowCache _rowCache; + void Function()? _rowListenFn; + + RowBloc({ + required GridRow rowData, + required GridRowCache rowCache, + }) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), + _rowCache = rowCache, + super(RowState.initial(rowData)) { + on( + (event, emit) async { + await event.map( + initial: (_InitialRow value) async { + await _startListening(); + await _loadRow(emit); + }, + createRow: (_CreateRow value) { + _rowService.createRow(); + }, + didReceiveCellDatas: (_DidReceiveCellDatas value) async { + emit(state.copyWith(cellDataMap: Some(value.cellData))); + }, + ); + }, + ); + } + + @override + Future close() async { + if (_rowListenFn != null) { + _rowCache.removeRowListener(_rowListenFn!); + } + return super.close(); + } + + Future _startListening() async { + _rowListenFn = _rowCache.addRowListener( + rowId: state.rowData.rowId, + onUpdated: (cellDatas) => add(RowEvent.didReceiveCellDatas(cellDatas)), + listenWhen: () => !isClosed, + ); + } + + Future _loadRow(Emitter emit) async { + final data = _rowCache.loadCellData(state.rowData.rowId); + data.foldRight(null, (cellDatas, _) { + if (!isClosed) { + add(RowEvent.didReceiveCellDatas(cellDatas)); + } + }); + } +} + +@freezed +class RowEvent with _$RowEvent { + const factory RowEvent.initial() = _InitialRow; + const factory RowEvent.createRow() = _CreateRow; + const factory RowEvent.didReceiveCellDatas(CellDataMap cellData) = _DidReceiveCellDatas; +} + +@freezed +class RowState with _$RowState { + const factory RowState({ + required GridRow rowData, + required Option cellDataMap, + }) = _RowState; + + factory RowState.initial(GridRow rowData) => RowState( + rowData: rowData, + cellDataMap: none(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart new file mode 100644 index 0000000000..2390dc40a0 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -0,0 +1,74 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'row_service.dart'; + +part 'row_detail_bloc.freezed.dart'; + +class RowDetailBloc extends Bloc { + final GridRow rowData; + final GridRowCache _rowCache; + void Function()? _rowListenFn; + + RowDetailBloc({ + required this.rowData, + required GridRowCache rowCache, + }) : _rowCache = rowCache, + super(RowDetailState.initial()) { + on( + (event, emit) async { + await event.map( + initial: (_Initial value) async { + await _startListening(); + _loadCellData(); + }, + didReceiveCellDatas: (_DidReceiveCellDatas value) { + emit(state.copyWith(cellDatas: value.cellDatas)); + }, + ); + }, + ); + } + + @override + Future close() async { + if (_rowListenFn != null) { + _rowCache.removeRowListener(_rowListenFn!); + } + return super.close(); + } + + Future _startListening() async { + _rowListenFn = _rowCache.addRowListener( + rowId: rowData.rowId, + onUpdated: (cellDatas) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())), + listenWhen: () => !isClosed, + ); + } + + Future _loadCellData() async { + final data = _rowCache.loadCellData(rowData.rowId); + data.foldRight(null, (cellDataMap, _) { + if (!isClosed) { + add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList())); + } + }); + } +} + +@freezed +class RowDetailEvent with _$RowDetailEvent { + const factory RowDetailEvent.initial() = _Initial; + const factory RowDetailEvent.didReceiveCellDatas(List cellDatas) = _DidReceiveCellDatas; +} + +@freezed +class RowDetailState with _$RowDetailState { + const factory RowDetailState({ + required List cellDatas, + }) = _RowDetailState; + + factory RowDetailState.initial() => RowDetailState( + cellDatas: List.empty(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart new file mode 100644 index 0000000000..7d947b8482 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart @@ -0,0 +1,42 @@ +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'dart:async'; +import 'dart:typed_data'; +import 'package:app_flowy/core/notification_helper.dart'; +import 'package:dartz/dartz.dart'; + +typedef UpdateRowNotifiedValue = Either; +typedef UpdateFieldNotifiedValue = Either, FlowyError>; + +class RowListener { + final String rowId; + PublishNotifier? updateRowNotifier = PublishNotifier(); + GridNotificationListener? _listener; + + RowListener({required this.rowId}); + + void start() { + _listener = GridNotificationListener(objectId: rowId, handler: _handler); + } + + void _handler(GridNotification ty, Either result) { + switch (ty) { + case GridNotification.DidUpdateRow: + result.fold( + (payload) => updateRowNotifier?.value = left(Row.fromBuffer(payload)), + (error) => updateRowNotifier?.value = right(error), + ); + break; + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + updateRowNotifier?.dispose(); + updateRowNotifier = null; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart new file mode 100644 index 0000000000..f524e03d0c --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -0,0 +1,374 @@ +import 'dart:collection'; + +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:app_flowy/workspace/application/grid/grid_listener.dart'; +part 'row_service.freezed.dart'; + +typedef RowUpdateCallback = void Function(); +typedef FieldDidUpdateCallback = void Function(); +typedef CellDataMap = LinkedHashMap; + +abstract class GridRowDataDelegate { + UnmodifiableListView get fields; + GridRow buildGridRow(RowOrder rowOrder); + CellDataMap buildCellDataMap(Row rowData); + void onFieldChanged(FieldDidUpdateCallback callback); +} + +class GridRowCache { + final String gridId; + final RowsNotifier _rowNotifier; + final GridRowListener _rowsListener; + final GridRowDataDelegate _dataDelegate; + + List get clonedRows => _rowNotifier.clonedRows; + + GridRowCache({required this.gridId, required GridRowDataDelegate dataDelegate}) + : _rowNotifier = RowsNotifier(rowBuilder: dataDelegate.buildGridRow), + _rowsListener = GridRowListener(gridId: gridId), + _dataDelegate = dataDelegate { + // + dataDelegate.onFieldChanged(() => _rowNotifier.fieldDidChange()); + + // listen on the row update + _rowsListener.rowsUpdateNotifier.addPublishListener((result) { + result.fold( + (changesets) { + for (final changeset in changesets) { + _rowNotifier.deleteRows(changeset.deletedRows); + _rowNotifier.insertRows(changeset.insertedRows); + _rowNotifier.updateRows(changeset.updatedRows); + } + }, + (err) => Log.error(err), + ); + }); + _rowsListener.start(); + } + + Future dispose() async { + await _rowsListener.stop(); + _rowNotifier.dispose(); + } + + void addListener({ + void Function(List, GridRowChangeReason)? onChanged, + bool Function()? listenWhen, + }) { + _rowNotifier.addListener(() { + if (onChanged == null) { + return; + } + + if (listenWhen != null && listenWhen() == false) { + return; + } + + onChanged(clonedRows, _rowNotifier._changeReason); + }); + } + + RowUpdateCallback addRowListener({ + required String rowId, + void Function(CellDataMap)? onUpdated, + bool Function()? listenWhen, + }) { + listenrHandler() { + if (onUpdated == null) { + return; + } + + if (listenWhen != null && listenWhen() == false) { + return; + } + + notify() { + final row = _rowNotifier.rowDataWithId(rowId); + if (row != null) { + final cellDataMap = _dataDelegate.buildCellDataMap(row); + onUpdated(cellDataMap); + } + } + + _rowNotifier._changeReason.whenOrNull( + update: (indexs) { + if (indexs[rowId] != null) { + notify(); + } + }, + fieldDidChange: () => notify(), + ); + } + + _rowNotifier.addListener(listenrHandler); + return listenrHandler; + } + + void removeRowListener(VoidCallback callback) { + _rowNotifier.removeListener(callback); + } + + Option loadCellData(String rowId) { + final Row? data = _rowNotifier.rowDataWithId(rowId); + if (data != null) { + return Some(_dataDelegate.buildCellDataMap(data)); + } + + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + GridEventGetRow(payload).send().then((result) { + result.fold( + (rowData) => _rowNotifier.rowData = rowData, + (err) => Log.error(err), + ); + }); + return none(); + } + + void updateWithBlock(List blocks) { + final rowOrders = blocks.expand((block) => block.rowOrders).toList(); + _rowNotifier.reset(rowOrders); + } +} + +class RowsNotifier extends ChangeNotifier { + List _rows = []; + HashMap _rowDataMap = HashMap(); + GridRowChangeReason _changeReason = const InitialListState(); + final GridRow Function(RowOrder) rowBuilder; + + RowsNotifier({ + required this.rowBuilder, + }); + + void reset(List rowOrders) { + _rowDataMap = HashMap(); + final rows = rowOrders.map((rowOrder) => rowBuilder(rowOrder)).toList(); + _update(rows, const GridRowChangeReason.initial()); + } + + void deleteRows(List deletedRows) { + if (deletedRows.isEmpty) { + return; + } + + final List newRows = []; + final DeletedIndexs deletedIndex = []; + final Map deletedRowMap = {for (var e in deletedRows) e.rowId: e}; + + _rows.asMap().forEach((index, row) { + if (deletedRowMap[row.rowId] == null) { + newRows.add(row); + } else { + deletedIndex.add(DeletedIndex(index: index, row: row)); + } + }); + + _update(newRows, GridRowChangeReason.delete(deletedIndex)); + } + + void insertRows(List createdRows) { + if (createdRows.isEmpty) { + return; + } + + InsertedIndexs insertIndexs = []; + final List newRows = clonedRows; + for (final createdRow in createdRows) { + final insertIndex = InsertedIndex( + index: createdRow.index, + rowId: createdRow.rowOrder.rowId, + ); + insertIndexs.add(insertIndex); + newRows.insert(createdRow.index, (rowBuilder(createdRow.rowOrder))); + } + _update(newRows, GridRowChangeReason.insert(insertIndexs)); + } + + void updateRows(List updatedRows) { + if (updatedRows.isEmpty) { + return; + } + + final UpdatedIndexs updatedIndexs = UpdatedIndexs(); + final List newRows = clonedRows; + for (final rowOrder in updatedRows) { + final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); + if (index != -1) { + // Remove the old row data, the data will be filled if the loadRow method gets called. + _rowDataMap.remove(rowOrder.rowId); + + newRows.removeAt(index); + newRows.insert(index, rowBuilder(rowOrder)); + updatedIndexs[rowOrder.rowId] = UpdatedIndex(index: index, rowId: rowOrder.rowId); + } + } + + _update(newRows, GridRowChangeReason.update(updatedIndexs)); + } + + void fieldDidChange() { + _update(_rows, const GridRowChangeReason.fieldDidChange()); + } + + void _update(List rows, GridRowChangeReason reason) { + _rows = rows; + _changeReason = reason; + + _changeReason.map( + insert: (_) => notifyListeners(), + delete: (_) => notifyListeners(), + update: (_) => notifyListeners(), + fieldDidChange: (_) => notifyListeners(), + initial: (_) {}, + ); + } + + set rowData(Row rowData) { + rowData.freeze(); + + _rowDataMap[rowData.id] = rowData; + final index = _rows.indexWhere((row) => row.rowId == rowData.id); + if (index != -1) { + // update the corresponding row in _rows if they are not the same + if (_rows[index].data != rowData) { + final row = _rows.removeAt(index).copyWith(data: rowData); + _rows.insert(index, row); + + // Calculate the update index + final UpdatedIndexs updatedIndexs = UpdatedIndexs(); + updatedIndexs[row.rowId] = UpdatedIndex(index: index, rowId: row.rowId); + _changeReason = GridRowChangeReason.update(updatedIndexs); + + // + notifyListeners(); + } + } + } + + Row? rowDataWithId(String rowId) { + return _rowDataMap[rowId]; + } + + List get clonedRows => [..._rows]; +} + +class RowService { + final String gridId; + final String rowId; + + RowService({required this.gridId, required this.rowId}); + + Future> createRow() { + CreateRowPayload payload = CreateRowPayload.create() + ..gridId = gridId + ..startRowId = rowId; + + return GridEventCreateRow(payload).send(); + } + + Future> moveRow(String rowId, int fromIndex, int toIndex) { + final payload = MoveItemPayload.create() + ..gridId = gridId + ..itemId = rowId + ..ty = MoveItemType.MoveRow + ..fromIndex = fromIndex + ..toIndex = toIndex; + + return GridEventMoveItem(payload).send(); + } + + Future> getRow() { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + return GridEventGetRow(payload).send(); + } + + Future> deleteRow() { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + return GridEventDeleteRow(payload).send(); + } + + Future> duplicateRow() { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + return GridEventDuplicateRow(payload).send(); + } +} + +@freezed +class GridRow with _$GridRow { + const factory GridRow({ + required String gridId, + required String rowId, + required List fields, + required double height, + Row? data, + }) = _GridRow; +} + +@freezed +class GridCell with _$GridCell { + const factory GridCell({ + required String gridId, + required String rowId, + required Field field, + Cell? cell, + }) = _GridCell; +} + +typedef InsertedIndexs = List; +typedef DeletedIndexs = List; +typedef UpdatedIndexs = LinkedHashMap; + +@freezed +class GridRowChangeReason with _$GridRowChangeReason { + const factory GridRowChangeReason.insert(InsertedIndexs items) = _Insert; + const factory GridRowChangeReason.delete(DeletedIndexs items) = _Delete; + const factory GridRowChangeReason.update(UpdatedIndexs indexs) = _Update; + const factory GridRowChangeReason.fieldDidChange() = _FieldDidChange; + const factory GridRowChangeReason.initial() = InitialListState; +} + +class InsertedIndex { + final int index; + final String rowId; + InsertedIndex({ + required this.index, + required this.rowId, + }); +} + +class DeletedIndex { + final int index; + final GridRow row; + DeletedIndex({ + required this.index, + required this.row, + }); +} + +class UpdatedIndex { + final int index; + final String rowId; + UpdatedIndex({ + required this.index, + required this.rowId, + }); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart new file mode 100644 index 0000000000..c69b8062bf --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -0,0 +1,79 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; + +part 'property_bloc.freezed.dart'; + +class GridPropertyBloc extends Bloc { + final FieldService _service; + final GridFieldCache _fieldCache; + Function()? _listenFieldCallback; + + GridPropertyBloc({required String gridId, required GridFieldCache fieldCache}) + : _service = FieldService(gridId: gridId), + _fieldCache = fieldCache, + super(GridPropertyState.initial(gridId, fieldCache.clonedFields)) { + on( + (event, emit) async { + await event.map( + initial: (_Initial value) { + _startListening(); + }, + setFieldVisibility: (_SetFieldVisibility value) async { + final result = await _service.updateField(fieldId: value.fieldId, visibility: value.visibility); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(fields: value.fields)); + }, + moveField: (_MoveField value) { + // + }, + ); + }, + ); + } + + @override + Future close() async { + if (_listenFieldCallback != null) { + _fieldCache.removeListener(_listenFieldCallback!); + } + return super.close(); + } + + void _startListening() { + _listenFieldCallback = _fieldCache.addListener( + onChanged: (fields) => add(GridPropertyEvent.didReceiveFieldUpdate(fields)), + listenWhen: () => !isClosed, + ); + } +} + +@freezed +class GridPropertyEvent with _$GridPropertyEvent { + const factory GridPropertyEvent.initial() = _Initial; + const factory GridPropertyEvent.setFieldVisibility(String fieldId, bool visibility) = _SetFieldVisibility; + const factory GridPropertyEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridPropertyEvent.moveField(int fromIndex, int toIndex) = _MoveField; +} + +@freezed +class GridPropertyState with _$GridPropertyState { + const factory GridPropertyState({ + required String gridId, + required List fields, + }) = _GridPropertyState; + + factory GridPropertyState.initial(String gridId, List fields) => GridPropertyState( + gridId: gridId, + fields: fields, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/setting_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/setting_bloc.dart new file mode 100644 index 0000000000..bea2b87da6 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/setting_bloc.dart @@ -0,0 +1,46 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'package:dartz/dartz.dart'; + +part 'setting_bloc.freezed.dart'; + +class GridSettingBloc extends Bloc { + final String gridId; + GridSettingBloc({required this.gridId}) : super(GridSettingState.initial()) { + on( + (event, emit) async { + event.map(performAction: (_PerformAction value) { + emit(state.copyWith(selectedAction: Some(value.action))); + }); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class GridSettingEvent with _$GridSettingEvent { + const factory GridSettingEvent.performAction(GridSettingAction action) = _PerformAction; +} + +@freezed +class GridSettingState with _$GridSettingState { + const factory GridSettingState({ + required Option selectedAction, + }) = _GridSettingState; + + factory GridSettingState.initial() => GridSettingState( + selectedAction: none(), + ); +} + +enum GridSettingAction { + filter, + sortBy, + properties, +} diff --git a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart index e4b0482989..5ed7ce959d 100644 --- a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart @@ -12,10 +12,10 @@ class HomeBloc extends Bloc { emit(state.copyWith(isLoading: e.isLoading)); }, setEditPannel: (e) async { - emit(state.copyWith(editContext: some(e.editContext))); + emit(state.copyWith(pannelContext: some(e.editContext))); }, dismissEditPannel: (value) async { - emit(state.copyWith(editContext: none())); + emit(state.copyWith(pannelContext: none())); }, forceCollapse: (e) async { emit(state.copyWith(forceCollapse: e.forceCollapse)); @@ -43,12 +43,12 @@ class HomeState with _$HomeState { const factory HomeState({ required bool isLoading, required bool forceCollapse, - required Option editContext, + required Option pannelContext, }) = _HomeState; factory HomeState.initial() => HomeState( isLoading: false, forceCollapse: false, - editContext: none(), + pannelContext: none(), ); } diff --git a/frontend/app_flowy/lib/workspace/application/home/home_listen_bloc.dart b/frontend/app_flowy/lib/workspace/application/home/home_listen_bloc.dart index f3da1af678..0ebb572e17 100644 --- a/frontend/app_flowy/lib/workspace/application/home/home_listen_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/home/home_listen_bloc.dart @@ -1,5 +1,5 @@ import 'package:app_flowy/user/application/user_listener.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/error-code/error_code.pbenum.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/home/prelude.dart b/frontend/app_flowy/lib/workspace/application/home/prelude.dart new file mode 100644 index 0000000000..8d1173c2d6 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/home/prelude.dart @@ -0,0 +1 @@ +export 'home_listen_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart index 0ea811711e..6ee18986b5 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'package:app_flowy/plugin/plugin.dart'; -import 'package:app_flowy/startup/tasks/load_plugin.dart'; import 'package:app_flowy/workspace/application/workspace/workspace_listener.dart'; import 'package:app_flowy/workspace/application/workspace/workspace_service.dart'; import 'package:dartz/dartz.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/menu/prelude.dart b/frontend/app_flowy/lib/workspace/application/menu/prelude.dart new file mode 100644 index 0000000000..0bf94ea60b --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/menu/prelude.dart @@ -0,0 +1,2 @@ +export 'menu_bloc.dart'; +export 'menu_user_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/trash/prelude.dart b/frontend/app_flowy/lib/workspace/application/trash/prelude.dart new file mode 100644 index 0000000000..5a638a58d1 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/trash/prelude.dart @@ -0,0 +1,3 @@ +export 'trash_bloc.dart'; +export 'trash_listener.dart'; +export 'trash_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart b/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart index 8bef2e41fd..e6b61af3e2 100644 --- a/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart @@ -14,7 +14,7 @@ class TrashBloc extends Bloc { TrashBloc({required this.service, required this.listener}) : super(TrashState.init()) { on((event, emit) async { await event.map(initial: (e) async { - listener.startListening(trashUpdated: _listenTrashUpdated); + listener.start(trashUpdated: _listenTrashUpdated); final result = await service.readTrash(); emit(result.fold( (object) => state.copyWith(objects: object.items, successOrFailure: left(unit)), diff --git a/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart b/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart index 6a95de958e..36dc982466 100644 --- a/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart @@ -13,12 +13,12 @@ typedef TrashUpdatedCallback = void Function(Either, FlowyError> tra class TrashListener { StreamSubscription? _subscription; TrashUpdatedCallback? _trashUpdated; - late FolderNotificationParser _parser; + FolderNotificationParser? _parser; - void startListening({TrashUpdatedCallback? trashUpdated}) { + void start({TrashUpdatedCallback? trashUpdated}) { _trashUpdated = trashUpdated; _parser = FolderNotificationParser(callback: _bservableCallback); - _subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable)); + _subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable)); } void _bservableCallback(FolderNotification ty, Either result) { @@ -40,6 +40,7 @@ class TrashListener { } Future close() async { + _parser = null; await _subscription?.cancel(); _trashUpdated = null; } diff --git a/frontend/app_flowy/lib/workspace/application/view/prelude.dart b/frontend/app_flowy/lib/workspace/application/view/prelude.dart new file mode 100644 index 0000000000..f789b90fcd --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/view/prelude.dart @@ -0,0 +1,3 @@ +export 'view_bloc.dart'; +export 'view_listener.dart'; +export 'view_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart b/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart index 1528600236..5b5a953922 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart @@ -34,12 +34,14 @@ class ViewBloc extends Bloc { }, viewDidUpdate: (e) { e.result.fold( - (view) => emit(state.copyWith(view: view, successOrFailure: left(unit))), + (view) => + emit(state.copyWith(view: view, successOrFailure: left(unit))), (error) => emit(state.copyWith(successOrFailure: right(error))), ); }, rename: (e) async { - final result = await service.updateView(viewId: view.id, name: e.newName); + final result = + await service.updateView(viewId: view.id, name: e.newName); emit( result.fold( (l) => state.copyWith(successOrFailure: left(unit)), @@ -49,6 +51,7 @@ class ViewBloc extends Bloc { }, delete: (e) async { final result = await service.delete(viewId: view.id); + await service.updateView(viewId: view.id); emit( result.fold( (l) => state.copyWith(successOrFailure: left(unit)), @@ -83,7 +86,8 @@ 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 result) = ViewDidUpdate; + const factory ViewEvent.viewDidUpdate(Either result) = + ViewDidUpdate; } @freezed diff --git a/frontend/app_flowy/lib/workspace/application/view/view_ext.dart b/frontend/app_flowy/lib/workspace/application/view/view_ext.dart index cf80a820a0..78230e1311 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_ext.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_ext.dart @@ -39,7 +39,7 @@ extension ViewExtension on View { thumbnail = "file_icon"; } - final Widget widget = svg(thumbnail, color: iconColor); + final Widget widget = svgWidget(thumbnail, color: iconColor); return widget; } diff --git a/frontend/app_flowy/lib/workspace/application/view/view_listener.dart b/frontend/app_flowy/lib/workspace/application/view/view_listener.dart index c5a202e25e..ee27d55139 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_listener.dart @@ -9,16 +9,16 @@ import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; import 'package:flowy_sdk/rust_stream.dart'; import 'package:flowy_infra/notifier.dart'; -typedef DeleteNotifierValue = Either; -typedef UpdateNotifierValue = Either; -typedef RestoreNotifierValue = Either; +typedef DeleteViewNotifyValue = Either; +typedef UpdateViewNotifiedValue = Either; +typedef RestoreViewNotifiedValue = Either; class ViewListener { StreamSubscription? _subscription; - PublishNotifier updatedNotifier = PublishNotifier(); - PublishNotifier deletedNotifier = PublishNotifier(); - PublishNotifier restoredNotifier = PublishNotifier(); - late FolderNotificationParser _parser; + PublishNotifier updatedNotifier = PublishNotifier(); + PublishNotifier deletedNotifier = PublishNotifier(); + PublishNotifier restoredNotifier = PublishNotifier(); + FolderNotificationParser? _parser; View view; ViewListener({ @@ -33,7 +33,7 @@ class ViewListener { }, ); - _subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable)); + _subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable)); } void _handleObservableType(FolderNotification ty, Either result) { @@ -62,6 +62,7 @@ class ViewListener { } Future close() async { + _parser = null; await _subscription?.cancel(); updatedNotifier.dispose(); deletedNotifier.dispose(); diff --git a/frontend/app_flowy/lib/workspace/application/workspace/prelude.dart b/frontend/app_flowy/lib/workspace/application/workspace/prelude.dart new file mode 100644 index 0000000000..129462beb0 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/workspace/prelude.dart @@ -0,0 +1,3 @@ +export 'welcome_bloc.dart'; +export 'workspace_listener.dart'; +export 'workspace_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart b/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart index e5959d1562..9ac51e36f8 100644 --- a/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart @@ -12,7 +12,6 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; import 'package:flowy_sdk/rust_stream.dart'; - typedef WorkspaceAppsChangedCallback = void Function(Either, FlowyError> appsOrFail); typedef WorkspaceUpdatedCallback = void Function(String name, String desc); @@ -31,12 +30,11 @@ class WorkspaceListener { } } - class WorkspaceListenerService { StreamSubscription? _subscription; WorkspaceAppsChangedCallback? _appsChanged; WorkspaceUpdatedCallback? _update; - late FolderNotificationParser _parser; + FolderNotificationParser? _parser; final UserProfile user; final String workspaceId; @@ -59,7 +57,7 @@ class WorkspaceListenerService { }, ); - _subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable)); + _subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable)); } void _handleObservableType(FolderNotification ty, Either result) { @@ -91,6 +89,7 @@ class WorkspaceListenerService { } Future close() async { + _parser = null; await _subscription?.cancel(); // _appsChanged = null; // _update = null; diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart index f0192a846b..0405279851 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart @@ -20,7 +20,7 @@ class HomeLayout { HomeLayout(BuildContext context, BoxConstraints homeScreenConstraint, bool forceCollapse) { final homeBlocState = context.read().state; - showEditPannel = homeBlocState.editContext.isSome(); + showEditPannel = homeBlocState.pannelContext.isSome(); menuWidth = Sizes.sideBarMed; if (context.widthPx >= PageBreaks.desktop) { diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart index 88ec0f5ad6..e9bb80dd30 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -126,13 +126,22 @@ class _HomeScreenState extends State { Widget _buildEditPannel({required HomeState homeState, required BuildContext context, required HomeLayout layout}) { final homeBloc = context.read(); - Widget editPannel = EditPannel( - context: homeState.editContext, - onEndEdit: () => homeBloc.add(const HomeEvent.dismissEditPannel()), + return BlocBuilder( + buildWhen: (previous, current) => previous.pannelContext != current.pannelContext, + builder: (context, state) { + return state.pannelContext.fold( + () => const SizedBox(), + (pannelContext) => FocusTraversalGroup( + child: RepaintBoundary( + child: EditPannel( + pannelContext: pannelContext, + onEndEdit: () => homeBloc.add(const HomeEvent.dismissEditPannel()), + ), + ), + ), + ); + }, ); - // editPannel = RepaintBoundary(child: editPannel); - // editPannel = FocusTraversalGroup(child: editPannel); - return editPannel; } Widget _layoutWidgets({ diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart index 6127440a89..65e315f56d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_stack.dart @@ -8,7 +8,6 @@ import 'package:time/time.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:app_flowy/plugin/plugin.dart'; -import 'package:app_flowy/startup/tasks/load_plugin.dart'; import 'package:app_flowy/workspace/presentation/plugins/blank/blank.dart'; import 'package:app_flowy/workspace/presentation/home/home_sizes.dart'; import 'package:app_flowy/workspace/presentation/home/navigation.dart'; @@ -108,20 +107,20 @@ class HomeStackNotifier extends ChangeNotifier { Plugin _plugin; PublishNotifier collapsedNotifier = PublishNotifier(); - Widget get titleWidget => _plugin.pluginDisplay.leftBarItem; + Widget get titleWidget => _plugin.display.leftBarItem; HomeStackNotifier({Plugin? plugin}) : _plugin = plugin ?? makePlugin(pluginType: DefaultPlugin.blank.type()); set plugin(Plugin newPlugin) { - if (newPlugin.pluginId == _plugin.pluginId) { + if (newPlugin.id == _plugin.id) { return; } - _plugin.displayNotifier?.removeListener(notifyListeners); + _plugin.display.notifier?.removeListener(notifyListeners); _plugin.dispose(); _plugin = newPlugin; - _plugin.displayNotifier?.addListener(notifyListeners); + _plugin.display.notifier?.addListener(notifyListeners); notifyListeners(); } @@ -134,7 +133,7 @@ class HomeStackManager { HomeStackManager(); Widget title() { - return _notifier.plugin.pluginDisplay.leftBarItem; + return _notifier.plugin.display.leftBarItem; } PublishNotifier get collapsedNotifier => _notifier.collapsedNotifier; @@ -166,12 +165,12 @@ class HomeStackManager { ], child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) { return FadingIndexedStack( - index: getIt().indexOf(notifier.plugin.pluginType), + index: getIt().indexOf(notifier.plugin.ty), children: getIt().supportPluginTypes.map((pluginType) { - if (pluginType == notifier.plugin.pluginType) { - return notifier.plugin.pluginDisplay.buildWidget(); + if (pluginType == notifier.plugin.ty) { + return notifier.plugin.display.buildWidget().padding(horizontal: 40, vertical: 28); } else { - return const BlankStackPage(); + return const BlankPage(); } }).toList(), ); @@ -198,7 +197,7 @@ class HomeTopBar extends StatelessWidget { value: Provider.of(context, listen: false), child: Consumer( builder: (BuildContext context, HomeStackNotifier notifier, Widget? child) { - return notifier.plugin.pluginDisplay.rightBarItem ?? const SizedBox(); + return notifier.plugin.display.rightBarItem ?? const SizedBox(); }, ), ) // _renderMoreButton(), diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart index 9e696e8a73..a7de233006 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart @@ -28,7 +28,7 @@ class AddButton extends StatelessWidget { onSelected: onSelected, ).show(context); }, - icon: svg("home/add").padding(horizontal: 3, vertical: 3), + icon: svgWidget("home/add").padding(horizontal: 3, vertical: 3), ); } } @@ -78,20 +78,18 @@ class CreateItem extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.watch(); - final config = HoverDisplayConfig(hoverColor: theme.hover); + final config = HoverStyle(hoverColor: theme.hover); return FlowyHover( - config: config, - builder: (context, onHover) { - return GestureDetector( - onTap: () => onSelected(pluginBuilder), - child: FlowyText.medium( - pluginBuilder.menuName, - color: theme.textColor, - fontSize: 12, - ).padding(horizontal: 10, vertical: 6), - ); - }, + style: config, + child: GestureDetector( + onTap: () => onSelected(pluginBuilder), + child: FlowyText.medium( + pluginBuilder.menuName, + color: theme.textColor, + fontSize: 12, + ).padding(horizontal: 10, vertical: 6), + ), ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart index 58ebabc0c2..ff1d6e6822 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart @@ -37,7 +37,7 @@ class MenuAppHeader extends StatelessWidget { _renderExpandedIcon(context, theme), // HSpace(MenuAppSizes.iconPadding), _renderTitle(context, theme), - _renderAddButton(context), + _renderCreateViewButton(context), ], ), ); @@ -81,7 +81,6 @@ class MenuAppHeader extends StatelessWidget { onSecondaryTap: () { final actionList = AppDisclosureActionSheet(onSelected: (action) => _handleAction(context, action)); actionList.show( - context, context, anchorDirection: AnchorDirection.bottomWithCenterAligned, ); @@ -99,7 +98,7 @@ class MenuAppHeader extends StatelessWidget { ); } - Widget _renderAddButton(BuildContext context) { + Widget _renderCreateViewButton(BuildContext context) { return Tooltip( message: LocaleKeys.menuAppHeader_addPageTooltip.tr(), child: AddButton( @@ -154,9 +153,9 @@ extension AppDisclosureExtension on AppDisclosureAction { Widget get icon { switch (this) { case AppDisclosureAction.rename: - return svg('editor/edit', color: const Color(0xffe5e5e5)); + return svgWidget('editor/edit', color: const Color(0xffe5e5e5)); case AppDisclosureAction.delete: - return svg('editor/delete', color: const Color(0xffe5e5e5)); + return svgWidget('editor/delete', color: const Color(0xffe5e5e5)); } } } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/right_click_action.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/right_click_action.dart index 8938443236..be6a97dbfb 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/right_click_action.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/right_click_action.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'header.dart'; -class AppDisclosureActionSheet with ActionList implements FlowyOverlayDelegate { +class AppDisclosureActionSheet with ActionList, FlowyOverlayDelegate { final Function(dartz.Option) onSelected; final _items = AppDisclosureAction.values.map((action) => DisclosureActionWrapper(action)).toList(); diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart index 41ba6ab4d1..d028355ed1 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart @@ -95,9 +95,11 @@ class _MenuAppState extends State { Widget _renderViewSection(AppDataNotifier notifier) { return MultiProvider( providers: [ChangeNotifierProvider.value(value: notifier)], - child: Consumer(builder: (context, AppDataNotifier notifier, child) { - return ViewSection(appData: notifier); - }), + child: Consumer( + builder: (context, AppDataNotifier notifier, child) { + return ViewSection(appData: notifier); + }, + ), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/disclosure_action.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/disclosure_action.dart index a2cd2edcac..c9a02a9de7 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/disclosure_action.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/disclosure_action.dart @@ -11,9 +11,7 @@ import 'item.dart'; // [[Widget: LifeCycle]] // https://flutterbyexample.com/lesson/stateful-widget-lifecycle -class ViewDisclosureButton extends StatelessWidget - with ActionList - implements FlowyOverlayDelegate { +class ViewDisclosureButton extends StatelessWidget with ActionList, FlowyOverlayDelegate { final Function() onTap; final Function(dartz.Option) onSelected; final _items = ViewDisclosureAction.values.map((action) => ViewDisclosureActionWrapper(action)).toList(); @@ -32,9 +30,9 @@ class ViewDisclosureButton extends StatelessWidget width: 26, onPressed: () { onTap(); - show(context, context); + show(context); }, - icon: svg("editor/details", color: theme.iconColor), + icon: svgWidget("editor/details", color: theme.iconColor), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart index 1503835bf6..290d2bd328 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart @@ -43,9 +43,9 @@ class ViewSectionItem extends StatelessWidget { return InkWell( onTap: () => onSelected(context.read().state.view), child: FlowyHover( - config: HoverDisplayConfig(hoverColor: theme.bg3), + style: HoverStyle(hoverColor: theme.bg3), builder: (_, onHover) => _render(context, onHover, state, theme.iconColor), - isOnSelected: () => state.isEditing || isSelected, + setSelected: () => state.isEditing || isSelected, ), ); }, @@ -126,11 +126,11 @@ extension ViewDisclosureExtension on ViewDisclosureAction { Widget get icon { switch (this) { case ViewDisclosureAction.rename: - return svg('editor/edit', color: const Color(0xff999999)); + return svgWidget('editor/edit', color: const Color(0xff999999)); case ViewDisclosureAction.delete: - return svg('editor/delete', color: const Color(0xff999999)); + return svgWidget('editor/delete', color: const Color(0xff999999)); case ViewDisclosureAction.duplicate: - return svg('editor/copy', color: const Color(0xff999999)); + return svgWidget('editor/copy', color: const Color(0xff999999)); } } } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart index 79f595a428..59324fa0a7 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:developer'; import 'package:app_flowy/startup/startup.dart'; @@ -10,7 +11,6 @@ import 'package:provider/provider.dart'; import 'package:reorderables/reorderables.dart'; import 'package:styled_widget/styled_widget.dart'; import 'item.dart'; -import 'package:async/async.dart'; class ViewSection extends StatelessWidget { final AppDataNotifier appData; @@ -149,7 +149,7 @@ class ViewSectionNotifier with ChangeNotifier { bool isDisposed = false; List _views; View? _selectedView; - CancelableOperation? _notifyListenerOperation; + Timer? _notifyListenerOperation; ViewSectionNotifier({ required BuildContext context, @@ -205,9 +205,7 @@ class ViewSectionNotifier with ChangeNotifier { void _notifyListeners() { _notifyListenerOperation?.cancel(); - _notifyListenerOperation = CancelableOperation.fromFuture( - Future.delayed(const Duration(milliseconds: 30), () {}), - ).then((_) { + _notifyListenerOperation = Timer(const Duration(milliseconds: 30), () { if (!isDisposed) { notifyListeners(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart index 6db19495ac..17d7326f0a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart @@ -64,7 +64,7 @@ class _HomeMenuState extends State { child: MultiBlocListener( listeners: [ BlocListener( - listenWhen: (p, c) => p.plugin.pluginId != c.plugin.pluginId, + listenWhen: (p, c) => p.plugin.id != c.plugin.id, listener: (context, state) { getIt().setPlugin(state.plugin); }, @@ -235,7 +235,7 @@ class MenuTopBar extends StatelessWidget { width: 28, onPressed: () => context.read().add(const MenuEvent.collapse()), iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4), - icon: svg("home/hide_menu", color: theme.iconColor), + icon: svgWidget("home/hide_menu", color: theme.iconColor), ) ], ), diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart index fb0a4284d8..3a1674e486 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart @@ -80,7 +80,7 @@ class MenuUser extends StatelessWidget { }, icon: SizedBox.square( dimension: 20, - child: svg("home/settings", color: theme.iconColor), + child: svgWidget("home/settings", color: theme.iconColor), ), ), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/home/navigation.dart b/frontend/app_flowy/lib/workspace/presentation/home/navigation.dart index e8a9c3d457..b6947c79fe 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/navigation.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/navigation.dart @@ -17,8 +17,8 @@ class NavigationNotifier with ChangeNotifier { void update(HomeStackNotifier notifier) { bool shouldNotify = false; - if (navigationItems != notifier.plugin.pluginDisplay.navigationItems) { - navigationItems = notifier.plugin.pluginDisplay.navigationItems; + if (navigationItems != notifier.plugin.display.navigationItems) { + navigationItems = notifier.plugin.display.navigationItems; shouldNotify = true; } @@ -59,7 +59,7 @@ class FlowyNavigation extends StatelessWidget { create: (_) { final notifier = Provider.of(context, listen: false); return NavigationNotifier( - navigationItems: notifier.plugin.pluginDisplay.navigationItems, + navigationItems: notifier.plugin.display.navigationItems, collapasedNotifier: notifier.collapsedNotifier, ); }, @@ -97,7 +97,7 @@ class FlowyNavigation extends StatelessWidget { notifier.value = false; }, iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), - icon: svg("home/hide_menu", color: theme.iconColor), + icon: svgWidget("home/hide_menu", color: theme.iconColor), ), ); } else { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart index 4534053ad8..05456f20f4 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart @@ -1,4 +1,3 @@ -import 'package:app_flowy/startup/tasks/load_plugin.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; @@ -32,37 +31,34 @@ class BlankPagePlugin extends Plugin { }) : _pluginType = pluginType; @override - void dispose() {} + PluginDisplay get display => BlankPagePluginDisplay(); @override - PluginDisplay get pluginDisplay => BlankPagePluginDisplay(); + PluginId get id => "BlankStack"; @override - PluginId get pluginId => "BlankStack"; - - @override - PluginType get pluginType => _pluginType; + PluginType get ty => _pluginType; } -class BlankPagePluginDisplay extends PluginDisplay { +class BlankPagePluginDisplay extends PluginDisplay with NavigationItem { @override Widget get leftBarItem => FlowyText.medium(LocaleKeys.blankPageTitle.tr(), fontSize: 12); @override - Widget buildWidget() => const BlankStackPage(); + Widget buildWidget() => const BlankPage(); @override List get navigationItems => [this]; } -class BlankStackPage extends StatefulWidget { - const BlankStackPage({Key? key}) : super(key: key); +class BlankPage extends StatefulWidget { + const BlankPage({Key? key}) : super(key: key); @override - State createState() => _BlankStackPageState(); + State createState() => _BlankPageState(); } -class _BlankStackPageState extends State { +class _BlankPageState extends State { @override Widget build(BuildContext context) { return SizedBox.expand( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart index 021478866a..b0727bb73a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart @@ -7,21 +7,20 @@ export './src/widget/toolbar/tool_bar.dart'; import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/startup/tasks/load_plugin.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/application/doc/share_bloc.dart'; import 'package:app_flowy/workspace/application/view/view_listener.dart'; -import 'package:app_flowy/workspace/application/view/view_service.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; +import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart'; import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/notifier.dart'; import 'package:flowy_infra/size.dart'; -import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/widget/rounded_button.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder-data-model/share.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-text-block/entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flutter/material.dart'; @@ -47,16 +46,15 @@ class DocumentPluginBuilder extends PluginBuilder { String get menuName => "Doc"; @override - PluginType get pluginType => DefaultPlugin.quillEditor.type(); + PluginType get pluginType => DefaultPlugin.quill.type(); @override - ViewDataType get dataType => ViewDataType.RichText; + ViewDataType get dataType => ViewDataType.TextBlock; } class DocumentPlugin implements Plugin { late View _view; ViewListener? _listener; - final ValueNotifier _displayNotifier = ValueNotifier(0); late PluginType _pluginType; DocumentPlugin({required PluginType pluginType, required View view, Key? key}) : _view = view { @@ -66,7 +64,7 @@ class DocumentPlugin implements Plugin { result.fold( (newView) { _view = newView; - _displayNotifier.value = _view.hashCode; + display.notifier!.value = _view.hashCode; }, (error) {}, ); @@ -81,19 +79,17 @@ class DocumentPlugin implements Plugin { } @override - PluginDisplay get pluginDisplay => DocumentPluginDisplay(view: _view); + PluginDisplay get display => DocumentPluginDisplay(view: _view); @override - PluginType get pluginType => _pluginType; + PluginType get ty => _pluginType; @override - PluginId get pluginId => _view.id; - - @override - ChangeNotifier? get displayNotifier => _displayNotifier; + PluginId get id => _view.id; } -class DocumentPluginDisplay extends PluginDisplay { +class DocumentPluginDisplay extends PluginDisplay with NavigationItem { + final PublishNotifier _displayNotifier = PublishNotifier(); final View _view; DocumentPluginDisplay({required View view, Key? key}) : _view = view; @@ -102,87 +98,16 @@ class DocumentPluginDisplay extends PluginDisplay { Widget buildWidget() => DocumentPage(view: _view, key: ValueKey(_view.id)); @override - Widget get leftBarItem => DocumentLeftBarItem(view: _view); + Widget get leftBarItem => ViewLeftBarItem(view: _view); @override Widget? get rightBarItem => DocumentShareButton(view: _view); @override - List get navigationItems => _makeNavigationItems(); - - List _makeNavigationItems() { - return [ - this, - ]; - } -} - -class DocumentLeftBarItem extends StatefulWidget { - final View view; - - DocumentLeftBarItem({required this.view, Key? key}) : super(key: ValueKey(view.hashCode)); + List get navigationItems => [this]; @override - State createState() => _DocumentLeftBarItemState(); -} - -class _DocumentLeftBarItemState extends State { - final _controller = TextEditingController(); - final _focusNode = FocusNode(); - late ViewService service; - - @override - void initState() { - service = ViewService(/*view: widget.view*/); - _focusNode.addListener(_handleFocusChanged); - super.initState(); - } - - @override - void dispose() { - _controller.dispose(); - _focusNode.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - _controller.text = widget.view.name; - - final theme = context.watch(); - return IntrinsicWidth( - key: ValueKey(_controller.text), - child: TextField( - controller: _controller, - focusNode: _focusNode, - scrollPadding: EdgeInsets.zero, - decoration: const InputDecoration( - contentPadding: EdgeInsets.zero, - border: InputBorder.none, - isDense: true, - ), - style: TextStyle( - color: theme.textColor, - fontSize: 14, - fontWeight: FontWeight.w500, - overflow: TextOverflow.ellipsis, - ), - // cursorColor: widget.cursorColor, - // obscureText: widget.enableObscure, - ), - ); - } - - void _handleFocusChanged() { - if (_controller.text.isEmpty) { - _controller.text = widget.view.name; - return; - } - - if (_controller.text != widget.view.name) { - service.updateView(viewId: widget.view.id, name: _controller.text); - } - } + PublishNotifier? get notifier => _displayNotifier; } class DocumentShareButton extends StatelessWidget { @@ -257,25 +182,20 @@ class DocumentShareButton extends StatelessWidget { context.read().add(const DocShareEvent.shareMarkdown()); break; case ShareAction.copyLink: - showWorkInProgressDialog(context); + FlowyAlertDialog(title: LocaleKeys.shareAction_workInProgress.tr()).show(context); break; } }); }); actionList.show( - context, context, anchorDirection: AnchorDirection.bottomWithCenterAligned, anchorOffset: offset, ); } - - void showWorkInProgressDialog(BuildContext context) { - FlowyAlertDialog(title: LocaleKeys.shareAction_workInProgress.tr()).show(context); - } } -class ShareActions with ActionList implements FlowyOverlayDelegate { +class ShareActions with ActionList, FlowyOverlayDelegate { final Function(dartz.Option) onSelected; final _items = ShareAction.values.map((action) => ShareActionWrapper(action)).toList(); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart index 30b88e652f..5983102047 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart @@ -10,7 +10,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; -import 'package:styled_widget/styled_widget.dart'; import 'styles.dart'; import 'widget/banner.dart'; @@ -62,6 +61,7 @@ class _DocumentPageState extends State { @override Future dispose() async { documentBloc.close(); + _focusNode.dispose(); super.dispose(); } @@ -82,7 +82,7 @@ class _DocumentPageState extends State { _renderToolbar(controller), const VSpace(10), ], - ).padding(horizontal: 40, top: 28), + ), ), ], ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/style_widgets.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/style_widgets.dart index 9d307b3ace..4f09b64053 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/style_widgets.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/style_widgets.dart @@ -51,7 +51,7 @@ class _FlowyEditorCheckboxState extends State { @override Widget build(BuildContext context) { - final icon = isChecked ? svg('editor/editor_check') : svg('editor/editor_uncheck'); + final icon = isChecked ? svgWidget('editor/editor_check') : svgWidget('editor/editor_uncheck'); return Align( alignment: Alignment.centerLeft, child: FlowyIconButton( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/color_picker.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/color_picker.dart index 793399989c..57299bd6cc 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/color_picker.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/color_picker.dart @@ -117,15 +117,6 @@ class _FlowyColorButtonState extends State { } void _showColorPicker() { - // FlowyPoppuWindow.show( - // context, - // size: Size(600, 200), - // child: MaterialPicker( - // pickerColor: const Color(0x00000000), - // onColorChanged: (color) => _changeColor(context, color), - // ), - // ); - final style = widget.controller.getSelectionStyle(); final values = style.values.where((v) => v.key == Attribute.background.key).map((v) => v.value); int initialColor = 0; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/link_button.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/link_button.dart index 3daa9f0679..60b654302f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/link_button.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/link_button.dart @@ -54,11 +54,11 @@ class _FlowyLinkStyleButtonState extends State { final isEnabled = !widget.controller.selection.isCollapsed; final pressedHandler = isEnabled ? () => _openLinkDialog(context) : null; final icon = isEnabled - ? svg( + ? svgWidget( 'editor/share', color: theme.iconColor, ) - : svg( + : svgWidget( 'editor/share', color: theme.disableIconColor, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/toolbar_icon_button.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/toolbar_icon_button.dart index 500f683355..b6dddefbb3 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/toolbar_icon_button.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/widget/toolbar/toolbar_icon_button.dart @@ -29,7 +29,7 @@ class ToolbarIconButton extends StatelessWidget { iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4), onPressed: onPressed, width: width, - icon: isToggled == true ? svg(iconName, color: Colors.white) : svg(iconName), + icon: isToggled == true ? svgWidget(iconName, color: Colors.white) : svgWidget(iconName), fillColor: isToggled == true ? theme.main1 : theme.shader6, hoverColor: isToggled == true ? theme.main1 : theme.shader5, tooltipText: tooltipText, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart new file mode 100644 index 0000000000..adc2a91fa9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart @@ -0,0 +1,66 @@ +import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; +import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:app_flowy/plugin/plugin.dart'; +import 'package:flutter/material.dart'; + +import 'src/grid_page.dart'; + +class GridPluginBuilder implements PluginBuilder { + @override + Plugin build(dynamic data) { + if (data is View) { + return GridPlugin(pluginType: pluginType, view: data); + } else { + throw FlowyPluginException.invalidData; + } + } + + @override + String get menuName => "Grid"; + + @override + PluginType get pluginType => DefaultPlugin.grid.type(); + + @override + ViewDataType get dataType => ViewDataType.Grid; +} + +class GridPluginConfig implements PluginConfig { + @override + bool get creatable => true; +} + +class GridPlugin extends Plugin { + final View _view; + final PluginType _pluginType; + + GridPlugin({ + required View view, + required PluginType pluginType, + }) : _pluginType = pluginType, + _view = view; + + @override + PluginDisplay get display => GridPluginDisplay(view: _view); + + @override + PluginId get id => _view.id; + + @override + PluginType get ty => _pluginType; +} + +class GridPluginDisplay extends PluginDisplay { + final View _view; + GridPluginDisplay({required View view, Key? key}) : _view = view; + + @override + Widget get leftBarItem => ViewLeftBarItem(view: _view); + + @override + Widget buildWidget() => GridPage(view: _view); + + @override + List get navigationItems => [this]; +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/flowy_table_selection.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/flowy_table_selection.dart new file mode 100755 index 0000000000..7f01b7dcf0 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/flowy_table_selection.dart @@ -0,0 +1,73 @@ +/// The data structor representing each selection of flowy table. +enum FlowyTableSelectionType { + item, + row, + col, +} + +class FlowyTableSelectionItem { + final FlowyTableSelectionType type; + final int? row; + final int? column; + + const FlowyTableSelectionItem({ + required this.type, + this.row, + this.column, + }); + + @override + String toString() { + return '$type($row, $column)'; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is FlowyTableSelectionItem && + type == other.type && + row == other.row && + column == other.column; + } + + @override + int get hashCode => type.hashCode ^ row.hashCode ^ column.hashCode; +} + +class FlowyTableSelection { + Set _items = {}; + + Set get items => _items; + + FlowyTableSelection( + this._items, + ); + + FlowyTableSelection.combine( + FlowyTableSelection lhs, FlowyTableSelection rhs) { + this..combine(lhs)..combine(rhs); + } + + FlowyTableSelection operator +(FlowyTableSelection other) { + return this..combine(other); + } + + void combine(FlowyTableSelection other) { + var totalItems = items..union(other.items); + final rows = totalItems + .where((ele) => ele.type == FlowyTableSelectionType.row) + .map((e) => e.row) + .toSet(); + final cols = totalItems + .where((ele) => ele.type == FlowyTableSelectionType.col) + .map((e) => e.column) + .toSet(); + totalItems.removeWhere((ele) { + return ele.type == FlowyTableSelectionType.item && + (rows.contains(ele.row) || cols.contains(ele.column)); + }); + _items = totalItems; + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart new file mode 100755 index 0000000000..dddd93d175 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:linked_scroll_controller/linked_scroll_controller.dart'; + +class GridScrollController { + final LinkedScrollControllerGroup _scrollGroupContorller; + final ScrollController verticalController; + final ScrollController horizontalController; + + final List _linkHorizontalControllers = []; + + GridScrollController({required LinkedScrollControllerGroup scrollGroupContorller}) + : _scrollGroupContorller = scrollGroupContorller, + verticalController = ScrollController(), + horizontalController = scrollGroupContorller.addAndGet(); + + ScrollController linkHorizontalController() { + final controller = _scrollGroupContorller.addAndGet(); + _linkHorizontalControllers.add(controller); + return controller; + } + + void dispose() { + for (final controller in _linkHorizontalControllers) { + controller.dispose(); + } + verticalController.dispose(); + horizontalController.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart new file mode 100755 index 0000000000..6e01d56b66 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -0,0 +1,264 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart'; +import 'package:flowy_infra_ui/widget/error_page.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:linked_scroll_controller/linked_scroll_controller.dart'; +import 'controller/grid_scroll.dart'; +import 'layout/layout.dart'; +import 'layout/sizes.dart'; +import 'widgets/row/grid_row.dart'; +import 'widgets/footer/grid_footer.dart'; +import 'widgets/header/grid_header.dart'; +import 'widgets/toolbar/grid_toolbar.dart'; + +class GridPage extends StatefulWidget { + final View view; + + GridPage({Key? key, required this.view}) : super(key: ValueKey(view.id)); + + @override + State createState() => _GridPageState(); +} + +class _GridPageState extends State { + @override + Widget build(BuildContext context) { + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => getIt(param1: widget.view)..add(const GridEvent.initial()), + ), + ], + child: BlocBuilder( + builder: (context, state) { + return state.loadingState.map( + loading: (_) => const Center(child: CircularProgressIndicator.adaptive()), + finish: (result) => result.successOrFail.fold( + (_) => const FlowyGrid(), + (err) => FlowyErrorPage(err.toString()), + ), + ); + }, + ), + ); + } + + @override + void dispose() { + super.dispose(); + } + + @override + void deactivate() { + super.deactivate(); + } + + @override + void didUpdateWidget(covariant GridPage oldWidget) { + super.didUpdateWidget(oldWidget); + } +} + +class FlowyGrid extends StatefulWidget { + const FlowyGrid({Key? key}) : super(key: key); + + @override + State createState() => _FlowyGridState(); +} + +class _FlowyGridState extends State { + final _scrollController = GridScrollController(scrollGroupContorller: LinkedScrollControllerGroup()); + late ScrollController headerScrollController; + + @override + void initState() { + headerScrollController = _scrollController.linkHorizontalController(); + super.initState(); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.fields.length != current.fields.length, + builder: (context, state) { + final contentWidth = GridLayout.headerWidth(state.fields); + final child = _wrapScrollView( + contentWidth, + [ + const _GridRows(), + const _GridFooter(), + ], + ); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const _GridToolbarAdaptor(), + _gridHeader(context, state.gridId), + Flexible(child: child), + ], + ); + }, + ); + } + + Widget _wrapScrollView( + double contentWidth, + List slivers, + ) { + final verticalScrollView = ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(scrollbars: false), + child: CustomScrollView( + physics: StyledScrollPhysics(), + controller: _scrollController.verticalController, + slivers: slivers, + ), + ); + + final sizedVerticalScrollView = SizedBox( + width: contentWidth, + child: verticalScrollView, + ); + + final horizontalScrollView = StyledSingleChildScrollView( + controller: _scrollController.horizontalController, + axis: Axis.horizontal, + child: sizedVerticalScrollView, + ); + + return ScrollbarListStack( + axis: Axis.vertical, + controller: _scrollController.verticalController, + barSize: GridSize.scrollBarSize, + child: horizontalScrollView, + ); + } + + Widget _gridHeader(BuildContext context, String gridId) { + final fieldCache = context.read().fieldCache; + return GridHeaderSliverAdaptor( + gridId: gridId, + fieldCache: fieldCache, + anchorScrollController: headerScrollController, + ); + } +} + +class _GridToolbarAdaptor extends StatelessWidget { + const _GridToolbarAdaptor({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocSelector( + selector: (state) { + final fieldCache = context.read().fieldCache; + return GridToolbarContext( + gridId: state.gridId, + fieldCache: fieldCache, + ); + }, + builder: (context, toolbarContext) { + return GridToolbar(toolbarContext: toolbarContext); + }, + ); + } +} + +class _GridRows extends StatefulWidget { + const _GridRows({Key? key}) : super(key: key); + + @override + State<_GridRows> createState() => _GridRowsState(); +} + +class _GridRowsState extends State<_GridRows> { + final _key = GlobalKey(); + + @override + Widget build(BuildContext context) { + return BlocConsumer( + listenWhen: (previous, current) => previous.listState != current.listState, + listener: (context, state) { + state.listState.mapOrNull( + insert: (value) { + for (final item in value.items) { + _key.currentState?.insertItem(item.index); + } + }, + delete: (value) { + for (final item in value.items) { + _key.currentState?.removeItem( + item.index, + (context, animation) => _renderRow(context, item.row, animation), + ); + } + }, + ); + }, + buildWhen: (previous, current) => false, + builder: (context, state) { + return SliverAnimatedList( + key: _key, + initialItemCount: context.read().state.rows.length, + itemBuilder: (BuildContext context, int index, Animation animation) { + final rowData = context.read().state.rows[index]; + return _renderRow(context, rowData, animation); + }, + ); + }, + ); + } + + Widget _renderRow( + BuildContext context, + GridRow rowData, + Animation animation, + ) { + final rowCache = context.read().rowCache; + return SizeTransition( + sizeFactor: animation, + child: GridRowWidget( + rowData: rowData, + rowCache: rowCache, + key: ValueKey(rowData.rowId), + ), + ); + } +} + +class _GridFooter extends StatelessWidget { + const _GridFooter({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverPadding( + padding: const EdgeInsets.only(bottom: 200), + sliver: SliverToBoxAdapter( + child: SizedBox( + height: GridSize.footerHeight, + child: Padding( + padding: GridSize.headerContentInsets, + child: Row( + children: [ + SizedBox(width: GridSize.leadingHeaderPadding), + const SizedBox(width: 120, child: GridAddRowButton()), + ], + ), + ), + ), + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart new file mode 100755 index 0000000000..3f076fc89f --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart @@ -0,0 +1,13 @@ +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; + +import 'sizes.dart'; + +class GridLayout { + static double headerWidth(List fields) { + if (fields.isEmpty) return 0; + + final fieldsWidth = fields.map((field) => field.width.toDouble()).reduce((value, element) => value + element); + + return fieldsWidth + GridSize.leadingHeaderPadding + GridSize.trailHeaderPadding; + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart new file mode 100755 index 0000000000..8dc0b20263 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart @@ -0,0 +1,43 @@ +import 'package:flutter/widgets.dart'; + +class GridSize { + static double scale = 1; + + static double get scrollBarSize => 12 * scale; + static double get headerHeight => 40 * scale; + static double get footerHeight => 40 * scale; + static double get leadingHeaderPadding => 50 * scale; + static double get trailHeaderPadding => 140 * scale; + static double get headerContainerPadding => 0 * scale; + static double get cellHPadding => 10 * scale; + static double get cellVPadding => 8 * scale; + static double get typeOptionItemHeight => 32 * scale; + static double get typeOptionSeparatorHeight => 6 * scale; + + // + static EdgeInsets get headerContentInsets => EdgeInsets.symmetric( + horizontal: GridSize.headerContainerPadding, + vertical: GridSize.headerContainerPadding, + ); + static EdgeInsets get cellContentInsets => EdgeInsets.symmetric( + horizontal: GridSize.cellHPadding, + vertical: GridSize.cellVPadding, + ); + + static EdgeInsets get fieldContentInsets => EdgeInsets.symmetric( + horizontal: GridSize.cellHPadding, + vertical: GridSize.cellVPadding, + ); + + static EdgeInsets get typeOptionContentInsets => const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ); + + static EdgeInsets get footerContentInsets => EdgeInsets.fromLTRB( + 0, + GridSize.headerContainerPadding, + GridSize.headerContainerPadding, + GridSize.headerContainerPadding, + ); +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart new file mode 100755 index 0000000000..015fea1c32 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -0,0 +1,46 @@ +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; +import 'package:flutter/widgets.dart'; +import 'checkbox_cell.dart'; +import 'date_cell.dart'; +import 'number_cell.dart'; +import 'selection_cell/selection_cell.dart'; +import 'text_cell.dart'; + +GridCellWidget buildGridCell(GridCell cellData, {GridCellStyle? style}) { + final key = ValueKey(cellData.field.id + cellData.rowId); + switch (cellData.field.fieldType) { + case FieldType.Checkbox: + return CheckboxCell(cellData: cellData, key: key); + case FieldType.DateTime: + return DateCell(cellData: cellData, key: key); + case FieldType.MultiSelect: + return MultiSelectCell(cellData: cellData, key: key); + case FieldType.Number: + return NumberCell(cellData: cellData, key: key); + case FieldType.RichText: + return GridTextCell(cellData: cellData, key: key, style: style); + case FieldType.SingleSelect: + return SingleSelectCell(cellData: cellData, key: key); + default: + throw UnimplementedError; + } +} + +class BlankCell extends StatelessWidget { + const BlankCell({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container(); + } +} + +abstract class GridCellWidget extends HoverWidget { + @override + final ValueNotifier onFocus = ValueNotifier(false); + GridCellWidget({Key? key}) : super(key: key); +} + +abstract class GridCellStyle {} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart new file mode 100755 index 0000000000..17c1e87710 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart @@ -0,0 +1,107 @@ +import 'package:flowy_infra/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'cell_builder.dart'; + +class CellStateNotifier extends ChangeNotifier { + bool _isFocus = false; + bool _onEnter = false; + + set isFocus(bool value) { + if (_isFocus != value) { + _isFocus = value; + notifyListeners(); + } + } + + set onEnter(bool value) { + if (_onEnter != value) { + _onEnter = value; + notifyListeners(); + } + } + + bool get isFocus => _isFocus; + + bool get onEnter => _onEnter; +} + +class CellContainer extends StatelessWidget { + final GridCellWidget child; + final Widget? expander; + final double width; + const CellContainer({ + Key? key, + required this.child, + required this.width, + this.expander, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider( + create: (_) => CellStateNotifier(), + child: Selector( + selector: (context, notifier) => notifier.isFocus, + builder: (context, isFocus, _) { + Widget container = Center(child: child); + child.onFocus.addListener(() { + Provider.of(context, listen: false).isFocus = child.onFocus.value; + }); + + if (expander != null) { + container = _CellEnterRegion(child: container, expander: expander!); + } + + return Container( + constraints: BoxConstraints(maxWidth: width), + decoration: _makeBoxDecoration(context, isFocus), + padding: GridSize.cellContentInsets, + child: container, + ); + }, + ), + ); + } + + BoxDecoration _makeBoxDecoration(BuildContext context, bool isFocus) { + final theme = context.watch(); + if (isFocus) { + final borderSide = BorderSide(color: theme.main1, width: 1.0); + return BoxDecoration(border: Border.fromBorderSide(borderSide)); + } else { + final borderSide = BorderSide(color: theme.shader4, width: 0.4); + return BoxDecoration(border: Border(right: borderSide, bottom: borderSide)); + } + } +} + +class _CellEnterRegion extends StatelessWidget { + final Widget child; + final Widget expander; + const _CellEnterRegion({required this.child, required this.expander, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (context, notifier) => notifier.onEnter, + builder: (context, onEnter, _) { + List children = [Expanded(child: child)]; + if (onEnter) { + children.add(expander); + } + + return MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (p) => Provider.of(context, listen: false).onEnter = true, + onExit: (p) => Provider.of(context, listen: false).onEnter = false, + child: Row( + // alignment: AlignmentDirectional.centerEnd, + children: children, + ), + ); + }, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_decoration.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_decoration.dart new file mode 100755 index 0000000000..0e74073e14 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_decoration.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class CellDecoration { + static BoxDecoration box({required Color color}) { + return BoxDecoration( + border: Border.all(color: Colors.black26, width: 0.2), + color: color, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart new file mode 100644 index 0000000000..608913d41d --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart @@ -0,0 +1,56 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'cell_builder.dart'; + +class CheckboxCell extends GridCellWidget { + final GridCell cellData; + + CheckboxCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _CheckboxCellState(); +} + +class _CheckboxCellState extends State { + late CheckboxCellBloc _cellBloc; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData)..add(const CheckboxCellEvent.initial()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + final icon = state.isSelected ? svgWidget('editor/editor_check') : svgWidget('editor/editor_uncheck'); + return Align( + alignment: Alignment.centerLeft, + child: FlowyIconButton( + onPressed: () => context.read().add(const CheckboxCellEvent.select()), + iconPadding: EdgeInsets.zero, + icon: icon, + width: 23, + ), + ); + }, + ), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart new file mode 100644 index 0000000000..84d60c797a --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart @@ -0,0 +1,201 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'cell_builder.dart'; + +abstract class GridCellDelegate { + void onFocus(bool isFocus); + GridCellDelegate get delegate; +} + +class DateCell extends GridCellWidget { + final GridCell cellData; + + DateCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _DateCellState(); +} + +class _DateCellState extends State { + late DateCellBloc _cellBloc; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData)..add(const DateCellEvent.initial()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + return SizedBox.expand( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + widget.onFocus.value = true; + _CellCalendar.show( + context, + onSelected: (day) { + context.read().add(DateCellEvent.selectDay(day)); + }, + onDismissed: () => widget.onFocus.value = false, + ); + }, + child: MouseRegion( + opaque: false, + cursor: SystemMouseCursors.click, + child: Center(child: FlowyText.medium(state.content, fontSize: 12)), + ), + ), + ); + }, + ), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} + +final kToday = DateTime.now(); +final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); +final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); + +class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate { + final void Function(DateTime) onSelected; + final VoidCallback onDismissed; + final bool includeTime; + const _CellCalendar({ + required this.onSelected, + required this.onDismissed, + required this.includeTime, + Key? key, + }) : super(key: key); + + @override + State<_CellCalendar> createState() => _CellCalendarState(); + + static Future show( + BuildContext context, { + required void Function(DateTime) onSelected, + required VoidCallback onDismissed, + }) async { + _CellCalendar.remove(context); + + final calendar = _CellCalendar( + onSelected: onSelected, + onDismissed: onDismissed, + includeTime: false, + ); + // const size = Size(460, 400); + // final window = await getWindowInfo(); + // FlowyOverlay.of(context).insertWithRect( + // widget: OverlayContainer( + // child: calendar, + // constraints: BoxConstraints.loose(const Size(460, 400)), + // ), + // identifier: _CellCalendar.identifier(), + // anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), + // anchorSize: window.frame.size, + // anchorDirection: AnchorDirection.center, + // style: FlowyOverlayStyle(blur: false), + // delegate: calendar, + // ); + + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: calendar, + constraints: BoxConstraints.tight(const Size(320, 320)), + ), + identifier: _CellCalendar.identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.leftWithCenterAligned, + style: FlowyOverlayStyle(blur: false), + delegate: calendar, + ); + } + + static void remove(BuildContext context) { + FlowyOverlay.of(context).remove(identifier()); + } + + static String identifier() { + return (_CellCalendar).toString(); + } + + @override + void didRemove() => onDismissed(); +} + +class _CellCalendarState extends State<_CellCalendar> { + CalendarFormat _calendarFormat = CalendarFormat.month; + DateTime _focusedDay = DateTime.now(); + DateTime? _selectedDay; + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: _focusedDay, + rowHeight: 40, + calendarFormat: _calendarFormat, + headerStyle: const HeaderStyle(formatButtonVisible: false), + calendarStyle: CalendarStyle( + selectedDecoration: BoxDecoration( + color: theme.main1, + shape: BoxShape.circle, + ), + todayDecoration: BoxDecoration( + color: theme.shader4, + shape: BoxShape.circle, + ), + selectedTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + todayTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + ), + selectedDayPredicate: (day) { + return isSameDay(_selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + if (!isSameDay(_selectedDay, selectedDay)) { + // Call `setState()` when updating the selected day + setState(() { + _selectedDay = selectedDay; + _focusedDay = focusedDay; + widget.onSelected(selectedDay); + }); + } + }, + onFormatChanged: (format) { + setState(() { + _calendarFormat = format; + }); + }, + onPageChanged: (focusedDay) { + _focusedDay = focusedDay; + }, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart new file mode 100644 index 0000000000..2d98aa0bd6 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart @@ -0,0 +1,91 @@ +import 'dart:async'; + +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'cell_builder.dart'; + +class NumberCell extends GridCellWidget { + final GridCell cellData; + + NumberCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _NumberCellState(); +} + +class _NumberCellState extends State { + late NumberCellBloc _cellBloc; + late TextEditingController _controller; + late FocusNode _focusNode; + Timer? _delayOperation; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData)..add(const NumberCellEvent.initial()); + _controller = TextEditingController(text: _cellBloc.state.content); + _focusNode = FocusNode(); + _focusNode.addListener(() { + widget.onFocus.value = _focusNode.hasFocus; + focusChanged(); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocConsumer( + listener: (context, state) { + if (_controller.text != state.content) { + _controller.text = state.content; + } + }, + builder: (context, state) { + return TextField( + controller: _controller, + focusNode: _focusNode, + onEditingComplete: () => _focusNode.unfocus(), + maxLines: 1, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + decoration: const InputDecoration( + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + isDense: true, + ), + ); + }, + ), + ); + } + + @override + Future dispose() async { + _delayOperation?.cancel(); + _cellBloc.close(); + _focusNode.dispose(); + super.dispose(); + } + + Future focusChanged() async { + if (mounted) { + _delayOperation?.cancel(); + _delayOperation = Timer(const Duration(milliseconds: 300), () { + if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) { + final number = num.tryParse(_controller.text); + if (number != null) { + _cellBloc.add(NumberCellEvent.updateCell(_controller.text)); + } else { + _controller.text = ""; + } + } + }); + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart new file mode 100644 index 0000000000..7fc3b3246f --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart @@ -0,0 +1,7 @@ +export 'cell_builder.dart'; +export 'cell_container.dart'; +export 'text_cell.dart'; +export 'number_cell.dart'; +export 'date_cell.dart'; +export 'checkbox_cell.dart'; +export 'selection_cell/selection_cell.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart new file mode 100644 index 0000000000..bdf4d01158 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart @@ -0,0 +1,80 @@ +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +extension SelectOptionColorExtension on SelectOptionColor { + Color make(BuildContext context) { + final theme = context.watch(); + switch (this) { + case SelectOptionColor.Purple: + return theme.tint1; + case SelectOptionColor.Pink: + return theme.tint2; + case SelectOptionColor.LightPink: + return theme.tint3; + case SelectOptionColor.Orange: + return theme.tint4; + case SelectOptionColor.Yellow: + return theme.tint5; + case SelectOptionColor.Lime: + return theme.tint6; + case SelectOptionColor.Green: + return theme.tint7; + case SelectOptionColor.Aqua: + return theme.tint8; + case SelectOptionColor.Blue: + return theme.tint9; + default: + throw ArgumentError; + } + } + + String optionName() { + switch (this) { + case SelectOptionColor.Purple: + return LocaleKeys.grid_selectOption_purpleColor.tr(); + case SelectOptionColor.Pink: + return LocaleKeys.grid_selectOption_pinkColor.tr(); + case SelectOptionColor.LightPink: + return LocaleKeys.grid_selectOption_lightPinkColor.tr(); + case SelectOptionColor.Orange: + return LocaleKeys.grid_selectOption_orangeColor.tr(); + case SelectOptionColor.Yellow: + return LocaleKeys.grid_selectOption_yellowColor.tr(); + case SelectOptionColor.Lime: + return LocaleKeys.grid_selectOption_limeColor.tr(); + case SelectOptionColor.Green: + return LocaleKeys.grid_selectOption_greenColor.tr(); + case SelectOptionColor.Aqua: + return LocaleKeys.grid_selectOption_aquaColor.tr(); + case SelectOptionColor.Blue: + return LocaleKeys.grid_selectOption_blueColor.tr(); + default: + throw ArgumentError; + } + } +} + +class SelectOptionTag extends StatelessWidget { + final SelectOption option; + final bool isSelected; + const SelectOptionTag({required this.option, this.isSelected = false, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: option.color.make(context), + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8.0), + ), + child: Center(child: FlowyText.medium(option.name, fontSize: 12)), + margin: const EdgeInsets.symmetric(horizontal: 3.0), + padding: const EdgeInsets.symmetric(horizontal: 6.0), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart new file mode 100644 index 0000000000..05dd66e224 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -0,0 +1,119 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'extension.dart'; +import 'selection_editor.dart'; + +class SingleSelectCell extends GridCellWidget { + final GridCell cellData; + + SingleSelectCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _SingleSelectCellState(); +} + +class _SingleSelectCellState extends State { + late SelectionCellBloc _cellBloc; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData)..add(const SelectionCellEvent.initial()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + return SizedBox.expand( + child: InkWell( + onTap: () { + widget.onFocus.value = true; + SelectOptionCellEditor.show( + context, + state.cellData, + state.options, + state.selectedOptions, + () => widget.onFocus.value = false, + ); + }, + child: ClipRRect(child: Row(children: children)), + ), + ); + }, + ), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} + +//---------------------------------------------------------------- +class MultiSelectCell extends GridCellWidget { + final GridCell cellData; + + MultiSelectCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _MultiSelectCellState(); +} + +class _MultiSelectCellState extends State { + late SelectionCellBloc _cellBloc; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData)..add(const SelectionCellEvent.initial()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + return SizedBox.expand( + child: InkWell( + onTap: () { + widget.onFocus.value = true; + SelectOptionCellEditor.show( + context, + state.cellData, + state.options, + state.selectedOptions, + () => widget.onFocus.value = false, + ); + }, + child: ClipRRect(child: Row(children: children)), + ), + ); + }, + ), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart new file mode 100644 index 0000000000..d3fcd9efcf --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart @@ -0,0 +1,257 @@ +import 'dart:collection'; +import 'package:app_flowy/workspace/application/grid/cell/selection_editor_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:textfield_tags/textfield_tags.dart'; + +import 'extension.dart'; +import 'text_field.dart'; + +const double _editorPannelWidth = 300; + +class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { + final GridCell cellData; + final List options; + final List selectedOptions; + final VoidCallback onDismissed; + + const SelectOptionCellEditor({ + required this.cellData, + required this.options, + required this.selectedOptions, + required this.onDismissed, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => SelectOptionEditorBloc( + cellData: cellData, + options: options, + selectedOptions: selectedOptions, + )..add(const SelectOptionEditorEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + return CustomScrollView( + shrinkWrap: true, + slivers: [ + SliverToBoxAdapter(child: _TextField()), + const SliverToBoxAdapter(child: VSpace(6)), + const SliverToBoxAdapter(child: TypeOptionSeparator()), + const SliverToBoxAdapter(child: VSpace(6)), + const SliverToBoxAdapter(child: _Title()), + const SliverToBoxAdapter(child: _OptionList()), + ], + ); + }, + ), + ); + } + + static void show( + BuildContext context, + GridCell cellData, + List options, + List selectedOptions, + VoidCallback onDismissed, + ) { + SelectOptionCellEditor.remove(context); + final editor = SelectOptionCellEditor( + cellData: cellData, + options: options, + selectedOptions: selectedOptions, + onDismissed: onDismissed, + ); + + // + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: SizedBox(width: _editorPannelWidth, child: editor), + constraints: BoxConstraints.loose(const Size(_editorPannelWidth, 300)), + ), + identifier: SelectOptionCellEditor.identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.bottomWithCenterAligned, + delegate: editor, + ); + } + + static void remove(BuildContext context) { + FlowyOverlay.of(context).remove(identifier()); + } + + static String identifier() { + return (SelectOptionCellEditor).toString(); + } + + @override + bool asBarrier() => true; + + @override + void didRemove() => onDismissed(); +} + +class _OptionList extends StatelessWidget { + const _OptionList({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final cells = state.options.map((option) { + return _SelectOptionCell(option, state.selectedOptions.contains(option)); + }).toList(); + final list = ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + itemCount: cells.length, + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + physics: StyledScrollPhysics(), + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ); + return list; + }, + ); + } +} + +class _TextField extends StatelessWidget { + final TextfieldTagsController _tagController = TextfieldTagsController(); + + _TextField({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final optionMap = LinkedHashMap.fromIterable(state.selectedOptions, + key: (option) => option.name, value: (option) => option); + + return SizedBox( + height: 42, + child: SelectOptionTextField( + options: state.options, + selectedOptionMap: optionMap, + distanceToText: _editorPannelWidth * 0.7, + tagController: _tagController, + onNewTag: (tagName) { + context.read().add(SelectOptionEditorEvent.newOption(tagName)); + }, + ), + ); + }, + ); + } +} + +class _Title extends StatelessWidget { + const _Title({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: FlowyText.medium( + LocaleKeys.grid_selectOption_pannelTitle.tr(), + fontSize: 12, + color: theme.shader3, + ), + ), + ); + } +} + +class _SelectOptionCell extends StatelessWidget { + final SelectOption option; + final bool isSelected; + const _SelectOptionCell(this.option, this.isSelected, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: InkWell( + onTap: () { + context.read().add(SelectOptionEditorEvent.selectOption(option.id)); + }, + child: FlowyHover( + style: HoverStyle(hoverColor: theme.hover), + builder: (_, onHover) { + List children = [ + SelectOptionTag(option: option, isSelected: isSelected), + const Spacer(), + ]; + + if (isSelected) { + children.add(svgWidget("grid/checkmark")); + } + + if (onHover) { + children.add(FlowyIconButton( + width: 30, + onPressed: () => _showEditPannel(context), + iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4), + icon: svgWidget("editor/details", color: theme.iconColor), + )); + } + + return Padding( + padding: const EdgeInsets.all(3.0), + child: Row(children: children), + ); + }, + ), + ), + ); + } + + void _showEditPannel(BuildContext context) { + final pannel = EditSelectOptionPannel( + option: option, + onDeleted: () { + context.read().add(SelectOptionEditorEvent.deleteOption(option)); + }, + onUpdated: (updatedOption) { + context.read().add(SelectOptionEditorEvent.updateOption(updatedOption)); + }, + key: ValueKey(option.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value. + ); + final overlayIdentifier = (EditSelectOptionPannel).toString(); + + FlowyOverlay.of(context).remove(overlayIdentifier); + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: pannel, + constraints: BoxConstraints.loose(const Size(200, 300)), + ), + identifier: overlayIdentifier, + anchorContext: context, + anchorDirection: AnchorDirection.rightWithCenterAligned, + anchorOffset: Offset(2 * overlayContainerPadding.left, 0), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/text_field.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/text_field.dart new file mode 100644 index 0000000000..e7f4e98851 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/text_field.dart @@ -0,0 +1,101 @@ +import 'dart:collection'; + +import 'package:flowy_infra/size.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:textfield_tags/textfield_tags.dart'; + +import 'extension.dart'; + +class SelectOptionTextField extends StatelessWidget { + final FocusNode _focusNode; + final TextEditingController _controller; + final TextfieldTagsController tagController; + final List options; + final LinkedHashMap selectedOptionMap; + + final double distanceToText; + + final Function(String) onNewTag; + + SelectOptionTextField({ + required this.options, + required this.selectedOptionMap, + required this.distanceToText, + required this.tagController, + required this.onNewTag, + TextEditingController? controller, + FocusNode? focusNode, + Key? key, + }) : _controller = controller ?? TextEditingController(), + _focusNode = focusNode ?? FocusNode(), + super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return TextFieldTags( + textEditingController: _controller, + textfieldTagsController: tagController, + initialTags: selectedOptionMap.keys.toList(), + focusNode: _focusNode, + textSeparators: const [' ', ','], + inputfieldBuilder: (BuildContext context, editController, focusNode, error, onChanged, onSubmitted) { + return ((context, sc, tags, onTagDelegate) { + return TextField( + autofocus: true, + controller: editController, + focusNode: focusNode, + onChanged: onChanged, + onSubmitted: (text) { + if (onSubmitted != null) { + onSubmitted(text); + } + + if (text.isNotEmpty) { + onNewTag(text); + } + }, + maxLines: 1, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: theme.main1, width: 1.0), + borderRadius: Corners.s10Border, + ), + isDense: true, + prefixIcon: _renderTags(sc), + hintText: LocaleKeys.grid_selectOption_searchOption.tr(), + prefixIconConstraints: BoxConstraints(maxWidth: distanceToText), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: theme.main1, width: 1.0), + borderRadius: Corners.s10Border, + ), + ), + ); + }); + }, + ); + } + + Widget? _renderTags(ScrollController sc) { + if (selectedOptionMap.isEmpty) { + return null; + } + + final children = selectedOptionMap.values.map((option) => SelectOptionTag(option: option)).toList(); + return Padding( + padding: const EdgeInsets.all(8.0), + child: SingleChildScrollView( + controller: sc, + scrollDirection: Axis.horizontal, + child: Row(children: children), + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart new file mode 100644 index 0000000000..4c9c07697e --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart @@ -0,0 +1,104 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'cell_builder.dart'; + +class GridTextCellStyle extends GridCellStyle { + String? placeholder; + + GridTextCellStyle({ + this.placeholder, + }); +} + +class GridTextCell extends GridCellWidget { + final GridCell cellData; + late final GridTextCellStyle? cellStyle; + GridTextCell({ + required this.cellData, + GridCellStyle? style, + Key? key, + }) : super(key: key) { + if (style != null) { + cellStyle = (style as GridTextCellStyle); + } else { + cellStyle = null; + } + } + + @override + State createState() => _GridTextCellState(); +} + +class _GridTextCellState extends State { + late TextCellBloc _cellBloc; + late TextEditingController _controller; + late FocusNode _focusNode; + + Timer? _delayOperation; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData); + _cellBloc.add(const TextCellEvent.initial()); + _controller = TextEditingController(text: _cellBloc.state.content); + _focusNode = FocusNode(); + _focusNode.addListener(() { + widget.onFocus.value = _focusNode.hasFocus; + focusChanged(); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocConsumer( + listener: (context, state) { + if (_controller.text != state.content) { + _controller.text = state.content; + } + }, + buildWhen: (previous, current) => previous.content != current.content, + builder: (context, state) { + return TextField( + controller: _controller, + focusNode: _focusNode, + onChanged: (value) => focusChanged(), + onEditingComplete: () => _focusNode.unfocus(), + maxLines: 1, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + decoration: InputDecoration( + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + hintText: widget.cellStyle?.placeholder, + isDense: true, + ), + ); + }, + ), + ); + } + + @override + Future dispose() async { + _delayOperation?.cancel(); + _cellBloc.close(); + _focusNode.dispose(); + super.dispose(); + } + + Future focusChanged() async { + if (mounted) { + _delayOperation?.cancel(); + _delayOperation = Timer(const Duration(milliseconds: 300), () { + if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) { + _cellBloc.add(TextCellEvent.updateText(_controller.text)); + } + }); + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart new file mode 100755 index 0000000000..6ed8700cfc --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart @@ -0,0 +1,22 @@ +import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class GridAddRowButton extends StatelessWidget { + const GridAddRowButton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyButton( + text: const FlowyText.medium('New row', fontSize: 12), + hoverColor: theme.hover, + onTap: () => context.read().add(const GridEvent.createRow()), + leftIcon: svgWidget("home/add"), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/constants.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/constants.dart new file mode 100755 index 0000000000..0a02de5076 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/constants.dart @@ -0,0 +1,5 @@ +import 'package:flutter/material.dart'; + +class GridHeaderConstants { + static Color get backgroundColor => Colors.grey; +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart new file mode 100755 index 0000000000..aa45487fe2 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -0,0 +1,156 @@ +import 'package:app_flowy/workspace/application/grid/field/field_cell_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'field_type_extension.dart'; + +import 'field_cell_action_sheet.dart'; +import 'field_editor.dart'; + +class GridFieldCell extends StatelessWidget { + final GridFieldCellContext cellContext; + const GridFieldCell(this.cellContext, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => FieldCellBloc(cellContext: cellContext)..add(const FieldCellEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + final button = FieldCellButton( + field: state.field, + onTap: () => _showActionSheet(context), + ); + + const line = Positioned( + top: 0, + bottom: 0, + right: 0, + child: _DragToExpandLine(), + ); + + return _CellContainer( + width: state.field.width.toDouble(), + child: Stack( + alignment: Alignment.centerRight, + fit: StackFit.expand, + children: [button, line], + ), + ); + }, + ), + ); + } + + void _showActionSheet(BuildContext context) { + final state = context.read().state; + GridFieldCellActionSheet( + cellContext: GridFieldCellContext(gridId: state.gridId, field: state.field), + onEdited: () => _showFieldEditor(context), + ).show(context); + } + + void _showFieldEditor(BuildContext context) { + final state = context.read().state; + + FieldEditor( + gridId: state.gridId, + fieldContextLoader: FieldContextLoaderAdaptor( + gridId: state.gridId, + field: state.field, + ), + ).show(context); + } +} + +class _CellContainer extends StatelessWidget { + final Widget child; + final double width; + const _CellContainer({ + required this.child, + required this.width, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final borderSide = BorderSide(color: theme.shader4, width: 0.4); + final decoration = BoxDecoration( + border: Border( + top: borderSide, + right: borderSide, + bottom: borderSide, + )); + + return Container( + width: width, + decoration: decoration, + child: ConstrainedBox(constraints: const BoxConstraints.expand(), child: child), + ); + } +} + +class _DragToExpandLine extends StatelessWidget { + const _DragToExpandLine({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return InkWell( + onTap: () {}, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onHorizontalDragCancel: () {}, + onHorizontalDragUpdate: (value) { + // context.read().add(FieldCellEvent.updateWidth(value.delta.dx)); + Log.info(value); + }, + onHorizontalDragEnd: (end) { + Log.info(end); + }, + child: FlowyHover( + style: HoverStyle( + hoverColor: theme.main1, + borderRadius: BorderRadius.zero, + contentMargin: const EdgeInsets.only(left: 5), + ), + child: const SizedBox(width: 2), + ), + ), + ); + } +} + +class FieldCellButton extends StatelessWidget { + final VoidCallback onTap; + final Field field; + const FieldCellButton({ + required this.field, + required this.onTap, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyButton( + hoverColor: theme.shader6, + onTap: onTap, + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + text: FlowyText.medium(field.name, fontSize: 12), + padding: GridSize.cellContentInsets, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart new file mode 100644 index 0000000000..3e7f0c9271 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart @@ -0,0 +1,201 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; + +class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate { + final GridFieldCellContext cellContext; + final VoidCallback onEdited; + const GridFieldCellActionSheet({required this.cellContext, required this.onEdited, Key? key}) : super(key: key); + + void show(BuildContext overlayContext) { + FlowyOverlay.of(overlayContext).insertWithAnchor( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.loose(const Size(240, 200)), + ), + identifier: GridFieldCellActionSheet.identifier(), + anchorContext: overlayContext, + anchorDirection: AnchorDirection.bottomWithLeftAligned, + delegate: this, + ); + } + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: cellContext), + child: SingleChildScrollView( + child: Column( + children: [ + _EditFieldButton( + onEdited: () { + FlowyOverlay.of(context).remove(identifier()); + onEdited(); + }, + ), + const VSpace(6), + _FieldOperationList(cellContext, () => FlowyOverlay.of(context).remove(identifier())), + ], + ), + ), + ); + } + + static String identifier() { + return (GridFieldCellActionSheet).toString(); + } + + @override + bool asBarrier() { + return true; + } +} + +class _EditFieldButton extends StatelessWidget { + final Function() onEdited; + const _EditFieldButton({required this.onEdited, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocBuilder( + builder: (context, state) { + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), + hoverColor: theme.hover, + onTap: onEdited, + ), + ); + }, + ); + } +} + +class _FieldOperationList extends StatelessWidget { + final GridFieldCellContext fieldData; + final VoidCallback onDismissed; + const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GridView( + // https://api.flutter.dev/flutter/widgets/AnimatedList/shrinkWrap.html + shrinkWrap: true, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 4.0, + mainAxisSpacing: 8, + ), + children: buildCells(), + ); + } + + List buildCells() { + return FieldAction.values.map( + (action) { + bool enable = true; + switch (action) { + case FieldAction.delete: + enable = !fieldData.field.isPrimary; + break; + default: + break; + } + + return FieldActionCell( + fieldId: fieldData.field.id, + action: action, + onTap: onDismissed, + enable: enable, + ); + }, + ).toList(); + } +} + +class FieldActionCell extends StatelessWidget { + final String fieldId; + final VoidCallback onTap; + final FieldAction action; + final bool enable; + + const FieldActionCell({ + required this.fieldId, + required this.action, + required this.onTap, + required this.enable, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyButton( + text: FlowyText.medium(action.title(), fontSize: 12, color: enable ? null : theme.shader4), + hoverColor: theme.hover, + onTap: () { + if (enable) { + action.run(context); + onTap(); + } + }, + leftIcon: svgWidget(action.iconName(), color: theme.iconColor), + ); + } +} + +enum FieldAction { + hide, + duplicate, + delete, +} + +extension _FieldActionExtension on FieldAction { + String iconName() { + switch (this) { + case FieldAction.hide: + return 'grid/hide'; + case FieldAction.duplicate: + return 'grid/duplicate'; + case FieldAction.delete: + return 'grid/delete'; + } + } + + String title() { + switch (this) { + case FieldAction.hide: + return LocaleKeys.grid_field_hide.tr(); + case FieldAction.duplicate: + return LocaleKeys.grid_field_duplicate.tr(); + case FieldAction.delete: + return LocaleKeys.grid_field_delete.tr(); + } + } + + void run(BuildContext context) { + switch (this) { + case FieldAction.hide: + context.read().add(const FieldActionSheetEvent.hideField()); + break; + case FieldAction.duplicate: + context.read().add(const FieldActionSheetEvent.duplicateField()); + break; + case FieldAction.delete: + context.read().add(const FieldActionSheetEvent.deleteField()); + break; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart new file mode 100644 index 0000000000..6efe439399 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart @@ -0,0 +1,119 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_editor_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_switch_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'field_name_input.dart'; +import 'field_switcher.dart'; + +class FieldEditor extends FlowyOverlayDelegate { + final String gridId; + final FieldEditorBloc _fieldEditorBloc; + final EditFieldContextLoader fieldContextLoader; + FieldEditor({ + required this.gridId, + required this.fieldContextLoader, + Key? key, + }) : _fieldEditorBloc = getIt(param1: gridId, param2: fieldContextLoader) { + _fieldEditorBloc.add(const FieldEditorEvent.initial()); + } + + void show( + BuildContext context, { + AnchorDirection anchorDirection = AnchorDirection.bottomWithLeftAligned, + }) { + FlowyOverlay.of(context).remove(identifier()); + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: _FieldEditorWidget(_fieldEditorBloc, fieldContextLoader), + constraints: BoxConstraints.loose(const Size(220, 400)), + ), + identifier: identifier(), + anchorContext: context, + anchorDirection: anchorDirection, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + } + + static String identifier() { + return (FieldEditor).toString(); + } + + @override + void didRemove() { + _fieldEditorBloc.add(const FieldEditorEvent.done()); + } + + @override + bool asBarrier() => true; +} + +class _FieldEditorWidget extends StatelessWidget { + final FieldEditorBloc editorBloc; + final EditFieldContextLoader fieldContextLoader; + const _FieldEditorWidget(this.editorBloc, this.fieldContextLoader, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: editorBloc, + child: BlocBuilder( + builder: (context, state) { + return state.field.fold( + () => const SizedBox(width: 200), + (field) => ListView( + shrinkWrap: true, + children: [ + FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), + const VSpace(10), + const _FieldNameTextField(), + const VSpace(10), + _renderSwitchButton(context, field, state), + ], + ), + ); + }, + ), + ); + } + + Widget _renderSwitchButton(BuildContext context, Field field, FieldEditorState state) { + return FieldSwitcher( + switchContext: SwitchFieldContext(state.gridId, field, state.typeOptionData), + onSwitchToField: (fieldId, fieldType) { + return fieldContextLoader.switchToField(fieldId, fieldType); + }, + onUpdated: (field, typeOptionData) { + context.read().add(FieldEditorEvent.switchField(field, typeOptionData)); + }, + ); + } +} + +class _FieldNameTextField extends StatelessWidget { + const _FieldNameTextField({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.fieldName != current.fieldName, + builder: (context, state) { + return FieldNameTextField( + name: state.fieldName, + errorText: context.read().state.errorText, + onNameChanged: (newName) { + context.read().add(FieldEditorEvent.updateName(newName)); + }, + ); + }, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_name_input.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_name_input.dart new file mode 100644 index 0000000000..80cb327379 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_name_input.dart @@ -0,0 +1,32 @@ +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class FieldNameTextField extends StatelessWidget { + final void Function(String) onNameChanged; + final String name; + final String errorText; + const FieldNameTextField({ + required this.name, + required this.errorText, + required this.onNameChanged, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return RoundedInputField( + height: 36, + style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500), + initialValue: name, + normalBorderColor: theme.shader4, + errorBorderColor: theme.red, + focusBorderColor: theme.main1, + cursorColor: theme.main1, + errorText: errorText, + onChanged: onNameChanged, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart new file mode 100644 index 0000000000..5d86b7249d --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart @@ -0,0 +1,240 @@ +import 'dart:typed_data'; + +import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; +import 'package:dartz/dartz.dart' show Either; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pbserver.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart'; + +import 'field_type_extension.dart'; +import 'type_option/multi_select.dart'; +import 'type_option/number.dart'; +import 'type_option/single_select.dart'; + +typedef UpdateFieldCallback = void Function(Field, Uint8List); +typedef SwitchToFieldCallback = Future> Function( + String fieldId, + FieldType fieldType, +); + +class FieldSwitcher extends StatefulWidget { + final SwitchFieldContext switchContext; + final UpdateFieldCallback onUpdated; + final SwitchToFieldCallback onSwitchToField; + + const FieldSwitcher({ + required this.switchContext, + required this.onUpdated, + required this.onSwitchToField, + Key? key, + }) : super(key: key); + + @override + State createState() => _FieldSwitcherState(); +} + +class _FieldSwitcherState extends State { + String? currentOverlayIdentifier; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: widget.switchContext), + child: BlocConsumer( + listener: (context, state) { + widget.onUpdated(state.field, state.typeOptionData); + }, + builder: (context, state) { + List children = [_switchFieldTypeButton(context, state.field)]; + final typeOptionWidget = _typeOptionWidget(context: context, state: state); + + if (typeOptionWidget != null) { + children.add(typeOptionWidget); + } + + return ListView( + shrinkWrap: true, + children: children, + ); + }, + ), + ); + } + + Widget _switchFieldTypeButton(BuildContext context, Field field) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(field.fieldType.title(), fontSize: 12), + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + hoverColor: theme.hover, + onTap: () { + final list = FieldTypeList(onSelectField: (newFieldType) { + widget.onSwitchToField(field.id, newFieldType).then((result) { + result.fold( + (editFieldContext) { + context.read().add( + FieldSwitchEvent.toFieldType( + editFieldContext.gridField, + editFieldContext.typeOptionData, + ), + ); + }, + (err) => Log.error(err), + ); + }); + }); + _showOverlay(context, list); + }, + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ), + ); + } + + Widget? _typeOptionWidget({ + required BuildContext context, + required FieldSwitchState state, + }) { + final overlayDelegate = TypeOptionOverlayDelegate( + showOverlay: _showOverlay, + hideOverlay: _hideOverlay, + ); + + final dataDelegate = TypeOptionDataDelegate(didUpdateTypeOptionData: (data) { + context.read().add(FieldSwitchEvent.didUpdateTypeOptionData(data)); + }); + + final typeOptionContext = TypeOptionContext( + gridId: state.gridId, + field: state.field, + data: state.typeOptionData, + ); + + final builder = _makeTypeOptionBuild( + typeOptionContext: typeOptionContext, + overlayDelegate: overlayDelegate, + dataDelegate: dataDelegate, + ); + + return builder.customWidget; + } + + void _showOverlay(BuildContext context, Widget child, {VoidCallback? onRemoved}) { + final identifier = child.toString(); + if (currentOverlayIdentifier != null) { + FlowyOverlay.of(context).remove(currentOverlayIdentifier!); + } + + currentOverlayIdentifier = identifier; + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: child, + constraints: BoxConstraints.loose(const Size(340, 400)), + ), + identifier: identifier, + anchorContext: context, + anchorDirection: AnchorDirection.leftWithCenterAligned, + style: FlowyOverlayStyle(blur: false), + anchorOffset: const Offset(-20, 0), + ); + } + + void _hideOverlay(BuildContext context) { + if (currentOverlayIdentifier != null) { + FlowyOverlay.of(context).remove(currentOverlayIdentifier!); + } + } +} + +abstract class TypeOptionBuilder { + Widget? get customWidget; +} + +TypeOptionBuilder _makeTypeOptionBuild({ + required TypeOptionContext typeOptionContext, + required TypeOptionOverlayDelegate overlayDelegate, + required TypeOptionDataDelegate dataDelegate, +}) { + switch (typeOptionContext.field.fieldType) { + case FieldType.Checkbox: + return CheckboxTypeOptionBuilder(typeOptionContext.data); + case FieldType.DateTime: + return DateTypeOptionBuilder(typeOptionContext.data, overlayDelegate, dataDelegate); + case FieldType.SingleSelect: + return SingleSelectTypeOptionBuilder(typeOptionContext, overlayDelegate, dataDelegate); + case FieldType.MultiSelect: + return MultiSelectTypeOptionBuilder(typeOptionContext, overlayDelegate, dataDelegate); + case FieldType.Number: + return NumberTypeOptionBuilder(typeOptionContext.data, overlayDelegate, dataDelegate); + case FieldType.RichText: + return RichTextTypeOptionBuilder(typeOptionContext.data); + + default: + throw UnimplementedError; + } +} + +abstract class TypeOptionWidget extends StatelessWidget { + const TypeOptionWidget({Key? key}) : super(key: key); +} + +typedef TypeOptionData = Uint8List; +typedef TypeOptionDataCallback = void Function(TypeOptionData typeOptionData); +typedef ShowOverlayCallback = void Function( + BuildContext anchorContext, + Widget child, { + VoidCallback? onRemoved, +}); +typedef HideOverlayCallback = void Function(BuildContext anchorContext); + +class TypeOptionOverlayDelegate { + ShowOverlayCallback showOverlay; + HideOverlayCallback hideOverlay; + TypeOptionOverlayDelegate({ + required this.showOverlay, + required this.hideOverlay, + }); +} + +class TypeOptionDataDelegate { + TypeOptionDataCallback didUpdateTypeOptionData; + + TypeOptionDataDelegate({ + required this.didUpdateTypeOptionData, + }); +} + +class RichTextTypeOptionBuilder extends TypeOptionBuilder { + RichTextTypeOption typeOption; + + RichTextTypeOptionBuilder(TypeOptionData typeOptionData) : typeOption = RichTextTypeOption.fromBuffer(typeOptionData); + + @override + Widget? get customWidget => null; +} + +class CheckboxTypeOptionBuilder extends TypeOptionBuilder { + CheckboxTypeOption typeOption; + + CheckboxTypeOptionBuilder(TypeOptionData typeOptionData) : typeOption = CheckboxTypeOption.fromBuffer(typeOptionData); + + @override + Widget? get customWidget => null; +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart new file mode 100644 index 0000000000..a4da8fa1b9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart @@ -0,0 +1,43 @@ +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:easy_localization/easy_localization.dart'; + +extension FieldTypeListExtension on FieldType { + String iconName() { + switch (this) { + case FieldType.Checkbox: + return "grid/field/checkbox"; + case FieldType.DateTime: + return "grid/field/date"; + case FieldType.MultiSelect: + return "grid/field/multi_select"; + case FieldType.Number: + return "grid/field/number"; + case FieldType.RichText: + return "grid/field/text"; + case FieldType.SingleSelect: + return "grid/field/single_select"; + default: + throw UnimplementedError; + } + } + + String title() { + switch (this) { + case FieldType.Checkbox: + return LocaleKeys.grid_field_checkboxFieldName.tr(); + case FieldType.DateTime: + return LocaleKeys.grid_field_dateFieldName.tr(); + case FieldType.MultiSelect: + return LocaleKeys.grid_field_multiSelectFieldName.tr(); + case FieldType.Number: + return LocaleKeys.grid_field_numberFieldName.tr(); + case FieldType.RichText: + return LocaleKeys.grid_field_textFieldName.tr(); + case FieldType.SingleSelect: + return LocaleKeys.grid_field_singleSelectFieldName.tr(); + default: + throw UnimplementedError; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart new file mode 100644 index 0000000000..bfced8f421 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart @@ -0,0 +1,77 @@ +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; +import 'package:flutter/material.dart'; +import 'field_type_extension.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +typedef SelectFieldCallback = void Function(FieldType); + +class FieldTypeList extends StatelessWidget with FlowyOverlayDelegate { + final SelectFieldCallback onSelectField; + const FieldTypeList({required this.onSelectField, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final cells = FieldType.values.map((fieldType) { + return FieldTypeCell( + fieldType: fieldType, + onSelectField: (fieldType) { + onSelectField(fieldType); + FlowyOverlay.of(context).remove(FieldTypeList.identifier()); + }, + ); + }).toList(); + + return SizedBox( + width: 140, + child: ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + itemCount: cells.length, + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + physics: StyledScrollPhysics(), + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ), + ); + } + + static String identifier() { + return (FieldTypeList).toString(); + } +} + +class FieldTypeCell extends StatelessWidget { + final FieldType fieldType; + final SelectFieldCallback onSelectField; + const FieldTypeCell({ + required this.fieldType, + required this.onSelectField, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(fieldType.title(), fontSize: 12), + hoverColor: theme.hover, + onTap: () => onSelectField(fieldType), + leftIcon: svgWidget(fieldType.iconName(), color: theme.iconColor), + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart new file mode 100644 index 0000000000..63a397710c --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -0,0 +1,184 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:reorderables/reorderables.dart'; +import 'field_editor.dart'; +import 'field_cell.dart'; + +class GridHeaderSliverAdaptor extends StatefulWidget { + final String gridId; + final GridFieldCache fieldCache; + final ScrollController anchorScrollController; + const GridHeaderSliverAdaptor({ + required this.gridId, + required this.fieldCache, + required this.anchorScrollController, + Key? key, + }) : super(key: key); + + @override + State createState() => _GridHeaderSliverAdaptorState(); +} + +class _GridHeaderSliverAdaptorState extends State { + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) { + final bloc = getIt(param1: widget.gridId, param2: widget.fieldCache); + bloc.add(const GridHeaderEvent.initial()); + return bloc; + }, + child: BlocBuilder( + buildWhen: (previous, current) => previous.fields.length != current.fields.length, + builder: (context, state) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + controller: widget.anchorScrollController, + child: SizedBox( + height: GridSize.headerHeight, + child: _GridHeader(gridId: widget.gridId), + ), + ); + + // return SliverPersistentHeader( + // delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields), + // floating: true, + // pinned: true, + // ); + }, + ), + ); + } +} + +class _GridHeader extends StatefulWidget { + final String gridId; + const _GridHeader({Key? key, required this.gridId}) : super(key: key); + + @override + State<_GridHeader> createState() => _GridHeaderState(); +} + +class _GridHeaderState extends State<_GridHeader> { + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocBuilder( + buildWhen: (previous, current) => previous.fields != current.fields, + builder: (context, state) { + final cells = state.fields + .where((field) => field.visibility) + .map((field) => GridFieldCellContext(gridId: widget.gridId, field: field)) + .map((ctx) => GridFieldCell(ctx, key: ValueKey(ctx.field.id))) + .toList(); + + return Container( + color: theme.surface, + child: RepaintBoundary( + child: ReorderableRow( + crossAxisAlignment: CrossAxisAlignment.stretch, + scrollController: ScrollController(), + header: const _CellLeading(), + footer: _CellTrailing(gridId: widget.gridId), + onReorder: (int oldIndex, int newIndex) { + _onReorder(cells, oldIndex, context, newIndex); + }, + children: cells, + ), + ), + ); + }, + ); + } + + void _onReorder(List cells, int oldIndex, BuildContext context, int newIndex) { + if (cells.length > oldIndex) { + final field = cells[oldIndex].cellContext.field; + context.read().add(GridHeaderEvent.moveField(field, oldIndex, newIndex)); + } + } +} + +class _CellLeading extends StatelessWidget { + const _CellLeading({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: GridSize.leadingHeaderPadding, + ); + } +} + +class _CellTrailing extends StatelessWidget { + final String gridId; + const _CellTrailing({required this.gridId, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final borderSide = BorderSide(color: theme.shader4, width: 0.4); + return Container( + width: GridSize.trailHeaderPadding, + decoration: BoxDecoration( + border: Border(top: borderSide, bottom: borderSide), + ), + padding: GridSize.headerContentInsets, + child: CreateFieldButton(gridId: gridId), + ); + } +} + +class CreateFieldButton extends StatelessWidget { + final String gridId; + const CreateFieldButton({required this.gridId, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return FlowyButton( + text: const FlowyText.medium('New column', fontSize: 12), + hoverColor: theme.hover, + onTap: () => FieldEditor( + gridId: gridId, + fieldContextLoader: NewFieldContextLoader(gridId: gridId), + ).show(context), + leftIcon: svgWidget("home/add"), + ); + } +} + +class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate { + final String gridId; + final List fields; + + SliverHeaderDelegateImplementation({required this.gridId, required this.fields}); + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + return _GridHeader(gridId: gridId); + } + + @override + double get maxExtent => GridSize.headerHeight; + + @override + double get minExtent => GridSize.headerHeight; + + @override + bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { + if (oldDelegate is SliverHeaderDelegateImplementation) { + return fields.length != oldDelegate.fields.length; + } + return true; + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart new file mode 100644 index 0000000000..a580bbebf1 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart @@ -0,0 +1,307 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/date_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; +import 'package:easy_localization/easy_localization.dart' hide DateFormat; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class DateTypeOptionBuilder extends TypeOptionBuilder { + final DateTypeOptionWidget _widget; + + DateTypeOptionBuilder( + TypeOptionData typeOptionData, + TypeOptionOverlayDelegate overlayDelegate, + TypeOptionDataDelegate dataDelegate, + ) : _widget = DateTypeOptionWidget( + typeOption: DateTypeOption.fromBuffer(typeOptionData), + dataDelegate: dataDelegate, + overlayDelegate: overlayDelegate, + ); + + @override + Widget? get customWidget => _widget; +} + +class DateTypeOptionWidget extends TypeOptionWidget { + final DateTypeOption typeOption; + final TypeOptionOverlayDelegate overlayDelegate; + final TypeOptionDataDelegate dataDelegate; + const DateTypeOptionWidget({ + required this.typeOption, + required this.dataDelegate, + required this.overlayDelegate, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: typeOption), + child: BlocConsumer( + listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()), + builder: (context, state) { + return Column(children: [ + _dateFormatButton(context, state.typeOption.dateFormat), + _timeFormatButton(context, state.typeOption.timeFormat), + const _IncludeTimeButton(), + ]); + }, + ), + ); + } + + Widget _dateFormatButton(BuildContext context, DateFormat dataFormat) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_field_dateFormat.tr(), fontSize: 12), + padding: GridSize.typeOptionContentInsets, + hoverColor: theme.hover, + onTap: () { + final list = DateFormatList( + selectedFormat: dataFormat, + onSelected: (format) { + context.read().add(DateTypeOptionEvent.didSelectDateFormat(format)); + }, + ); + overlayDelegate.showOverlay(context, list); + }, + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ), + ); + } + + Widget _timeFormatButton(BuildContext context, TimeFormat timeFormat) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_field_timeFormat.tr(), fontSize: 12), + padding: GridSize.typeOptionContentInsets, + hoverColor: theme.hover, + onTap: () { + final list = TimeFormatList( + selectedFormat: timeFormat, + onSelected: (format) { + context.read().add(DateTypeOptionEvent.didSelectTimeFormat(format)); + }); + overlayDelegate.showOverlay(context, list); + }, + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ), + ); + } +} + +class _IncludeTimeButton extends StatelessWidget { + const _IncludeTimeButton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocSelector( + selector: (state) => state.typeOption.includeTime, + builder: (context, includeTime) { + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: Padding( + padding: GridSize.typeOptionContentInsets, + child: Row( + children: [ + FlowyText.medium(LocaleKeys.grid_field_includeTime.tr(), fontSize: 12), + const Spacer(), + Switch( + value: includeTime, + onChanged: (newValue) { + context.read().add(DateTypeOptionEvent.includeTime(newValue)); + }, + ), + ], + ), + ), + ); + }, + ); + } +} + +class DateFormatList extends StatelessWidget { + final DateFormat selectedFormat; + final Function(DateFormat format) onSelected; + const DateFormatList({required this.selectedFormat, required this.onSelected, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final cells = DateFormat.values.map((format) { + return DateFormatCell( + dateFormat: format, + onSelected: (format) { + onSelected(format); + FlowyOverlay.of(context).remove(DateFormatList.identifier()); + }, + isSelected: selectedFormat == format); + }).toList(); + + return SizedBox( + width: 180, + child: ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ), + ); + } + + static String identifier() { + return (DateFormatList).toString(); + } +} + +class DateFormatCell extends StatelessWidget { + final bool isSelected; + final DateFormat dateFormat; + final Function(DateFormat format) onSelected; + const DateFormatCell({ + required this.dateFormat, + required this.onSelected, + required this.isSelected, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + Widget? checkmark; + if (isSelected) { + checkmark = svgWidget("grid/checkmark"); + } + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(dateFormat.title(), fontSize: 12), + hoverColor: theme.hover, + rightIcon: checkmark, + onTap: () => onSelected(dateFormat), + ), + ); + } +} + +extension DateFormatExtension on DateFormat { + String title() { + switch (this) { + case DateFormat.Friendly: + return LocaleKeys.grid_field_dateFormatFriendly.tr(); + case DateFormat.ISO: + return LocaleKeys.grid_field_dateFormatISO.tr(); + case DateFormat.Local: + return LocaleKeys.grid_field_dateFormatLocal.tr(); + case DateFormat.US: + return LocaleKeys.grid_field_dateFormatUS.tr(); + default: + throw UnimplementedError; + } + } +} + +class TimeFormatList extends StatelessWidget { + final TimeFormat selectedFormat; + final Function(TimeFormat format) onSelected; + const TimeFormatList({ + required this.selectedFormat, + required this.onSelected, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final cells = TimeFormat.values.map((format) { + return TimeFormatCell( + isSelected: format == selectedFormat, + timeFormat: format, + onSelected: (format) { + onSelected(format); + FlowyOverlay.of(context).remove(TimeFormatList.identifier()); + }); + }).toList(); + + return SizedBox( + width: 120, + child: ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ), + ); + } + + static String identifier() { + return (TimeFormatList).toString(); + } +} + +class TimeFormatCell extends StatelessWidget { + final TimeFormat timeFormat; + final bool isSelected; + final Function(TimeFormat format) onSelected; + const TimeFormatCell({ + required this.timeFormat, + required this.onSelected, + required this.isSelected, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + Widget? checkmark; + if (isSelected) { + checkmark = svgWidget("grid/checkmark"); + } + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(timeFormat.title(), fontSize: 12), + hoverColor: theme.hover, + rightIcon: checkmark, + onTap: () => onSelected(timeFormat), + ), + ); + } +} + +extension TimeFormatExtension on TimeFormat { + String title() { + switch (this) { + case TimeFormat.TwelveHour: + return LocaleKeys.grid_field_timeFormatTwelveHour.tr(); + case TimeFormat.TwentyFourHour: + return LocaleKeys.grid_field_timeFormatTwentyFourHour.tr(); + default: + throw UnimplementedError; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart new file mode 100644 index 0000000000..f8805b7180 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart @@ -0,0 +1,188 @@ +import 'package:app_flowy/workspace/application/grid/field/type_option/edit_select_option_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; + +class EditSelectOptionPannel extends StatelessWidget { + final SelectOption option; + final VoidCallback onDeleted; + final Function(SelectOption) onUpdated; + const EditSelectOptionPannel({ + required this.option, + required this.onDeleted, + required this.onUpdated, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => EditSelectOptionBloc(option: option), + child: MultiBlocListener( + listeners: [ + BlocListener( + listenWhen: (p, c) => p.deleted != c.deleted, + listener: (context, state) { + state.deleted.fold(() => null, (_) => onDeleted()); + }, + ), + BlocListener( + listenWhen: (p, c) => p.option != c.option, + listener: (context, state) { + onUpdated(state.option); + }, + ), + ], + child: BlocBuilder( + builder: (context, state) { + List slivers = [ + SliverToBoxAdapter(child: _OptionNameTextField(state.option.name)), + const SliverToBoxAdapter(child: VSpace(10)), + const SliverToBoxAdapter(child: _DeleteTag()), + const SliverToBoxAdapter(child: TypeOptionSeparator()), + SliverToBoxAdapter(child: SelectOptionColorList(selectedColor: state.option.color)), + ]; + + return SizedBox( + width: 160, + child: CustomScrollView( + slivers: slivers, + controller: ScrollController(), + physics: StyledScrollPhysics(), + ), + ); + }, + ), + ), + ); + } +} + +class _DeleteTag extends StatelessWidget { + const _DeleteTag({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_selectOption_deleteTag.tr(), fontSize: 12), + hoverColor: theme.hover, + leftIcon: svgWidget("grid/delete", color: theme.iconColor), + onTap: () { + context.read().add(const EditSelectOptionEvent.delete()); + }, + ), + ); + } +} + +class _OptionNameTextField extends StatelessWidget { + final String name; + const _OptionNameTextField(this.name, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return NameTextField( + name: name, + onCanceled: () {}, + onDone: (optionName) { + if (name != optionName) { + context.read().add(EditSelectOptionEvent.updateName(optionName)); + } + }, + ); + } +} + +class SelectOptionColorList extends StatelessWidget { + final SelectOptionColor selectedColor; + const SelectOptionColorList({required this.selectedColor, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final cells = SelectOptionColor.values.map((color) { + return _SelectOptionColorCell(color: color, isSelected: selectedColor == color); + }).toList(); + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: GridSize.typeOptionContentInsets, + child: SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyText.medium( + LocaleKeys.grid_selectOption_colorPannelTitle.tr(), + fontSize: 12, + textAlign: TextAlign.left, + ), + ), + ), + ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: cells.length, + physics: StyledScrollPhysics(), + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ), + ], + ); + } +} + +class _SelectOptionColorCell extends StatelessWidget { + final SelectOptionColor color; + final bool isSelected; + const _SelectOptionColorCell({required this.color, required this.isSelected, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + Widget? checkmark; + if (isSelected) { + checkmark = svgWidget("grid/checkmark"); + } + + final colorIcon = SizedBox.square( + dimension: 16, + child: Container( + decoration: BoxDecoration( + color: color.make(context), + shape: BoxShape.circle, + ), + ), + ); + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(color.optionName(), fontSize: 12), + hoverColor: theme.hover, + leftIcon: colorIcon, + rightIcon: checkmark, + onTap: () { + context.read().add(EditSelectOptionEvent.updateColor(color)); + }, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/field_option_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/field_option_pannel.dart new file mode 100644 index 0000000000..359d0427c9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/field_option_pannel.dart @@ -0,0 +1,235 @@ +import 'package:app_flowy/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; + +import 'edit_option_pannel.dart'; +import 'widget.dart'; + +class FieldSelectOptionPannel extends StatelessWidget { + final List options; + final VoidCallback beginEdit; + final Function(String optionName) createOptionCallback; + final Function(SelectOption) updateOptionCallback; + final Function(SelectOption) deleteOptionCallback; + final TypeOptionOverlayDelegate overlayDelegate; + + const FieldSelectOptionPannel({ + required this.options, + required this.beginEdit, + required this.createOptionCallback, + required this.updateOptionCallback, + required this.deleteOptionCallback, + required this.overlayDelegate, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => FieldOptionPannelBloc(options: options), + child: BlocConsumer( + listener: (context, state) { + if (state.isEditingOption) { + beginEdit(); + } + state.newOptionName.fold( + () => null, + (optionName) => createOptionCallback(optionName), + ); + + state.updateOption.fold( + () => null, + (updateOption) => updateOptionCallback(updateOption), + ); + + state.deleteOption.fold( + () => null, + (deleteOption) => deleteOptionCallback(deleteOption), + ); + }, + builder: (context, state) { + List children = [ + const TypeOptionSeparator(), + const OptionTitle(), + ]; + if (state.isEditingOption) { + children.add(const _OptionNameTextField()); + } + + if (state.options.isEmpty && !state.isEditingOption) { + children.add(const _AddOptionButton()); + } + + if (state.options.isNotEmpty) { + children.add(_OptionList(overlayDelegate)); + } + + return Column(children: children); + }, + ), + ); + } +} + +class OptionTitle extends StatelessWidget { + const OptionTitle({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return BlocBuilder( + builder: (context, state) { + List children = [FlowyText.medium(LocaleKeys.grid_field_optionTitle.tr(), fontSize: 12)]; + if (state.options.isNotEmpty) { + children.add(const Spacer()); + children.add( + SizedBox( + width: 100, + height: 26, + child: FlowyButton( + text: FlowyText.medium( + LocaleKeys.grid_field_addOption.tr(), + fontSize: 12, + textAlign: TextAlign.center, + ), + hoverColor: theme.hover, + onTap: () { + context.read().add(const FieldOptionPannelEvent.beginAddingOption()); + }, + ), + ), + ); + } + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: Row(children: children), + ); + }, + ); + } +} + +class _OptionList extends StatelessWidget { + final TypeOptionOverlayDelegate delegate; + const _OptionList(this.delegate, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) { + return previous.options != current.options; + }, + builder: (context, state) { + final cells = state.options.map((option) { + return _makeOptionCell(context, option); + }).toList(); + + return ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ); + }, + ); + } + + _OptionCell _makeOptionCell(BuildContext context, SelectOption option) { + return _OptionCell( + option: option, + onEdited: (option) { + final pannel = EditSelectOptionPannel( + option: option, + onDeleted: () { + delegate.hideOverlay(context); + context.read().add(FieldOptionPannelEvent.deleteOption(option)); + }, + onUpdated: (updatedOption) { + delegate.hideOverlay(context); + context.read().add(FieldOptionPannelEvent.updateOption(updatedOption)); + }, + key: ValueKey(option.id), + ); + delegate.showOverlay(context, pannel); + }, + ); + } +} + +class _OptionCell extends StatelessWidget { + final SelectOption option; + final Function(SelectOption) onEdited; + const _OptionCell({ + required this.option, + required this.onEdited, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(option.name, fontSize: 12), + hoverColor: theme.hover, + onTap: () => onEdited(option), + rightIcon: svgWidget("grid/details", color: theme.iconColor), + ), + ); + } +} + +class _AddOptionButton extends StatelessWidget { + const _AddOptionButton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_field_addSelectOption.tr(), fontSize: 12), + hoverColor: theme.hover, + onTap: () { + context.read().add(const FieldOptionPannelEvent.beginAddingOption()); + }, + leftIcon: svgWidget("home/add", color: theme.iconColor), + ), + ); + } +} + +class _OptionNameTextField extends StatelessWidget { + const _OptionNameTextField({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return NameTextField( + name: "", + onCanceled: () { + context.read().add(const FieldOptionPannelEvent.endAddingOption()); + }, + onDone: (optionName) { + context.read().add(FieldOptionPannelEvent.createOption(optionName)); + }, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart new file mode 100644 index 0000000000..fb5da57bec --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart @@ -0,0 +1,67 @@ +import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'field_option_pannel.dart'; + +class MultiSelectTypeOptionBuilder extends TypeOptionBuilder { + final MultiSelectTypeOptionWidget _widget; + + MultiSelectTypeOptionBuilder( + TypeOptionContext typeOptionContext, + TypeOptionOverlayDelegate overlayDelegate, + TypeOptionDataDelegate dataDelegate, + ) : _widget = MultiSelectTypeOptionWidget( + typeOptionContext: typeOptionContext, + overlayDelegate: overlayDelegate, + dataDelegate: dataDelegate, + ); + + @override + Widget? get customWidget => _widget; +} + +class MultiSelectTypeOptionWidget extends TypeOptionWidget { + final TypeOptionContext typeOptionContext; + final TypeOptionOverlayDelegate overlayDelegate; + final TypeOptionDataDelegate dataDelegate; + const MultiSelectTypeOptionWidget({ + required this.typeOptionContext, + required this.overlayDelegate, + required this.dataDelegate, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => MultiSelectTypeOptionBloc(typeOptionContext), + child: BlocConsumer( + listener: (context, state) { + dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()); + }, + builder: (context, state) { + return FieldSelectOptionPannel( + options: state.typeOption.options, + beginEdit: () { + overlayDelegate.hideOverlay(context); + }, + createOptionCallback: (name) { + context.read().add(MultiSelectTypeOptionEvent.createOption(name)); + }, + updateOptionCallback: (updateOption) { + context.read().add(MultiSelectTypeOptionEvent.updateOption(updateOption)); + }, + deleteOptionCallback: (deleteOption) { + context.read().add(MultiSelectTypeOptionEvent.deleteOption(deleteOption)); + }, + overlayDelegate: overlayDelegate, + key: ValueKey(state.typeOption.hashCode), + ); + }, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart new file mode 100644 index 0000000000..5897699442 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart @@ -0,0 +1,159 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/number_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart' hide NumberFormat; +import 'package:app_flowy/generated/locale_keys.g.dart'; + +class NumberTypeOptionBuilder extends TypeOptionBuilder { + final NumberTypeOptionWidget _widget; + + NumberTypeOptionBuilder( + TypeOptionData typeOptionData, + TypeOptionOverlayDelegate overlayDelegate, + TypeOptionDataDelegate dataDelegate, + ) : _widget = NumberTypeOptionWidget( + typeOption: NumberTypeOption.fromBuffer(typeOptionData), + dataDelegate: dataDelegate, + overlayDelegate: overlayDelegate, + ); + + @override + Widget? get customWidget => _widget; +} + +class NumberTypeOptionWidget extends TypeOptionWidget { + final TypeOptionDataDelegate dataDelegate; + final TypeOptionOverlayDelegate overlayDelegate; + final NumberTypeOption typeOption; + const NumberTypeOptionWidget( + {required this.typeOption, required this.dataDelegate, required this.overlayDelegate, Key? key}) + : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocProvider( + create: (context) => getIt(param1: typeOption), + child: SizedBox( + height: GridSize.typeOptionItemHeight, + child: BlocConsumer( + listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()), + builder: (context, state) { + return FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_field_numberFormat.tr(), fontSize: 12), + padding: GridSize.typeOptionContentInsets, + hoverColor: theme.hover, + onTap: () { + final list = NumberFormatList(onSelected: (format) { + context.read().add(NumberTypeOptionEvent.didSelectFormat(format)); + }); + overlayDelegate.showOverlay(context, list); + }, + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ); + }, + ), + ), + ); + } +} + +typedef _SelectNumberFormatCallback = Function(NumberFormat format); + +class NumberFormatList extends StatelessWidget { + final _SelectNumberFormatCallback onSelected; + const NumberFormatList({required this.onSelected, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final cells = NumberFormat.values.map((format) { + return NumberFormatCell( + format: format, + onSelected: (format) { + onSelected(format); + FlowyOverlay.of(context).remove(NumberFormatList.identifier()); + }); + }).toList(); + + return SizedBox( + width: 120, + child: ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ), + ); + } + + static String identifier() { + return (NumberFormatList).toString(); + } +} + +class NumberFormatCell extends StatelessWidget { + final NumberFormat format; + final Function(NumberFormat format) onSelected; + const NumberFormatCell({required this.format, required this.onSelected, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(format.title(), fontSize: 12), + hoverColor: theme.hover, + onTap: () => onSelected(format), + leftIcon: svgWidget(format.iconName(), color: theme.iconColor), + ), + ); + } +} + +extension NumberFormatExtension on NumberFormat { + String title() { + switch (this) { + case NumberFormat.CNY: + return "Yen"; + case NumberFormat.EUR: + return "Euro"; + case NumberFormat.Number: + return "Numbers"; + case NumberFormat.USD: + return "US Dollar"; + default: + throw UnimplementedError; + } + } + + String iconName() { + switch (this) { + case NumberFormat.CNY: + return "grid/field/yen"; + case NumberFormat.EUR: + return "grid/field/euro"; + case NumberFormat.Number: + return "grid/field/numbers"; + case NumberFormat.USD: + return "grid/field/us_dollar"; + default: + throw UnimplementedError; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart new file mode 100644 index 0000000000..89d2f63a2d --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart @@ -0,0 +1,66 @@ +import 'package:app_flowy/workspace/application/grid/field/type_option/single_select_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'field_option_pannel.dart'; + +class SingleSelectTypeOptionBuilder extends TypeOptionBuilder { + final SingleSelectTypeOptionWidget _widget; + + SingleSelectTypeOptionBuilder( + TypeOptionContext typeOptionContext, + TypeOptionOverlayDelegate overlayDelegate, + TypeOptionDataDelegate dataDelegate, + ) : _widget = SingleSelectTypeOptionWidget( + typeOptionContext: typeOptionContext, + dataDelegate: dataDelegate, + overlayDelegate: overlayDelegate, + ); + + @override + Widget? get customWidget => _widget; +} + +class SingleSelectTypeOptionWidget extends TypeOptionWidget { + final TypeOptionContext typeOptionContext; + final TypeOptionOverlayDelegate overlayDelegate; + final TypeOptionDataDelegate dataDelegate; + const SingleSelectTypeOptionWidget({ + required this.typeOptionContext, + required this.dataDelegate, + required this.overlayDelegate, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => SingleSelectTypeOptionBloc(typeOptionContext), + child: BlocConsumer( + listener: (context, state) { + dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()); + }, + builder: (context, state) { + return FieldSelectOptionPannel( + options: state.typeOption.options, + beginEdit: () { + overlayDelegate.hideOverlay(context); + }, + createOptionCallback: (name) { + context.read().add(SingleSelectTypeOptionEvent.createOption(name)); + }, + updateOptionCallback: (updateOption) { + context.read().add(SingleSelectTypeOptionEvent.updateOption(updateOption)); + }, + deleteOptionCallback: (deleteOption) { + context.read().add(SingleSelectTypeOptionEvent.deleteOption(deleteOption)); + }, + overlayDelegate: overlayDelegate, + key: ValueKey(state.typeOption.hashCode), + ); + }, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart new file mode 100644 index 0000000000..12c1d4997b --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart @@ -0,0 +1,87 @@ +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class NameTextField extends StatefulWidget { + final void Function(String) onDone; + final void Function() onCanceled; + final String name; + + const NameTextField({ + required this.name, + required this.onDone, + required this.onCanceled, + Key? key, + }) : super(key: key); + + @override + State createState() => _NameTextFieldState(); +} + +class _NameTextFieldState extends State { + late FocusNode _focusNode; + var isEdited = false; + late TextEditingController _controller; + + @override + void initState() { + _focusNode = FocusNode(); + _controller = TextEditingController(text: widget.name); + + _focusNode.addListener(notifyDidEndEditing); + super.initState(); + } + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return RoundedInputField( + controller: _controller, + focusNode: _focusNode, + autoFocus: true, + height: 36, + style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500), + normalBorderColor: theme.shader4, + focusBorderColor: theme.main1, + cursorColor: theme.main1, + onEditingComplete: () { + widget.onDone(_controller.text); + }, + ); + } + + @override + void dispose() { + _focusNode.removeListener(notifyDidEndEditing); + _focusNode.dispose(); + super.dispose(); + } + + void notifyDidEndEditing() { + if (!_focusNode.hasFocus) { + if (_controller.text.isEmpty) { + widget.onCanceled(); + } else { + widget.onDone(_controller.text); + } + } + } +} + +class TypeOptionSeparator extends StatelessWidget { + const TypeOptionSeparator({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Container( + color: theme.shader4, + height: 0.25, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart new file mode 100644 index 0000000000..0f3f7c5f32 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart @@ -0,0 +1,44 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class NumberCell extends StatefulWidget { + final GridCell cellData; + + const NumberCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _NumberCellState(); +} + +class _NumberCellState extends State { + late NumberCellBloc _cellBloc; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + return Container(); + }, + ), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart new file mode 100755 index 0000000000..1201120f37 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart @@ -0,0 +1,252 @@ +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:provider/provider.dart'; +import 'row_action_sheet.dart'; +import 'package:dartz/dartz.dart' show Option; + +import 'row_detail.dart'; + +class GridRowWidget extends StatefulWidget { + final GridRow rowData; + final GridRowCache rowCache; + + const GridRowWidget({ + required this.rowData, + required this.rowCache, + Key? key, + }) : super(key: key); + + @override + State createState() => _GridRowWidgetState(); +} + +class _GridRowWidgetState extends State { + late RowBloc _rowBloc; + + @override + void initState() { + _rowBloc = RowBloc( + rowData: widget.rowData, + rowCache: widget.rowCache, + ); + _rowBloc.add(const RowEvent.initial()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _rowBloc, + child: _RowEnterRegion( + child: BlocBuilder( + buildWhen: (p, c) => p.rowData.height != c.rowData.height, + builder: (context, state) { + final children = [ + const _RowLeading(), + _RowCells(onExpand: () => onExpandCell(context)), + const _RowTrailing(), + ]; + + final child = Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ); + + return SizedBox(height: 42, child: child); + }, + ), + ), + ); + } + + @override + Future dispose() async { + _rowBloc.close(); + super.dispose(); + } + + void onExpandCell(BuildContext context) { + final page = RowDetailPage(rowData: widget.rowData, rowCache: widget.rowCache); + page.show(context); + } +} + +class _RowLeading extends StatelessWidget { + const _RowLeading({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Consumer<_RegionStateNotifier>( + builder: (context, state, _) { + return SizedBox(width: GridSize.leadingHeaderPadding, child: state.onEnter ? _activeWidget() : null); + }, + ); + } + + Widget _activeWidget() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + _InsertRowButton(), + _DeleteRowButton(), + ], + ); + } +} + +class _RowTrailing extends StatelessWidget { + const _RowTrailing({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return const SizedBox(); + } +} + +class _InsertRowButton extends StatelessWidget { + const _InsertRowButton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyIconButton( + hoverColor: theme.hover, + width: 20, + height: 30, + onPressed: () => context.read().add(const RowEvent.createRow()), + iconPadding: const EdgeInsets.all(3), + icon: svgWidget("home/add"), + ); + } +} + +class _DeleteRowButton extends StatelessWidget { + const _DeleteRowButton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyIconButton( + hoverColor: theme.hover, + width: 20, + height: 30, + onPressed: () => GridRowActionSheet( + rowData: context.read().state.rowData, + ).show(context), + iconPadding: const EdgeInsets.all(3), + icon: svgWidget("editor/details"), + ); + } +} + +class _RowCells extends StatelessWidget { + final VoidCallback onExpand; + const _RowCells({required this.onExpand, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap, + builder: (context, state) { + return Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: _makeCells(state.cellDataMap), + ); + }, + ); + } + + List _makeCells(Option data) { + return data.fold( + () => [], + (cellDataMap) => cellDataMap.values.map( + (cellData) { + Widget? expander; + if (cellData.field.isPrimary) { + expander = _CellExpander(onExpand: onExpand); + } + + return CellContainer( + width: cellData.field.width.toDouble(), + child: buildGridCell(cellData), + expander: expander, + ); + }, + ).toList(), + ); + } +} + +class _RegionStateNotifier extends ChangeNotifier { + bool _onEnter = false; + + set onEnter(bool value) { + if (_onEnter != value) { + _onEnter = value; + notifyListeners(); + } + } + + bool get onEnter => _onEnter; +} + +class _CellExpander extends StatelessWidget { + final VoidCallback onExpand; + const _CellExpander({required this.onExpand, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyIconButton( + width: 20, + onPressed: onExpand, + iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), + icon: svgWidget("grid/expander", color: theme.main1), + ); + } +} + +class _RowEnterRegion extends StatefulWidget { + final Widget child; + const _RowEnterRegion({required this.child, Key? key}) : super(key: key); + + @override + State<_RowEnterRegion> createState() => _RowEnterRegionState(); +} + +class _RowEnterRegionState extends State<_RowEnterRegion> { + late _RegionStateNotifier _rowStateNotifier; + + @override + void initState() { + _rowStateNotifier = _RegionStateNotifier(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _rowStateNotifier, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (p) => _rowStateNotifier.onEnter = true, + onExit: (p) => _rowStateNotifier.onEnter = false, + child: widget.child, + ), + ); + } + + @override + Future dispose() async { + _rowStateNotifier.dispose(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart new file mode 100644 index 0000000000..0f3f7c5f32 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart @@ -0,0 +1,44 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class NumberCell extends StatefulWidget { + final GridCell cellData; + + const NumberCell({ + required this.cellData, + Key? key, + }) : super(key: key); + + @override + State createState() => _NumberCellState(); +} + +class _NumberCellState extends State { + late NumberCellBloc _cellBloc; + + @override + void initState() { + _cellBloc = getIt(param1: widget.cellData); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + return Container(); + }, + ), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart new file mode 100644 index 0000000000..40e77d9c43 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart @@ -0,0 +1,148 @@ +import 'package:app_flowy/workspace/application/grid/row/row_action_sheet_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class GridRowActionSheet extends StatelessWidget { + final GridRow rowData; + const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => RowActionSheetBloc(rowData: rowData), + child: BlocBuilder( + builder: (context, state) { + final cells = _RowAction.values + .map( + (action) => _RowActionCell( + action: action, + onDismissed: () => remove(context), + ), + ) + .toList(); + + // + final list = ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + itemCount: cells.length, + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + physics: StyledScrollPhysics(), + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ); + return list; + }, + ), + ); + } + + void show(BuildContext overlayContext) { + FlowyOverlay.of(overlayContext).insertWithAnchor( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.loose(const Size(140, 200)), + ), + identifier: GridRowActionSheet.identifier(), + anchorContext: overlayContext, + anchorDirection: AnchorDirection.leftWithCenterAligned, + ); + } + + void remove(BuildContext overlayContext) { + FlowyOverlay.of(overlayContext).remove(GridRowActionSheet.identifier()); + } + + static String identifier() { + return (GridRowActionSheet).toString(); + } +} + +class _RowActionCell extends StatelessWidget { + final _RowAction action; + final VoidCallback onDismissed; + const _RowActionCell({required this.action, required this.onDismissed, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium( + action.title(), + fontSize: 12, + color: action.enable() ? theme.textColor : theme.shader3, + ), + hoverColor: theme.hover, + onTap: () { + if (action.enable()) { + action.performAction(context); + } + onDismissed(); + }, + leftIcon: svgWidget(action.iconName(), color: theme.iconColor), + ), + ); + } +} + +enum _RowAction { + delete, + duplicate, +} + +extension _RowActionExtension on _RowAction { + String iconName() { + switch (this) { + case _RowAction.duplicate: + return 'grid/duplicate'; + case _RowAction.delete: + return 'grid/delete'; + } + } + + String title() { + switch (this) { + case _RowAction.duplicate: + return LocaleKeys.grid_row_duplicate.tr(); + case _RowAction.delete: + return LocaleKeys.grid_row_delete.tr(); + } + } + + bool enable() { + switch (this) { + case _RowAction.duplicate: + return false; + case _RowAction.delete: + return true; + } + } + + void performAction(BuildContext context) { + switch (this) { + case _RowAction.duplicate: + context.read().add(const RowActionSheetEvent.duplicateRow()); + break; + case _RowAction.delete: + context.read().add(const RowActionSheetEvent.deleteRow()); + break; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart new file mode 100644 index 0000000000..4ba31f783b --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -0,0 +1,157 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:window_size/window_size.dart'; + +class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate { + final GridRow rowData; + final GridRowCache rowCache; + + const RowDetailPage({ + required this.rowData, + required this.rowCache, + Key? key, + }) : super(key: key); + + @override + State createState() => _RowDetailPageState(); + + void show(BuildContext context) async { + final window = await getWindowInfo(); + final size = Size(window.frame.size.width * 0.7, window.frame.size.height * 0.7); + FlowyOverlay.of(context).insertWithRect( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.tight(size), + ), + identifier: RowDetailPage.identifier(), + anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), + anchorSize: window.frame.size, + anchorDirection: AnchorDirection.center, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + } + + static String identifier() { + return (RowDetailPage).toString(); + } +} + +class _RowDetailPageState extends State { + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) { + final bloc = RowDetailBloc(rowData: widget.rowData, rowCache: widget.rowCache); + bloc.add(const RowDetailEvent.initial()); + return bloc; + }, + child: const Padding( + padding: EdgeInsets.symmetric(horizontal: 80, vertical: 40), + child: _PropertyList(), + ), + ); + } +} + +class _PropertyList extends StatelessWidget { + const _PropertyList({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.cellDatas != current.cellDatas, + builder: (context, state) { + return ListView.separated( + itemCount: state.cellDatas.length, + itemBuilder: (BuildContext context, int index) { + return _RowDetailCell(cellData: state.cellDatas[index]); + }, + separatorBuilder: (BuildContext context, int index) { + return const VSpace(2); + }, + ); + }, + ); + } +} + +class _RowDetailCell extends StatelessWidget { + final GridCell cellData; + const _RowDetailCell({required this.cellData, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final cell = buildGridCell( + cellData, + style: _buildCellStyle(theme, cellData.field.fieldType), + ); + return SizedBox( + height: 36, + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: 150, + child: FieldCellButton(field: cellData.field, onTap: () => _showFieldEditor(context)), + ), + const HSpace(10), + Expanded( + child: FlowyHover2( + child: cell, + contentPadding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), + ), + ), + ], + ), + ); + } + + void _showFieldEditor(BuildContext context) { + FieldEditor( + gridId: cellData.gridId, + fieldContextLoader: FieldContextLoaderAdaptor( + gridId: cellData.gridId, + field: cellData.field, + ), + ).show(context); + } +} + +GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) { + switch (fieldType) { + case FieldType.Checkbox: + return null; + case FieldType.DateTime: + return null; + case FieldType.MultiSelect: + return null; + case FieldType.Number: + return null; + case FieldType.RichText: + return GridTextCellStyle( + placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), + ); + case FieldType.SingleSelect: + return null; + default: + return null; + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart new file mode 100644 index 0000000000..aa8f88ab5d --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -0,0 +1,123 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; +import 'package:app_flowy/workspace/application/grid/setting/property_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:styled_widget/styled_widget.dart'; + +class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { + final String gridId; + final GridFieldCache fieldCache; + const GridPropertyList({ + required this.gridId, + required this.fieldCache, + Key? key, + }) : super(key: key); + + void show(BuildContext context) { + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.loose(const Size(260, 400)), + ), + identifier: identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.bottomRight, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + } + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => + getIt(param1: gridId, param2: fieldCache)..add(const GridPropertyEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + final cells = state.fields.map((field) { + return _GridPropertyCell(gridId: gridId, field: field, key: ValueKey(field.id)); + }).toList(); + + return ListView.separated( + shrinkWrap: true, + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + separatorBuilder: (BuildContext context, int index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + ); + }, + ), + ); + } + + String identifier() { + return (GridPropertyList).toString(); + } + + @override + bool asBarrier() => true; +} + +class _GridPropertyCell extends StatelessWidget { + final Field field; + final String gridId; + const _GridPropertyCell({required this.gridId, required this.field, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + final checkmark = field.visibility + ? svgWidget('home/show', color: theme.iconColor) + : svgWidget('home/hide', color: theme.iconColor); + + return Row( + children: [ + Expanded( + child: SizedBox( + height: GridSize.typeOptionItemHeight, + child: _editFieldButton(theme, context), + ), + ), + FlowyIconButton( + hoverColor: theme.hover, + width: GridSize.typeOptionItemHeight, + onPressed: () { + context.read().add(GridPropertyEvent.setFieldVisibility(field.id, !field.visibility)); + }, + icon: checkmark.padding(all: 6), + ) + ], + ); + } + + FlowyButton _editFieldButton(AppTheme theme, BuildContext context) { + return FlowyButton( + text: FlowyText.medium(field.name, fontSize: 12), + hoverColor: theme.hover, + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + onTap: () { + FieldEditor( + gridId: gridId, + fieldContextLoader: FieldContextLoaderAdaptor(gridId: gridId, field: field), + ).show(context, anchorDirection: AnchorDirection.bottomRight); + }, + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart new file mode 100644 index 0000000000..05a72a5504 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart @@ -0,0 +1,173 @@ +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; +import 'package:app_flowy/workspace/application/grid/setting/setting_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; + +import 'grid_property.dart'; + +class GridSettingContext { + final String gridId; + final GridFieldCache fieldCache; + + GridSettingContext({ + required this.gridId, + required this.fieldCache, + }); +} + +class GridSettingList extends StatelessWidget { + final GridSettingContext settingContext; + final Function(GridSettingAction, GridSettingContext) onAction; + const GridSettingList({required this.settingContext, required this.onAction, Key? key}) : super(key: key); + + static void show(BuildContext context, GridSettingContext settingContext) { + final list = GridSettingList( + settingContext: settingContext, + onAction: (action, settingContext) { + switch (action) { + case GridSettingAction.filter: + break; + case GridSettingAction.sortBy: + break; + case GridSettingAction.properties: + GridPropertyList(gridId: settingContext.gridId, fieldCache: settingContext.fieldCache).show(context); + break; + } + }, + ); + + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: list, + constraints: BoxConstraints.loose(const Size(140, 400)), + ), + identifier: list.identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.bottomRight, + style: FlowyOverlayStyle(blur: false), + ); + } + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => GridSettingBloc(gridId: settingContext.gridId), + child: BlocListener( + listenWhen: (previous, current) => previous.selectedAction != current.selectedAction, + listener: (context, state) { + state.selectedAction.foldLeft(null, (_, action) { + FlowyOverlay.of(context).remove(identifier()); + onAction(action, settingContext); + }); + }, + child: BlocBuilder( + builder: (context, state) { + return _renderList(); + }, + ), + ), + ); + } + + String identifier() { + return toString(); + } + + Widget _renderList() { + final cells = GridSettingAction.values.map((action) { + return _SettingItem(action: action); + }).toList(); + + return SizedBox( + width: 140, + child: ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + itemCount: cells.length, + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + physics: StyledScrollPhysics(), + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ), + ); + } +} + +class _SettingItem extends StatelessWidget { + final GridSettingAction action; + + const _SettingItem({ + required this.action, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final isSelected = context + .read() + .state + .selectedAction + .foldLeft(false, (_, selectedAction) => selectedAction == action); + + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + isSelected: isSelected, + text: FlowyText.medium(action.title(), fontSize: 12, color: action.enable() ? null : theme.shader4), + hoverColor: theme.hover, + onTap: () { + context.read().add(GridSettingEvent.performAction(action)); + }, + leftIcon: svgWidget(action.iconName(), color: theme.iconColor), + ), + ); + } +} + +extension _GridSettingExtension on GridSettingAction { + String iconName() { + switch (this) { + case GridSettingAction.filter: + return 'grid/setting/filter'; + case GridSettingAction.sortBy: + return 'grid/setting/sort'; + case GridSettingAction.properties: + return 'grid/setting/properties'; + } + } + + String title() { + switch (this) { + case GridSettingAction.filter: + return LocaleKeys.grid_settings_filter.tr(); + case GridSettingAction.sortBy: + return LocaleKeys.grid_settings_sortBy.tr(); + case GridSettingAction.properties: + return LocaleKeys.grid_settings_Properties.tr(); + } + } + + bool enable() { + switch (this) { + case GridSettingAction.properties: + return true; + default: + return false; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart new file mode 100644 index 0000000000..8d25189163 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart @@ -0,0 +1,59 @@ +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/extension.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; + +import 'grid_setting.dart'; + +class GridToolbarContext { + final String gridId; + final GridFieldCache fieldCache; + GridToolbarContext({ + required this.gridId, + required this.fieldCache, + }); +} + +class GridToolbar extends StatelessWidget { + final GridToolbarContext toolbarContext; + const GridToolbar({required this.toolbarContext, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final settingContext = GridSettingContext( + gridId: toolbarContext.gridId, + fieldCache: toolbarContext.fieldCache, + ); + return SizedBox( + height: 40, + child: Row( + children: [ + SizedBox(width: GridSize.leadingHeaderPadding), + _SettingButton(settingContext: settingContext), + const Spacer(), + ], + ), + ); + } +} + +class _SettingButton extends StatelessWidget { + final GridSettingContext settingContext; + const _SettingButton({required this.settingContext, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyIconButton( + hoverColor: theme.hover, + width: 22, + onPressed: () => GridSettingList.show(context, settingContext), + icon: svgWidget("grid/setting/setting").padding(horizontal: 3, vertical: 3), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/menu.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/menu.dart index 2053432264..770889c610 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/menu.dart @@ -1,6 +1,5 @@ import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/startup/tasks/load_plugin.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/home/menu/menu.dart'; @@ -37,7 +36,7 @@ class MenuTrash extends StatelessWidget { child: Selector( selector: (ctx, notifier) => notifier.theme, builder: (ctx, theme, child) => - SizedBox(width: 16, height: 16, child: svg("home/trash", color: theme.iconColor)), + SizedBox(width: 16, height: 16, child: svgWidget("home/trash", color: theme.iconColor)), ), ), const HSpace(6), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart index 4ba52edfe1..2c9679d97d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart @@ -29,13 +29,13 @@ class TrashCell extends StatelessWidget { FlowyIconButton( width: 16, onPressed: onRestore, - icon: svg("editor/restore", color: theme.iconColor), + icon: svgWidget("editor/restore", color: theme.iconColor), ), const HSpace(20), FlowyIconButton( width: 16, onPressed: onDelete, - icon: svg("editor/delete", color: theme.iconColor), + icon: svgWidget("editor/delete", color: theme.iconColor), ), ], ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart index b0324a1138..324b676fc3 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart @@ -4,7 +4,6 @@ export "./src/trash_header.dart"; import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/startup/tasks/load_plugin.dart'; import 'package:app_flowy/workspace/application/trash/trash_bloc.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -49,16 +48,13 @@ class TrashPlugin extends Plugin { TrashPlugin({required PluginType pluginType}) : _pluginType = pluginType; @override - void dispose() {} + PluginDisplay get display => TrashPluginDisplay(); @override - PluginDisplay get pluginDisplay => TrashPluginDisplay(); + PluginId get id => "TrashStack"; @override - PluginId get pluginId => "TrashStack"; - - @override - PluginType get pluginType => _pluginType; + PluginType get ty => _pluginType; } class TrashPluginDisplay extends PluginDisplay { @@ -69,20 +65,20 @@ class TrashPluginDisplay extends PluginDisplay { Widget? get rightBarItem => null; @override - Widget buildWidget() => const TrashStackPage(key: ValueKey('TrashStackPage')); + Widget buildWidget() => const TrashPage(key: ValueKey('TrashPage')); @override List get navigationItems => [this]; } -class TrashStackPage extends StatefulWidget { - const TrashStackPage({Key? key}) : super(key: key); +class TrashPage extends StatefulWidget { + const TrashPage({Key? key}) : super(key: key); @override - State createState() => _TrashStackPageState(); + State createState() => _TrashPageState(); } -class _TrashStackPageState extends State { +class _TrashPageState extends State { final ScrollController _scrollController = ScrollController(); @override Widget build(BuildContext context) { @@ -150,7 +146,7 @@ class _TrashStackPageState extends State { size: const Size(102, 30), child: FlowyButton( text: FlowyText.medium(LocaleKeys.trash_restoreAll.tr(), fontSize: 12), - icon: svg('editor/restore', color: theme.iconColor), + leftIcon: svgWidget('editor/restore', color: theme.iconColor), hoverColor: theme.hover, onTap: () => context.read().add(const TrashEvent.restoreAll()), ), @@ -160,7 +156,7 @@ class _TrashStackPageState extends State { size: const Size(102, 30), child: FlowyButton( text: FlowyText.medium(LocaleKeys.trash_deleteAll.tr(), fontSize: 12), - icon: svg('editor/delete', color: theme.iconColor), + leftIcon: svgWidget('editor/delete', color: theme.iconColor), hoverColor: theme.hover, onTap: () => context.read().add(const TrashEvent.deleteAll()), ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart new file mode 100644 index 0000000000..7c1e819cc5 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart @@ -0,0 +1,74 @@ +import 'package:app_flowy/workspace/application/view/view_service.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ViewLeftBarItem extends StatefulWidget { + final View view; + + ViewLeftBarItem({required this.view, Key? key}) : super(key: ValueKey(view.hashCode)); + + @override + State createState() => _ViewLeftBarItemState(); +} + +class _ViewLeftBarItemState extends State { + final _controller = TextEditingController(); + final _focusNode = FocusNode(); + late ViewService serviceService; + + @override + void initState() { + serviceService = ViewService(/*view: widget.view*/); + _focusNode.addListener(_handleFocusChanged); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + _focusNode.removeListener(_handleFocusChanged); + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _controller.text = widget.view.name; + + final theme = context.watch(); + return IntrinsicWidth( + key: ValueKey(_controller.text), + child: TextField( + controller: _controller, + focusNode: _focusNode, + scrollPadding: EdgeInsets.zero, + decoration: const InputDecoration( + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + isDense: true, + ), + style: TextStyle( + color: theme.textColor, + fontSize: 14, + fontWeight: FontWeight.w500, + overflow: TextOverflow.ellipsis, + ), + // cursorColor: widget.cursorColor, + // obscureText: widget.enableObscure, + ), + ); + } + + void _handleFocusChanged() { + if (_controller.text.isEmpty) { + _controller.text = widget.view.name; + return; + } + + if (_controller.text != widget.view.name) { + serviceService.updateView(viewId: widget.view.id, name: _controller.text); + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/edit_pannel/edit_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/edit_pannel/edit_pannel.dart index b892a8e49d..f9e5e0e6b5 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/edit_pannel/edit_pannel.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/edit_pannel/edit_pannel.dart @@ -2,7 +2,6 @@ import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dar import 'package:app_flowy/workspace/application/edit_pannel/edit_context.dart'; import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/presentation/home/home_sizes.dart'; -import 'package:dartz/dartz.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/style_widget/bar_title.dart'; import 'package:flowy_infra_ui/style_widget/close_button.dart'; @@ -11,15 +10,13 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; class EditPannel extends StatelessWidget { - late final EditPannelContext editContext; + final EditPannelContext pannelContext; final VoidCallback onEndEdit; - EditPannel({ + const EditPannel({ Key? key, - required Option context, + required this.pannelContext, required this.onEndEdit, - }) : super(key: key) { - editContext = context.fold(() => const BlankEditPannelContext(), (c) => c); - } + }) : super(key: key); @override Widget build(BuildContext context) { @@ -34,7 +31,7 @@ class EditPannel extends StatelessWidget { children: [ EditPannelTopBar(onClose: () => onEndEdit()), Expanded( - child: editContext.child, + child: pannelContext.child, ), ], ); diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart index 2c28b88660..3309566eaf 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart @@ -112,7 +112,6 @@ class QuestionBubble extends StatelessWidget { }); }); actionList.show( - context, context, anchorDirection: AnchorDirection.topWithRightAligned, anchorOffset: const Offset(0, -10), @@ -131,7 +130,7 @@ class QuestionBubble extends StatelessWidget { } } -class QuestionBubbleActionSheet with ActionList implements FlowyOverlayDelegate { +class QuestionBubbleActionSheet with ActionList, FlowyOverlayDelegate { final Function(dartz.Option) onSelected; final _items = BubbleAction.values.map((action) => BubbleActionWrapper(action)).toList(); diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart index 61caa84c2f..cbcec14fee 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart @@ -24,8 +24,8 @@ abstract class ActionList { FlowyOverlayDelegate? get delegate; void show( - BuildContext buildContext, - BuildContext anchorContext, { + BuildContext buildContext, { + BuildContext? anchorContext, AnchorDirection anchorDirection = AnchorDirection.bottomRight, Offset? anchorOffset, }) { @@ -47,7 +47,7 @@ abstract class ActionList { identifier: identifier, itemCount: widgets.length, itemBuilder: (context, index) => widgets[index], - anchorContext: anchorContext, + anchorContext: anchorContext ?? buildContext, anchorDirection: anchorDirection, width: maxWidth, height: widgets.length * (itemHeight + ActionListSizes.padding * 2), @@ -85,30 +85,28 @@ class ActionCell extends StatelessWidget { final theme = context.watch(); return FlowyHover( - config: HoverDisplayConfig(hoverColor: theme.hover), - builder: (context, onHover) { - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () => onSelected(action), - child: SizedBox( - height: itemHeight, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (action.icon != null) action.icon!, - HSpace(ActionListSizes.itemHPadding), - FlowyText.medium( - action.name, - fontSize: 12, - ), - ], - ), - ).padding( - horizontal: ActionListSizes.padding, - vertical: ActionListSizes.padding, + style: HoverStyle(hoverColor: theme.hover), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => onSelected(action), + child: SizedBox( + height: itemHeight, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (action.icon != null) action.icon!, + HSpace(ActionListSizes.itemHPadding), + FlowyText.medium( + action.name, + fontSize: 12, + ), + ], ), - ); - }, + ).padding( + horizontal: ActionListSizes.padding, + vertical: ActionListSizes.padding, + ), + ), ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_window.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_window.dart index bea342747b..1803257672 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_window.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_window.dart @@ -22,10 +22,7 @@ class FlowyPoppuWindow extends StatelessWidget { }) async { final window = await getWindowInfo(); FlowyOverlay.of(context).insertWithRect( - widget: SizedBox.fromSize( - size: size, - child: FlowyPoppuWindow(child: child), - ), + widget: FlowyPoppuWindow(child: child), identifier: 'FlowyPoppuWindow', anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), anchorSize: window.frame.size, diff --git a/frontend/app_flowy/packages/flowy_infra/lib/image.dart b/frontend/app_flowy/packages/flowy_infra/lib/image.dart index 68bea3cd6d..e70c8b4bff 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/image.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/image.dart @@ -1,7 +1,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; -Widget svg(String name, {Color? color}) { +Widget svgWidget(String name, {Color? color}) { final Widget svg = SvgPicture.asset('assets/images/$name.svg', color: color); return svg; @@ -10,6 +10,6 @@ Widget svg(String name, {Color? color}) { Widget svgWithSize(String name, Size size) { return SizedBox.fromSize( size: size, - child: svg(name), + child: svgWidget(name), ); } diff --git a/frontend/app_flowy/packages/flowy_infra/lib/language.dart b/frontend/app_flowy/packages/flowy_infra/lib/language.dart index e6726c3dbc..5567f46b8b 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/language.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/language.dart @@ -32,6 +32,8 @@ String languageFromLocale(Locale locale) { return "Português"; case "ru": return "русский"; + case "tr": + return "Türkçe"; // If not found then the language code will be displayed default: diff --git a/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart b/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart index 0e0c6bc4cf..7eaf139f0c 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart @@ -1,10 +1,29 @@ import 'package:flutter/material.dart'; +abstract class Comparable { + bool compare(T? previous, T? current); +} + +class ObjectComparable extends Comparable { + @override + bool compare(T? previous, T? current) { + return previous == current; + } +} + class PublishNotifier extends ChangeNotifier { T? _value; + Comparable? comparable = ObjectComparable(); + + PublishNotifier({this.comparable}); set value(T newValue) { - if (_value != newValue) { + if (comparable != null) { + if (comparable!.compare(_value, newValue)) { + _value = newValue; + notifyListeners(); + } + } else { _value = newValue; notifyListeners(); } @@ -12,12 +31,18 @@ class PublishNotifier extends ChangeNotifier { T? get currentValue => _value; - void addPublishListener(void Function(T) callback) { + void addPublishListener(void Function(T) callback, {bool Function()? listenWhen}) { super.addListener( () { - if (_value != null) { - callback(_value!); + if (_value == null) { + return; } + + if (listenWhen != null && listenWhen() == false) { + return; + } + + callback(_value!); }, ); } diff --git a/frontend/app_flowy/packages/flowy_infra/pubspec.lock b/frontend/app_flowy/packages/flowy_infra/pubspec.lock index 4cfc4b3c40..256c2dac3a 100644 --- a/frontend/app_flowy/packages/flowy_infra/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_infra/pubspec.lock @@ -95,6 +95,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: @@ -176,7 +183,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" textstyle_extensions: dependency: "direct main" description: diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart index 84c2cddd82..91412df599 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart @@ -1,9 +1,9 @@ // ignore_for_file: unused_element -import 'package:dartz/dartz.dart' show Tuple3; +import 'dart:ui'; import 'package:flowy_infra_ui/src/flowy_overlay/layout.dart'; import 'package:flutter/material.dart'; -import 'dart:ui'; +export './overlay_container.dart'; /// Specifies how overlay are anchored to the SourceWidget enum AnchorDirection { @@ -73,7 +73,8 @@ TransitionBuilder overlayManagerBuilder() { } abstract class FlowyOverlayDelegate { - void didRemove(); + bool asBarrier() => false; + void didRemove() => {}; } class FlowyOverlay extends StatefulWidget { @@ -108,8 +109,20 @@ class FlowyOverlay extends StatefulWidget { FlowyOverlayState createState() => FlowyOverlayState(); } +class OverlayItem { + Widget widget; + String identifier; + FlowyOverlayDelegate? delegate; + + OverlayItem({ + required this.widget, + required this.identifier, + this.delegate, + }); +} + class FlowyOverlayState extends State { - List> _overlayList = []; + final List _overlayList = []; FlowyOverlayStyle style = FlowyOverlayStyle(); /// Insert a overlay widget which frame is set by the widget, not the component. @@ -179,17 +192,37 @@ class FlowyOverlayState extends State { void remove(String identifier) { setState(() { - final index = _overlayList.indexWhere((ele) => ele.value2 == identifier); - _overlayList.removeAt(index).value3?.didRemove(); + final index = _overlayList.indexWhere((item) => item.identifier == identifier); + if (index != -1) { + _overlayList.removeAt(index).delegate?.didRemove(); + } }); } void removeAll() { setState(() { - for (var ele in _overlayList.reversed) { - ele.value3?.didRemove(); + if (_overlayList.isEmpty) { + return; + } + + final reveredList = _overlayList.reversed.toList(); + final firstItem = reveredList.removeAt(0); + _overlayList.remove(firstItem); + if (firstItem.delegate != null) { + firstItem.delegate!.didRemove(); + if (firstItem.delegate!.asBarrier()) { + return; + } + } + + for (final element in reveredList) { + if (element.delegate?.asBarrier() ?? false) { + return; + } else { + element.delegate?.didRemove(); + _overlayList.remove(element); + } } - _overlayList = []; }); } @@ -248,15 +281,63 @@ class FlowyOverlayState extends State { } setState(() { - _overlayList.add(Tuple3(overlay, identifier, delegate)); + _overlayList.add(OverlayItem( + widget: overlay, + identifier: identifier, + delegate: delegate, + )); }); } @override Widget build(BuildContext context) { - final overlays = _overlayList.map((ele) => ele.value1); - List children = [widget.child]; + final overlays = _overlayList.map((item) { + var widget = item.widget; + if (item.delegate?.asBarrier() ?? false) { + widget = Container( + color: style.barrierColor, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: _handleTapOnBackground, + child: widget, + ), + ); + } + return widget; + }).toList(); + List children = [widget.child]; + Widget? child = _renderBackground(overlays); + if (child != null) { + children.add(child); + } + + // Try to fix there is no overlay for editabletext widget. e.g. TextField. + // // Check out the TextSelectionOverlay class in text_selection.dart. + // // ... + // // final OverlayState? overlay = Overlay.of(context, rootOverlay: true); + // // assert( + // // overlay != null, + // // 'No Overlay widget exists above $context.\n' + // // 'Usually the Navigator created by WidgetsApp provides the overlay. Perhaps your ' + // // 'app content was created above the Navigator with the WidgetsApp builder parameter.', + // // ); + // // ... + + return MaterialApp( + theme: Theme.of(context), + debugShowCheckedModeBanner: false, + home: Stack( + children: children..addAll(overlays), + ), + ); + } + + void _handleTapOnBackground() { + removeAll(); + } + + Widget? _renderBackground(List overlays) { Widget? child; if (overlays.isNotEmpty) { child = Container( @@ -274,17 +355,6 @@ class FlowyOverlayState extends State { ); } } - - if (child != null) { - children.add(child); - } - - return Stack( - children: children..addAll(overlays), - ); - } - - void _handleTapOnBackground() { - removeAll(); + return child; } } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart index 862f47b662..16d3b55f47 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart @@ -1,8 +1,5 @@ import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; -import 'package:flowy_infra_ui/style_widget/decoration.dart'; import 'package:flutter/material.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:provider/provider.dart'; class ListOverlayFooter { Widget widget; @@ -35,36 +32,29 @@ class ListOverlay extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = context.watch(); const padding = EdgeInsets.symmetric(horizontal: 6, vertical: 6); double totalHeight = height + padding.vertical; if (footer != null) { totalHeight = totalHeight + footer!.height + footer!.padding.vertical; } - return Material( - type: MaterialType.transparency, - child: Container( - decoration: FlowyDecoration.decoration(theme.surface, theme.shadowColor.withOpacity(0.1)), - constraints: BoxConstraints.tight(Size(width, totalHeight)), - child: Padding( - padding: padding, - child: Column( - children: [ - ListView.builder( - shrinkWrap: true, - itemBuilder: itemBuilder, - itemCount: itemCount, - controller: controller, - ), - if (footer != null) - Padding( - padding: footer!.padding, - child: footer!.widget, - ), - ], + return OverlayContainer( + constraints: BoxConstraints.tight(Size(width, totalHeight)), + padding: padding, + child: Column( + children: [ + ListView.builder( + shrinkWrap: true, + itemBuilder: itemBuilder, + itemCount: itemCount, + controller: controller, ), - ), + if (footer != null) + Padding( + padding: footer!.padding, + child: footer!.widget, + ), + ], ), ); } @@ -103,38 +93,4 @@ class ListOverlay extends StatelessWidget { style: style, ); } - - static void showWithRect( - BuildContext context, { - required BuildContext anchorContext, - required String identifier, - required IndexedWidgetBuilder itemBuilder, - int? itemCount, - ScrollController? controller, - double maxWidth = double.infinity, - double maxHeight = double.infinity, - required Offset anchorPosition, - required Size anchorSize, - AnchorDirection? anchorDirection, - FlowyOverlayDelegate? delegate, - OverlapBehaviour? overlapBehaviour, - FlowyOverlayStyle? style, - }) { - FlowyOverlay.of(context).insertWithRect( - widget: ListOverlay( - itemBuilder: itemBuilder, - itemCount: itemCount, - controller: controller, - width: maxWidth, - height: maxHeight, - ), - identifier: identifier, - anchorPosition: anchorPosition, - anchorSize: anchorSize, - anchorDirection: anchorDirection, - delegate: delegate, - overlapBehaviour: overlapBehaviour, - style: style, - ); - } } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart new file mode 100644 index 0000000000..85de2c71a7 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart @@ -0,0 +1,32 @@ +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/decoration.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +const overlayContainerPadding = EdgeInsets.all(12); + +class OverlayContainer extends StatelessWidget { + final Widget child; + final BoxConstraints? constraints; + final EdgeInsets padding; + const OverlayContainer({ + required this.child, + this.constraints, + this.padding = overlayContainerPadding, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return Material( + type: MaterialType.transparency, + child: Container( + padding: padding, + decoration: FlowyDecoration.decoration(theme.surface, theme.shadowColor.withOpacity(0.15)), + constraints: constraints, + child: child, + ), + ); + } +} diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart index 6b67081ca2..8249bc115b 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart @@ -8,15 +8,19 @@ class FlowyButton extends StatelessWidget { final Widget text; final VoidCallback? onTap; final EdgeInsets padding; - final Widget? icon; + final Widget? leftIcon; + final Widget? rightIcon; final Color hoverColor; + final bool isSelected; const FlowyButton({ Key? key, required this.text, this.onTap, - this.padding = const EdgeInsets.symmetric(horizontal: 3, vertical: 2), - this.icon, + this.padding = const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + this.leftIcon, + this.rightIcon, this.hoverColor = Colors.transparent, + this.isSelected = false, }) : super(key: key); @override @@ -24,7 +28,8 @@ class FlowyButton extends StatelessWidget { return InkWell( onTap: onTap, child: FlowyHover( - config: HoverDisplayConfig(borderRadius: Corners.s6Border, hoverColor: hoverColor), + style: HoverStyle(borderRadius: Corners.s6Border, hoverColor: hoverColor), + setSelected: () => isSelected, builder: (context, onHover) => _render(), ), ); @@ -33,16 +38,22 @@ class FlowyButton extends StatelessWidget { Widget _render() { List children = List.empty(growable: true); - if (icon != null) { - children.add(SizedBox.fromSize(size: const Size.square(16), child: icon!)); + if (leftIcon != null) { + children.add(SizedBox.fromSize(size: const Size.square(16), child: leftIcon!)); children.add(const HSpace(6)); } - children.add(Align(child: text)); + children.add(Expanded(child: text)); + + if (rightIcon != null) { + children.add(SizedBox.fromSize(size: const Size.square(16), child: rightIcon!)); + } return Padding( padding: padding, child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: children, ), ); diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart index a85867e456..5189908192 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart @@ -1,21 +1,24 @@ import 'package:flutter/material.dart'; // ignore: unused_import import 'package:flowy_infra/time/duration.dart'; +import 'package:flowy_infra/size.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:provider/provider.dart'; typedef HoverBuilder = Widget Function(BuildContext context, bool onHover); -typedef IsOnSelected = bool Function(); - class FlowyHover extends StatefulWidget { - final HoverDisplayConfig config; - final HoverBuilder builder; - final IsOnSelected? isOnSelected; + final HoverStyle style; + final HoverBuilder? builder; + final Widget? child; + final bool Function()? setSelected; const FlowyHover({ Key? key, - required this.builder, - required this.config, - this.isOnSelected, + this.builder, + this.child, + required this.style, + this.setSelected, }) : super(key: key); @override @@ -29,70 +32,180 @@ class _FlowyHoverState extends State { Widget build(BuildContext context) { return MouseRegion( cursor: SystemMouseCursors.click, - onEnter: (p) => setOnHover(true), - onExit: (p) => setOnHover(false), - child: render(), + opaque: false, + onEnter: (p) => setState(() => _onHover = true), + onExit: (p) => setState(() => _onHover = false), + child: renderWidget(), ); } - void setOnHover(bool value) => setState(() => _onHover = value); - - Widget render() { + Widget renderWidget() { var showHover = _onHover; - - if (showHover == false && widget.isOnSelected != null) { - showHover = widget.isOnSelected!(); + if (!showHover && widget.setSelected != null) { + showHover = widget.setSelected!(); } + final child = widget.child ?? widget.builder!(context, _onHover); if (showHover) { - return FlowyHoverBackground( - config: widget.config, - child: widget.builder(context, _onHover), + return FlowyHoverContainer( + style: widget.style, + child: child, ); } else { - return widget.builder(context, _onHover); + return child; } } } -class HoverDisplayConfig { +class HoverStyle { final Color borderColor; final double borderWidth; final Color hoverColor; final BorderRadius borderRadius; + final EdgeInsets contentMargin; - const HoverDisplayConfig( + const HoverStyle( {this.borderColor = Colors.transparent, this.borderWidth = 0, this.borderRadius = const BorderRadius.all(Radius.circular(6)), + this.contentMargin = EdgeInsets.zero, required this.hoverColor}); } -class FlowyHoverBackground extends StatelessWidget { - final HoverDisplayConfig config; +class FlowyHoverContainer extends StatelessWidget { + final HoverStyle style; + final Widget? child; - final Widget child; - - const FlowyHoverBackground({ + const FlowyHoverContainer({ Key? key, - required this.child, - required this.config, + this.child, + required this.style, }) : super(key: key); @override Widget build(BuildContext context) { final hoverBorder = Border.all( - color: config.borderColor, - width: config.borderWidth, + color: style.borderColor, + width: style.borderWidth, ); return Container( + margin: style.contentMargin, decoration: BoxDecoration( border: hoverBorder, - color: config.hoverColor, - borderRadius: config.borderRadius, + color: style.hoverColor, + borderRadius: style.borderRadius, ), child: child, ); } } + +// +abstract class HoverWidget extends StatefulWidget { + const HoverWidget({Key? key}) : super(key: key); + + ValueNotifier get onFocus; +} + +class FlowyHover2 extends StatefulWidget { + final HoverWidget child; + final EdgeInsets contentPadding; + const FlowyHover2({ + required this.child, + this.contentPadding = EdgeInsets.zero, + Key? key, + }) : super(key: key); + + @override + State createState() => _FlowyHover2State(); +} + +class _FlowyHover2State extends State { + late FlowyHoverState _hoverState; + + @override + void initState() { + _hoverState = FlowyHoverState(); + widget.child.onFocus.addListener(() { + _hoverState.onFocus = widget.child.onFocus.value; + }); + super.initState(); + } + + @override + void dispose() { + _hoverState.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _hoverState, + child: MouseRegion( + cursor: SystemMouseCursors.click, + opaque: false, + onEnter: (p) => setState(() => _hoverState.onHover = true), + onExit: (p) => setState(() => _hoverState.onHover = false), + child: Stack( + fit: StackFit.loose, + alignment: AlignmentDirectional.center, + children: [ + const _HoverBackground(), + Padding( + padding: widget.contentPadding, + child: widget.child, + ), + ], + ), + ), + ); + } +} + +class _HoverBackground extends StatelessWidget { + const _HoverBackground({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return Consumer( + builder: (context, state, child) { + if (state.onHover || state.onFocus) { + return FlowyHoverContainer( + style: HoverStyle( + borderRadius: Corners.s6Border, + hoverColor: theme.shader6, + ), + ); + } else { + return const SizedBox(); + } + }, + ); + } +} + +class FlowyHoverState extends ChangeNotifier { + bool _onHover = false; + bool _onFocus = false; + + set onHover(bool value) { + if (_onHover != value) { + _onHover = value; + notifyListeners(); + } + } + + bool get onHover => _onHover; + + set onFocus(bool value) { + if (_onFocus != value) { + _onFocus = value; + notifyListeners(); + } + } + + bool get onFocus => _onFocus; +} diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/icon_button.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/icon_button.dart index 79e9c648ea..f3ecd23005 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/icon_button.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/icon_button.dart @@ -77,7 +77,7 @@ class FlowyDropdownButton extends StatelessWidget { return FlowyIconButton( width: 16, onPressed: onPressed, - icon: svg("home/drop_down_show"), + icon: svgWidget("home/drop_down_show"), ); } } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart index 3df1fea4c7..da316685dd 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart @@ -63,34 +63,32 @@ class _StyledSingleChildScrollViewState extends State slivers; + final double barSize; const StyledCustomScrollView({ Key? key, - this.contentSize, this.axis = Axis.vertical, this.trackColor, this.handleColor, - this.controller, + this.verticalController, this.slivers = const [], + this.barSize = 12, }) : super(key: key); @override @@ -98,17 +96,17 @@ class StyledCustomScrollView extends StatefulWidget { } class _StyledCustomScrollViewState extends State { - late ScrollController scrollController; + late ScrollController controller; @override void initState() { - scrollController = widget.controller ?? ScrollController(); + controller = widget.verticalController ?? ScrollController(); + super.initState(); } @override void dispose() { - scrollController.dispose(); super.dispose(); } @@ -122,19 +120,23 @@ class _StyledCustomScrollViewState extends State { @override Widget build(BuildContext context) { - return ScrollbarListStack( - contentSize: widget.contentSize, - axis: widget.axis, - controller: scrollController, - barSize: 12, - trackColor: widget.trackColor, - handleColor: widget.handleColor, + var child = ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(scrollbars: false), child: CustomScrollView( scrollDirection: widget.axis, physics: StyledScrollPhysics(), - controller: scrollController, + controller: controller, slivers: widget.slivers, ), ); + + return ScrollbarListStack( + axis: widget.axis, + controller: controller, + barSize: widget.barSize, + trackColor: widget.trackColor, + handleColor: widget.handleColor, + child: child, + ); } } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart index 243cf37b7a..55f29eba93 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart @@ -1,5 +1,5 @@ import 'package:flowy_infra/theme.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class FlowyText extends StatelessWidget { @@ -42,8 +42,9 @@ class FlowyText extends StatelessWidget { return Text(title, overflow: overflow, softWrap: false, + textAlign: textAlign, style: TextStyle( - color: theme.textColor, + color: color ?? theme.textColor, fontWeight: fontWeight, fontSize: fontSize + 2, fontFamily: 'Mulish', diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart index e6e9684854..19b3accc59 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart @@ -1,85 +1,118 @@ import 'package:flowy_infra/size.dart'; import 'package:flowy_infra_ui/widget/rounded_button.dart'; -import 'package:flowy_infra_ui/widget/text_field_container.dart'; import 'package:flutter/material.dart'; import 'package:flowy_infra/time/duration.dart'; -// ignore: must_be_immutable class RoundedInputField extends StatefulWidget { final String? hintText; - final IconData? icon; final bool obscureText; final Widget? obscureIcon; final Widget? obscureHideIcon; final Color normalBorderColor; - final Color highlightBorderColor; + final Color errorBorderColor; final Color cursorColor; + final Color? focusBorderColor; final String errorText; final TextStyle style; final ValueChanged? onChanged; + final VoidCallback? onEditingComplete; final String? initialValue; - late bool enableObscure; - var _text = ""; + final EdgeInsets margin; + final EdgeInsets padding; + final EdgeInsets contentPadding; + final double height; + final FocusNode? focusNode; + final TextEditingController? controller; + final bool autoFocus; - RoundedInputField({ + const RoundedInputField({ Key? key, this.hintText, this.errorText = "", this.initialValue, - this.icon, this.obscureText = false, this.obscureIcon, this.obscureHideIcon, this.onChanged, + this.onEditingComplete, this.normalBorderColor = Colors.transparent, - this.highlightBorderColor = Colors.transparent, + this.errorBorderColor = Colors.transparent, + this.focusBorderColor, this.cursorColor = Colors.black, this.style = const TextStyle(fontSize: 20, fontWeight: FontWeight.w500), - }) : super(key: key) { - enableObscure = obscureText; - } + this.margin = EdgeInsets.zero, + this.padding = EdgeInsets.zero, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 10), + this.height = 48, + this.focusNode, + this.controller, + this.autoFocus = false, + }) : super(key: key); @override State createState() => _RoundedInputFieldState(); } class _RoundedInputFieldState extends State { + String inputText = ""; + bool obscuteText = false; + + @override + void initState() { + obscuteText = widget.obscureText; + super.initState(); + } + @override Widget build(BuildContext context) { - final Icon? newIcon = widget.icon == null - ? null - : Icon( - widget.icon!, - color: const Color(0xFF6F35A5), - ); - var borderColor = widget.normalBorderColor; + var focusBorderColor = widget.focusBorderColor ?? borderColor; + if (widget.errorText.isNotEmpty) { - borderColor = widget.highlightBorderColor; + borderColor = widget.errorBorderColor; + focusBorderColor = borderColor; } List children = [ - TextFieldContainer( - height: 48, - borderRadius: Corners.s10Border, - borderColor: borderColor, + Container( + margin: widget.margin, + padding: widget.padding, + height: widget.height, child: TextFormField( + controller: widget.controller, initialValue: widget.initialValue, + focusNode: widget.focusNode, + autofocus: widget.autoFocus, onChanged: (value) { - widget._text = value; + inputText = value; if (widget.onChanged != null) { widget.onChanged!(value); } setState(() {}); }, + onEditingComplete: widget.onEditingComplete, cursorColor: widget.cursorColor, - obscureText: widget.enableObscure, + obscureText: obscuteText, + style: widget.style, decoration: InputDecoration( - icon: newIcon, + contentPadding: widget.contentPadding, hintText: widget.hintText, hintStyle: TextStyle(color: widget.normalBorderColor), - border: InputBorder.none, - suffixIcon: suffixIcon(), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: borderColor, + width: 1.0, + ), + borderRadius: Corners.s10Border, + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: focusBorderColor, + width: 1.0, + ), + borderRadius: Corners.s10Border, + ), + suffixIcon: obscureIcon(), ), ), ), @@ -100,39 +133,32 @@ class _RoundedInputFieldState extends State { return AnimatedSize( duration: .4.seconds, curve: Curves.easeInOut, - child: Column( - children: children, - ), + child: Column(children: children), ); } - Widget? suffixIcon() { + Widget? obscureIcon() { if (widget.obscureText == false) { return null; } - if (widget._text.isEmpty) { - return SizedBox.fromSize(size: const Size.square(16)); + const double iconWidth = 16; + if (inputText.isEmpty) { + return SizedBox.fromSize(size: const Size.square(iconWidth)); } + assert(widget.obscureIcon != null && widget.obscureHideIcon != null); Widget? icon; - if (widget.obscureText == true) { - assert(widget.obscureIcon != null && widget.obscureHideIcon != null); - if (widget.enableObscure) { - icon = widget.obscureIcon!; - } else { - icon = widget.obscureHideIcon!; - } - } - - if (icon == null) { - return null; + if (obscuteText) { + icon = widget.obscureIcon!; + } else { + icon = widget.obscureHideIcon!; } return RoundedImageButton( - size: 16, + size: iconWidth, press: () { - widget.enableObscure = !widget.enableObscure; + obscuteText = !obscuteText; setState(() {}); }, child: icon, diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart deleted file mode 100644 index 7c1bf131a1..0000000000 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/text_field_container.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -class TextFieldContainer extends StatelessWidget { - final Widget child; - final BorderRadius borderRadius; - final Color borderColor; - final double? height; - final double? width; - const TextFieldContainer({ - Key? key, - required this.child, - this.borderRadius = BorderRadius.zero, - this.borderColor = Colors.white, - this.height, - this.width, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.symmetric(vertical: 10), - padding: const EdgeInsets.symmetric(horizontal: 15), - height: height, - width: width, - decoration: BoxDecoration( - border: Border.all(color: borderColor), - color: Colors.white, - borderRadius: borderRadius, - ), - child: Align(alignment: Alignment.center, child: child), - ); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('child', child)); - } -} diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-folder/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-folder/dart_event.dart index 99d6d56d89..48549a5f28 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-folder/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-folder/dart_event.dart @@ -267,18 +267,18 @@ class FolderEventCopyLink { } } -class FolderEventOpenView { +class FolderEventSetLatestView { ViewId request; - FolderEventOpenView(this.request); + FolderEventSetLatestView(this.request); - Future> send() { + Future> send() { final request = FFIRequest.create() - ..event = FolderEvent.OpenView.toString() + ..event = FolderEvent.SetLatestView.toString() ..payload = requestToBytes(this.request); return Dispatch.asyncRequest(request) .then((bytesResult) => bytesResult.fold( - (okBytes) => left(BlockDelta.fromBuffer(okBytes)), + (bytes) => left(unit), (errBytes) => right(FlowyError.fromBuffer(errBytes)), )); } @@ -377,37 +377,3 @@ class FolderEventDeleteAllTrash { } } -class FolderEventApplyDocDelta { - BlockDelta request; - FolderEventApplyDocDelta(this.request); - - Future> send() { - final request = FFIRequest.create() - ..event = FolderEvent.ApplyDocDelta.toString() - ..payload = requestToBytes(this.request); - - return Dispatch.asyncRequest(request) - .then((bytesResult) => bytesResult.fold( - (okBytes) => left(BlockDelta.fromBuffer(okBytes)), - (errBytes) => right(FlowyError.fromBuffer(errBytes)), - )); - } -} - -class FolderEventExportDocument { - ExportPayload request; - FolderEventExportDocument(this.request); - - Future> send() { - final request = FFIRequest.create() - ..event = FolderEvent.ExportDocument.toString() - ..payload = requestToBytes(this.request); - - return Dispatch.asyncRequest(request) - .then((bytesResult) => bytesResult.fold( - (okBytes) => left(ExportData.fromBuffer(okBytes)), - (errBytes) => right(FlowyError.fromBuffer(errBytes)), - )); - } -} - diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart new file mode 100644 index 0000000000..9f87c2ad26 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -0,0 +1,343 @@ + +/// Auto generate. Do not edit +part of '../../dispatch.dart'; +class GridEventGetGridData { + GridId request; + GridEventGetGridData(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetGridData.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(Grid.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventGetGridBlocks { + QueryGridBlocksPayload request; + GridEventGetGridBlocks(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetGridBlocks.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(RepeatedGridBlock.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventGetFields { + QueryFieldPayload request; + GridEventGetFields(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetFields.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(RepeatedField.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventUpdateField { + FieldChangesetPayload request; + GridEventUpdateField(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.UpdateField.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventInsertField { + InsertFieldPayload request; + GridEventInsertField(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.InsertField.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventDeleteField { + FieldIdentifierPayload request; + GridEventDeleteField(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.DeleteField.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventSwitchToField { + EditFieldPayload request; + GridEventSwitchToField(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.SwitchToField.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(EditFieldContext.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventDuplicateField { + FieldIdentifierPayload request; + GridEventDuplicateField(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.DuplicateField.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventGetEditFieldContext { + GetEditFieldContextPayload request; + GridEventGetEditFieldContext(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetEditFieldContext.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(EditFieldContext.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventMoveItem { + MoveItemPayload request; + GridEventMoveItem(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.MoveItem.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventNewSelectOption { + CreateSelectOptionPayload request; + GridEventNewSelectOption(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.NewSelectOption.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(SelectOption.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventGetSelectOptionContext { + CellIdentifierPayload request; + GridEventGetSelectOptionContext(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetSelectOptionContext.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(SelectOptionContext.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventUpdateSelectOption { + SelectOptionChangesetPayload request; + GridEventUpdateSelectOption(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.UpdateSelectOption.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventCreateRow { + CreateRowPayload request; + GridEventCreateRow(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.CreateRow.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(Row.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventGetRow { + RowIdentifierPayload request; + GridEventGetRow(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetRow.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(Row.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventDeleteRow { + RowIdentifierPayload request; + GridEventDeleteRow(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.DeleteRow.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventDuplicateRow { + RowIdentifierPayload request; + GridEventDuplicateRow(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.DuplicateRow.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventGetCell { + CellIdentifierPayload request; + GridEventGetCell(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetCell.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(Cell.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventUpdateCell { + CellChangeset request; + GridEventUpdateCell(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.UpdateCell.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventUpdateCellSelectOption { + SelectOptionCellChangesetPayload request; + GridEventUpdateCellSelectOption(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.UpdateCellSelectOption.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-text-block/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-text-block/dart_event.dart new file mode 100644 index 0000000000..6785a1c681 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-text-block/dart_event.dart @@ -0,0 +1,54 @@ + +/// Auto generate. Do not edit +part of '../../dispatch.dart'; +class BlockEventGetBlockData { + TextBlockId request; + BlockEventGetBlockData(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = BlockEvent.GetBlockData.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(TextBlockDelta.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class BlockEventApplyDelta { + TextBlockDelta request; + BlockEventApplyDelta(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = BlockEvent.ApplyDelta.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(TextBlockDelta.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class BlockEventExportDocument { + ExportPayload request; + BlockEventExportDocument(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = BlockEvent.ExportDocument.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(ExportData.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart index 8c65b29b9b..db010e9f75 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart @@ -3,12 +3,16 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/log.dart'; // ignore: unnecessary_import import 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-collaboration/document_info.pb.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/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-net/event.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/event_map.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/event_map.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/event_map.pb.dart'; import 'package:isolates/isolates.dart'; import 'package:isolates/ports.dart'; import 'package:ffi/ffi.dart'; @@ -20,7 +24,9 @@ import 'package:flowy_sdk/ffi.dart' as ffi; import 'package:flowy_sdk/protobuf/flowy-user-data-model/protobuf.dart'; import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/protobuf.dart'; -import 'package:flowy_sdk/protobuf/flowy-collaboration/protobuf.dart'; +import 'package:flowy_sdk/protobuf/flowy-text-block/protobuf.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart'; +import 'package:flowy_sdk/protobuf/flowy-sync/protobuf.dart'; // ignore: unused_import import 'package:protobuf/protobuf.dart'; @@ -30,6 +36,8 @@ import 'error.dart'; part 'dart_event/flowy-folder/dart_event.dart'; part 'dart_event/flowy-net/dart_event.dart'; part 'dart_event/flowy-user/dart_event.dart'; +part 'dart_event/flowy-grid/dart_event.dart'; +part 'dart_event/flowy-text-block/dart_event.dart'; enum FFIException { RequestIsEmpty, diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart b/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart index 798c33b318..0ade770a23 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/ffi.dart @@ -16,8 +16,8 @@ DynamicLibrary _open() { final prefix = "${Directory.current.path}/.sandbox"; if (Platform.isLinux) return DynamicLibrary.open('${prefix}/libdart_ffi.so'); if (Platform.isAndroid) return DynamicLibrary.open('${prefix}/libdart_ffi.so'); - if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.dylib'); - if (Platform.isIOS) return DynamicLibrary.open('${prefix}/libdart_ffi.dylib'); + if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.a'); + if (Platform.isIOS) return DynamicLibrary.open('${prefix}/libdart_ffi.a'); if (Platform.isWindows) return DynamicLibrary.open('${prefix}/dart_ffi.dll'); } else { if (Platform.isLinux) return DynamicLibrary.open('libdart_ffi.so'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pb.dart similarity index 98% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pb.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pb.dart index c90de870dd..bcd8d6051a 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pb.dart @@ -1,6 +1,6 @@ /// // Generated code. Do not modify. -// source: share.proto +// source: entities.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields @@ -9,9 +9,9 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; -import 'share.pbenum.dart'; +import 'entities.pbenum.dart'; -export 'share.pbenum.dart'; +export 'entities.pbenum.dart'; class ExportPayload extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ExportPayload', createEmptyInstance: create) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbenum.dart similarity index 97% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbenum.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbenum.dart index aa1d037ab7..f5413e61f2 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbenum.dart @@ -1,6 +1,6 @@ /// // Generated code. Do not modify. -// source: share.proto +// source: entities.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbjson.dart similarity index 98% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbjson.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbjson.dart index 8224855b02..4935602b83 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbjson.dart @@ -1,6 +1,6 @@ /// // Generated code. Do not modify. -// source: share.proto +// source: entities.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbserver.dart similarity index 85% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbserver.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbserver.dart index 18b02b9216..88741cd6c2 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbserver.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/entities.pbserver.dart @@ -1,9 +1,9 @@ /// // Generated code. Do not modify. -// source: errors.proto +// source: entities.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package -export 'errors.pb.dart'; +export 'entities.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pb.dart similarity index 83% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pb.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pb.dart index f2ec97799a..5bfad20674 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pb.dart @@ -1,11 +1,11 @@ /// // Generated code. Do not modify. -// source: errors.proto +// source: event_map.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields import 'dart:core' as $core; -export 'errors.pbenum.dart'; +export 'event_map.pbenum.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbenum.dart new file mode 100644 index 0000000000..d88c52395c --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbenum.dart @@ -0,0 +1,28 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class BlockEvent extends $pb.ProtobufEnum { + static const BlockEvent GetBlockData = BlockEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetBlockData'); + static const BlockEvent ApplyDelta = BlockEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplyDelta'); + static const BlockEvent ExportDocument = BlockEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ExportDocument'); + + static const $core.List values = [ + GetBlockData, + ApplyDelta, + ExportDocument, + ]; + + static final $core.Map<$core.int, BlockEvent> _byValue = $pb.ProtobufEnum.initByValue(values); + static BlockEvent? valueOf($core.int value) => _byValue[value]; + + const BlockEvent._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbjson.dart new file mode 100644 index 0000000000..ac0f243e6f --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbjson.dart @@ -0,0 +1,22 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use blockEventDescriptor instead') +const BlockEvent$json = const { + '1': 'BlockEvent', + '2': const [ + const {'1': 'GetBlockData', '2': 0}, + const {'1': 'ApplyDelta', '2': 1}, + const {'1': 'ExportDocument', '2': 2}, + ], +}; + +/// Descriptor for `BlockEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List blockEventDescriptor = $convert.base64Decode('CgpCbG9ja0V2ZW50EhAKDEdldEJsb2NrRGF0YRAAEg4KCkFwcGx5RGVsdGEQARISCg5FeHBvcnREb2N1bWVudBAC'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbserver.dart similarity index 83% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbserver.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbserver.dart index b619f42f96..e359d1146c 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbserver.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/event_map.pbserver.dart @@ -1,9 +1,9 @@ /// // Generated code. Do not modify. -// source: document_info.proto +// source: event_map.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package -export 'document_info.pb.dart'; +export 'event_map.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/protobuf.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/protobuf.dart new file mode 100644 index 0000000000..a2db1d12ab --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-block/protobuf.dart @@ -0,0 +1,3 @@ +// Auto-generated, do not edit +export './entities.pb.dart'; +export './event_map.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbjson.dart deleted file mode 100644 index d25e3b92b4..0000000000 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbjson.dart +++ /dev/null @@ -1,78 +0,0 @@ -/// -// Generated code. Do not modify. -// source: document_info.proto -// -// @dart = 2.12 -// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package - -import 'dart:core' as $core; -import 'dart:convert' as $convert; -import 'dart:typed_data' as $typed_data; -@$core.Deprecated('Use createBlockParamsDescriptor instead') -const CreateBlockParams$json = const { - '1': 'CreateBlockParams', - '2': const [ - const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, - const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'}, - ], -}; - -/// Descriptor for `CreateBlockParams`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List createBlockParamsDescriptor = $convert.base64Decode('ChFDcmVhdGVCbG9ja1BhcmFtcxIOCgJpZBgBIAEoCVICaWQSLwoJcmV2aXNpb25zGAIgASgLMhEuUmVwZWF0ZWRSZXZpc2lvblIJcmV2aXNpb25z'); -@$core.Deprecated('Use blockInfoDescriptor instead') -const BlockInfo$json = const { - '1': 'BlockInfo', - '2': const [ - const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'}, - const {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'}, - const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'}, - const {'1': 'base_rev_id', '3': 4, '4': 1, '5': 3, '10': 'baseRevId'}, - ], -}; - -/// Descriptor for `BlockInfo`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List blockInfoDescriptor = $convert.base64Decode('CglCbG9ja0luZm8SFQoGZG9jX2lkGAEgASgJUgVkb2NJZBISCgR0ZXh0GAIgASgJUgR0ZXh0EhUKBnJldl9pZBgDIAEoA1IFcmV2SWQSHgoLYmFzZV9yZXZfaWQYBCABKANSCWJhc2VSZXZJZA=='); -@$core.Deprecated('Use resetDocumentParamsDescriptor instead') -const ResetDocumentParams$json = const { - '1': 'ResetDocumentParams', - '2': const [ - const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'}, - const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'}, - ], -}; - -/// Descriptor for `ResetDocumentParams`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List resetDocumentParamsDescriptor = $convert.base64Decode('ChNSZXNldERvY3VtZW50UGFyYW1zEhUKBmRvY19pZBgBIAEoCVIFZG9jSWQSLwoJcmV2aXNpb25zGAIgASgLMhEuUmVwZWF0ZWRSZXZpc2lvblIJcmV2aXNpb25z'); -@$core.Deprecated('Use blockDeltaDescriptor instead') -const BlockDelta$json = const { - '1': 'BlockDelta', - '2': const [ - const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, - const {'1': 'delta_json', '3': 2, '4': 1, '5': 9, '10': 'deltaJson'}, - ], -}; - -/// Descriptor for `BlockDelta`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List blockDeltaDescriptor = $convert.base64Decode('CgpCbG9ja0RlbHRhEhkKCGJsb2NrX2lkGAEgASgJUgdibG9ja0lkEh0KCmRlbHRhX2pzb24YAiABKAlSCWRlbHRhSnNvbg=='); -@$core.Deprecated('Use newDocUserDescriptor instead') -const NewDocUser$json = const { - '1': 'NewDocUser', - '2': const [ - const {'1': 'user_id', '3': 1, '4': 1, '5': 9, '10': 'userId'}, - const {'1': 'rev_id', '3': 2, '4': 1, '5': 3, '10': 'revId'}, - const {'1': 'doc_id', '3': 3, '4': 1, '5': 9, '10': 'docId'}, - ], -}; - -/// Descriptor for `NewDocUser`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List newDocUserDescriptor = $convert.base64Decode('CgpOZXdEb2NVc2VyEhcKB3VzZXJfaWQYASABKAlSBnVzZXJJZBIVCgZyZXZfaWQYAiABKANSBXJldklkEhUKBmRvY19pZBgDIAEoCVIFZG9jSWQ='); -@$core.Deprecated('Use blockIdDescriptor instead') -const BlockId$json = const { - '1': 'BlockId', - '2': const [ - const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'}, - ], -}; - -/// Descriptor for `BlockId`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List blockIdDescriptor = $convert.base64Decode('CgdCbG9ja0lkEhQKBXZhbHVlGAEgASgJUgV2YWx1ZQ=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart index dcf1e69936..0d1eabddf8 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart @@ -13,6 +13,7 @@ class ErrorCode extends $pb.ProtobufEnum { static const ErrorCode Internal = ErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Internal'); static const ErrorCode UserUnauthorized = ErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserUnauthorized'); static const ErrorCode RecordNotFound = ErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RecordNotFound'); + static const ErrorCode UserIdIsEmpty = ErrorCode._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdIsEmpty'); static const ErrorCode WorkspaceNameInvalid = ErrorCode._(100, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceNameInvalid'); static const ErrorCode WorkspaceIdInvalid = ErrorCode._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceIdInvalid'); static const ErrorCode AppColorStyleInvalid = ErrorCode._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppColorStyleInvalid'); @@ -40,11 +41,24 @@ class ErrorCode extends $pb.ProtobufEnum { static const ErrorCode UserNameIsEmpty = ErrorCode._(310, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNameIsEmpty'); static const ErrorCode UserIdInvalid = ErrorCode._(311, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserIdInvalid'); static const ErrorCode UserNotExist = ErrorCode._(312, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserNotExist'); + static const ErrorCode TextTooLong = ErrorCode._(400, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TextTooLong'); + static const ErrorCode GridIdIsEmpty = ErrorCode._(410, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridIdIsEmpty'); + static const ErrorCode BlockIdIsEmpty = ErrorCode._(420, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'BlockIdIsEmpty'); + static const ErrorCode RowIdIsEmpty = ErrorCode._(430, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RowIdIsEmpty'); + static const ErrorCode OptionIdIsEmpty = ErrorCode._(431, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OptionIdIsEmpty'); + static const ErrorCode FieldIdIsEmpty = ErrorCode._(440, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldIdIsEmpty'); + static const ErrorCode FieldDoesNotExist = ErrorCode._(441, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldDoesNotExist'); + static const ErrorCode SelectOptionNameIsEmpty = ErrorCode._(442, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SelectOptionNameIsEmpty'); + static const ErrorCode FieldNotExists = ErrorCode._(443, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldNotExists'); + static const ErrorCode FieldInvalidOperation = ErrorCode._(444, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldInvalidOperation'); + static const ErrorCode TypeOptionDataIsEmpty = ErrorCode._(450, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TypeOptionDataIsEmpty'); + static const ErrorCode InvalidData = ErrorCode._(500, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InvalidData'); static const $core.List values = [ Internal, UserUnauthorized, RecordNotFound, + UserIdIsEmpty, WorkspaceNameInvalid, WorkspaceIdInvalid, AppColorStyleInvalid, @@ -72,6 +86,18 @@ class ErrorCode extends $pb.ProtobufEnum { UserNameIsEmpty, UserIdInvalid, UserNotExist, + TextTooLong, + GridIdIsEmpty, + BlockIdIsEmpty, + RowIdIsEmpty, + OptionIdIsEmpty, + FieldIdIsEmpty, + FieldDoesNotExist, + SelectOptionNameIsEmpty, + FieldNotExists, + FieldInvalidOperation, + TypeOptionDataIsEmpty, + InvalidData, ]; static final $core.Map<$core.int, ErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart index c8d7191d54..fa6ba4076b 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart @@ -15,6 +15,7 @@ const ErrorCode$json = const { const {'1': 'Internal', '2': 0}, const {'1': 'UserUnauthorized', '2': 2}, const {'1': 'RecordNotFound', '2': 3}, + const {'1': 'UserIdIsEmpty', '2': 4}, const {'1': 'WorkspaceNameInvalid', '2': 100}, const {'1': 'WorkspaceIdInvalid', '2': 101}, const {'1': 'AppColorStyleInvalid', '2': 102}, @@ -42,8 +43,20 @@ const ErrorCode$json = const { const {'1': 'UserNameIsEmpty', '2': 310}, const {'1': 'UserIdInvalid', '2': 311}, const {'1': 'UserNotExist', '2': 312}, + const {'1': 'TextTooLong', '2': 400}, + const {'1': 'GridIdIsEmpty', '2': 410}, + const {'1': 'BlockIdIsEmpty', '2': 420}, + const {'1': 'RowIdIsEmpty', '2': 430}, + const {'1': 'OptionIdIsEmpty', '2': 431}, + const {'1': 'FieldIdIsEmpty', '2': 440}, + const {'1': 'FieldDoesNotExist', '2': 441}, + const {'1': 'SelectOptionNameIsEmpty', '2': 442}, + const {'1': 'FieldNotExists', '2': 443}, + const {'1': 'FieldInvalidOperation', '2': 444}, + const {'1': 'TypeOptionDataIsEmpty', '2': 450}, + const {'1': 'InvalidData', '2': 500}, ], }; /// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQABIUChBVc2VyVW5hdXRob3JpemVkEAISEgoOUmVjb3JkTm90Rm91bmQQAxIYChRXb3Jrc3BhY2VOYW1lSW52YWxpZBBkEhYKEldvcmtzcGFjZUlkSW52YWxpZBBlEhgKFEFwcENvbG9yU3R5bGVJbnZhbGlkEGYSGAoUV29ya3NwYWNlRGVzY1Rvb0xvbmcQZxIYChRXb3Jrc3BhY2VOYW1lVG9vTG9uZxBoEhAKDEFwcElkSW52YWxpZBBuEhIKDkFwcE5hbWVJbnZhbGlkEG8SEwoPVmlld05hbWVJbnZhbGlkEHgSGAoUVmlld1RodW1ibmFpbEludmFsaWQQeRIRCg1WaWV3SWRJbnZhbGlkEHoSEwoPVmlld0Rlc2NUb29Mb25nEHsSEwoPVmlld0RhdGFJbnZhbGlkEHwSEwoPVmlld05hbWVUb29Mb25nEH0SEQoMQ29ubmVjdEVycm9yEMgBEhEKDEVtYWlsSXNFbXB0eRCsAhIXChJFbWFpbEZvcm1hdEludmFsaWQQrQISFwoSRW1haWxBbHJlYWR5RXhpc3RzEK4CEhQKD1Bhc3N3b3JkSXNFbXB0eRCvAhIUCg9QYXNzd29yZFRvb0xvbmcQsAISJQogUGFzc3dvcmRDb250YWluc0ZvcmJpZENoYXJhY3RlcnMQsQISGgoVUGFzc3dvcmRGb3JtYXRJbnZhbGlkELICEhUKEFBhc3N3b3JkTm90TWF0Y2gQswISFAoPVXNlck5hbWVUb29Mb25nELQCEicKIlVzZXJOYW1lQ29udGFpbkZvcmJpZGRlbkNoYXJhY3RlcnMQtQISFAoPVXNlck5hbWVJc0VtcHR5ELYCEhIKDVVzZXJJZEludmFsaWQQtwISEQoMVXNlck5vdEV4aXN0ELgC'); +final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQABIUChBVc2VyVW5hdXRob3JpemVkEAISEgoOUmVjb3JkTm90Rm91bmQQAxIRCg1Vc2VySWRJc0VtcHR5EAQSGAoUV29ya3NwYWNlTmFtZUludmFsaWQQZBIWChJXb3Jrc3BhY2VJZEludmFsaWQQZRIYChRBcHBDb2xvclN0eWxlSW52YWxpZBBmEhgKFFdvcmtzcGFjZURlc2NUb29Mb25nEGcSGAoUV29ya3NwYWNlTmFtZVRvb0xvbmcQaBIQCgxBcHBJZEludmFsaWQQbhISCg5BcHBOYW1lSW52YWxpZBBvEhMKD1ZpZXdOYW1lSW52YWxpZBB4EhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEHkSEQoNVmlld0lkSW52YWxpZBB6EhMKD1ZpZXdEZXNjVG9vTG9uZxB7EhMKD1ZpZXdEYXRhSW52YWxpZBB8EhMKD1ZpZXdOYW1lVG9vTG9uZxB9EhEKDENvbm5lY3RFcnJvchDIARIRCgxFbWFpbElzRW1wdHkQrAISFwoSRW1haWxGb3JtYXRJbnZhbGlkEK0CEhcKEkVtYWlsQWxyZWFkeUV4aXN0cxCuAhIUCg9QYXNzd29yZElzRW1wdHkQrwISFAoPUGFzc3dvcmRUb29Mb25nELACEiUKIFBhc3N3b3JkQ29udGFpbnNGb3JiaWRDaGFyYWN0ZXJzELECEhoKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBCyAhIVChBQYXNzd29yZE5vdE1hdGNoELMCEhQKD1VzZXJOYW1lVG9vTG9uZxC0AhInCiJVc2VyTmFtZUNvbnRhaW5Gb3JiaWRkZW5DaGFyYWN0ZXJzELUCEhQKD1VzZXJOYW1lSXNFbXB0eRC2AhISCg1Vc2VySWRJbnZhbGlkELcCEhEKDFVzZXJOb3RFeGlzdBC4AhIQCgtUZXh0VG9vTG9uZxCQAxISCg1HcmlkSWRJc0VtcHR5EJoDEhMKDkJsb2NrSWRJc0VtcHR5EKQDEhEKDFJvd0lkSXNFbXB0eRCuAxIUCg9PcHRpb25JZElzRW1wdHkQrwMSEwoORmllbGRJZElzRW1wdHkQuAMSFgoRRmllbGREb2VzTm90RXhpc3QQuQMSHAoXU2VsZWN0T3B0aW9uTmFtZUlzRW1wdHkQugMSEwoORmllbGROb3RFeGlzdHMQuwMSGgoVRmllbGRJbnZhbGlkT3BlcmF0aW9uELwDEhoKFVR5cGVPcHRpb25EYXRhSXNFbXB0eRDCAxIQCgtJbnZhbGlkRGF0YRD0Aw=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbenum.dart deleted file mode 100644 index 52eb16349e..0000000000 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbenum.dart +++ /dev/null @@ -1,56 +0,0 @@ -/// -// Generated code. Do not modify. -// source: errors.proto -// -// @dart = 2.12 -// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields - -// ignore_for_file: UNDEFINED_SHOWN_NAME -import 'dart:core' as $core; -import 'package:protobuf/protobuf.dart' as $pb; - -class ErrorCode extends $pb.ProtobufEnum { - static const ErrorCode WorkspaceNameInvalid = ErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceNameInvalid'); - static const ErrorCode WorkspaceIdInvalid = ErrorCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceIdInvalid'); - static const ErrorCode AppColorStyleInvalid = ErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppColorStyleInvalid'); - static const ErrorCode WorkspaceDescTooLong = ErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDescTooLong'); - static const ErrorCode WorkspaceNameTooLong = ErrorCode._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceNameTooLong'); - static const ErrorCode AppIdInvalid = ErrorCode._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppIdInvalid'); - static const ErrorCode AppNameInvalid = ErrorCode._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppNameInvalid'); - static const ErrorCode ViewNameInvalid = ErrorCode._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewNameInvalid'); - static const ErrorCode ViewThumbnailInvalid = ErrorCode._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewThumbnailInvalid'); - static const ErrorCode ViewIdInvalid = ErrorCode._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewIdInvalid'); - static const ErrorCode ViewDescTooLong = ErrorCode._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewDescTooLong'); - static const ErrorCode ViewDataInvalid = ErrorCode._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewDataInvalid'); - static const ErrorCode ViewNameTooLong = ErrorCode._(25, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewNameTooLong'); - static const ErrorCode UserUnauthorized = ErrorCode._(100, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserUnauthorized'); - static const ErrorCode WsConnectError = ErrorCode._(200, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WsConnectError'); - static const ErrorCode InternalError = ErrorCode._(1000, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InternalError'); - static const ErrorCode RecordNotFound = ErrorCode._(1001, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RecordNotFound'); - - static const $core.List values = [ - WorkspaceNameInvalid, - WorkspaceIdInvalid, - AppColorStyleInvalid, - WorkspaceDescTooLong, - WorkspaceNameTooLong, - AppIdInvalid, - AppNameInvalid, - ViewNameInvalid, - ViewThumbnailInvalid, - ViewIdInvalid, - ViewDescTooLong, - ViewDataInvalid, - ViewNameTooLong, - UserUnauthorized, - WsConnectError, - InternalError, - RecordNotFound, - ]; - - static final $core.Map<$core.int, ErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values); - static ErrorCode? valueOf($core.int value) => _byValue[value]; - - const ErrorCode._($core.int v, $core.String n) : super(v, n); -} - diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbjson.dart deleted file mode 100644 index a829c0ed5d..0000000000 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/errors.pbjson.dart +++ /dev/null @@ -1,36 +0,0 @@ -/// -// Generated code. Do not modify. -// source: errors.proto -// -// @dart = 2.12 -// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package - -import 'dart:core' as $core; -import 'dart:convert' as $convert; -import 'dart:typed_data' as $typed_data; -@$core.Deprecated('Use errorCodeDescriptor instead') -const ErrorCode$json = const { - '1': 'ErrorCode', - '2': const [ - const {'1': 'WorkspaceNameInvalid', '2': 0}, - const {'1': 'WorkspaceIdInvalid', '2': 1}, - const {'1': 'AppColorStyleInvalid', '2': 2}, - const {'1': 'WorkspaceDescTooLong', '2': 3}, - const {'1': 'WorkspaceNameTooLong', '2': 4}, - const {'1': 'AppIdInvalid', '2': 10}, - const {'1': 'AppNameInvalid', '2': 11}, - const {'1': 'ViewNameInvalid', '2': 20}, - const {'1': 'ViewThumbnailInvalid', '2': 21}, - const {'1': 'ViewIdInvalid', '2': 22}, - const {'1': 'ViewDescTooLong', '2': 23}, - const {'1': 'ViewDataInvalid', '2': 24}, - const {'1': 'ViewNameTooLong', '2': 25}, - const {'1': 'UserUnauthorized', '2': 100}, - const {'1': 'WsConnectError', '2': 200}, - const {'1': 'InternalError', '2': 1000}, - const {'1': 'RecordNotFound', '2': 1001}, - ], -}; - -/// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSGAoUV29ya3NwYWNlTmFtZUludmFsaWQQABIWChJXb3Jrc3BhY2VJZEludmFsaWQQARIYChRBcHBDb2xvclN0eWxlSW52YWxpZBACEhgKFFdvcmtzcGFjZURlc2NUb29Mb25nEAMSGAoUV29ya3NwYWNlTmFtZVRvb0xvbmcQBBIQCgxBcHBJZEludmFsaWQQChISCg5BcHBOYW1lSW52YWxpZBALEhMKD1ZpZXdOYW1lSW52YWxpZBAUEhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEBUSEQoNVmlld0lkSW52YWxpZBAWEhMKD1ZpZXdEZXNjVG9vTG9uZxAXEhMKD1ZpZXdEYXRhSW52YWxpZBAYEhMKD1ZpZXdOYW1lVG9vTG9uZxAZEhQKEFVzZXJVbmF1dGhvcml6ZWQQZBITCg5Xc0Nvbm5lY3RFcnJvchDIARISCg1JbnRlcm5hbEVycm9yEOgHEhMKDlJlY29yZE5vdEZvdW5kEOkH'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/protobuf.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/protobuf.dart index 4a0477e02c..4ca4fa1fd1 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/protobuf.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/protobuf.dart @@ -1,5 +1,4 @@ // Auto-generated, do not edit -export './share.pb.dart'; export './app.pb.dart'; export './view.pb.dart'; export './trash.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pb.dart index 6bf9801803..98882f444d 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pb.dart @@ -20,7 +20,7 @@ class View extends $pb.GeneratedMessage { ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'belongToId') ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc') - ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.RichText, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values) + ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.TextBlock, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values) ..aInt64(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'version') ..aOM(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'belongings', subBuilder: RepeatedView.create) ..aInt64(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'modifiedTime') @@ -274,9 +274,9 @@ class CreateViewPayload extends $pb.GeneratedMessage { ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc') ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail') - ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.RichText, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values) - ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'extData') - ..a<$core.int>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pluginType', $pb.PbFieldType.O3) + ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.TextBlock, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values) + ..a<$core.int>(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pluginType', $pb.PbFieldType.O3) + ..a<$core.List<$core.int>>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..hasRequiredFields = false ; @@ -287,8 +287,8 @@ class CreateViewPayload extends $pb.GeneratedMessage { $core.String? desc, $core.String? thumbnail, ViewDataType? dataType, - $core.String? extData, $core.int? pluginType, + $core.List<$core.int>? data, }) { final _result = create(); if (belongToId != null) { @@ -306,12 +306,12 @@ class CreateViewPayload extends $pb.GeneratedMessage { if (dataType != null) { _result.dataType = dataType; } - if (extData != null) { - _result.extData = extData; - } if (pluginType != null) { _result.pluginType = pluginType; } + if (data != null) { + _result.data = data; + } return _result; } factory CreateViewPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -384,22 +384,22 @@ class CreateViewPayload extends $pb.GeneratedMessage { void clearDataType() => clearField(5); @$pb.TagNumber(6) - $core.String get extData => $_getSZ(5); + $core.int get pluginType => $_getIZ(5); @$pb.TagNumber(6) - set extData($core.String v) { $_setString(5, v); } + set pluginType($core.int v) { $_setSignedInt32(5, v); } @$pb.TagNumber(6) - $core.bool hasExtData() => $_has(5); + $core.bool hasPluginType() => $_has(5); @$pb.TagNumber(6) - void clearExtData() => clearField(6); + void clearPluginType() => clearField(6); @$pb.TagNumber(7) - $core.int get pluginType => $_getIZ(6); + $core.List<$core.int> get data => $_getN(6); @$pb.TagNumber(7) - set pluginType($core.int v) { $_setSignedInt32(6, v); } + set data($core.List<$core.int> v) { $_setBytes(6, v); } @$pb.TagNumber(7) - $core.bool hasPluginType() => $_has(6); + $core.bool hasData() => $_has(6); @$pb.TagNumber(7) - void clearPluginType() => clearField(7); + void clearData() => clearField(7); } class CreateViewParams extends $pb.GeneratedMessage { @@ -408,11 +408,10 @@ class CreateViewParams extends $pb.GeneratedMessage { ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc') ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail') - ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.RichText, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values) - ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'extData') - ..aOS(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId') - ..aOS(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data') - ..a<$core.int>(9, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pluginType', $pb.PbFieldType.O3) + ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.TextBlock, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values) + ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId') + ..a<$core.List<$core.int>>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) + ..a<$core.int>(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pluginType', $pb.PbFieldType.O3) ..hasRequiredFields = false ; @@ -423,9 +422,8 @@ class CreateViewParams extends $pb.GeneratedMessage { $core.String? desc, $core.String? thumbnail, ViewDataType? dataType, - $core.String? extData, $core.String? viewId, - $core.String? data, + $core.List<$core.int>? data, $core.int? pluginType, }) { final _result = create(); @@ -444,9 +442,6 @@ class CreateViewParams extends $pb.GeneratedMessage { if (dataType != null) { _result.dataType = dataType; } - if (extData != null) { - _result.extData = extData; - } if (viewId != null) { _result.viewId = viewId; } @@ -525,40 +520,31 @@ class CreateViewParams extends $pb.GeneratedMessage { void clearDataType() => clearField(5); @$pb.TagNumber(6) - $core.String get extData => $_getSZ(5); + $core.String get viewId => $_getSZ(5); @$pb.TagNumber(6) - set extData($core.String v) { $_setString(5, v); } + set viewId($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) - $core.bool hasExtData() => $_has(5); + $core.bool hasViewId() => $_has(5); @$pb.TagNumber(6) - void clearExtData() => clearField(6); + void clearViewId() => clearField(6); @$pb.TagNumber(7) - $core.String get viewId => $_getSZ(6); + $core.List<$core.int> get data => $_getN(6); @$pb.TagNumber(7) - set viewId($core.String v) { $_setString(6, v); } + set data($core.List<$core.int> v) { $_setBytes(6, v); } @$pb.TagNumber(7) - $core.bool hasViewId() => $_has(6); + $core.bool hasData() => $_has(6); @$pb.TagNumber(7) - void clearViewId() => clearField(7); + void clearData() => clearField(7); @$pb.TagNumber(8) - $core.String get data => $_getSZ(7); + $core.int get pluginType => $_getIZ(7); @$pb.TagNumber(8) - set data($core.String v) { $_setString(7, v); } + set pluginType($core.int v) { $_setSignedInt32(7, v); } @$pb.TagNumber(8) - $core.bool hasData() => $_has(7); + $core.bool hasPluginType() => $_has(7); @$pb.TagNumber(8) - void clearData() => clearField(8); - - @$pb.TagNumber(9) - $core.int get pluginType => $_getIZ(8); - @$pb.TagNumber(9) - set pluginType($core.int v) { $_setSignedInt32(8, v); } - @$pb.TagNumber(9) - $core.bool hasPluginType() => $_has(8); - @$pb.TagNumber(9) - void clearPluginType() => clearField(9); + void clearPluginType() => clearField(8); } class ViewId extends $pb.GeneratedMessage { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbenum.dart index 452830c084..aa7b0105b1 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbenum.dart @@ -10,12 +10,12 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; class ViewDataType extends $pb.ProtobufEnum { - static const ViewDataType RichText = ViewDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RichText'); - static const ViewDataType PlainText = ViewDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PlainText'); + static const ViewDataType TextBlock = ViewDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TextBlock'); + static const ViewDataType Grid = ViewDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Grid'); static const $core.List values = [ - RichText, - PlainText, + TextBlock, + Grid, ]; static final $core.Map<$core.int, ViewDataType> _byValue = $pb.ProtobufEnum.initByValue(values); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbjson.dart index 8c50bd08fc..0f1949754f 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbjson.dart @@ -12,13 +12,13 @@ import 'dart:typed_data' as $typed_data; const ViewDataType$json = const { '1': 'ViewDataType', '2': const [ - const {'1': 'RichText', '2': 0}, - const {'1': 'PlainText', '2': 1}, + const {'1': 'TextBlock', '2': 0}, + const {'1': 'Grid', '2': 1}, ], }; /// Descriptor for `ViewDataType`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSDAoIUmljaFRleHQQABINCglQbGFpblRleHQQAQ=='); +final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSDQoJVGV4dEJsb2NrEAASCAoER3JpZBAB'); @$core.Deprecated('Use viewDescriptor instead') const View$json = const { '1': 'View', @@ -59,8 +59,8 @@ const CreateViewPayload$json = const { const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'}, const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'thumbnail'}, const {'1': 'data_type', '3': 5, '4': 1, '5': 14, '6': '.ViewDataType', '10': 'dataType'}, - const {'1': 'ext_data', '3': 6, '4': 1, '5': 9, '10': 'extData'}, - const {'1': 'plugin_type', '3': 7, '4': 1, '5': 5, '10': 'pluginType'}, + const {'1': 'plugin_type', '3': 6, '4': 1, '5': 5, '10': 'pluginType'}, + const {'1': 'data', '3': 7, '4': 1, '5': 12, '10': 'data'}, ], '8': const [ const {'1': 'one_of_thumbnail'}, @@ -68,7 +68,7 @@ const CreateViewPayload$json = const { }; /// Descriptor for `CreateViewPayload`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List createViewPayloadDescriptor = $convert.base64Decode('ChFDcmVhdGVWaWV3UGF5bG9hZBIgCgxiZWxvbmdfdG9faWQYASABKAlSCmJlbG9uZ1RvSWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgAUgl0aHVtYm5haWwSKgoJZGF0YV90eXBlGAUgASgOMg0uVmlld0RhdGFUeXBlUghkYXRhVHlwZRIZCghleHRfZGF0YRgGIAEoCVIHZXh0RGF0YRIfCgtwbHVnaW5fdHlwZRgHIAEoBVIKcGx1Z2luVHlwZUISChBvbmVfb2ZfdGh1bWJuYWls'); +final $typed_data.Uint8List createViewPayloadDescriptor = $convert.base64Decode('ChFDcmVhdGVWaWV3UGF5bG9hZBIgCgxiZWxvbmdfdG9faWQYASABKAlSCmJlbG9uZ1RvSWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgAUgl0aHVtYm5haWwSKgoJZGF0YV90eXBlGAUgASgOMg0uVmlld0RhdGFUeXBlUghkYXRhVHlwZRIfCgtwbHVnaW5fdHlwZRgGIAEoBVIKcGx1Z2luVHlwZRISCgRkYXRhGAcgASgMUgRkYXRhQhIKEG9uZV9vZl90aHVtYm5haWw='); @$core.Deprecated('Use createViewParamsDescriptor instead') const CreateViewParams$json = const { '1': 'CreateViewParams', @@ -78,15 +78,14 @@ const CreateViewParams$json = const { const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'}, const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '10': 'thumbnail'}, const {'1': 'data_type', '3': 5, '4': 1, '5': 14, '6': '.ViewDataType', '10': 'dataType'}, - const {'1': 'ext_data', '3': 6, '4': 1, '5': 9, '10': 'extData'}, - const {'1': 'view_id', '3': 7, '4': 1, '5': 9, '10': 'viewId'}, - const {'1': 'data', '3': 8, '4': 1, '5': 9, '10': 'data'}, - const {'1': 'plugin_type', '3': 9, '4': 1, '5': 5, '10': 'pluginType'}, + const {'1': 'view_id', '3': 6, '4': 1, '5': 9, '10': 'viewId'}, + const {'1': 'data', '3': 7, '4': 1, '5': 12, '10': 'data'}, + const {'1': 'plugin_type', '3': 8, '4': 1, '5': 5, '10': 'pluginType'}, ], }; /// Descriptor for `CreateViewParams`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSKgoJZGF0YV90eXBlGAUgASgOMg0uVmlld0RhdGFUeXBlUghkYXRhVHlwZRIZCghleHRfZGF0YRgGIAEoCVIHZXh0RGF0YRIXCgd2aWV3X2lkGAcgASgJUgZ2aWV3SWQSEgoEZGF0YRgIIAEoCVIEZGF0YRIfCgtwbHVnaW5fdHlwZRgJIAEoBVIKcGx1Z2luVHlwZQ=='); +final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSKgoJZGF0YV90eXBlGAUgASgOMg0uVmlld0RhdGFUeXBlUghkYXRhVHlwZRIXCgd2aWV3X2lkGAYgASgJUgZ2aWV3SWQSEgoEZGF0YRgHIAEoDFIEZGF0YRIfCgtwbHVnaW5fdHlwZRgIIAEoBVIKcGx1Z2luVHlwZQ=='); @$core.Deprecated('Use viewIdDescriptor instead') const ViewId$json = const { '1': 'ViewId', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbenum.dart index dd502e087f..73484cead5 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbenum.dart @@ -26,15 +26,13 @@ class FolderEvent extends $pb.ProtobufEnum { static const FolderEvent DeleteView = FolderEvent._(204, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteView'); static const FolderEvent DuplicateView = FolderEvent._(205, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateView'); static const FolderEvent CopyLink = FolderEvent._(206, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CopyLink'); - static const FolderEvent OpenView = FolderEvent._(207, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenView'); + static const FolderEvent SetLatestView = FolderEvent._(207, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SetLatestView'); static const FolderEvent CloseView = FolderEvent._(208, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CloseView'); static const FolderEvent ReadTrash = FolderEvent._(300, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadTrash'); static const FolderEvent PutbackTrash = FolderEvent._(301, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PutbackTrash'); static const FolderEvent DeleteTrash = FolderEvent._(302, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteTrash'); static const FolderEvent RestoreAllTrash = FolderEvent._(303, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RestoreAllTrash'); static const FolderEvent DeleteAllTrash = FolderEvent._(304, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteAllTrash'); - static const FolderEvent ApplyDocDelta = FolderEvent._(400, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplyDocDelta'); - static const FolderEvent ExportDocument = FolderEvent._(500, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ExportDocument'); static const $core.List values = [ CreateWorkspace, @@ -53,15 +51,13 @@ class FolderEvent extends $pb.ProtobufEnum { DeleteView, DuplicateView, CopyLink, - OpenView, + SetLatestView, CloseView, ReadTrash, PutbackTrash, DeleteTrash, RestoreAllTrash, DeleteAllTrash, - ApplyDocDelta, - ExportDocument, ]; static final $core.Map<$core.int, FolderEvent> _byValue = $pb.ProtobufEnum.initByValue(values); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbjson.dart index e992c85ab7..136849065b 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder/event_map.pbjson.dart @@ -28,17 +28,15 @@ const FolderEvent$json = const { const {'1': 'DeleteView', '2': 204}, const {'1': 'DuplicateView', '2': 205}, const {'1': 'CopyLink', '2': 206}, - const {'1': 'OpenView', '2': 207}, + const {'1': 'SetLatestView', '2': 207}, const {'1': 'CloseView', '2': 208}, const {'1': 'ReadTrash', '2': 300}, const {'1': 'PutbackTrash', '2': 301}, const {'1': 'DeleteTrash', '2': 302}, const {'1': 'RestoreAllTrash', '2': 303}, const {'1': 'DeleteAllTrash', '2': 304}, - const {'1': 'ApplyDocDelta', '2': 400}, - const {'1': 'ExportDocument', '2': 500}, ], }; /// Descriptor for `FolderEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List folderEventDescriptor = $convert.base64Decode('CgtGb2xkZXJFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARINCghPcGVuVmlldxDPARIOCglDbG9zZVZpZXcQ0AESDgoJUmVhZFRyYXNoEKwCEhEKDFB1dGJhY2tUcmFzaBCtAhIQCgtEZWxldGVUcmFzaBCuAhIUCg9SZXN0b3JlQWxsVHJhc2gQrwISEwoORGVsZXRlQWxsVHJhc2gQsAISEgoNQXBwbHlEb2NEZWx0YRCQAxITCg5FeHBvcnREb2N1bWVudBD0Aw=='); +final $typed_data.Uint8List folderEventDescriptor = $convert.base64Decode('CgtGb2xkZXJFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARISCg1TZXRMYXRlc3RWaWV3EM8BEg4KCUNsb3NlVmlldxDQARIOCglSZWFkVHJhc2gQrAISEQoMUHV0YmFja1RyYXNoEK0CEhAKC0RlbGV0ZVRyYXNoEK4CEhQKD1Jlc3RvcmVBbGxUcmFzaBCvAhITCg5EZWxldGVBbGxUcmFzaBCwAg=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart new file mode 100644 index 0000000000..e64431b1f9 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -0,0 +1,2305 @@ +/// +// Generated code. Do not modify. +// source: grid.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'grid.pbenum.dart'; + +export 'grid.pbenum.dart'; + +class Grid extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Grid', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldOrders', $pb.PbFieldType.PM, subBuilder: FieldOrder.create) + ..pc(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockOrders', $pb.PbFieldType.PM, subBuilder: GridBlockOrder.create) + ..hasRequiredFields = false + ; + + Grid._() : super(); + factory Grid({ + $core.String? id, + $core.Iterable? fieldOrders, + $core.Iterable? blockOrders, + }) { + final _result = create(); + if (id != null) { + _result.id = id; + } + if (fieldOrders != null) { + _result.fieldOrders.addAll(fieldOrders); + } + if (blockOrders != null) { + _result.blockOrders.addAll(blockOrders); + } + return _result; + } + factory Grid.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Grid.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Grid clone() => Grid()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Grid copyWith(void Function(Grid) updates) => super.copyWith((message) => updates(message as Grid)) as Grid; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static Grid create() => Grid._(); + Grid createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Grid getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Grid? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get id => $_getSZ(0); + @$pb.TagNumber(1) + set id($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasId() => $_has(0); + @$pb.TagNumber(1) + void clearId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get fieldOrders => $_getList(1); + + @$pb.TagNumber(3) + $core.List get blockOrders => $_getList(2); +} + +class Field extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Field', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc') + ..e(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values) + ..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'frozen') + ..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'visibility') + ..a<$core.int>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'width', $pb.PbFieldType.O3) + ..aOB(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isPrimary') + ..hasRequiredFields = false + ; + + Field._() : super(); + factory Field({ + $core.String? id, + $core.String? name, + $core.String? desc, + FieldType? fieldType, + $core.bool? frozen, + $core.bool? visibility, + $core.int? width, + $core.bool? isPrimary, + }) { + final _result = create(); + if (id != null) { + _result.id = id; + } + if (name != null) { + _result.name = name; + } + if (desc != null) { + _result.desc = desc; + } + if (fieldType != null) { + _result.fieldType = fieldType; + } + if (frozen != null) { + _result.frozen = frozen; + } + if (visibility != null) { + _result.visibility = visibility; + } + if (width != null) { + _result.width = width; + } + if (isPrimary != null) { + _result.isPrimary = isPrimary; + } + return _result; + } + factory Field.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Field.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Field clone() => Field()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Field copyWith(void Function(Field) updates) => super.copyWith((message) => updates(message as Field)) as Field; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static Field create() => Field._(); + Field createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Field getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Field? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get id => $_getSZ(0); + @$pb.TagNumber(1) + set id($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasId() => $_has(0); + @$pb.TagNumber(1) + void clearId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get name => $_getSZ(1); + @$pb.TagNumber(2) + set name($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasName() => $_has(1); + @$pb.TagNumber(2) + void clearName() => clearField(2); + + @$pb.TagNumber(3) + $core.String get desc => $_getSZ(2); + @$pb.TagNumber(3) + set desc($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasDesc() => $_has(2); + @$pb.TagNumber(3) + void clearDesc() => clearField(3); + + @$pb.TagNumber(4) + FieldType get fieldType => $_getN(3); + @$pb.TagNumber(4) + set fieldType(FieldType v) { setField(4, v); } + @$pb.TagNumber(4) + $core.bool hasFieldType() => $_has(3); + @$pb.TagNumber(4) + void clearFieldType() => clearField(4); + + @$pb.TagNumber(5) + $core.bool get frozen => $_getBF(4); + @$pb.TagNumber(5) + set frozen($core.bool v) { $_setBool(4, v); } + @$pb.TagNumber(5) + $core.bool hasFrozen() => $_has(4); + @$pb.TagNumber(5) + void clearFrozen() => clearField(5); + + @$pb.TagNumber(6) + $core.bool get visibility => $_getBF(5); + @$pb.TagNumber(6) + set visibility($core.bool v) { $_setBool(5, v); } + @$pb.TagNumber(6) + $core.bool hasVisibility() => $_has(5); + @$pb.TagNumber(6) + void clearVisibility() => clearField(6); + + @$pb.TagNumber(7) + $core.int get width => $_getIZ(6); + @$pb.TagNumber(7) + set width($core.int v) { $_setSignedInt32(6, v); } + @$pb.TagNumber(7) + $core.bool hasWidth() => $_has(6); + @$pb.TagNumber(7) + void clearWidth() => clearField(7); + + @$pb.TagNumber(8) + $core.bool get isPrimary => $_getBF(7); + @$pb.TagNumber(8) + set isPrimary($core.bool v) { $_setBool(7, v); } + @$pb.TagNumber(8) + $core.bool hasIsPrimary() => $_has(7); + @$pb.TagNumber(8) + void clearIsPrimary() => clearField(8); +} + +class FieldOrder extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldOrder', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..hasRequiredFields = false + ; + + FieldOrder._() : super(); + factory FieldOrder({ + $core.String? fieldId, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + return _result; + } + factory FieldOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FieldOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + FieldOrder clone() => FieldOrder()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FieldOrder copyWith(void Function(FieldOrder) updates) => super.copyWith((message) => updates(message as FieldOrder)) as FieldOrder; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static FieldOrder create() => FieldOrder._(); + FieldOrder createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FieldOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FieldOrder? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); +} + +class GridFieldChangeset extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridFieldChangeset', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedFields', $pb.PbFieldType.PM, subBuilder: IndexField.create) + ..pc(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedFields', $pb.PbFieldType.PM, subBuilder: FieldOrder.create) + ..pc(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedFields', $pb.PbFieldType.PM, subBuilder: Field.create) + ..hasRequiredFields = false + ; + + GridFieldChangeset._() : super(); + factory GridFieldChangeset({ + $core.String? gridId, + $core.Iterable? insertedFields, + $core.Iterable? deletedFields, + $core.Iterable? updatedFields, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (insertedFields != null) { + _result.insertedFields.addAll(insertedFields); + } + if (deletedFields != null) { + _result.deletedFields.addAll(deletedFields); + } + if (updatedFields != null) { + _result.updatedFields.addAll(updatedFields); + } + return _result; + } + factory GridFieldChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridFieldChangeset.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GridFieldChangeset clone() => GridFieldChangeset()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridFieldChangeset copyWith(void Function(GridFieldChangeset) updates) => super.copyWith((message) => updates(message as GridFieldChangeset)) as GridFieldChangeset; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridFieldChangeset create() => GridFieldChangeset._(); + GridFieldChangeset createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridFieldChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridFieldChangeset? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get insertedFields => $_getList(1); + + @$pb.TagNumber(3) + $core.List get deletedFields => $_getList(2); + + @$pb.TagNumber(4) + $core.List get updatedFields => $_getList(3); +} + +class IndexField extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'IndexField', createEmptyInstance: create) + ..aOM(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'field', subBuilder: Field.create) + ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'index', $pb.PbFieldType.O3) + ..hasRequiredFields = false + ; + + IndexField._() : super(); + factory IndexField({ + Field? field_1, + $core.int? index, + }) { + final _result = create(); + if (field_1 != null) { + _result.field_1 = field_1; + } + if (index != null) { + _result.index = index; + } + return _result; + } + factory IndexField.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory IndexField.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + IndexField clone() => IndexField()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + IndexField copyWith(void Function(IndexField) updates) => super.copyWith((message) => updates(message as IndexField)) as IndexField; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static IndexField create() => IndexField._(); + IndexField createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static IndexField getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static IndexField? _defaultInstance; + + @$pb.TagNumber(1) + Field get field_1 => $_getN(0); + @$pb.TagNumber(1) + set field_1(Field v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasField_1() => $_has(0); + @$pb.TagNumber(1) + void clearField_1() => clearField(1); + @$pb.TagNumber(1) + Field ensureField_1() => $_ensure(0); + + @$pb.TagNumber(2) + $core.int get index => $_getIZ(1); + @$pb.TagNumber(2) + set index($core.int v) { $_setSignedInt32(1, v); } + @$pb.TagNumber(2) + $core.bool hasIndex() => $_has(1); + @$pb.TagNumber(2) + void clearIndex() => clearField(2); +} + +enum GetEditFieldContextPayload_OneOfFieldId { + fieldId, + notSet +} + +class GetEditFieldContextPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, GetEditFieldContextPayload_OneOfFieldId> _GetEditFieldContextPayload_OneOfFieldIdByTag = { + 2 : GetEditFieldContextPayload_OneOfFieldId.fieldId, + 0 : GetEditFieldContextPayload_OneOfFieldId.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GetEditFieldContextPayload', createEmptyInstance: create) + ..oo(0, [2]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..e(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values) + ..hasRequiredFields = false + ; + + GetEditFieldContextPayload._() : super(); + factory GetEditFieldContextPayload({ + $core.String? gridId, + $core.String? fieldId, + FieldType? fieldType, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (fieldType != null) { + _result.fieldType = fieldType; + } + return _result; + } + factory GetEditFieldContextPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GetEditFieldContextPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GetEditFieldContextPayload clone() => GetEditFieldContextPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GetEditFieldContextPayload copyWith(void Function(GetEditFieldContextPayload) updates) => super.copyWith((message) => updates(message as GetEditFieldContextPayload)) as GetEditFieldContextPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GetEditFieldContextPayload create() => GetEditFieldContextPayload._(); + GetEditFieldContextPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GetEditFieldContextPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GetEditFieldContextPayload? _defaultInstance; + + GetEditFieldContextPayload_OneOfFieldId whichOneOfFieldId() => _GetEditFieldContextPayload_OneOfFieldIdByTag[$_whichOneof(0)]!; + void clearOneOfFieldId() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get fieldId => $_getSZ(1); + @$pb.TagNumber(2) + set fieldId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasFieldId() => $_has(1); + @$pb.TagNumber(2) + void clearFieldId() => clearField(2); + + @$pb.TagNumber(3) + FieldType get fieldType => $_getN(2); + @$pb.TagNumber(3) + set fieldType(FieldType v) { setField(3, v); } + @$pb.TagNumber(3) + $core.bool hasFieldType() => $_has(2); + @$pb.TagNumber(3) + void clearFieldType() => clearField(3); +} + +class EditFieldPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'EditFieldPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..e(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values) + ..hasRequiredFields = false + ; + + EditFieldPayload._() : super(); + factory EditFieldPayload({ + $core.String? gridId, + $core.String? fieldId, + FieldType? fieldType, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (fieldType != null) { + _result.fieldType = fieldType; + } + return _result; + } + factory EditFieldPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory EditFieldPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + EditFieldPayload clone() => EditFieldPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + EditFieldPayload copyWith(void Function(EditFieldPayload) updates) => super.copyWith((message) => updates(message as EditFieldPayload)) as EditFieldPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static EditFieldPayload create() => EditFieldPayload._(); + EditFieldPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static EditFieldPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static EditFieldPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get fieldId => $_getSZ(1); + @$pb.TagNumber(2) + set fieldId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasFieldId() => $_has(1); + @$pb.TagNumber(2) + void clearFieldId() => clearField(2); + + @$pb.TagNumber(3) + FieldType get fieldType => $_getN(2); + @$pb.TagNumber(3) + set fieldType(FieldType v) { setField(3, v); } + @$pb.TagNumber(3) + $core.bool hasFieldType() => $_has(2); + @$pb.TagNumber(3) + void clearFieldType() => clearField(3); +} + +class EditFieldContext extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'EditFieldContext', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOM(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridField', subBuilder: Field.create) + ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + EditFieldContext._() : super(); + factory EditFieldContext({ + $core.String? gridId, + Field? gridField, + $core.List<$core.int>? typeOptionData, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (gridField != null) { + _result.gridField = gridField; + } + if (typeOptionData != null) { + _result.typeOptionData = typeOptionData; + } + return _result; + } + factory EditFieldContext.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory EditFieldContext.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + EditFieldContext clone() => EditFieldContext()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + EditFieldContext copyWith(void Function(EditFieldContext) updates) => super.copyWith((message) => updates(message as EditFieldContext)) as EditFieldContext; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static EditFieldContext create() => EditFieldContext._(); + EditFieldContext createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static EditFieldContext getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static EditFieldContext? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + Field get gridField => $_getN(1); + @$pb.TagNumber(2) + set gridField(Field v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasGridField() => $_has(1); + @$pb.TagNumber(2) + void clearGridField() => clearField(2); + @$pb.TagNumber(2) + Field ensureGridField() => $_ensure(1); + + @$pb.TagNumber(3) + $core.List<$core.int> get typeOptionData => $_getN(2); + @$pb.TagNumber(3) + set typeOptionData($core.List<$core.int> v) { $_setBytes(2, v); } + @$pb.TagNumber(3) + $core.bool hasTypeOptionData() => $_has(2); + @$pb.TagNumber(3) + void clearTypeOptionData() => clearField(3); +} + +class RepeatedField extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedField', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Field.create) + ..hasRequiredFields = false + ; + + RepeatedField._() : super(); + factory RepeatedField({ + $core.Iterable? items, + }) { + final _result = create(); + if (items != null) { + _result.items.addAll(items); + } + return _result; + } + factory RepeatedField.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RepeatedField.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RepeatedField clone() => RepeatedField()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RepeatedField copyWith(void Function(RepeatedField) updates) => super.copyWith((message) => updates(message as RepeatedField)) as RepeatedField; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RepeatedField create() => RepeatedField._(); + RepeatedField createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RepeatedField getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RepeatedField? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get items => $_getList(0); +} + +class RepeatedFieldOrder extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedFieldOrder', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: FieldOrder.create) + ..hasRequiredFields = false + ; + + RepeatedFieldOrder._() : super(); + factory RepeatedFieldOrder({ + $core.Iterable? items, + }) { + final _result = create(); + if (items != null) { + _result.items.addAll(items); + } + return _result; + } + factory RepeatedFieldOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RepeatedFieldOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RepeatedFieldOrder clone() => RepeatedFieldOrder()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RepeatedFieldOrder copyWith(void Function(RepeatedFieldOrder) updates) => super.copyWith((message) => updates(message as RepeatedFieldOrder)) as RepeatedFieldOrder; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RepeatedFieldOrder create() => RepeatedFieldOrder._(); + RepeatedFieldOrder createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RepeatedFieldOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RepeatedFieldOrder? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get items => $_getList(0); +} + +class RowOrder extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RowOrder', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') + ..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', $pb.PbFieldType.O3) + ..hasRequiredFields = false + ; + + RowOrder._() : super(); + factory RowOrder({ + $core.String? rowId, + $core.String? blockId, + $core.int? height, + }) { + final _result = create(); + if (rowId != null) { + _result.rowId = rowId; + } + if (blockId != null) { + _result.blockId = blockId; + } + if (height != null) { + _result.height = height; + } + return _result; + } + factory RowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RowOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RowOrder clone() => RowOrder()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RowOrder copyWith(void Function(RowOrder) updates) => super.copyWith((message) => updates(message as RowOrder)) as RowOrder; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RowOrder create() => RowOrder._(); + RowOrder createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RowOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RowOrder? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get rowId => $_getSZ(0); + @$pb.TagNumber(1) + set rowId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasRowId() => $_has(0); + @$pb.TagNumber(1) + void clearRowId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get blockId => $_getSZ(1); + @$pb.TagNumber(2) + set blockId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasBlockId() => $_has(1); + @$pb.TagNumber(2) + void clearBlockId() => clearField(2); + + @$pb.TagNumber(3) + $core.int get height => $_getIZ(2); + @$pb.TagNumber(3) + set height($core.int v) { $_setSignedInt32(2, v); } + @$pb.TagNumber(3) + $core.bool hasHeight() => $_has(2); + @$pb.TagNumber(3) + void clearHeight() => clearField(3); +} + +class Row extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Row', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..m<$core.String, Cell>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'cellByFieldId', entryClassName: 'Row.CellByFieldIdEntry', keyFieldType: $pb.PbFieldType.OS, valueFieldType: $pb.PbFieldType.OM, valueCreator: Cell.create) + ..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', $pb.PbFieldType.O3) + ..hasRequiredFields = false + ; + + Row._() : super(); + factory Row({ + $core.String? id, + $core.Map<$core.String, Cell>? cellByFieldId, + $core.int? height, + }) { + final _result = create(); + if (id != null) { + _result.id = id; + } + if (cellByFieldId != null) { + _result.cellByFieldId.addAll(cellByFieldId); + } + if (height != null) { + _result.height = height; + } + return _result; + } + factory Row.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Row.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Row clone() => Row()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Row copyWith(void Function(Row) updates) => super.copyWith((message) => updates(message as Row)) as Row; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static Row create() => Row._(); + Row createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Row getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Row? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get id => $_getSZ(0); + @$pb.TagNumber(1) + set id($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasId() => $_has(0); + @$pb.TagNumber(1) + void clearId() => clearField(1); + + @$pb.TagNumber(2) + $core.Map<$core.String, Cell> get cellByFieldId => $_getMap(1); + + @$pb.TagNumber(3) + $core.int get height => $_getIZ(2); + @$pb.TagNumber(3) + set height($core.int v) { $_setSignedInt32(2, v); } + @$pb.TagNumber(3) + $core.bool hasHeight() => $_has(2); + @$pb.TagNumber(3) + void clearHeight() => clearField(3); +} + +class RepeatedRow extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedRow', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Row.create) + ..hasRequiredFields = false + ; + + RepeatedRow._() : super(); + factory RepeatedRow({ + $core.Iterable? items, + }) { + final _result = create(); + if (items != null) { + _result.items.addAll(items); + } + return _result; + } + factory RepeatedRow.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RepeatedRow.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RepeatedRow clone() => RepeatedRow()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RepeatedRow copyWith(void Function(RepeatedRow) updates) => super.copyWith((message) => updates(message as RepeatedRow)) as RepeatedRow; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RepeatedRow create() => RepeatedRow._(); + RepeatedRow createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RepeatedRow getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RepeatedRow? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get items => $_getList(0); +} + +class RepeatedGridBlock extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedGridBlock', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: GridBlock.create) + ..hasRequiredFields = false + ; + + RepeatedGridBlock._() : super(); + factory RepeatedGridBlock({ + $core.Iterable? items, + }) { + final _result = create(); + if (items != null) { + _result.items.addAll(items); + } + return _result; + } + factory RepeatedGridBlock.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RepeatedGridBlock.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RepeatedGridBlock clone() => RepeatedGridBlock()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RepeatedGridBlock copyWith(void Function(RepeatedGridBlock) updates) => super.copyWith((message) => updates(message as RepeatedGridBlock)) as RepeatedGridBlock; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RepeatedGridBlock create() => RepeatedGridBlock._(); + RepeatedGridBlock createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RepeatedGridBlock getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RepeatedGridBlock? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get items => $_getList(0); +} + +class GridBlockOrder extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockOrder', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrders', $pb.PbFieldType.PM, subBuilder: RowOrder.create) + ..hasRequiredFields = false + ; + + GridBlockOrder._() : super(); + factory GridBlockOrder({ + $core.String? blockId, + $core.Iterable? rowOrders, + }) { + final _result = create(); + if (blockId != null) { + _result.blockId = blockId; + } + if (rowOrders != null) { + _result.rowOrders.addAll(rowOrders); + } + return _result; + } + factory GridBlockOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridBlockOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GridBlockOrder clone() => GridBlockOrder()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridBlockOrder copyWith(void Function(GridBlockOrder) updates) => super.copyWith((message) => updates(message as GridBlockOrder)) as GridBlockOrder; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridBlockOrder create() => GridBlockOrder._(); + GridBlockOrder createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridBlockOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridBlockOrder? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get blockId => $_getSZ(0); + @$pb.TagNumber(1) + set blockId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasBlockId() => $_has(0); + @$pb.TagNumber(1) + void clearBlockId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get rowOrders => $_getList(1); +} + +enum IndexRowOrder_OneOfIndex { + index_, + notSet +} + +class IndexRowOrder extends $pb.GeneratedMessage { + static const $core.Map<$core.int, IndexRowOrder_OneOfIndex> _IndexRowOrder_OneOfIndexByTag = { + 2 : IndexRowOrder_OneOfIndex.index_, + 0 : IndexRowOrder_OneOfIndex.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'IndexRowOrder', createEmptyInstance: create) + ..oo(0, [2]) + ..aOM(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrder', subBuilder: RowOrder.create) + ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'index', $pb.PbFieldType.O3) + ..hasRequiredFields = false + ; + + IndexRowOrder._() : super(); + factory IndexRowOrder({ + RowOrder? rowOrder, + $core.int? index, + }) { + final _result = create(); + if (rowOrder != null) { + _result.rowOrder = rowOrder; + } + if (index != null) { + _result.index = index; + } + return _result; + } + factory IndexRowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory IndexRowOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + IndexRowOrder clone() => IndexRowOrder()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + IndexRowOrder copyWith(void Function(IndexRowOrder) updates) => super.copyWith((message) => updates(message as IndexRowOrder)) as IndexRowOrder; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static IndexRowOrder create() => IndexRowOrder._(); + IndexRowOrder createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static IndexRowOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static IndexRowOrder? _defaultInstance; + + IndexRowOrder_OneOfIndex whichOneOfIndex() => _IndexRowOrder_OneOfIndexByTag[$_whichOneof(0)]!; + void clearOneOfIndex() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + RowOrder get rowOrder => $_getN(0); + @$pb.TagNumber(1) + set rowOrder(RowOrder v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasRowOrder() => $_has(0); + @$pb.TagNumber(1) + void clearRowOrder() => clearField(1); + @$pb.TagNumber(1) + RowOrder ensureRowOrder() => $_ensure(0); + + @$pb.TagNumber(2) + $core.int get index => $_getIZ(1); + @$pb.TagNumber(2) + set index($core.int v) { $_setSignedInt32(1, v); } + @$pb.TagNumber(2) + $core.bool hasIndex() => $_has(1); + @$pb.TagNumber(2) + void clearIndex() => clearField(2); +} + +class GridRowsChangeset extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridRowsChangeset', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedRows', $pb.PbFieldType.PM, subBuilder: IndexRowOrder.create) + ..pc(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create) + ..pc(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create) + ..hasRequiredFields = false + ; + + GridRowsChangeset._() : super(); + factory GridRowsChangeset({ + $core.String? blockId, + $core.Iterable? insertedRows, + $core.Iterable? deletedRows, + $core.Iterable? updatedRows, + }) { + final _result = create(); + if (blockId != null) { + _result.blockId = blockId; + } + if (insertedRows != null) { + _result.insertedRows.addAll(insertedRows); + } + if (deletedRows != null) { + _result.deletedRows.addAll(deletedRows); + } + if (updatedRows != null) { + _result.updatedRows.addAll(updatedRows); + } + return _result; + } + factory GridRowsChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridRowsChangeset.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GridRowsChangeset clone() => GridRowsChangeset()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridRowsChangeset copyWith(void Function(GridRowsChangeset) updates) => super.copyWith((message) => updates(message as GridRowsChangeset)) as GridRowsChangeset; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridRowsChangeset create() => GridRowsChangeset._(); + GridRowsChangeset createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridRowsChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridRowsChangeset? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get blockId => $_getSZ(0); + @$pb.TagNumber(1) + set blockId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasBlockId() => $_has(0); + @$pb.TagNumber(1) + void clearBlockId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get insertedRows => $_getList(1); + + @$pb.TagNumber(3) + $core.List get deletedRows => $_getList(2); + + @$pb.TagNumber(4) + $core.List get updatedRows => $_getList(3); +} + +class GridBlock extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlock', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrders', $pb.PbFieldType.PM, subBuilder: RowOrder.create) + ..hasRequiredFields = false + ; + + GridBlock._() : super(); + factory GridBlock({ + $core.String? id, + $core.Iterable? rowOrders, + }) { + final _result = create(); + if (id != null) { + _result.id = id; + } + if (rowOrders != null) { + _result.rowOrders.addAll(rowOrders); + } + return _result; + } + factory GridBlock.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridBlock.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GridBlock clone() => GridBlock()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridBlock copyWith(void Function(GridBlock) updates) => super.copyWith((message) => updates(message as GridBlock)) as GridBlock; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridBlock create() => GridBlock._(); + GridBlock createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridBlock getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridBlock? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get id => $_getSZ(0); + @$pb.TagNumber(1) + set id($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasId() => $_has(0); + @$pb.TagNumber(1) + void clearId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get rowOrders => $_getList(1); +} + +class Cell extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Cell', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content') + ..hasRequiredFields = false + ; + + Cell._() : super(); + factory Cell({ + $core.String? fieldId, + $core.String? content, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (content != null) { + _result.content = content; + } + return _result; + } + factory Cell.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory Cell.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + Cell clone() => Cell()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + Cell copyWith(void Function(Cell) updates) => super.copyWith((message) => updates(message as Cell)) as Cell; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static Cell create() => Cell._(); + Cell createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static Cell getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Cell? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get content => $_getSZ(1); + @$pb.TagNumber(2) + set content($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasContent() => $_has(1); + @$pb.TagNumber(2) + void clearContent() => clearField(2); +} + +enum CellNotificationData_OneOfContent { + content, + notSet +} + +class CellNotificationData extends $pb.GeneratedMessage { + static const $core.Map<$core.int, CellNotificationData_OneOfContent> _CellNotificationData_OneOfContentByTag = { + 4 : CellNotificationData_OneOfContent.content, + 0 : CellNotificationData_OneOfContent.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellNotificationData', createEmptyInstance: create) + ..oo(0, [4]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content') + ..hasRequiredFields = false + ; + + CellNotificationData._() : super(); + factory CellNotificationData({ + $core.String? gridId, + $core.String? fieldId, + $core.String? rowId, + $core.String? content, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (rowId != null) { + _result.rowId = rowId; + } + if (content != null) { + _result.content = content; + } + return _result; + } + factory CellNotificationData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CellNotificationData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CellNotificationData clone() => CellNotificationData()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CellNotificationData copyWith(void Function(CellNotificationData) updates) => super.copyWith((message) => updates(message as CellNotificationData)) as CellNotificationData; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CellNotificationData create() => CellNotificationData._(); + CellNotificationData createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CellNotificationData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CellNotificationData? _defaultInstance; + + CellNotificationData_OneOfContent whichOneOfContent() => _CellNotificationData_OneOfContentByTag[$_whichOneof(0)]!; + void clearOneOfContent() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get fieldId => $_getSZ(1); + @$pb.TagNumber(2) + set fieldId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasFieldId() => $_has(1); + @$pb.TagNumber(2) + void clearFieldId() => clearField(2); + + @$pb.TagNumber(3) + $core.String get rowId => $_getSZ(2); + @$pb.TagNumber(3) + set rowId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasRowId() => $_has(2); + @$pb.TagNumber(3) + void clearRowId() => clearField(3); + + @$pb.TagNumber(4) + $core.String get content => $_getSZ(3); + @$pb.TagNumber(4) + set content($core.String v) { $_setString(3, v); } + @$pb.TagNumber(4) + $core.bool hasContent() => $_has(3); + @$pb.TagNumber(4) + void clearContent() => clearField(4); +} + +class RepeatedCell extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedCell', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Cell.create) + ..hasRequiredFields = false + ; + + RepeatedCell._() : super(); + factory RepeatedCell({ + $core.Iterable? items, + }) { + final _result = create(); + if (items != null) { + _result.items.addAll(items); + } + return _result; + } + factory RepeatedCell.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RepeatedCell.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RepeatedCell clone() => RepeatedCell()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RepeatedCell copyWith(void Function(RepeatedCell) updates) => super.copyWith((message) => updates(message as RepeatedCell)) as RepeatedCell; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RepeatedCell create() => RepeatedCell._(); + RepeatedCell createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RepeatedCell getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RepeatedCell? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get items => $_getList(0); +} + +class CreateGridPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateGridPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') + ..hasRequiredFields = false + ; + + CreateGridPayload._() : super(); + factory CreateGridPayload({ + $core.String? name, + }) { + final _result = create(); + if (name != null) { + _result.name = name; + } + return _result; + } + factory CreateGridPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CreateGridPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CreateGridPayload clone() => CreateGridPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CreateGridPayload copyWith(void Function(CreateGridPayload) updates) => super.copyWith((message) => updates(message as CreateGridPayload)) as CreateGridPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CreateGridPayload create() => CreateGridPayload._(); + CreateGridPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CreateGridPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CreateGridPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get name => $_getSZ(0); + @$pb.TagNumber(1) + set name($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasName() => $_has(0); + @$pb.TagNumber(1) + void clearName() => clearField(1); +} + +class GridId extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridId', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value') + ..hasRequiredFields = false + ; + + GridId._() : super(); + factory GridId({ + $core.String? value, + }) { + final _result = create(); + if (value != null) { + _result.value = value; + } + return _result; + } + factory GridId.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridId.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GridId clone() => GridId()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridId copyWith(void Function(GridId) updates) => super.copyWith((message) => updates(message as GridId)) as GridId; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridId create() => GridId._(); + GridId createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridId getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridId? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get value => $_getSZ(0); + @$pb.TagNumber(1) + set value($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasValue() => $_has(0); + @$pb.TagNumber(1) + void clearValue() => clearField(1); +} + +class GridBlockId extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockId', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value') + ..hasRequiredFields = false + ; + + GridBlockId._() : super(); + factory GridBlockId({ + $core.String? value, + }) { + final _result = create(); + if (value != null) { + _result.value = value; + } + return _result; + } + factory GridBlockId.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridBlockId.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + GridBlockId clone() => GridBlockId()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridBlockId copyWith(void Function(GridBlockId) updates) => super.copyWith((message) => updates(message as GridBlockId)) as GridBlockId; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridBlockId create() => GridBlockId._(); + GridBlockId createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridBlockId getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridBlockId? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get value => $_getSZ(0); + @$pb.TagNumber(1) + set value($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasValue() => $_has(0); + @$pb.TagNumber(1) + void clearValue() => clearField(1); +} + +enum CreateRowPayload_OneOfStartRowId { + startRowId, + notSet +} + +class CreateRowPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, CreateRowPayload_OneOfStartRowId> _CreateRowPayload_OneOfStartRowIdByTag = { + 2 : CreateRowPayload_OneOfStartRowId.startRowId, + 0 : CreateRowPayload_OneOfStartRowId.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateRowPayload', createEmptyInstance: create) + ..oo(0, [2]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'startRowId') + ..hasRequiredFields = false + ; + + CreateRowPayload._() : super(); + factory CreateRowPayload({ + $core.String? gridId, + $core.String? startRowId, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (startRowId != null) { + _result.startRowId = startRowId; + } + return _result; + } + factory CreateRowPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CreateRowPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CreateRowPayload clone() => CreateRowPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CreateRowPayload copyWith(void Function(CreateRowPayload) updates) => super.copyWith((message) => updates(message as CreateRowPayload)) as CreateRowPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CreateRowPayload create() => CreateRowPayload._(); + CreateRowPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CreateRowPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CreateRowPayload? _defaultInstance; + + CreateRowPayload_OneOfStartRowId whichOneOfStartRowId() => _CreateRowPayload_OneOfStartRowIdByTag[$_whichOneof(0)]!; + void clearOneOfStartRowId() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get startRowId => $_getSZ(1); + @$pb.TagNumber(2) + set startRowId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasStartRowId() => $_has(1); + @$pb.TagNumber(2) + void clearStartRowId() => clearField(2); +} + +enum InsertFieldPayload_OneOfStartFieldId { + startFieldId, + notSet +} + +class InsertFieldPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, InsertFieldPayload_OneOfStartFieldId> _InsertFieldPayload_OneOfStartFieldIdByTag = { + 4 : InsertFieldPayload_OneOfStartFieldId.startFieldId, + 0 : InsertFieldPayload_OneOfStartFieldId.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'InsertFieldPayload', createEmptyInstance: create) + ..oo(0, [4]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOM(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'field', subBuilder: Field.create) + ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY) + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'startFieldId') + ..hasRequiredFields = false + ; + + InsertFieldPayload._() : super(); + factory InsertFieldPayload({ + $core.String? gridId, + Field? field_2, + $core.List<$core.int>? typeOptionData, + $core.String? startFieldId, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (field_2 != null) { + _result.field_2 = field_2; + } + if (typeOptionData != null) { + _result.typeOptionData = typeOptionData; + } + if (startFieldId != null) { + _result.startFieldId = startFieldId; + } + return _result; + } + factory InsertFieldPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory InsertFieldPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + InsertFieldPayload clone() => InsertFieldPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + InsertFieldPayload copyWith(void Function(InsertFieldPayload) updates) => super.copyWith((message) => updates(message as InsertFieldPayload)) as InsertFieldPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static InsertFieldPayload create() => InsertFieldPayload._(); + InsertFieldPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static InsertFieldPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static InsertFieldPayload? _defaultInstance; + + InsertFieldPayload_OneOfStartFieldId whichOneOfStartFieldId() => _InsertFieldPayload_OneOfStartFieldIdByTag[$_whichOneof(0)]!; + void clearOneOfStartFieldId() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + Field get field_2 => $_getN(1); + @$pb.TagNumber(2) + set field_2(Field v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasField_2() => $_has(1); + @$pb.TagNumber(2) + void clearField_2() => clearField(2); + @$pb.TagNumber(2) + Field ensureField_2() => $_ensure(1); + + @$pb.TagNumber(3) + $core.List<$core.int> get typeOptionData => $_getN(2); + @$pb.TagNumber(3) + set typeOptionData($core.List<$core.int> v) { $_setBytes(2, v); } + @$pb.TagNumber(3) + $core.bool hasTypeOptionData() => $_has(2); + @$pb.TagNumber(3) + void clearTypeOptionData() => clearField(3); + + @$pb.TagNumber(4) + $core.String get startFieldId => $_getSZ(3); + @$pb.TagNumber(4) + set startFieldId($core.String v) { $_setString(3, v); } + @$pb.TagNumber(4) + $core.bool hasStartFieldId() => $_has(3); + @$pb.TagNumber(4) + void clearStartFieldId() => clearField(4); +} + +class QueryFieldPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryFieldPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOM(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldOrders', subBuilder: RepeatedFieldOrder.create) + ..hasRequiredFields = false + ; + + QueryFieldPayload._() : super(); + factory QueryFieldPayload({ + $core.String? gridId, + RepeatedFieldOrder? fieldOrders, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (fieldOrders != null) { + _result.fieldOrders = fieldOrders; + } + return _result; + } + factory QueryFieldPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory QueryFieldPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + QueryFieldPayload clone() => QueryFieldPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + QueryFieldPayload copyWith(void Function(QueryFieldPayload) updates) => super.copyWith((message) => updates(message as QueryFieldPayload)) as QueryFieldPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static QueryFieldPayload create() => QueryFieldPayload._(); + QueryFieldPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static QueryFieldPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static QueryFieldPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + RepeatedFieldOrder get fieldOrders => $_getN(1); + @$pb.TagNumber(2) + set fieldOrders(RepeatedFieldOrder v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasFieldOrders() => $_has(1); + @$pb.TagNumber(2) + void clearFieldOrders() => clearField(2); + @$pb.TagNumber(2) + RepeatedFieldOrder ensureFieldOrders() => $_ensure(1); +} + +class QueryGridBlocksPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryGridBlocksPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockOrders', $pb.PbFieldType.PM, subBuilder: GridBlockOrder.create) + ..hasRequiredFields = false + ; + + QueryGridBlocksPayload._() : super(); + factory QueryGridBlocksPayload({ + $core.String? gridId, + $core.Iterable? blockOrders, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (blockOrders != null) { + _result.blockOrders.addAll(blockOrders); + } + return _result; + } + factory QueryGridBlocksPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory QueryGridBlocksPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + QueryGridBlocksPayload clone() => QueryGridBlocksPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + QueryGridBlocksPayload copyWith(void Function(QueryGridBlocksPayload) updates) => super.copyWith((message) => updates(message as QueryGridBlocksPayload)) as QueryGridBlocksPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static QueryGridBlocksPayload create() => QueryGridBlocksPayload._(); + QueryGridBlocksPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static QueryGridBlocksPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static QueryGridBlocksPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get blockOrders => $_getList(1); +} + +enum FieldChangesetPayload_OneOfName { + name, + notSet +} + +enum FieldChangesetPayload_OneOfDesc { + desc, + notSet +} + +enum FieldChangesetPayload_OneOfFieldType { + fieldType, + notSet +} + +enum FieldChangesetPayload_OneOfFrozen { + frozen, + notSet +} + +enum FieldChangesetPayload_OneOfVisibility { + visibility, + notSet +} + +enum FieldChangesetPayload_OneOfWidth { + width, + notSet +} + +enum FieldChangesetPayload_OneOfTypeOptionData { + typeOptionData, + notSet +} + +class FieldChangesetPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, FieldChangesetPayload_OneOfName> _FieldChangesetPayload_OneOfNameByTag = { + 3 : FieldChangesetPayload_OneOfName.name, + 0 : FieldChangesetPayload_OneOfName.notSet + }; + static const $core.Map<$core.int, FieldChangesetPayload_OneOfDesc> _FieldChangesetPayload_OneOfDescByTag = { + 4 : FieldChangesetPayload_OneOfDesc.desc, + 0 : FieldChangesetPayload_OneOfDesc.notSet + }; + static const $core.Map<$core.int, FieldChangesetPayload_OneOfFieldType> _FieldChangesetPayload_OneOfFieldTypeByTag = { + 5 : FieldChangesetPayload_OneOfFieldType.fieldType, + 0 : FieldChangesetPayload_OneOfFieldType.notSet + }; + static const $core.Map<$core.int, FieldChangesetPayload_OneOfFrozen> _FieldChangesetPayload_OneOfFrozenByTag = { + 6 : FieldChangesetPayload_OneOfFrozen.frozen, + 0 : FieldChangesetPayload_OneOfFrozen.notSet + }; + static const $core.Map<$core.int, FieldChangesetPayload_OneOfVisibility> _FieldChangesetPayload_OneOfVisibilityByTag = { + 7 : FieldChangesetPayload_OneOfVisibility.visibility, + 0 : FieldChangesetPayload_OneOfVisibility.notSet + }; + static const $core.Map<$core.int, FieldChangesetPayload_OneOfWidth> _FieldChangesetPayload_OneOfWidthByTag = { + 8 : FieldChangesetPayload_OneOfWidth.width, + 0 : FieldChangesetPayload_OneOfWidth.notSet + }; + static const $core.Map<$core.int, FieldChangesetPayload_OneOfTypeOptionData> _FieldChangesetPayload_OneOfTypeOptionDataByTag = { + 9 : FieldChangesetPayload_OneOfTypeOptionData.typeOptionData, + 0 : FieldChangesetPayload_OneOfTypeOptionData.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldChangesetPayload', createEmptyInstance: create) + ..oo(0, [3]) + ..oo(1, [4]) + ..oo(2, [5]) + ..oo(3, [6]) + ..oo(4, [7]) + ..oo(5, [8]) + ..oo(6, [9]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc') + ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values) + ..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'frozen') + ..aOB(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'visibility') + ..a<$core.int>(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'width', $pb.PbFieldType.O3) + ..a<$core.List<$core.int>>(9, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + FieldChangesetPayload._() : super(); + factory FieldChangesetPayload({ + $core.String? fieldId, + $core.String? gridId, + $core.String? name, + $core.String? desc, + FieldType? fieldType, + $core.bool? frozen, + $core.bool? visibility, + $core.int? width, + $core.List<$core.int>? typeOptionData, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (gridId != null) { + _result.gridId = gridId; + } + if (name != null) { + _result.name = name; + } + if (desc != null) { + _result.desc = desc; + } + if (fieldType != null) { + _result.fieldType = fieldType; + } + if (frozen != null) { + _result.frozen = frozen; + } + if (visibility != null) { + _result.visibility = visibility; + } + if (width != null) { + _result.width = width; + } + if (typeOptionData != null) { + _result.typeOptionData = typeOptionData; + } + return _result; + } + factory FieldChangesetPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FieldChangesetPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + FieldChangesetPayload clone() => FieldChangesetPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FieldChangesetPayload copyWith(void Function(FieldChangesetPayload) updates) => super.copyWith((message) => updates(message as FieldChangesetPayload)) as FieldChangesetPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static FieldChangesetPayload create() => FieldChangesetPayload._(); + FieldChangesetPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FieldChangesetPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FieldChangesetPayload? _defaultInstance; + + FieldChangesetPayload_OneOfName whichOneOfName() => _FieldChangesetPayload_OneOfNameByTag[$_whichOneof(0)]!; + void clearOneOfName() => clearField($_whichOneof(0)); + + FieldChangesetPayload_OneOfDesc whichOneOfDesc() => _FieldChangesetPayload_OneOfDescByTag[$_whichOneof(1)]!; + void clearOneOfDesc() => clearField($_whichOneof(1)); + + FieldChangesetPayload_OneOfFieldType whichOneOfFieldType() => _FieldChangesetPayload_OneOfFieldTypeByTag[$_whichOneof(2)]!; + void clearOneOfFieldType() => clearField($_whichOneof(2)); + + FieldChangesetPayload_OneOfFrozen whichOneOfFrozen() => _FieldChangesetPayload_OneOfFrozenByTag[$_whichOneof(3)]!; + void clearOneOfFrozen() => clearField($_whichOneof(3)); + + FieldChangesetPayload_OneOfVisibility whichOneOfVisibility() => _FieldChangesetPayload_OneOfVisibilityByTag[$_whichOneof(4)]!; + void clearOneOfVisibility() => clearField($_whichOneof(4)); + + FieldChangesetPayload_OneOfWidth whichOneOfWidth() => _FieldChangesetPayload_OneOfWidthByTag[$_whichOneof(5)]!; + void clearOneOfWidth() => clearField($_whichOneof(5)); + + FieldChangesetPayload_OneOfTypeOptionData whichOneOfTypeOptionData() => _FieldChangesetPayload_OneOfTypeOptionDataByTag[$_whichOneof(6)]!; + void clearOneOfTypeOptionData() => clearField($_whichOneof(6)); + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get gridId => $_getSZ(1); + @$pb.TagNumber(2) + set gridId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasGridId() => $_has(1); + @$pb.TagNumber(2) + void clearGridId() => clearField(2); + + @$pb.TagNumber(3) + $core.String get name => $_getSZ(2); + @$pb.TagNumber(3) + set name($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasName() => $_has(2); + @$pb.TagNumber(3) + void clearName() => clearField(3); + + @$pb.TagNumber(4) + $core.String get desc => $_getSZ(3); + @$pb.TagNumber(4) + set desc($core.String v) { $_setString(3, v); } + @$pb.TagNumber(4) + $core.bool hasDesc() => $_has(3); + @$pb.TagNumber(4) + void clearDesc() => clearField(4); + + @$pb.TagNumber(5) + FieldType get fieldType => $_getN(4); + @$pb.TagNumber(5) + set fieldType(FieldType v) { setField(5, v); } + @$pb.TagNumber(5) + $core.bool hasFieldType() => $_has(4); + @$pb.TagNumber(5) + void clearFieldType() => clearField(5); + + @$pb.TagNumber(6) + $core.bool get frozen => $_getBF(5); + @$pb.TagNumber(6) + set frozen($core.bool v) { $_setBool(5, v); } + @$pb.TagNumber(6) + $core.bool hasFrozen() => $_has(5); + @$pb.TagNumber(6) + void clearFrozen() => clearField(6); + + @$pb.TagNumber(7) + $core.bool get visibility => $_getBF(6); + @$pb.TagNumber(7) + set visibility($core.bool v) { $_setBool(6, v); } + @$pb.TagNumber(7) + $core.bool hasVisibility() => $_has(6); + @$pb.TagNumber(7) + void clearVisibility() => clearField(7); + + @$pb.TagNumber(8) + $core.int get width => $_getIZ(7); + @$pb.TagNumber(8) + set width($core.int v) { $_setSignedInt32(7, v); } + @$pb.TagNumber(8) + $core.bool hasWidth() => $_has(7); + @$pb.TagNumber(8) + void clearWidth() => clearField(8); + + @$pb.TagNumber(9) + $core.List<$core.int> get typeOptionData => $_getN(8); + @$pb.TagNumber(9) + set typeOptionData($core.List<$core.int> v) { $_setBytes(8, v); } + @$pb.TagNumber(9) + $core.bool hasTypeOptionData() => $_has(8); + @$pb.TagNumber(9) + void clearTypeOptionData() => clearField(9); +} + +class MoveItemPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'MoveItemPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'itemId') + ..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fromIndex', $pb.PbFieldType.O3) + ..a<$core.int>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'toIndex', $pb.PbFieldType.O3) + ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: MoveItemType.MoveField, valueOf: MoveItemType.valueOf, enumValues: MoveItemType.values) + ..hasRequiredFields = false + ; + + MoveItemPayload._() : super(); + factory MoveItemPayload({ + $core.String? gridId, + $core.String? itemId, + $core.int? fromIndex, + $core.int? toIndex, + MoveItemType? ty, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (itemId != null) { + _result.itemId = itemId; + } + if (fromIndex != null) { + _result.fromIndex = fromIndex; + } + if (toIndex != null) { + _result.toIndex = toIndex; + } + if (ty != null) { + _result.ty = ty; + } + return _result; + } + factory MoveItemPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory MoveItemPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + MoveItemPayload clone() => MoveItemPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + MoveItemPayload copyWith(void Function(MoveItemPayload) updates) => super.copyWith((message) => updates(message as MoveItemPayload)) as MoveItemPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static MoveItemPayload create() => MoveItemPayload._(); + MoveItemPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static MoveItemPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static MoveItemPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get itemId => $_getSZ(1); + @$pb.TagNumber(2) + set itemId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasItemId() => $_has(1); + @$pb.TagNumber(2) + void clearItemId() => clearField(2); + + @$pb.TagNumber(3) + $core.int get fromIndex => $_getIZ(2); + @$pb.TagNumber(3) + set fromIndex($core.int v) { $_setSignedInt32(2, v); } + @$pb.TagNumber(3) + $core.bool hasFromIndex() => $_has(2); + @$pb.TagNumber(3) + void clearFromIndex() => clearField(3); + + @$pb.TagNumber(4) + $core.int get toIndex => $_getIZ(3); + @$pb.TagNumber(4) + set toIndex($core.int v) { $_setSignedInt32(3, v); } + @$pb.TagNumber(4) + $core.bool hasToIndex() => $_has(3); + @$pb.TagNumber(4) + void clearToIndex() => clearField(4); + + @$pb.TagNumber(5) + MoveItemType get ty => $_getN(4); + @$pb.TagNumber(5) + set ty(MoveItemType v) { setField(5, v); } + @$pb.TagNumber(5) + $core.bool hasTy() => $_has(4); + @$pb.TagNumber(5) + void clearTy() => clearField(5); +} + +enum CellChangeset_OneOfData { + data, + notSet +} + +class CellChangeset extends $pb.GeneratedMessage { + static const $core.Map<$core.int, CellChangeset_OneOfData> _CellChangeset_OneOfDataByTag = { + 4 : CellChangeset_OneOfData.data, + 0 : CellChangeset_OneOfData.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellChangeset', createEmptyInstance: create) + ..oo(0, [4]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data') + ..hasRequiredFields = false + ; + + CellChangeset._() : super(); + factory CellChangeset({ + $core.String? gridId, + $core.String? rowId, + $core.String? fieldId, + $core.String? data, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (rowId != null) { + _result.rowId = rowId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (data != null) { + _result.data = data; + } + return _result; + } + factory CellChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CellChangeset.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CellChangeset clone() => CellChangeset()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CellChangeset copyWith(void Function(CellChangeset) updates) => super.copyWith((message) => updates(message as CellChangeset)) as CellChangeset; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CellChangeset create() => CellChangeset._(); + CellChangeset createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CellChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CellChangeset? _defaultInstance; + + CellChangeset_OneOfData whichOneOfData() => _CellChangeset_OneOfDataByTag[$_whichOneof(0)]!; + void clearOneOfData() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get rowId => $_getSZ(1); + @$pb.TagNumber(2) + set rowId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasRowId() => $_has(1); + @$pb.TagNumber(2) + void clearRowId() => clearField(2); + + @$pb.TagNumber(3) + $core.String get fieldId => $_getSZ(2); + @$pb.TagNumber(3) + set fieldId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasFieldId() => $_has(2); + @$pb.TagNumber(3) + void clearFieldId() => clearField(3); + + @$pb.TagNumber(4) + $core.String get data => $_getSZ(3); + @$pb.TagNumber(4) + set data($core.String v) { $_setString(3, v); } + @$pb.TagNumber(4) + $core.bool hasData() => $_has(3); + @$pb.TagNumber(4) + void clearData() => clearField(4); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart new file mode 100644 index 0000000000..e6cb17314b --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart @@ -0,0 +1,49 @@ +/// +// Generated code. Do not modify. +// source: grid.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class MoveItemType extends $pb.ProtobufEnum { + static const MoveItemType MoveField = MoveItemType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveField'); + static const MoveItemType MoveRow = MoveItemType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveRow'); + + static const $core.List values = [ + MoveField, + MoveRow, + ]; + + static final $core.Map<$core.int, MoveItemType> _byValue = $pb.ProtobufEnum.initByValue(values); + static MoveItemType? valueOf($core.int value) => _byValue[value]; + + const MoveItemType._($core.int v, $core.String n) : super(v, n); +} + +class FieldType extends $pb.ProtobufEnum { + static const FieldType RichText = FieldType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RichText'); + static const FieldType Number = FieldType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Number'); + static const FieldType DateTime = FieldType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DateTime'); + static const FieldType SingleSelect = FieldType._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SingleSelect'); + static const FieldType MultiSelect = FieldType._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MultiSelect'); + static const FieldType Checkbox = FieldType._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Checkbox'); + + static const $core.List values = [ + RichText, + Number, + DateTime, + SingleSelect, + MultiSelect, + Checkbox, + ]; + + static final $core.Map<$core.int, FieldType> _byValue = $pb.ProtobufEnum.initByValue(values); + static FieldType? valueOf($core.int value) => _byValue[value]; + + const FieldType._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart new file mode 100644 index 0000000000..722a8ebcd6 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -0,0 +1,438 @@ +/// +// Generated code. Do not modify. +// source: grid.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use moveItemTypeDescriptor instead') +const MoveItemType$json = const { + '1': 'MoveItemType', + '2': const [ + const {'1': 'MoveField', '2': 0}, + const {'1': 'MoveRow', '2': 1}, + ], +}; + +/// Descriptor for `MoveItemType`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List moveItemTypeDescriptor = $convert.base64Decode('CgxNb3ZlSXRlbVR5cGUSDQoJTW92ZUZpZWxkEAASCwoHTW92ZVJvdxAB'); +@$core.Deprecated('Use fieldTypeDescriptor instead') +const FieldType$json = const { + '1': 'FieldType', + '2': const [ + const {'1': 'RichText', '2': 0}, + const {'1': 'Number', '2': 1}, + const {'1': 'DateTime', '2': 2}, + const {'1': 'SingleSelect', '2': 3}, + const {'1': 'MultiSelect', '2': 4}, + const {'1': 'Checkbox', '2': 5}, + ], +}; + +/// Descriptor for `FieldType`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List fieldTypeDescriptor = $convert.base64Decode('CglGaWVsZFR5cGUSDAoIUmljaFRleHQQABIKCgZOdW1iZXIQARIMCghEYXRlVGltZRACEhAKDFNpbmdsZVNlbGVjdBADEg8KC011bHRpU2VsZWN0EAQSDAoIQ2hlY2tib3gQBQ=='); +@$core.Deprecated('Use gridDescriptor instead') +const Grid$json = const { + '1': 'Grid', + '2': const [ + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + const {'1': 'field_orders', '3': 2, '4': 3, '5': 11, '6': '.FieldOrder', '10': 'fieldOrders'}, + const {'1': 'block_orders', '3': 3, '4': 3, '5': 11, '6': '.GridBlockOrder', '10': 'blockOrders'}, + ], +}; + +/// Descriptor for `Grid`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridDescriptor = $convert.base64Decode('CgRHcmlkEg4KAmlkGAEgASgJUgJpZBIuCgxmaWVsZF9vcmRlcnMYAiADKAsyCy5GaWVsZE9yZGVyUgtmaWVsZE9yZGVycxIyCgxibG9ja19vcmRlcnMYAyADKAsyDy5HcmlkQmxvY2tPcmRlclILYmxvY2tPcmRlcnM='); +@$core.Deprecated('Use fieldDescriptor instead') +const Field$json = const { + '1': 'Field', + '2': const [ + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'}, + const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'}, + const {'1': 'field_type', '3': 4, '4': 1, '5': 14, '6': '.FieldType', '10': 'fieldType'}, + const {'1': 'frozen', '3': 5, '4': 1, '5': 8, '10': 'frozen'}, + const {'1': 'visibility', '3': 6, '4': 1, '5': 8, '10': 'visibility'}, + const {'1': 'width', '3': 7, '4': 1, '5': 5, '10': 'width'}, + const {'1': 'is_primary', '3': 8, '4': 1, '5': 8, '10': 'isPrimary'}, + ], +}; + +/// Descriptor for `Field`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldDescriptor = $convert.base64Decode('CgVGaWVsZBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEikKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZRIWCgZmcm96ZW4YBSABKAhSBmZyb3plbhIeCgp2aXNpYmlsaXR5GAYgASgIUgp2aXNpYmlsaXR5EhQKBXdpZHRoGAcgASgFUgV3aWR0aBIdCgppc19wcmltYXJ5GAggASgIUglpc1ByaW1hcnk='); +@$core.Deprecated('Use fieldOrderDescriptor instead') +const FieldOrder$json = const { + '1': 'FieldOrder', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + ], +}; + +/// Descriptor for `FieldOrder`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldOrderDescriptor = $convert.base64Decode('CgpGaWVsZE9yZGVyEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElk'); +@$core.Deprecated('Use gridFieldChangesetDescriptor instead') +const GridFieldChangeset$json = const { + '1': 'GridFieldChangeset', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'inserted_fields', '3': 2, '4': 3, '5': 11, '6': '.IndexField', '10': 'insertedFields'}, + const {'1': 'deleted_fields', '3': 3, '4': 3, '5': 11, '6': '.FieldOrder', '10': 'deletedFields'}, + const {'1': 'updated_fields', '3': 4, '4': 3, '5': 11, '6': '.Field', '10': 'updatedFields'}, + ], +}; + +/// Descriptor for `GridFieldChangeset`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridFieldChangesetDescriptor = $convert.base64Decode('ChJHcmlkRmllbGRDaGFuZ2VzZXQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEjQKD2luc2VydGVkX2ZpZWxkcxgCIAMoCzILLkluZGV4RmllbGRSDmluc2VydGVkRmllbGRzEjIKDmRlbGV0ZWRfZmllbGRzGAMgAygLMgsuRmllbGRPcmRlclINZGVsZXRlZEZpZWxkcxItCg51cGRhdGVkX2ZpZWxkcxgEIAMoCzIGLkZpZWxkUg11cGRhdGVkRmllbGRz'); +@$core.Deprecated('Use indexFieldDescriptor instead') +const IndexField$json = const { + '1': 'IndexField', + '2': const [ + const {'1': 'field', '3': 1, '4': 1, '5': 11, '6': '.Field', '10': 'field'}, + const {'1': 'index', '3': 2, '4': 1, '5': 5, '10': 'index'}, + ], +}; + +/// Descriptor for `IndexField`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List indexFieldDescriptor = $convert.base64Decode('CgpJbmRleEZpZWxkEhwKBWZpZWxkGAEgASgLMgYuRmllbGRSBWZpZWxkEhQKBWluZGV4GAIgASgFUgVpbmRleA=='); +@$core.Deprecated('Use getEditFieldContextPayloadDescriptor instead') +const GetEditFieldContextPayload$json = const { + '1': 'GetEditFieldContextPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'fieldId'}, + const {'1': 'field_type', '3': 3, '4': 1, '5': 14, '6': '.FieldType', '10': 'fieldType'}, + ], + '8': const [ + const {'1': 'one_of_field_id'}, + ], +}; + +/// Descriptor for `GetEditFieldContextPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List getEditFieldContextPayloadDescriptor = $convert.base64Decode('ChpHZXRFZGl0RmllbGRDb250ZXh0UGF5bG9hZBIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSGwoIZmllbGRfaWQYAiABKAlIAFIHZmllbGRJZBIpCgpmaWVsZF90eXBlGAMgASgOMgouRmllbGRUeXBlUglmaWVsZFR5cGVCEQoPb25lX29mX2ZpZWxkX2lk'); +@$core.Deprecated('Use editFieldPayloadDescriptor instead') +const EditFieldPayload$json = const { + '1': 'EditFieldPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'field_type', '3': 3, '4': 1, '5': 14, '6': '.FieldType', '10': 'fieldType'}, + ], +}; + +/// Descriptor for `EditFieldPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List editFieldPayloadDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIZCghmaWVsZF9pZBgCIAEoCVIHZmllbGRJZBIpCgpmaWVsZF90eXBlGAMgASgOMgouRmllbGRUeXBlUglmaWVsZFR5cGU='); +@$core.Deprecated('Use editFieldContextDescriptor instead') +const EditFieldContext$json = const { + '1': 'EditFieldContext', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'grid_field', '3': 2, '4': 1, '5': 11, '6': '.Field', '10': 'gridField'}, + const {'1': 'type_option_data', '3': 3, '4': 1, '5': 12, '10': 'typeOptionData'}, + ], +}; + +/// Descriptor for `EditFieldContext`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List editFieldContextDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRDb250ZXh0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIlCgpncmlkX2ZpZWxkGAIgASgLMgYuRmllbGRSCWdyaWRGaWVsZBIoChB0eXBlX29wdGlvbl9kYXRhGAMgASgMUg50eXBlT3B0aW9uRGF0YQ=='); +@$core.Deprecated('Use repeatedFieldDescriptor instead') +const RepeatedField$json = const { + '1': 'RepeatedField', + '2': const [ + const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.Field', '10': 'items'}, + ], +}; + +/// Descriptor for `RepeatedField`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List repeatedFieldDescriptor = $convert.base64Decode('Cg1SZXBlYXRlZEZpZWxkEhwKBWl0ZW1zGAEgAygLMgYuRmllbGRSBWl0ZW1z'); +@$core.Deprecated('Use repeatedFieldOrderDescriptor instead') +const RepeatedFieldOrder$json = const { + '1': 'RepeatedFieldOrder', + '2': const [ + const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.FieldOrder', '10': 'items'}, + ], +}; + +/// Descriptor for `RepeatedFieldOrder`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List repeatedFieldOrderDescriptor = $convert.base64Decode('ChJSZXBlYXRlZEZpZWxkT3JkZXISIQoFaXRlbXMYASADKAsyCy5GaWVsZE9yZGVyUgVpdGVtcw=='); +@$core.Deprecated('Use rowOrderDescriptor instead') +const RowOrder$json = const { + '1': 'RowOrder', + '2': const [ + const {'1': 'row_id', '3': 1, '4': 1, '5': 9, '10': 'rowId'}, + const {'1': 'block_id', '3': 2, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'height', '3': 3, '4': 1, '5': 5, '10': 'height'}, + ], +}; + +/// Descriptor for `RowOrder`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lkEhkKCGJsb2NrX2lkGAIgASgJUgdibG9ja0lkEhYKBmhlaWdodBgDIAEoBVIGaGVpZ2h0'); +@$core.Deprecated('Use rowDescriptor instead') +const Row$json = const { + '1': 'Row', + '2': const [ + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + const {'1': 'cell_by_field_id', '3': 2, '4': 3, '5': 11, '6': '.Row.CellByFieldIdEntry', '10': 'cellByFieldId'}, + const {'1': 'height', '3': 3, '4': 1, '5': 5, '10': 'height'}, + ], + '3': const [Row_CellByFieldIdEntry$json], +}; + +@$core.Deprecated('Use rowDescriptor instead') +const Row_CellByFieldIdEntry$json = const { + '1': 'CellByFieldIdEntry', + '2': const [ + const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, + const {'1': 'value', '3': 2, '4': 1, '5': 11, '6': '.Cell', '10': 'value'}, + ], + '7': const {'7': true}, +}; + +/// Descriptor for `Row`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List rowDescriptor = $convert.base64Decode('CgNSb3cSDgoCaWQYASABKAlSAmlkEkAKEGNlbGxfYnlfZmllbGRfaWQYAiADKAsyFy5Sb3cuQ2VsbEJ5RmllbGRJZEVudHJ5Ug1jZWxsQnlGaWVsZElkEhYKBmhlaWdodBgDIAEoBVIGaGVpZ2h0GkcKEkNlbGxCeUZpZWxkSWRFbnRyeRIQCgNrZXkYASABKAlSA2tleRIbCgV2YWx1ZRgCIAEoCzIFLkNlbGxSBXZhbHVlOgI4AQ=='); +@$core.Deprecated('Use repeatedRowDescriptor instead') +const RepeatedRow$json = const { + '1': 'RepeatedRow', + '2': const [ + const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.Row', '10': 'items'}, + ], +}; + +/// Descriptor for `RepeatedRow`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List repeatedRowDescriptor = $convert.base64Decode('CgtSZXBlYXRlZFJvdxIaCgVpdGVtcxgBIAMoCzIELlJvd1IFaXRlbXM='); +@$core.Deprecated('Use repeatedGridBlockDescriptor instead') +const RepeatedGridBlock$json = const { + '1': 'RepeatedGridBlock', + '2': const [ + const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.GridBlock', '10': 'items'}, + ], +}; + +/// Descriptor for `RepeatedGridBlock`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List repeatedGridBlockDescriptor = $convert.base64Decode('ChFSZXBlYXRlZEdyaWRCbG9jaxIgCgVpdGVtcxgBIAMoCzIKLkdyaWRCbG9ja1IFaXRlbXM='); +@$core.Deprecated('Use gridBlockOrderDescriptor instead') +const GridBlockOrder$json = const { + '1': 'GridBlockOrder', + '2': const [ + const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'row_orders', '3': 2, '4': 3, '5': 11, '6': '.RowOrder', '10': 'rowOrders'}, + ], +}; + +/// Descriptor for `GridBlockOrder`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg5HcmlkQmxvY2tPcmRlchIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIoCgpyb3dfb3JkZXJzGAIgAygLMgkuUm93T3JkZXJSCXJvd09yZGVycw=='); +@$core.Deprecated('Use indexRowOrderDescriptor instead') +const IndexRowOrder$json = const { + '1': 'IndexRowOrder', + '2': const [ + const {'1': 'row_order', '3': 1, '4': 1, '5': 11, '6': '.RowOrder', '10': 'rowOrder'}, + const {'1': 'index', '3': 2, '4': 1, '5': 5, '9': 0, '10': 'index'}, + ], + '8': const [ + const {'1': 'one_of_index'}, + ], +}; + +/// Descriptor for `IndexRowOrder`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List indexRowOrderDescriptor = $convert.base64Decode('Cg1JbmRleFJvd09yZGVyEiYKCXJvd19vcmRlchgBIAEoCzIJLlJvd09yZGVyUghyb3dPcmRlchIWCgVpbmRleBgCIAEoBUgAUgVpbmRleEIOCgxvbmVfb2ZfaW5kZXg='); +@$core.Deprecated('Use gridRowsChangesetDescriptor instead') +const GridRowsChangeset$json = const { + '1': 'GridRowsChangeset', + '2': const [ + const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'inserted_rows', '3': 2, '4': 3, '5': 11, '6': '.IndexRowOrder', '10': 'insertedRows'}, + const {'1': 'deleted_rows', '3': 3, '4': 3, '5': 11, '6': '.RowOrder', '10': 'deletedRows'}, + const {'1': 'updated_rows', '3': 4, '4': 3, '5': 11, '6': '.RowOrder', '10': 'updatedRows'}, + ], +}; + +/// Descriptor for `GridRowsChangeset`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M='); +@$core.Deprecated('Use gridBlockDescriptor instead') +const GridBlock$json = const { + '1': 'GridBlock', + '2': const [ + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + const {'1': 'row_orders', '3': 2, '4': 3, '5': 11, '6': '.RowOrder', '10': 'rowOrders'}, + ], +}; + +/// Descriptor for `GridBlock`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSDgoCaWQYASABKAlSAmlkEigKCnJvd19vcmRlcnMYAiADKAsyCS5Sb3dPcmRlclIJcm93T3JkZXJz'); +@$core.Deprecated('Use cellDescriptor instead') +const Cell$json = const { + '1': 'Cell', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'content', '3': 2, '4': 1, '5': 9, '10': 'content'}, + ], +}; + +/// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ='); +@$core.Deprecated('Use cellNotificationDataDescriptor instead') +const CellNotificationData$json = const { + '1': 'CellNotificationData', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'row_id', '3': 3, '4': 1, '5': 9, '10': 'rowId'}, + const {'1': 'content', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'content'}, + ], + '8': const [ + const {'1': 'one_of_content'}, + ], +}; + +/// Descriptor for `CellNotificationData`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List cellNotificationDataDescriptor = $convert.base64Decode('ChRDZWxsTm90aWZpY2F0aW9uRGF0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSGQoIZmllbGRfaWQYAiABKAlSB2ZpZWxkSWQSFQoGcm93X2lkGAMgASgJUgVyb3dJZBIaCgdjb250ZW50GAQgASgJSABSB2NvbnRlbnRCEAoOb25lX29mX2NvbnRlbnQ='); +@$core.Deprecated('Use repeatedCellDescriptor instead') +const RepeatedCell$json = const { + '1': 'RepeatedCell', + '2': const [ + const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.Cell', '10': 'items'}, + ], +}; + +/// Descriptor for `RepeatedCell`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List repeatedCellDescriptor = $convert.base64Decode('CgxSZXBlYXRlZENlbGwSGwoFaXRlbXMYASADKAsyBS5DZWxsUgVpdGVtcw=='); +@$core.Deprecated('Use createGridPayloadDescriptor instead') +const CreateGridPayload$json = const { + '1': 'CreateGridPayload', + '2': const [ + const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, + ], +}; + +/// Descriptor for `CreateGridPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List createGridPayloadDescriptor = $convert.base64Decode('ChFDcmVhdGVHcmlkUGF5bG9hZBISCgRuYW1lGAEgASgJUgRuYW1l'); +@$core.Deprecated('Use gridIdDescriptor instead') +const GridId$json = const { + '1': 'GridId', + '2': const [ + const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'}, + ], +}; + +/// Descriptor for `GridId`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridIdDescriptor = $convert.base64Decode('CgZHcmlkSWQSFAoFdmFsdWUYASABKAlSBXZhbHVl'); +@$core.Deprecated('Use gridBlockIdDescriptor instead') +const GridBlockId$json = const { + '1': 'GridBlockId', + '2': const [ + const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'}, + ], +}; + +/// Descriptor for `GridBlockId`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridBlockIdDescriptor = $convert.base64Decode('CgtHcmlkQmxvY2tJZBIUCgV2YWx1ZRgBIAEoCVIFdmFsdWU='); +@$core.Deprecated('Use createRowPayloadDescriptor instead') +const CreateRowPayload$json = const { + '1': 'CreateRowPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'start_row_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'startRowId'}, + ], + '8': const [ + const {'1': 'one_of_start_row_id'}, + ], +}; + +/// Descriptor for `CreateRowPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List createRowPayloadDescriptor = $convert.base64Decode('ChBDcmVhdGVSb3dQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIiCgxzdGFydF9yb3dfaWQYAiABKAlIAFIKc3RhcnRSb3dJZEIVChNvbmVfb2Zfc3RhcnRfcm93X2lk'); +@$core.Deprecated('Use insertFieldPayloadDescriptor instead') +const InsertFieldPayload$json = const { + '1': 'InsertFieldPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field', '3': 2, '4': 1, '5': 11, '6': '.Field', '10': 'field'}, + const {'1': 'type_option_data', '3': 3, '4': 1, '5': 12, '10': 'typeOptionData'}, + const {'1': 'start_field_id', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'startFieldId'}, + ], + '8': const [ + const {'1': 'one_of_start_field_id'}, + ], +}; + +/// Descriptor for `InsertFieldPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List insertFieldPayloadDescriptor = $convert.base64Decode('ChJJbnNlcnRGaWVsZFBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhwKBWZpZWxkGAIgASgLMgYuRmllbGRSBWZpZWxkEigKEHR5cGVfb3B0aW9uX2RhdGEYAyABKAxSDnR5cGVPcHRpb25EYXRhEiYKDnN0YXJ0X2ZpZWxkX2lkGAQgASgJSABSDHN0YXJ0RmllbGRJZEIXChVvbmVfb2Zfc3RhcnRfZmllbGRfaWQ='); +@$core.Deprecated('Use queryFieldPayloadDescriptor instead') +const QueryFieldPayload$json = const { + '1': 'QueryFieldPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field_orders', '3': 2, '4': 1, '5': 11, '6': '.RepeatedFieldOrder', '10': 'fieldOrders'}, + ], +}; + +/// Descriptor for `QueryFieldPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List queryFieldPayloadDescriptor = $convert.base64Decode('ChFRdWVyeUZpZWxkUGF5bG9hZBIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSNgoMZmllbGRfb3JkZXJzGAIgASgLMhMuUmVwZWF0ZWRGaWVsZE9yZGVyUgtmaWVsZE9yZGVycw=='); +@$core.Deprecated('Use queryGridBlocksPayloadDescriptor instead') +const QueryGridBlocksPayload$json = const { + '1': 'QueryGridBlocksPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'block_orders', '3': 2, '4': 3, '5': 11, '6': '.GridBlockOrder', '10': 'blockOrders'}, + ], +}; + +/// Descriptor for `QueryGridBlocksPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List queryGridBlocksPayloadDescriptor = $convert.base64Decode('ChZRdWVyeUdyaWRCbG9ja3NQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIyCgxibG9ja19vcmRlcnMYAiADKAsyDy5HcmlkQmxvY2tPcmRlclILYmxvY2tPcmRlcnM='); +@$core.Deprecated('Use fieldChangesetPayloadDescriptor instead') +const FieldChangesetPayload$json = const { + '1': 'FieldChangesetPayload', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'grid_id', '3': 2, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'name', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'name'}, + const {'1': 'desc', '3': 4, '4': 1, '5': 9, '9': 1, '10': 'desc'}, + const {'1': 'field_type', '3': 5, '4': 1, '5': 14, '6': '.FieldType', '9': 2, '10': 'fieldType'}, + const {'1': 'frozen', '3': 6, '4': 1, '5': 8, '9': 3, '10': 'frozen'}, + const {'1': 'visibility', '3': 7, '4': 1, '5': 8, '9': 4, '10': 'visibility'}, + const {'1': 'width', '3': 8, '4': 1, '5': 5, '9': 5, '10': 'width'}, + const {'1': 'type_option_data', '3': 9, '4': 1, '5': 12, '9': 6, '10': 'typeOptionData'}, + ], + '8': const [ + const {'1': 'one_of_name'}, + const {'1': 'one_of_desc'}, + const {'1': 'one_of_field_type'}, + const {'1': 'one_of_frozen'}, + const {'1': 'one_of_visibility'}, + const {'1': 'one_of_width'}, + const {'1': 'one_of_type_option_data'}, + ], +}; + +/// Descriptor for `FieldChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldChangesetPayloadDescriptor = $convert.base64Decode('ChVGaWVsZENoYW5nZXNldFBheWxvYWQSGQoIZmllbGRfaWQYASABKAlSB2ZpZWxkSWQSFwoHZ3JpZF9pZBgCIAEoCVIGZ3JpZElkEhQKBG5hbWUYAyABKAlIAFIEbmFtZRIUCgRkZXNjGAQgASgJSAFSBGRlc2MSKwoKZmllbGRfdHlwZRgFIAEoDjIKLkZpZWxkVHlwZUgCUglmaWVsZFR5cGUSGAoGZnJvemVuGAYgASgISANSBmZyb3plbhIgCgp2aXNpYmlsaXR5GAcgASgISARSCnZpc2liaWxpdHkSFgoFd2lkdGgYCCABKAVIBVIFd2lkdGgSKgoQdHlwZV9vcHRpb25fZGF0YRgJIAEoDEgGUg50eXBlT3B0aW9uRGF0YUINCgtvbmVfb2ZfbmFtZUINCgtvbmVfb2ZfZGVzY0ITChFvbmVfb2ZfZmllbGRfdHlwZUIPCg1vbmVfb2ZfZnJvemVuQhMKEW9uZV9vZl92aXNpYmlsaXR5Qg4KDG9uZV9vZl93aWR0aEIZChdvbmVfb2ZfdHlwZV9vcHRpb25fZGF0YQ=='); +@$core.Deprecated('Use moveItemPayloadDescriptor instead') +const MoveItemPayload$json = const { + '1': 'MoveItemPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'item_id', '3': 2, '4': 1, '5': 9, '10': 'itemId'}, + const {'1': 'from_index', '3': 3, '4': 1, '5': 5, '10': 'fromIndex'}, + const {'1': 'to_index', '3': 4, '4': 1, '5': 5, '10': 'toIndex'}, + const {'1': 'ty', '3': 5, '4': 1, '5': 14, '6': '.MoveItemType', '10': 'ty'}, + ], +}; + +/// Descriptor for `MoveItemPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List moveItemPayloadDescriptor = $convert.base64Decode('Cg9Nb3ZlSXRlbVBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhcKB2l0ZW1faWQYAiABKAlSBml0ZW1JZBIdCgpmcm9tX2luZGV4GAMgASgFUglmcm9tSW5kZXgSGQoIdG9faW5kZXgYBCABKAVSB3RvSW5kZXgSHQoCdHkYBSABKA4yDS5Nb3ZlSXRlbVR5cGVSAnR5'); +@$core.Deprecated('Use cellChangesetDescriptor instead') +const CellChangeset$json = const { + '1': 'CellChangeset', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'row_id', '3': 2, '4': 1, '5': 9, '10': 'rowId'}, + const {'1': 'field_id', '3': 3, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'data', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'data'}, + ], + '8': const [ + const {'1': 'one_of_data'}, + ], +}; + +/// Descriptor for `CellChangeset`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List cellChangesetDescriptor = $convert.base64Decode('Cg1DZWxsQ2hhbmdlc2V0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIVCgZyb3dfaWQYAiABKAlSBXJvd0lkEhkKCGZpZWxkX2lkGAMgASgJUgdmaWVsZElkEhQKBGRhdGEYBCABKAlIAFIEZGF0YUINCgtvbmVfb2ZfZGF0YQ=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbserver.dart similarity index 86% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbserver.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbserver.dart index 2fa95db4fe..1ea5bad0ba 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/share.pbserver.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbserver.dart @@ -1,9 +1,9 @@ /// // Generated code. Do not modify. -// source: share.proto +// source: grid.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package -export 'share.pb.dart'; +export 'grid.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/protobuf.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/protobuf.dart new file mode 100644 index 0000000000..3f0100c8d6 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/protobuf.dart @@ -0,0 +1,2 @@ +// Auto-generated, do not edit +export './grid.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pb.dart new file mode 100644 index 0000000000..7645632fb8 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pb.dart @@ -0,0 +1,151 @@ +/// +// Generated code. Do not modify. +// source: cell_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'field_entities.pb.dart' as $0; + +class CreateSelectOptionPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateSelectOptionPayload', createEmptyInstance: create) + ..aOM<$0.FieldIdentifierPayload>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldIdentifier', subBuilder: $0.FieldIdentifierPayload.create) + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'optionName') + ..hasRequiredFields = false + ; + + CreateSelectOptionPayload._() : super(); + factory CreateSelectOptionPayload({ + $0.FieldIdentifierPayload? fieldIdentifier, + $core.String? optionName, + }) { + final _result = create(); + if (fieldIdentifier != null) { + _result.fieldIdentifier = fieldIdentifier; + } + if (optionName != null) { + _result.optionName = optionName; + } + return _result; + } + factory CreateSelectOptionPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CreateSelectOptionPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CreateSelectOptionPayload clone() => CreateSelectOptionPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CreateSelectOptionPayload copyWith(void Function(CreateSelectOptionPayload) updates) => super.copyWith((message) => updates(message as CreateSelectOptionPayload)) as CreateSelectOptionPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CreateSelectOptionPayload create() => CreateSelectOptionPayload._(); + CreateSelectOptionPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CreateSelectOptionPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CreateSelectOptionPayload? _defaultInstance; + + @$pb.TagNumber(1) + $0.FieldIdentifierPayload get fieldIdentifier => $_getN(0); + @$pb.TagNumber(1) + set fieldIdentifier($0.FieldIdentifierPayload v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasFieldIdentifier() => $_has(0); + @$pb.TagNumber(1) + void clearFieldIdentifier() => clearField(1); + @$pb.TagNumber(1) + $0.FieldIdentifierPayload ensureFieldIdentifier() => $_ensure(0); + + @$pb.TagNumber(2) + $core.String get optionName => $_getSZ(1); + @$pb.TagNumber(2) + set optionName($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasOptionName() => $_has(1); + @$pb.TagNumber(2) + void clearOptionName() => clearField(2); +} + +class CellIdentifierPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellIdentifierPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') + ..hasRequiredFields = false + ; + + CellIdentifierPayload._() : super(); + factory CellIdentifierPayload({ + $core.String? gridId, + $core.String? fieldId, + $core.String? rowId, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (rowId != null) { + _result.rowId = rowId; + } + return _result; + } + factory CellIdentifierPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CellIdentifierPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CellIdentifierPayload clone() => CellIdentifierPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CellIdentifierPayload copyWith(void Function(CellIdentifierPayload) updates) => super.copyWith((message) => updates(message as CellIdentifierPayload)) as CellIdentifierPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CellIdentifierPayload create() => CellIdentifierPayload._(); + CellIdentifierPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CellIdentifierPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CellIdentifierPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get fieldId => $_getSZ(1); + @$pb.TagNumber(2) + set fieldId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasFieldId() => $_has(1); + @$pb.TagNumber(2) + void clearFieldId() => clearField(2); + + @$pb.TagNumber(3) + $core.String get rowId => $_getSZ(2); + @$pb.TagNumber(3) + set rowId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasRowId() => $_has(2); + @$pb.TagNumber(3) + void clearRowId() => clearField(3); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbenum.dart similarity index 89% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbenum.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbenum.dart index 4c8f36115e..a53c27b1fe 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbenum.dart @@ -1,6 +1,6 @@ /// // Generated code. Do not modify. -// source: document_info.proto +// source: cell_entities.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbjson.dart new file mode 100644 index 0000000000..931b310a69 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbjson.dart @@ -0,0 +1,33 @@ +/// +// Generated code. Do not modify. +// source: cell_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use createSelectOptionPayloadDescriptor instead') +const CreateSelectOptionPayload$json = const { + '1': 'CreateSelectOptionPayload', + '2': const [ + const {'1': 'field_identifier', '3': 1, '4': 1, '5': 11, '6': '.FieldIdentifierPayload', '10': 'fieldIdentifier'}, + const {'1': 'option_name', '3': 2, '4': 1, '5': 9, '10': 'optionName'}, + ], +}; + +/// Descriptor for `CreateSelectOptionPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List createSelectOptionPayloadDescriptor = $convert.base64Decode('ChlDcmVhdGVTZWxlY3RPcHRpb25QYXlsb2FkEkIKEGZpZWxkX2lkZW50aWZpZXIYASABKAsyFy5GaWVsZElkZW50aWZpZXJQYXlsb2FkUg9maWVsZElkZW50aWZpZXISHwoLb3B0aW9uX25hbWUYAiABKAlSCm9wdGlvbk5hbWU='); +@$core.Deprecated('Use cellIdentifierPayloadDescriptor instead') +const CellIdentifierPayload$json = const { + '1': 'CellIdentifierPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'row_id', '3': 3, '4': 1, '5': 9, '10': 'rowId'}, + ], +}; + +/// Descriptor for `CellIdentifierPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List cellIdentifierPayloadDescriptor = $convert.base64Decode('ChVDZWxsSWRlbnRpZmllclBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhkKCGZpZWxkX2lkGAIgASgJUgdmaWVsZElkEhUKBnJvd19pZBgDIAEoCVIFcm93SWQ='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbserver.dart new file mode 100644 index 0000000000..a0f185bca8 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/cell_entities.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: cell_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'cell_entities.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pb.dart new file mode 100644 index 0000000000..fb907766cf --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pb.dart @@ -0,0 +1,58 @@ +/// +// Generated code. Do not modify. +// source: checkbox_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class CheckboxTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CheckboxTypeOption', createEmptyInstance: create) + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isSelected') + ..hasRequiredFields = false + ; + + CheckboxTypeOption._() : super(); + factory CheckboxTypeOption({ + $core.bool? isSelected, + }) { + final _result = create(); + if (isSelected != null) { + _result.isSelected = isSelected; + } + return _result; + } + factory CheckboxTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CheckboxTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + CheckboxTypeOption clone() => CheckboxTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CheckboxTypeOption copyWith(void Function(CheckboxTypeOption) updates) => super.copyWith((message) => updates(message as CheckboxTypeOption)) as CheckboxTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CheckboxTypeOption create() => CheckboxTypeOption._(); + CheckboxTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CheckboxTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CheckboxTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + $core.bool get isSelected => $_getBF(0); + @$pb.TagNumber(1) + set isSelected($core.bool v) { $_setBool(0, v); } + @$pb.TagNumber(1) + $core.bool hasIsSelected() => $_has(0); + @$pb.TagNumber(1) + void clearIsSelected() => clearField(1); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbenum.dart new file mode 100644 index 0000000000..7c03d6985e --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: checkbox_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbjson.dart new file mode 100644 index 0000000000..33c4627985 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbjson.dart @@ -0,0 +1,20 @@ +/// +// Generated code. Do not modify. +// source: checkbox_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use checkboxTypeOptionDescriptor instead') +const CheckboxTypeOption$json = const { + '1': 'CheckboxTypeOption', + '2': const [ + const {'1': 'is_selected', '3': 1, '4': 1, '5': 8, '10': 'isSelected'}, + ], +}; + +/// Descriptor for `CheckboxTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List checkboxTypeOptionDescriptor = $convert.base64Decode('ChJDaGVja2JveFR5cGVPcHRpb24SHwoLaXNfc2VsZWN0ZWQYASABKAhSCmlzU2VsZWN0ZWQ='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbserver.dart new file mode 100644 index 0000000000..5424623115 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/checkbox_type_option.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: checkbox_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'checkbox_type_option.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pb.dart new file mode 100644 index 0000000000..402c0a4115 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pb.dart @@ -0,0 +1,11 @@ +/// +// Generated code. Do not modify. +// source: dart_notification.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +export 'dart_notification.pbenum.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart new file mode 100644 index 0000000000..7a89d33361 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart @@ -0,0 +1,36 @@ +/// +// Generated code. Do not modify. +// source: dart_notification.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class GridNotification extends $pb.ProtobufEnum { + static const GridNotification Unknown = GridNotification._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown'); + static const GridNotification DidCreateBlock = GridNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidCreateBlock'); + static const GridNotification DidUpdateGridRow = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridRow'); + static const GridNotification DidUpdateGridField = GridNotification._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridField'); + static const GridNotification DidUpdateRow = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateRow'); + static const GridNotification DidUpdateCell = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateCell'); + static const GridNotification DidUpdateField = GridNotification._(50, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateField'); + + static const $core.List values = [ + Unknown, + DidCreateBlock, + DidUpdateGridRow, + DidUpdateGridField, + DidUpdateRow, + DidUpdateCell, + DidUpdateField, + ]; + + static final $core.Map<$core.int, GridNotification> _byValue = $pb.ProtobufEnum.initByValue(values); + static GridNotification? valueOf($core.int value) => _byValue[value]; + + const GridNotification._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart new file mode 100644 index 0000000000..96a087ca40 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart @@ -0,0 +1,26 @@ +/// +// Generated code. Do not modify. +// source: dart_notification.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use gridNotificationDescriptor instead') +const GridNotification$json = const { + '1': 'GridNotification', + '2': const [ + const {'1': 'Unknown', '2': 0}, + const {'1': 'DidCreateBlock', '2': 11}, + const {'1': 'DidUpdateGridRow', '2': 20}, + const {'1': 'DidUpdateGridField', '2': 21}, + const {'1': 'DidUpdateRow', '2': 30}, + const {'1': 'DidUpdateCell', '2': 40}, + const {'1': 'DidUpdateField', '2': 50}, + ], +}; + +/// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhQKEERpZFVwZGF0ZUdyaWRSb3cQFBIWChJEaWRVcGRhdGVHcmlkRmllbGQQFRIQCgxEaWRVcGRhdGVSb3cQHhIRCg1EaWRVcGRhdGVDZWxsECgSEgoORGlkVXBkYXRlRmllbGQQMg=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbserver.dart new file mode 100644 index 0000000000..8be819e83e --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: dart_notification.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'dart_notification.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart new file mode 100644 index 0000000000..db19e676d1 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart @@ -0,0 +1,90 @@ +/// +// Generated code. Do not modify. +// source: date_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'date_type_option.pbenum.dart'; + +export 'date_type_option.pbenum.dart'; + +class DateTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DateTypeOption', createEmptyInstance: create) + ..e(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dateFormat', $pb.PbFieldType.OE, defaultOrMaker: DateFormat.Local, valueOf: DateFormat.valueOf, enumValues: DateFormat.values) + ..e(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timeFormat', $pb.PbFieldType.OE, defaultOrMaker: TimeFormat.TwelveHour, valueOf: TimeFormat.valueOf, enumValues: TimeFormat.values) + ..aOB(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'includeTime') + ..hasRequiredFields = false + ; + + DateTypeOption._() : super(); + factory DateTypeOption({ + DateFormat? dateFormat, + TimeFormat? timeFormat, + $core.bool? includeTime, + }) { + final _result = create(); + if (dateFormat != null) { + _result.dateFormat = dateFormat; + } + if (timeFormat != null) { + _result.timeFormat = timeFormat; + } + if (includeTime != null) { + _result.includeTime = includeTime; + } + return _result; + } + factory DateTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory DateTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + DateTypeOption clone() => DateTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + DateTypeOption copyWith(void Function(DateTypeOption) updates) => super.copyWith((message) => updates(message as DateTypeOption)) as DateTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static DateTypeOption create() => DateTypeOption._(); + DateTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static DateTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static DateTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + DateFormat get dateFormat => $_getN(0); + @$pb.TagNumber(1) + set dateFormat(DateFormat v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasDateFormat() => $_has(0); + @$pb.TagNumber(1) + void clearDateFormat() => clearField(1); + + @$pb.TagNumber(2) + TimeFormat get timeFormat => $_getN(1); + @$pb.TagNumber(2) + set timeFormat(TimeFormat v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasTimeFormat() => $_has(1); + @$pb.TagNumber(2) + void clearTimeFormat() => clearField(2); + + @$pb.TagNumber(3) + $core.bool get includeTime => $_getBF(2); + @$pb.TagNumber(3) + set includeTime($core.bool v) { $_setBool(2, v); } + @$pb.TagNumber(3) + $core.bool hasIncludeTime() => $_has(2); + @$pb.TagNumber(3) + void clearIncludeTime() => clearField(3); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbenum.dart new file mode 100644 index 0000000000..63255cb1ab --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbenum.dart @@ -0,0 +1,45 @@ +/// +// Generated code. Do not modify. +// source: date_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class DateFormat extends $pb.ProtobufEnum { + static const DateFormat Local = DateFormat._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Local'); + static const DateFormat US = DateFormat._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'US'); + static const DateFormat ISO = DateFormat._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ISO'); + static const DateFormat Friendly = DateFormat._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Friendly'); + + static const $core.List values = [ + Local, + US, + ISO, + Friendly, + ]; + + static final $core.Map<$core.int, DateFormat> _byValue = $pb.ProtobufEnum.initByValue(values); + static DateFormat? valueOf($core.int value) => _byValue[value]; + + const DateFormat._($core.int v, $core.String n) : super(v, n); +} + +class TimeFormat extends $pb.ProtobufEnum { + static const TimeFormat TwelveHour = TimeFormat._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TwelveHour'); + static const TimeFormat TwentyFourHour = TimeFormat._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TwentyFourHour'); + + static const $core.List values = [ + TwelveHour, + TwentyFourHour, + ]; + + static final $core.Map<$core.int, TimeFormat> _byValue = $pb.ProtobufEnum.initByValue(values); + static TimeFormat? valueOf($core.int value) => _byValue[value]; + + const TimeFormat._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart new file mode 100644 index 0000000000..f419cc0e95 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart @@ -0,0 +1,46 @@ +/// +// Generated code. Do not modify. +// source: date_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use dateFormatDescriptor instead') +const DateFormat$json = const { + '1': 'DateFormat', + '2': const [ + const {'1': 'Local', '2': 0}, + const {'1': 'US', '2': 1}, + const {'1': 'ISO', '2': 2}, + const {'1': 'Friendly', '2': 3}, + ], +}; + +/// Descriptor for `DateFormat`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List dateFormatDescriptor = $convert.base64Decode('CgpEYXRlRm9ybWF0EgkKBUxvY2FsEAASBgoCVVMQARIHCgNJU08QAhIMCghGcmllbmRseRAD'); +@$core.Deprecated('Use timeFormatDescriptor instead') +const TimeFormat$json = const { + '1': 'TimeFormat', + '2': const [ + const {'1': 'TwelveHour', '2': 0}, + const {'1': 'TwentyFourHour', '2': 1}, + ], +}; + +/// Descriptor for `TimeFormat`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List timeFormatDescriptor = $convert.base64Decode('CgpUaW1lRm9ybWF0Eg4KClR3ZWx2ZUhvdXIQABISCg5Ud2VudHlGb3VySG91chAB'); +@$core.Deprecated('Use dateTypeOptionDescriptor instead') +const DateTypeOption$json = const { + '1': 'DateTypeOption', + '2': const [ + const {'1': 'date_format', '3': 1, '4': 1, '5': 14, '6': '.DateFormat', '10': 'dateFormat'}, + const {'1': 'time_format', '3': 2, '4': 1, '5': 14, '6': '.TimeFormat', '10': 'timeFormat'}, + const {'1': 'include_time', '3': 3, '4': 1, '5': 8, '10': 'includeTime'}, + ], +}; + +/// Descriptor for `DateTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List dateTypeOptionDescriptor = $convert.base64Decode('Cg5EYXRlVHlwZU9wdGlvbhIsCgtkYXRlX2Zvcm1hdBgBIAEoDjILLkRhdGVGb3JtYXRSCmRhdGVGb3JtYXQSLAoLdGltZV9mb3JtYXQYAiABKA4yCy5UaW1lRm9ybWF0Ugp0aW1lRm9ybWF0EiEKDGluY2x1ZGVfdGltZRgDIAEoCFILaW5jbHVkZVRpbWU='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbserver.dart new file mode 100644 index 0000000000..b95719d206 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: date_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'date_type_option.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pb.dart new file mode 100644 index 0000000000..5bfad20674 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pb.dart @@ -0,0 +1,11 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +export 'event_map.pbenum.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart new file mode 100644 index 0000000000..4c898182c7 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -0,0 +1,62 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class GridEvent extends $pb.ProtobufEnum { + static const GridEvent GetGridData = GridEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetGridData'); + static const GridEvent GetGridBlocks = GridEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetGridBlocks'); + static const GridEvent GetFields = GridEvent._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFields'); + static const GridEvent UpdateField = GridEvent._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateField'); + static const GridEvent InsertField = GridEvent._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InsertField'); + static const GridEvent DeleteField = GridEvent._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteField'); + static const GridEvent SwitchToField = GridEvent._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SwitchToField'); + static const GridEvent DuplicateField = GridEvent._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); + static const GridEvent GetEditFieldContext = GridEvent._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetEditFieldContext'); + static const GridEvent MoveItem = GridEvent._(17, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem'); + static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption'); + static const GridEvent GetSelectOptionContext = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionContext'); + static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption'); + static const GridEvent CreateRow = GridEvent._(50, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow'); + static const GridEvent GetRow = GridEvent._(51, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRow'); + static const GridEvent DeleteRow = GridEvent._(52, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteRow'); + static const GridEvent DuplicateRow = GridEvent._(53, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateRow'); + static const GridEvent GetCell = GridEvent._(70, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetCell'); + static const GridEvent UpdateCell = GridEvent._(71, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell'); + static const GridEvent UpdateCellSelectOption = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCellSelectOption'); + + static const $core.List values = [ + GetGridData, + GetGridBlocks, + GetFields, + UpdateField, + InsertField, + DeleteField, + SwitchToField, + DuplicateField, + GetEditFieldContext, + MoveItem, + NewSelectOption, + GetSelectOptionContext, + UpdateSelectOption, + CreateRow, + GetRow, + DeleteRow, + DuplicateRow, + GetCell, + UpdateCell, + UpdateCellSelectOption, + ]; + + static final $core.Map<$core.int, GridEvent> _byValue = $pb.ProtobufEnum.initByValue(values); + static GridEvent? valueOf($core.int value) => _byValue[value]; + + const GridEvent._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart new file mode 100644 index 0000000000..b03ea1cc64 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -0,0 +1,39 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use gridEventDescriptor instead') +const GridEvent$json = const { + '1': 'GridEvent', + '2': const [ + const {'1': 'GetGridData', '2': 0}, + const {'1': 'GetGridBlocks', '2': 1}, + const {'1': 'GetFields', '2': 10}, + const {'1': 'UpdateField', '2': 11}, + const {'1': 'InsertField', '2': 12}, + const {'1': 'DeleteField', '2': 13}, + const {'1': 'SwitchToField', '2': 14}, + const {'1': 'DuplicateField', '2': 15}, + const {'1': 'GetEditFieldContext', '2': 16}, + const {'1': 'MoveItem', '2': 17}, + const {'1': 'NewSelectOption', '2': 30}, + const {'1': 'GetSelectOptionContext', '2': 31}, + const {'1': 'UpdateSelectOption', '2': 32}, + const {'1': 'CreateRow', '2': 50}, + const {'1': 'GetRow', '2': 51}, + const {'1': 'DeleteRow', '2': 52}, + const {'1': 'DuplicateRow', '2': 53}, + const {'1': 'GetCell', '2': 70}, + const {'1': 'UpdateCell', '2': 71}, + const {'1': 'UpdateCellSelectOption', '2': 72}, + ], +}; + +/// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtJbnNlcnRGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEgwKCE1vdmVJdGVtEBESEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbserver.dart new file mode 100644 index 0000000000..e359d1146c --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'event_map.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pb.dart new file mode 100644 index 0000000000..a99c401bf2 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pb.dart @@ -0,0 +1,72 @@ +/// +// Generated code. Do not modify. +// source: field_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class FieldIdentifierPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldIdentifierPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..hasRequiredFields = false + ; + + FieldIdentifierPayload._() : super(); + factory FieldIdentifierPayload({ + $core.String? fieldId, + $core.String? gridId, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (gridId != null) { + _result.gridId = gridId; + } + return _result; + } + factory FieldIdentifierPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FieldIdentifierPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + FieldIdentifierPayload clone() => FieldIdentifierPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FieldIdentifierPayload copyWith(void Function(FieldIdentifierPayload) updates) => super.copyWith((message) => updates(message as FieldIdentifierPayload)) as FieldIdentifierPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static FieldIdentifierPayload create() => FieldIdentifierPayload._(); + FieldIdentifierPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FieldIdentifierPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FieldIdentifierPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get gridId => $_getSZ(1); + @$pb.TagNumber(2) + set gridId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasGridId() => $_has(1); + @$pb.TagNumber(2) + void clearGridId() => clearField(2); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbenum.dart new file mode 100644 index 0000000000..e9ca968924 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: field_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbjson.dart new file mode 100644 index 0000000000..e8b768c21a --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbjson.dart @@ -0,0 +1,21 @@ +/// +// Generated code. Do not modify. +// source: field_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use fieldIdentifierPayloadDescriptor instead') +const FieldIdentifierPayload$json = const { + '1': 'FieldIdentifierPayload', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'grid_id', '3': 2, '4': 1, '5': 9, '10': 'gridId'}, + ], +}; + +/// Descriptor for `FieldIdentifierPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldIdentifierPayloadDescriptor = $convert.base64Decode('ChZGaWVsZElkZW50aWZpZXJQYXlsb2FkEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhcKB2dyaWRfaWQYAiABKAlSBmdyaWRJZA=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbserver.dart new file mode 100644 index 0000000000..9c99be4d1d --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/field_entities.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: field_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'field_entities.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pb.dart new file mode 100644 index 0000000000..54f4d9546f --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pb.dart @@ -0,0 +1,118 @@ +/// +// Generated code. Do not modify. +// source: number_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'number_type_option.pbenum.dart'; + +export 'number_type_option.pbenum.dart'; + +class NumberTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NumberTypeOption', createEmptyInstance: create) + ..e(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'format', $pb.PbFieldType.OE, defaultOrMaker: NumberFormat.Number, valueOf: NumberFormat.valueOf, enumValues: NumberFormat.values) + ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'scale', $pb.PbFieldType.OU3) + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'symbol') + ..aOB(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'signPositive') + ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') + ..hasRequiredFields = false + ; + + NumberTypeOption._() : super(); + factory NumberTypeOption({ + NumberFormat? format, + $core.int? scale, + $core.String? symbol, + $core.bool? signPositive, + $core.String? name, + }) { + final _result = create(); + if (format != null) { + _result.format = format; + } + if (scale != null) { + _result.scale = scale; + } + if (symbol != null) { + _result.symbol = symbol; + } + if (signPositive != null) { + _result.signPositive = signPositive; + } + if (name != null) { + _result.name = name; + } + return _result; + } + factory NumberTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory NumberTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + NumberTypeOption clone() => NumberTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + NumberTypeOption copyWith(void Function(NumberTypeOption) updates) => super.copyWith((message) => updates(message as NumberTypeOption)) as NumberTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static NumberTypeOption create() => NumberTypeOption._(); + NumberTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static NumberTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static NumberTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + NumberFormat get format => $_getN(0); + @$pb.TagNumber(1) + set format(NumberFormat v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasFormat() => $_has(0); + @$pb.TagNumber(1) + void clearFormat() => clearField(1); + + @$pb.TagNumber(2) + $core.int get scale => $_getIZ(1); + @$pb.TagNumber(2) + set scale($core.int v) { $_setUnsignedInt32(1, v); } + @$pb.TagNumber(2) + $core.bool hasScale() => $_has(1); + @$pb.TagNumber(2) + void clearScale() => clearField(2); + + @$pb.TagNumber(3) + $core.String get symbol => $_getSZ(2); + @$pb.TagNumber(3) + set symbol($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasSymbol() => $_has(2); + @$pb.TagNumber(3) + void clearSymbol() => clearField(3); + + @$pb.TagNumber(4) + $core.bool get signPositive => $_getBF(3); + @$pb.TagNumber(4) + set signPositive($core.bool v) { $_setBool(3, v); } + @$pb.TagNumber(4) + $core.bool hasSignPositive() => $_has(3); + @$pb.TagNumber(4) + void clearSignPositive() => clearField(4); + + @$pb.TagNumber(5) + $core.String get name => $_getSZ(4); + @$pb.TagNumber(5) + set name($core.String v) { $_setString(4, v); } + @$pb.TagNumber(5) + $core.bool hasName() => $_has(4); + @$pb.TagNumber(5) + void clearName() => clearField(5); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbenum.dart new file mode 100644 index 0000000000..5e486443c6 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbenum.dart @@ -0,0 +1,30 @@ +/// +// Generated code. Do not modify. +// source: number_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class NumberFormat extends $pb.ProtobufEnum { + static const NumberFormat Number = NumberFormat._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Number'); + static const NumberFormat USD = NumberFormat._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'USD'); + static const NumberFormat CNY = NumberFormat._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CNY'); + static const NumberFormat EUR = NumberFormat._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EUR'); + + static const $core.List values = [ + Number, + USD, + CNY, + EUR, + ]; + + static final $core.Map<$core.int, NumberFormat> _byValue = $pb.ProtobufEnum.initByValue(values); + static NumberFormat? valueOf($core.int value) => _byValue[value]; + + const NumberFormat._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbjson.dart new file mode 100644 index 0000000000..d3c593d40e --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbjson.dart @@ -0,0 +1,37 @@ +/// +// Generated code. Do not modify. +// source: number_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use numberFormatDescriptor instead') +const NumberFormat$json = const { + '1': 'NumberFormat', + '2': const [ + const {'1': 'Number', '2': 0}, + const {'1': 'USD', '2': 1}, + const {'1': 'CNY', '2': 2}, + const {'1': 'EUR', '2': 3}, + ], +}; + +/// Descriptor for `NumberFormat`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List numberFormatDescriptor = $convert.base64Decode('CgxOdW1iZXJGb3JtYXQSCgoGTnVtYmVyEAASBwoDVVNEEAESBwoDQ05ZEAISBwoDRVVSEAM='); +@$core.Deprecated('Use numberTypeOptionDescriptor instead') +const NumberTypeOption$json = const { + '1': 'NumberTypeOption', + '2': const [ + const {'1': 'format', '3': 1, '4': 1, '5': 14, '6': '.NumberFormat', '10': 'format'}, + const {'1': 'scale', '3': 2, '4': 1, '5': 13, '10': 'scale'}, + const {'1': 'symbol', '3': 3, '4': 1, '5': 9, '10': 'symbol'}, + const {'1': 'sign_positive', '3': 4, '4': 1, '5': 8, '10': 'signPositive'}, + const {'1': 'name', '3': 5, '4': 1, '5': 9, '10': 'name'}, + ], +}; + +/// Descriptor for `NumberTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List numberTypeOptionDescriptor = $convert.base64Decode('ChBOdW1iZXJUeXBlT3B0aW9uEiUKBmZvcm1hdBgBIAEoDjINLk51bWJlckZvcm1hdFIGZm9ybWF0EhQKBXNjYWxlGAIgASgNUgVzY2FsZRIWCgZzeW1ib2wYAyABKAlSBnN5bWJvbBIjCg1zaWduX3Bvc2l0aXZlGAQgASgIUgxzaWduUG9zaXRpdmUSEgoEbmFtZRgFIAEoCVIEbmFtZQ=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbserver.dart new file mode 100644 index 0000000000..107c3a1d86 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_type_option.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: number_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'number_type_option.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/protobuf.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/protobuf.dart new file mode 100644 index 0000000000..af6583c106 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/protobuf.dart @@ -0,0 +1,11 @@ +// Auto-generated, do not edit +export './field_entities.pb.dart'; +export './number_type_option.pb.dart'; +export './dart_notification.pb.dart'; +export './selection_type_option.pb.dart'; +export './row_entities.pb.dart'; +export './cell_entities.pb.dart'; +export './checkbox_type_option.pb.dart'; +export './event_map.pb.dart'; +export './text_type_option.pb.dart'; +export './date_type_option.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pb.dart new file mode 100644 index 0000000000..8f8c278b12 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pb.dart @@ -0,0 +1,72 @@ +/// +// Generated code. Do not modify. +// source: row_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class RowIdentifierPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RowIdentifierPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') + ..hasRequiredFields = false + ; + + RowIdentifierPayload._() : super(); + factory RowIdentifierPayload({ + $core.String? gridId, + $core.String? rowId, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (rowId != null) { + _result.rowId = rowId; + } + return _result; + } + factory RowIdentifierPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RowIdentifierPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RowIdentifierPayload clone() => RowIdentifierPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RowIdentifierPayload copyWith(void Function(RowIdentifierPayload) updates) => super.copyWith((message) => updates(message as RowIdentifierPayload)) as RowIdentifierPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RowIdentifierPayload create() => RowIdentifierPayload._(); + RowIdentifierPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RowIdentifierPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RowIdentifierPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(3) + $core.String get rowId => $_getSZ(1); + @$pb.TagNumber(3) + set rowId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(3) + $core.bool hasRowId() => $_has(1); + @$pb.TagNumber(3) + void clearRowId() => clearField(3); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbenum.dart new file mode 100644 index 0000000000..a53bd30bf7 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: row_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbjson.dart new file mode 100644 index 0000000000..b5dd44d360 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbjson.dart @@ -0,0 +1,21 @@ +/// +// Generated code. Do not modify. +// source: row_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use rowIdentifierPayloadDescriptor instead') +const RowIdentifierPayload$json = const { + '1': 'RowIdentifierPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'row_id', '3': 3, '4': 1, '5': 9, '10': 'rowId'}, + ], +}; + +/// Descriptor for `RowIdentifierPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List rowIdentifierPayloadDescriptor = $convert.base64Decode('ChRSb3dJZGVudGlmaWVyUGF5bG9hZBIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSFQoGcm93X2lkGAMgASgJUgVyb3dJZA=='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbserver.dart new file mode 100644 index 0000000000..905505060a --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/row_entities.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: row_entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'row_entities.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart new file mode 100644 index 0000000000..d6e0bbcdaf --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart @@ -0,0 +1,516 @@ +/// +// Generated code. Do not modify. +// source: selection_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'cell_entities.pb.dart' as $0; + +import 'selection_type_option.pbenum.dart'; + +export 'selection_type_option.pbenum.dart'; + +class SingleSelectTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SingleSelectTypeOption', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'options', $pb.PbFieldType.PM, subBuilder: SelectOption.create) + ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'disableColor') + ..hasRequiredFields = false + ; + + SingleSelectTypeOption._() : super(); + factory SingleSelectTypeOption({ + $core.Iterable? options, + $core.bool? disableColor, + }) { + final _result = create(); + if (options != null) { + _result.options.addAll(options); + } + if (disableColor != null) { + _result.disableColor = disableColor; + } + return _result; + } + factory SingleSelectTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory SingleSelectTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + SingleSelectTypeOption clone() => SingleSelectTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + SingleSelectTypeOption copyWith(void Function(SingleSelectTypeOption) updates) => super.copyWith((message) => updates(message as SingleSelectTypeOption)) as SingleSelectTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static SingleSelectTypeOption create() => SingleSelectTypeOption._(); + SingleSelectTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static SingleSelectTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static SingleSelectTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get options => $_getList(0); + + @$pb.TagNumber(2) + $core.bool get disableColor => $_getBF(1); + @$pb.TagNumber(2) + set disableColor($core.bool v) { $_setBool(1, v); } + @$pb.TagNumber(2) + $core.bool hasDisableColor() => $_has(1); + @$pb.TagNumber(2) + void clearDisableColor() => clearField(2); +} + +class MultiSelectTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'MultiSelectTypeOption', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'options', $pb.PbFieldType.PM, subBuilder: SelectOption.create) + ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'disableColor') + ..hasRequiredFields = false + ; + + MultiSelectTypeOption._() : super(); + factory MultiSelectTypeOption({ + $core.Iterable? options, + $core.bool? disableColor, + }) { + final _result = create(); + if (options != null) { + _result.options.addAll(options); + } + if (disableColor != null) { + _result.disableColor = disableColor; + } + return _result; + } + factory MultiSelectTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory MultiSelectTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + MultiSelectTypeOption clone() => MultiSelectTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + MultiSelectTypeOption copyWith(void Function(MultiSelectTypeOption) updates) => super.copyWith((message) => updates(message as MultiSelectTypeOption)) as MultiSelectTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static MultiSelectTypeOption create() => MultiSelectTypeOption._(); + MultiSelectTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static MultiSelectTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static MultiSelectTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get options => $_getList(0); + + @$pb.TagNumber(2) + $core.bool get disableColor => $_getBF(1); + @$pb.TagNumber(2) + set disableColor($core.bool v) { $_setBool(1, v); } + @$pb.TagNumber(2) + $core.bool hasDisableColor() => $_has(1); + @$pb.TagNumber(2) + void clearDisableColor() => clearField(2); +} + +class SelectOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOption', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') + ..e(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'color', $pb.PbFieldType.OE, defaultOrMaker: SelectOptionColor.Purple, valueOf: SelectOptionColor.valueOf, enumValues: SelectOptionColor.values) + ..hasRequiredFields = false + ; + + SelectOption._() : super(); + factory SelectOption({ + $core.String? id, + $core.String? name, + SelectOptionColor? color, + }) { + final _result = create(); + if (id != null) { + _result.id = id; + } + if (name != null) { + _result.name = name; + } + if (color != null) { + _result.color = color; + } + return _result; + } + factory SelectOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory SelectOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + SelectOption clone() => SelectOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + SelectOption copyWith(void Function(SelectOption) updates) => super.copyWith((message) => updates(message as SelectOption)) as SelectOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static SelectOption create() => SelectOption._(); + SelectOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static SelectOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static SelectOption? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get id => $_getSZ(0); + @$pb.TagNumber(1) + set id($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasId() => $_has(0); + @$pb.TagNumber(1) + void clearId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get name => $_getSZ(1); + @$pb.TagNumber(2) + set name($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasName() => $_has(1); + @$pb.TagNumber(2) + void clearName() => clearField(2); + + @$pb.TagNumber(3) + SelectOptionColor get color => $_getN(2); + @$pb.TagNumber(3) + set color(SelectOptionColor v) { setField(3, v); } + @$pb.TagNumber(3) + $core.bool hasColor() => $_has(2); + @$pb.TagNumber(3) + void clearColor() => clearField(3); +} + +enum SelectOptionChangesetPayload_OneOfInsertOption { + insertOption, + notSet +} + +enum SelectOptionChangesetPayload_OneOfUpdateOption { + updateOption, + notSet +} + +enum SelectOptionChangesetPayload_OneOfDeleteOption { + deleteOption, + notSet +} + +class SelectOptionChangesetPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, SelectOptionChangesetPayload_OneOfInsertOption> _SelectOptionChangesetPayload_OneOfInsertOptionByTag = { + 2 : SelectOptionChangesetPayload_OneOfInsertOption.insertOption, + 0 : SelectOptionChangesetPayload_OneOfInsertOption.notSet + }; + static const $core.Map<$core.int, SelectOptionChangesetPayload_OneOfUpdateOption> _SelectOptionChangesetPayload_OneOfUpdateOptionByTag = { + 3 : SelectOptionChangesetPayload_OneOfUpdateOption.updateOption, + 0 : SelectOptionChangesetPayload_OneOfUpdateOption.notSet + }; + static const $core.Map<$core.int, SelectOptionChangesetPayload_OneOfDeleteOption> _SelectOptionChangesetPayload_OneOfDeleteOptionByTag = { + 4 : SelectOptionChangesetPayload_OneOfDeleteOption.deleteOption, + 0 : SelectOptionChangesetPayload_OneOfDeleteOption.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionChangesetPayload', createEmptyInstance: create) + ..oo(0, [2]) + ..oo(1, [3]) + ..oo(2, [4]) + ..aOM<$0.CellIdentifierPayload>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'cellIdentifier', subBuilder: $0.CellIdentifierPayload.create) + ..aOM(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertOption', subBuilder: SelectOption.create) + ..aOM(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updateOption', subBuilder: SelectOption.create) + ..aOM(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deleteOption', subBuilder: SelectOption.create) + ..hasRequiredFields = false + ; + + SelectOptionChangesetPayload._() : super(); + factory SelectOptionChangesetPayload({ + $0.CellIdentifierPayload? cellIdentifier, + SelectOption? insertOption, + SelectOption? updateOption, + SelectOption? deleteOption, + }) { + final _result = create(); + if (cellIdentifier != null) { + _result.cellIdentifier = cellIdentifier; + } + if (insertOption != null) { + _result.insertOption = insertOption; + } + if (updateOption != null) { + _result.updateOption = updateOption; + } + if (deleteOption != null) { + _result.deleteOption = deleteOption; + } + return _result; + } + factory SelectOptionChangesetPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory SelectOptionChangesetPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + SelectOptionChangesetPayload clone() => SelectOptionChangesetPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + SelectOptionChangesetPayload copyWith(void Function(SelectOptionChangesetPayload) updates) => super.copyWith((message) => updates(message as SelectOptionChangesetPayload)) as SelectOptionChangesetPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static SelectOptionChangesetPayload create() => SelectOptionChangesetPayload._(); + SelectOptionChangesetPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static SelectOptionChangesetPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static SelectOptionChangesetPayload? _defaultInstance; + + SelectOptionChangesetPayload_OneOfInsertOption whichOneOfInsertOption() => _SelectOptionChangesetPayload_OneOfInsertOptionByTag[$_whichOneof(0)]!; + void clearOneOfInsertOption() => clearField($_whichOneof(0)); + + SelectOptionChangesetPayload_OneOfUpdateOption whichOneOfUpdateOption() => _SelectOptionChangesetPayload_OneOfUpdateOptionByTag[$_whichOneof(1)]!; + void clearOneOfUpdateOption() => clearField($_whichOneof(1)); + + SelectOptionChangesetPayload_OneOfDeleteOption whichOneOfDeleteOption() => _SelectOptionChangesetPayload_OneOfDeleteOptionByTag[$_whichOneof(2)]!; + void clearOneOfDeleteOption() => clearField($_whichOneof(2)); + + @$pb.TagNumber(1) + $0.CellIdentifierPayload get cellIdentifier => $_getN(0); + @$pb.TagNumber(1) + set cellIdentifier($0.CellIdentifierPayload v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasCellIdentifier() => $_has(0); + @$pb.TagNumber(1) + void clearCellIdentifier() => clearField(1); + @$pb.TagNumber(1) + $0.CellIdentifierPayload ensureCellIdentifier() => $_ensure(0); + + @$pb.TagNumber(2) + SelectOption get insertOption => $_getN(1); + @$pb.TagNumber(2) + set insertOption(SelectOption v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasInsertOption() => $_has(1); + @$pb.TagNumber(2) + void clearInsertOption() => clearField(2); + @$pb.TagNumber(2) + SelectOption ensureInsertOption() => $_ensure(1); + + @$pb.TagNumber(3) + SelectOption get updateOption => $_getN(2); + @$pb.TagNumber(3) + set updateOption(SelectOption v) { setField(3, v); } + @$pb.TagNumber(3) + $core.bool hasUpdateOption() => $_has(2); + @$pb.TagNumber(3) + void clearUpdateOption() => clearField(3); + @$pb.TagNumber(3) + SelectOption ensureUpdateOption() => $_ensure(2); + + @$pb.TagNumber(4) + SelectOption get deleteOption => $_getN(3); + @$pb.TagNumber(4) + set deleteOption(SelectOption v) { setField(4, v); } + @$pb.TagNumber(4) + $core.bool hasDeleteOption() => $_has(3); + @$pb.TagNumber(4) + void clearDeleteOption() => clearField(4); + @$pb.TagNumber(4) + SelectOption ensureDeleteOption() => $_ensure(3); +} + +enum SelectOptionCellChangesetPayload_OneOfInsertOptionId { + insertOptionId, + notSet +} + +enum SelectOptionCellChangesetPayload_OneOfDeleteOptionId { + deleteOptionId, + notSet +} + +class SelectOptionCellChangesetPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, SelectOptionCellChangesetPayload_OneOfInsertOptionId> _SelectOptionCellChangesetPayload_OneOfInsertOptionIdByTag = { + 4 : SelectOptionCellChangesetPayload_OneOfInsertOptionId.insertOptionId, + 0 : SelectOptionCellChangesetPayload_OneOfInsertOptionId.notSet + }; + static const $core.Map<$core.int, SelectOptionCellChangesetPayload_OneOfDeleteOptionId> _SelectOptionCellChangesetPayload_OneOfDeleteOptionIdByTag = { + 5 : SelectOptionCellChangesetPayload_OneOfDeleteOptionId.deleteOptionId, + 0 : SelectOptionCellChangesetPayload_OneOfDeleteOptionId.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionCellChangesetPayload', createEmptyInstance: create) + ..oo(0, [4]) + ..oo(1, [5]) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertOptionId') + ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deleteOptionId') + ..hasRequiredFields = false + ; + + SelectOptionCellChangesetPayload._() : super(); + factory SelectOptionCellChangesetPayload({ + $core.String? gridId, + $core.String? rowId, + $core.String? fieldId, + $core.String? insertOptionId, + $core.String? deleteOptionId, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (rowId != null) { + _result.rowId = rowId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (insertOptionId != null) { + _result.insertOptionId = insertOptionId; + } + if (deleteOptionId != null) { + _result.deleteOptionId = deleteOptionId; + } + return _result; + } + factory SelectOptionCellChangesetPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory SelectOptionCellChangesetPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + SelectOptionCellChangesetPayload clone() => SelectOptionCellChangesetPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + SelectOptionCellChangesetPayload copyWith(void Function(SelectOptionCellChangesetPayload) updates) => super.copyWith((message) => updates(message as SelectOptionCellChangesetPayload)) as SelectOptionCellChangesetPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static SelectOptionCellChangesetPayload create() => SelectOptionCellChangesetPayload._(); + SelectOptionCellChangesetPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static SelectOptionCellChangesetPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static SelectOptionCellChangesetPayload? _defaultInstance; + + SelectOptionCellChangesetPayload_OneOfInsertOptionId whichOneOfInsertOptionId() => _SelectOptionCellChangesetPayload_OneOfInsertOptionIdByTag[$_whichOneof(0)]!; + void clearOneOfInsertOptionId() => clearField($_whichOneof(0)); + + SelectOptionCellChangesetPayload_OneOfDeleteOptionId whichOneOfDeleteOptionId() => _SelectOptionCellChangesetPayload_OneOfDeleteOptionIdByTag[$_whichOneof(1)]!; + void clearOneOfDeleteOptionId() => clearField($_whichOneof(1)); + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get rowId => $_getSZ(1); + @$pb.TagNumber(2) + set rowId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasRowId() => $_has(1); + @$pb.TagNumber(2) + void clearRowId() => clearField(2); + + @$pb.TagNumber(3) + $core.String get fieldId => $_getSZ(2); + @$pb.TagNumber(3) + set fieldId($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasFieldId() => $_has(2); + @$pb.TagNumber(3) + void clearFieldId() => clearField(3); + + @$pb.TagNumber(4) + $core.String get insertOptionId => $_getSZ(3); + @$pb.TagNumber(4) + set insertOptionId($core.String v) { $_setString(3, v); } + @$pb.TagNumber(4) + $core.bool hasInsertOptionId() => $_has(3); + @$pb.TagNumber(4) + void clearInsertOptionId() => clearField(4); + + @$pb.TagNumber(5) + $core.String get deleteOptionId => $_getSZ(4); + @$pb.TagNumber(5) + set deleteOptionId($core.String v) { $_setString(4, v); } + @$pb.TagNumber(5) + $core.bool hasDeleteOptionId() => $_has(4); + @$pb.TagNumber(5) + void clearDeleteOptionId() => clearField(5); +} + +class SelectOptionContext extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionContext', createEmptyInstance: create) + ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'options', $pb.PbFieldType.PM, subBuilder: SelectOption.create) + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'selectOptions', $pb.PbFieldType.PM, subBuilder: SelectOption.create) + ..hasRequiredFields = false + ; + + SelectOptionContext._() : super(); + factory SelectOptionContext({ + $core.Iterable? options, + $core.Iterable? selectOptions, + }) { + final _result = create(); + if (options != null) { + _result.options.addAll(options); + } + if (selectOptions != null) { + _result.selectOptions.addAll(selectOptions); + } + return _result; + } + factory SelectOptionContext.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory SelectOptionContext.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + SelectOptionContext clone() => SelectOptionContext()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + SelectOptionContext copyWith(void Function(SelectOptionContext) updates) => super.copyWith((message) => updates(message as SelectOptionContext)) as SelectOptionContext; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static SelectOptionContext create() => SelectOptionContext._(); + SelectOptionContext createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static SelectOptionContext getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static SelectOptionContext? _defaultInstance; + + @$pb.TagNumber(1) + $core.List get options => $_getList(0); + + @$pb.TagNumber(2) + $core.List get selectOptions => $_getList(1); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbenum.dart new file mode 100644 index 0000000000..0a063abf16 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbenum.dart @@ -0,0 +1,40 @@ +/// +// Generated code. Do not modify. +// source: selection_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class SelectOptionColor extends $pb.ProtobufEnum { + static const SelectOptionColor Purple = SelectOptionColor._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Purple'); + static const SelectOptionColor Pink = SelectOptionColor._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Pink'); + static const SelectOptionColor LightPink = SelectOptionColor._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'LightPink'); + static const SelectOptionColor Orange = SelectOptionColor._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Orange'); + static const SelectOptionColor Yellow = SelectOptionColor._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Yellow'); + static const SelectOptionColor Lime = SelectOptionColor._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Lime'); + static const SelectOptionColor Green = SelectOptionColor._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Green'); + static const SelectOptionColor Aqua = SelectOptionColor._(7, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Aqua'); + static const SelectOptionColor Blue = SelectOptionColor._(8, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Blue'); + + static const $core.List values = [ + Purple, + Pink, + LightPink, + Orange, + Yellow, + Lime, + Green, + Aqua, + Blue, + ]; + + static final $core.Map<$core.int, SelectOptionColor> _byValue = $pb.ProtobufEnum.initByValue(values); + static SelectOptionColor? valueOf($core.int value) => _byValue[value]; + + const SelectOptionColor._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart new file mode 100644 index 0000000000..9613b926bd --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart @@ -0,0 +1,109 @@ +/// +// Generated code. Do not modify. +// source: selection_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use selectOptionColorDescriptor instead') +const SelectOptionColor$json = const { + '1': 'SelectOptionColor', + '2': const [ + const {'1': 'Purple', '2': 0}, + const {'1': 'Pink', '2': 1}, + const {'1': 'LightPink', '2': 2}, + const {'1': 'Orange', '2': 3}, + const {'1': 'Yellow', '2': 4}, + const {'1': 'Lime', '2': 5}, + const {'1': 'Green', '2': 6}, + const {'1': 'Aqua', '2': 7}, + const {'1': 'Blue', '2': 8}, + ], +}; + +/// Descriptor for `SelectOptionColor`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List selectOptionColorDescriptor = $convert.base64Decode('ChFTZWxlY3RPcHRpb25Db2xvchIKCgZQdXJwbGUQABIICgRQaW5rEAESDQoJTGlnaHRQaW5rEAISCgoGT3JhbmdlEAMSCgoGWWVsbG93EAQSCAoETGltZRAFEgkKBUdyZWVuEAYSCAoEQXF1YRAHEggKBEJsdWUQCA=='); +@$core.Deprecated('Use singleSelectTypeOptionDescriptor instead') +const SingleSelectTypeOption$json = const { + '1': 'SingleSelectTypeOption', + '2': const [ + const {'1': 'options', '3': 1, '4': 3, '5': 11, '6': '.SelectOption', '10': 'options'}, + const {'1': 'disable_color', '3': 2, '4': 1, '5': 8, '10': 'disableColor'}, + ], +}; + +/// Descriptor for `SingleSelectTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List singleSelectTypeOptionDescriptor = $convert.base64Decode('ChZTaW5nbGVTZWxlY3RUeXBlT3B0aW9uEicKB29wdGlvbnMYASADKAsyDS5TZWxlY3RPcHRpb25SB29wdGlvbnMSIwoNZGlzYWJsZV9jb2xvchgCIAEoCFIMZGlzYWJsZUNvbG9y'); +@$core.Deprecated('Use multiSelectTypeOptionDescriptor instead') +const MultiSelectTypeOption$json = const { + '1': 'MultiSelectTypeOption', + '2': const [ + const {'1': 'options', '3': 1, '4': 3, '5': 11, '6': '.SelectOption', '10': 'options'}, + const {'1': 'disable_color', '3': 2, '4': 1, '5': 8, '10': 'disableColor'}, + ], +}; + +/// Descriptor for `MultiSelectTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List multiSelectTypeOptionDescriptor = $convert.base64Decode('ChVNdWx0aVNlbGVjdFR5cGVPcHRpb24SJwoHb3B0aW9ucxgBIAMoCzINLlNlbGVjdE9wdGlvblIHb3B0aW9ucxIjCg1kaXNhYmxlX2NvbG9yGAIgASgIUgxkaXNhYmxlQ29sb3I='); +@$core.Deprecated('Use selectOptionDescriptor instead') +const SelectOption$json = const { + '1': 'SelectOption', + '2': const [ + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'}, + const {'1': 'color', '3': 3, '4': 1, '5': 14, '6': '.SelectOptionColor', '10': 'color'}, + ], +}; + +/// Descriptor for `SelectOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectOptionDescriptor = $convert.base64Decode('CgxTZWxlY3RPcHRpb24SDgoCaWQYASABKAlSAmlkEhIKBG5hbWUYAiABKAlSBG5hbWUSKAoFY29sb3IYAyABKA4yEi5TZWxlY3RPcHRpb25Db2xvclIFY29sb3I='); +@$core.Deprecated('Use selectOptionChangesetPayloadDescriptor instead') +const SelectOptionChangesetPayload$json = const { + '1': 'SelectOptionChangesetPayload', + '2': const [ + const {'1': 'cell_identifier', '3': 1, '4': 1, '5': 11, '6': '.CellIdentifierPayload', '10': 'cellIdentifier'}, + const {'1': 'insert_option', '3': 2, '4': 1, '5': 11, '6': '.SelectOption', '9': 0, '10': 'insertOption'}, + const {'1': 'update_option', '3': 3, '4': 1, '5': 11, '6': '.SelectOption', '9': 1, '10': 'updateOption'}, + const {'1': 'delete_option', '3': 4, '4': 1, '5': 11, '6': '.SelectOption', '9': 2, '10': 'deleteOption'}, + ], + '8': const [ + const {'1': 'one_of_insert_option'}, + const {'1': 'one_of_update_option'}, + const {'1': 'one_of_delete_option'}, + ], +}; + +/// Descriptor for `SelectOptionChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectOptionChangesetPayloadDescriptor = $convert.base64Decode('ChxTZWxlY3RPcHRpb25DaGFuZ2VzZXRQYXlsb2FkEj8KD2NlbGxfaWRlbnRpZmllchgBIAEoCzIWLkNlbGxJZGVudGlmaWVyUGF5bG9hZFIOY2VsbElkZW50aWZpZXISNAoNaW5zZXJ0X29wdGlvbhgCIAEoCzINLlNlbGVjdE9wdGlvbkgAUgxpbnNlcnRPcHRpb24SNAoNdXBkYXRlX29wdGlvbhgDIAEoCzINLlNlbGVjdE9wdGlvbkgBUgx1cGRhdGVPcHRpb24SNAoNZGVsZXRlX29wdGlvbhgEIAEoCzINLlNlbGVjdE9wdGlvbkgCUgxkZWxldGVPcHRpb25CFgoUb25lX29mX2luc2VydF9vcHRpb25CFgoUb25lX29mX3VwZGF0ZV9vcHRpb25CFgoUb25lX29mX2RlbGV0ZV9vcHRpb24='); +@$core.Deprecated('Use selectOptionCellChangesetPayloadDescriptor instead') +const SelectOptionCellChangesetPayload$json = const { + '1': 'SelectOptionCellChangesetPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'row_id', '3': 2, '4': 1, '5': 9, '10': 'rowId'}, + const {'1': 'field_id', '3': 3, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'insert_option_id', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'insertOptionId'}, + const {'1': 'delete_option_id', '3': 5, '4': 1, '5': 9, '9': 1, '10': 'deleteOptionId'}, + ], + '8': const [ + const {'1': 'one_of_insert_option_id'}, + const {'1': 'one_of_delete_option_id'}, + ], +}; + +/// Descriptor for `SelectOptionCellChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectOptionCellChangesetPayloadDescriptor = $convert.base64Decode('CiBTZWxlY3RPcHRpb25DZWxsQ2hhbmdlc2V0UGF5bG9hZBIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSFQoGcm93X2lkGAIgASgJUgVyb3dJZBIZCghmaWVsZF9pZBgDIAEoCVIHZmllbGRJZBIqChBpbnNlcnRfb3B0aW9uX2lkGAQgASgJSABSDmluc2VydE9wdGlvbklkEioKEGRlbGV0ZV9vcHRpb25faWQYBSABKAlIAVIOZGVsZXRlT3B0aW9uSWRCGQoXb25lX29mX2luc2VydF9vcHRpb25faWRCGQoXb25lX29mX2RlbGV0ZV9vcHRpb25faWQ='); +@$core.Deprecated('Use selectOptionContextDescriptor instead') +const SelectOptionContext$json = const { + '1': 'SelectOptionContext', + '2': const [ + const {'1': 'options', '3': 1, '4': 3, '5': 11, '6': '.SelectOption', '10': 'options'}, + const {'1': 'select_options', '3': 2, '4': 3, '5': 11, '6': '.SelectOption', '10': 'selectOptions'}, + ], +}; + +/// Descriptor for `SelectOptionContext`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectOptionContextDescriptor = $convert.base64Decode('ChNTZWxlY3RPcHRpb25Db250ZXh0EicKB29wdGlvbnMYASADKAsyDS5TZWxlY3RPcHRpb25SB29wdGlvbnMSNAoOc2VsZWN0X29wdGlvbnMYAiADKAsyDS5TZWxlY3RPcHRpb25SDXNlbGVjdE9wdGlvbnM='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbserver.dart new file mode 100644 index 0000000000..2e9ff7c00b --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: selection_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'selection_type_option.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pb.dart new file mode 100644 index 0000000000..c8f930be1b --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pb.dart @@ -0,0 +1,58 @@ +/// +// Generated code. Do not modify. +// source: text_description.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class RichTextTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RichTextTypeOption', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'format') + ..hasRequiredFields = false + ; + + RichTextTypeOption._() : super(); + factory RichTextTypeOption({ + $core.String? format, + }) { + final _result = create(); + if (format != null) { + _result.format = format; + } + return _result; + } + factory RichTextTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RichTextTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RichTextTypeOption clone() => RichTextTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RichTextTypeOption copyWith(void Function(RichTextTypeOption) updates) => super.copyWith((message) => updates(message as RichTextTypeOption)) as RichTextTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RichTextTypeOption create() => RichTextTypeOption._(); + RichTextTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RichTextTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RichTextTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get format => $_getSZ(0); + @$pb.TagNumber(1) + set format($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFormat() => $_has(0); + @$pb.TagNumber(1) + void clearFormat() => clearField(1); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbenum.dart new file mode 100644 index 0000000000..e01054c586 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: text_description.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbjson.dart new file mode 100644 index 0000000000..ebe805501b --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbjson.dart @@ -0,0 +1,20 @@ +/// +// Generated code. Do not modify. +// source: text_description.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use richTextTypeOptionDescriptor instead') +const RichTextTypeOption$json = const { + '1': 'RichTextTypeOption', + '2': const [ + const {'1': 'format', '3': 1, '4': 1, '5': 9, '10': 'format'}, + ], +}; + +/// Descriptor for `RichTextTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List richTextTypeOptionDescriptor = $convert.base64Decode('ChJSaWNoVGV4dFR5cGVPcHRpb24SFgoGZm9ybWF0GAEgASgJUgZmb3JtYXQ='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbserver.dart new file mode 100644 index 0000000000..2a02dd56b1 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_description.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: text_description.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'text_description.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pb.dart new file mode 100644 index 0000000000..c30f2eb6e1 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pb.dart @@ -0,0 +1,58 @@ +/// +// Generated code. Do not modify. +// source: text_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class RichTextTypeOption extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RichTextTypeOption', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'format') + ..hasRequiredFields = false + ; + + RichTextTypeOption._() : super(); + factory RichTextTypeOption({ + $core.String? format, + }) { + final _result = create(); + if (format != null) { + _result.format = format; + } + return _result; + } + factory RichTextTypeOption.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory RichTextTypeOption.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + RichTextTypeOption clone() => RichTextTypeOption()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + RichTextTypeOption copyWith(void Function(RichTextTypeOption) updates) => super.copyWith((message) => updates(message as RichTextTypeOption)) as RichTextTypeOption; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static RichTextTypeOption create() => RichTextTypeOption._(); + RichTextTypeOption createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static RichTextTypeOption getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static RichTextTypeOption? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get format => $_getSZ(0); + @$pb.TagNumber(1) + set format($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFormat() => $_has(0); + @$pb.TagNumber(1) + void clearFormat() => clearField(1); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbenum.dart new file mode 100644 index 0000000000..f2bd90bfa5 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: text_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbjson.dart new file mode 100644 index 0000000000..e4ba6956ee --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbjson.dart @@ -0,0 +1,20 @@ +/// +// Generated code. Do not modify. +// source: text_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use richTextTypeOptionDescriptor instead') +const RichTextTypeOption$json = const { + '1': 'RichTextTypeOption', + '2': const [ + const {'1': 'format', '3': 1, '4': 1, '5': 9, '10': 'format'}, + ], +}; + +/// Descriptor for `RichTextTypeOption`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List richTextTypeOptionDescriptor = $convert.base64Decode('ChJSaWNoVGV4dFR5cGVPcHRpb24SFgoGZm9ybWF0GAEgASgJUgZmb3JtYXQ='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbserver.dart new file mode 100644 index 0000000000..6620aa1ee7 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/text_type_option.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: text_type_option.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'text_type_option.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pb.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pb.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pb.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pbenum.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pbenum.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pbenum.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pbjson.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pbjson.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pbjson.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pbserver.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/folder_info.pbserver.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/folder_info.pbserver.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/protobuf.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/protobuf.dart similarity index 77% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/protobuf.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/protobuf.dart index 050f20adc0..78a7a563db 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/protobuf.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/protobuf.dart @@ -1,5 +1,5 @@ // Auto-generated, do not edit export './folder_info.pb.dart'; export './ws_data.pb.dart'; +export './text_block_info.pb.dart'; export './revision.pb.dart'; -export './document_info.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pb.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pb.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pb.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbenum.dart similarity index 62% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbenum.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbenum.dart index 4c2ae91cea..f3c7efb417 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbenum.dart @@ -9,21 +9,6 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; -class RevisionState extends $pb.ProtobufEnum { - static const RevisionState Sync = RevisionState._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Sync'); - static const RevisionState Ack = RevisionState._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Ack'); - - static const $core.List values = [ - Sync, - Ack, - ]; - - static final $core.Map<$core.int, RevisionState> _byValue = $pb.ProtobufEnum.initByValue(values); - static RevisionState? valueOf($core.int value) => _byValue[value]; - - const RevisionState._($core.int v, $core.String n) : super(v, n); -} - class RevType extends $pb.ProtobufEnum { static const RevType DeprecatedLocal = RevType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeprecatedLocal'); static const RevType DeprecatedRemote = RevType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeprecatedRemote'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbjson.dart similarity index 88% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbjson.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbjson.dart index 64a4feed7e..5d4db67b74 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbjson.dart @@ -8,17 +8,6 @@ import 'dart:core' as $core; import 'dart:convert' as $convert; import 'dart:typed_data' as $typed_data; -@$core.Deprecated('Use revisionStateDescriptor instead') -const RevisionState$json = const { - '1': 'RevisionState', - '2': const [ - const {'1': 'Sync', '2': 0}, - const {'1': 'Ack', '2': 1}, - ], -}; - -/// Descriptor for `RevisionState`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List revisionStateDescriptor = $convert.base64Decode('Cg1SZXZpc2lvblN0YXRlEggKBFN5bmMQABIHCgNBY2sQAQ=='); @$core.Deprecated('Use revTypeDescriptor instead') const RevType$json = const { '1': 'RevType', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbserver.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/revision.pbserver.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/revision.pbserver.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pb.dart similarity index 63% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pb.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pb.dart index 968f76062a..43d315d340 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/document_info.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pb.dart @@ -1,6 +1,6 @@ /// // Generated code. Do not modify. -// source: document_info.proto +// source: text_block_info.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields @@ -12,15 +12,15 @@ import 'package:protobuf/protobuf.dart' as $pb; import 'revision.pb.dart' as $0; -class CreateBlockParams extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateBlockParams', createEmptyInstance: create) +class CreateTextBlockParams extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateTextBlockParams', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create) ..hasRequiredFields = false ; - CreateBlockParams._() : super(); - factory CreateBlockParams({ + CreateTextBlockParams._() : super(); + factory CreateTextBlockParams({ $core.String? id, $0.RepeatedRevision? revisions, }) { @@ -33,26 +33,26 @@ class CreateBlockParams extends $pb.GeneratedMessage { } return _result; } - factory CreateBlockParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory CreateBlockParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory CreateTextBlockParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CreateTextBlockParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - CreateBlockParams clone() => CreateBlockParams()..mergeFromMessage(this); + CreateTextBlockParams clone() => CreateTextBlockParams()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - CreateBlockParams copyWith(void Function(CreateBlockParams) updates) => super.copyWith((message) => updates(message as CreateBlockParams)) as CreateBlockParams; // ignore: deprecated_member_use + CreateTextBlockParams copyWith(void Function(CreateTextBlockParams) updates) => super.copyWith((message) => updates(message as CreateTextBlockParams)) as CreateTextBlockParams; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static CreateBlockParams create() => CreateBlockParams._(); - CreateBlockParams createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static CreateTextBlockParams create() => CreateTextBlockParams._(); + CreateTextBlockParams createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static CreateBlockParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static CreateBlockParams? _defaultInstance; + static CreateTextBlockParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CreateTextBlockParams? _defaultInstance; @$pb.TagNumber(1) $core.String get id => $_getSZ(0); @@ -75,25 +75,25 @@ class CreateBlockParams extends $pb.GeneratedMessage { $0.RepeatedRevision ensureRevisions() => $_ensure(1); } -class BlockInfo extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockInfo', createEmptyInstance: create) - ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId') +class TextBlockInfo extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TextBlockInfo', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'text') ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId') ..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'baseRevId') ..hasRequiredFields = false ; - BlockInfo._() : super(); - factory BlockInfo({ - $core.String? docId, + TextBlockInfo._() : super(); + factory TextBlockInfo({ + $core.String? blockId, $core.String? text, $fixnum.Int64? revId, $fixnum.Int64? baseRevId, }) { final _result = create(); - if (docId != null) { - _result.docId = docId; + if (blockId != null) { + _result.blockId = blockId; } if (text != null) { _result.text = text; @@ -106,35 +106,35 @@ class BlockInfo extends $pb.GeneratedMessage { } return _result; } - factory BlockInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BlockInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory TextBlockInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory TextBlockInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - BlockInfo clone() => BlockInfo()..mergeFromMessage(this); + TextBlockInfo clone() => TextBlockInfo()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - BlockInfo copyWith(void Function(BlockInfo) updates) => super.copyWith((message) => updates(message as BlockInfo)) as BlockInfo; // ignore: deprecated_member_use + TextBlockInfo copyWith(void Function(TextBlockInfo) updates) => super.copyWith((message) => updates(message as TextBlockInfo)) as TextBlockInfo; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BlockInfo create() => BlockInfo._(); - BlockInfo createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static TextBlockInfo create() => TextBlockInfo._(); + TextBlockInfo createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BlockInfo? _defaultInstance; + static TextBlockInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TextBlockInfo? _defaultInstance; @$pb.TagNumber(1) - $core.String get docId => $_getSZ(0); + $core.String get blockId => $_getSZ(0); @$pb.TagNumber(1) - set docId($core.String v) { $_setString(0, v); } + set blockId($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) - $core.bool hasDocId() => $_has(0); + $core.bool hasBlockId() => $_has(0); @$pb.TagNumber(1) - void clearDocId() => clearField(1); + void clearBlockId() => clearField(1); @$pb.TagNumber(2) $core.String get text => $_getSZ(1); @@ -164,56 +164,56 @@ class BlockInfo extends $pb.GeneratedMessage { void clearBaseRevId() => clearField(4); } -class ResetDocumentParams extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ResetDocumentParams', createEmptyInstance: create) - ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId') +class ResetTextBlockParams extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ResetTextBlockParams', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') ..aOM<$0.RepeatedRevision>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revisions', subBuilder: $0.RepeatedRevision.create) ..hasRequiredFields = false ; - ResetDocumentParams._() : super(); - factory ResetDocumentParams({ - $core.String? docId, + ResetTextBlockParams._() : super(); + factory ResetTextBlockParams({ + $core.String? blockId, $0.RepeatedRevision? revisions, }) { final _result = create(); - if (docId != null) { - _result.docId = docId; + if (blockId != null) { + _result.blockId = blockId; } if (revisions != null) { _result.revisions = revisions; } return _result; } - factory ResetDocumentParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory ResetDocumentParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory ResetTextBlockParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory ResetTextBlockParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - ResetDocumentParams clone() => ResetDocumentParams()..mergeFromMessage(this); + ResetTextBlockParams clone() => ResetTextBlockParams()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - ResetDocumentParams copyWith(void Function(ResetDocumentParams) updates) => super.copyWith((message) => updates(message as ResetDocumentParams)) as ResetDocumentParams; // ignore: deprecated_member_use + ResetTextBlockParams copyWith(void Function(ResetTextBlockParams) updates) => super.copyWith((message) => updates(message as ResetTextBlockParams)) as ResetTextBlockParams; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static ResetDocumentParams create() => ResetDocumentParams._(); - ResetDocumentParams createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static ResetTextBlockParams create() => ResetTextBlockParams._(); + ResetTextBlockParams createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static ResetDocumentParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static ResetDocumentParams? _defaultInstance; + static ResetTextBlockParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static ResetTextBlockParams? _defaultInstance; @$pb.TagNumber(1) - $core.String get docId => $_getSZ(0); + $core.String get blockId => $_getSZ(0); @$pb.TagNumber(1) - set docId($core.String v) { $_setString(0, v); } + set blockId($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) - $core.bool hasDocId() => $_has(0); + $core.bool hasBlockId() => $_has(0); @$pb.TagNumber(1) - void clearDocId() => clearField(1); + void clearBlockId() => clearField(1); @$pb.TagNumber(2) $0.RepeatedRevision get revisions => $_getN(1); @@ -227,47 +227,47 @@ class ResetDocumentParams extends $pb.GeneratedMessage { $0.RepeatedRevision ensureRevisions() => $_ensure(1); } -class BlockDelta extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockDelta', createEmptyInstance: create) +class TextBlockDelta extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TextBlockDelta', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') - ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deltaJson') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deltaStr') ..hasRequiredFields = false ; - BlockDelta._() : super(); - factory BlockDelta({ + TextBlockDelta._() : super(); + factory TextBlockDelta({ $core.String? blockId, - $core.String? deltaJson, + $core.String? deltaStr, }) { final _result = create(); if (blockId != null) { _result.blockId = blockId; } - if (deltaJson != null) { - _result.deltaJson = deltaJson; + if (deltaStr != null) { + _result.deltaStr = deltaStr; } return _result; } - factory BlockDelta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BlockDelta.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory TextBlockDelta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory TextBlockDelta.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - BlockDelta clone() => BlockDelta()..mergeFromMessage(this); + TextBlockDelta clone() => TextBlockDelta()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - BlockDelta copyWith(void Function(BlockDelta) updates) => super.copyWith((message) => updates(message as BlockDelta)) as BlockDelta; // ignore: deprecated_member_use + TextBlockDelta copyWith(void Function(TextBlockDelta) updates) => super.copyWith((message) => updates(message as TextBlockDelta)) as TextBlockDelta; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BlockDelta create() => BlockDelta._(); - BlockDelta createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static TextBlockDelta create() => TextBlockDelta._(); + TextBlockDelta createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockDelta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BlockDelta? _defaultInstance; + static TextBlockDelta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TextBlockDelta? _defaultInstance; @$pb.TagNumber(1) $core.String get blockId => $_getSZ(0); @@ -279,13 +279,13 @@ class BlockDelta extends $pb.GeneratedMessage { void clearBlockId() => clearField(1); @$pb.TagNumber(2) - $core.String get deltaJson => $_getSZ(1); + $core.String get deltaStr => $_getSZ(1); @$pb.TagNumber(2) - set deltaJson($core.String v) { $_setString(1, v); } + set deltaStr($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) - $core.bool hasDeltaJson() => $_has(1); + $core.bool hasDeltaStr() => $_has(1); @$pb.TagNumber(2) - void clearDeltaJson() => clearField(2); + void clearDeltaStr() => clearField(2); } class NewDocUser extends $pb.GeneratedMessage { @@ -363,14 +363,14 @@ class NewDocUser extends $pb.GeneratedMessage { void clearDocId() => clearField(3); } -class BlockId extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockId', createEmptyInstance: create) +class TextBlockId extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TextBlockId', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value') ..hasRequiredFields = false ; - BlockId._() : super(); - factory BlockId({ + TextBlockId._() : super(); + factory TextBlockId({ $core.String? value, }) { final _result = create(); @@ -379,26 +379,26 @@ class BlockId extends $pb.GeneratedMessage { } return _result; } - factory BlockId.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BlockId.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory TextBlockId.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory TextBlockId.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - BlockId clone() => BlockId()..mergeFromMessage(this); + TextBlockId clone() => TextBlockId()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - BlockId copyWith(void Function(BlockId) updates) => super.copyWith((message) => updates(message as BlockId)) as BlockId; // ignore: deprecated_member_use + TextBlockId copyWith(void Function(TextBlockId) updates) => super.copyWith((message) => updates(message as TextBlockId)) as TextBlockId; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BlockId create() => BlockId._(); - BlockId createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static TextBlockId create() => TextBlockId._(); + TextBlockId createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockId getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static BlockId? _defaultInstance; + static TextBlockId getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TextBlockId? _defaultInstance; @$pb.TagNumber(1) $core.String get value => $_getSZ(0); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbenum.dart new file mode 100644 index 0000000000..20728d1388 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbenum.dart @@ -0,0 +1,7 @@ +/// +// Generated code. Do not modify. +// source: text_block_info.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbjson.dart new file mode 100644 index 0000000000..794b4ca433 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbjson.dart @@ -0,0 +1,78 @@ +/// +// Generated code. Do not modify. +// source: text_block_info.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use createTextBlockParamsDescriptor instead') +const CreateTextBlockParams$json = const { + '1': 'CreateTextBlockParams', + '2': const [ + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, + const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'}, + ], +}; + +/// Descriptor for `CreateTextBlockParams`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List createTextBlockParamsDescriptor = $convert.base64Decode('ChVDcmVhdGVUZXh0QmxvY2tQYXJhbXMSDgoCaWQYASABKAlSAmlkEi8KCXJldmlzaW9ucxgCIAEoCzIRLlJlcGVhdGVkUmV2aXNpb25SCXJldmlzaW9ucw=='); +@$core.Deprecated('Use textBlockInfoDescriptor instead') +const TextBlockInfo$json = const { + '1': 'TextBlockInfo', + '2': const [ + const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'}, + const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'}, + const {'1': 'base_rev_id', '3': 4, '4': 1, '5': 3, '10': 'baseRevId'}, + ], +}; + +/// Descriptor for `TextBlockInfo`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List textBlockInfoDescriptor = $convert.base64Decode('Cg1UZXh0QmxvY2tJbmZvEhkKCGJsb2NrX2lkGAEgASgJUgdibG9ja0lkEhIKBHRleHQYAiABKAlSBHRleHQSFQoGcmV2X2lkGAMgASgDUgVyZXZJZBIeCgtiYXNlX3Jldl9pZBgEIAEoA1IJYmFzZVJldklk'); +@$core.Deprecated('Use resetTextBlockParamsDescriptor instead') +const ResetTextBlockParams$json = const { + '1': 'ResetTextBlockParams', + '2': const [ + const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'revisions', '3': 2, '4': 1, '5': 11, '6': '.RepeatedRevision', '10': 'revisions'}, + ], +}; + +/// Descriptor for `ResetTextBlockParams`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List resetTextBlockParamsDescriptor = $convert.base64Decode('ChRSZXNldFRleHRCbG9ja1BhcmFtcxIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIvCglyZXZpc2lvbnMYAiABKAsyES5SZXBlYXRlZFJldmlzaW9uUglyZXZpc2lvbnM='); +@$core.Deprecated('Use textBlockDeltaDescriptor instead') +const TextBlockDelta$json = const { + '1': 'TextBlockDelta', + '2': const [ + const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'delta_str', '3': 2, '4': 1, '5': 9, '10': 'deltaStr'}, + ], +}; + +/// Descriptor for `TextBlockDelta`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List textBlockDeltaDescriptor = $convert.base64Decode('Cg5UZXh0QmxvY2tEZWx0YRIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIbCglkZWx0YV9zdHIYAiABKAlSCGRlbHRhU3Ry'); +@$core.Deprecated('Use newDocUserDescriptor instead') +const NewDocUser$json = const { + '1': 'NewDocUser', + '2': const [ + const {'1': 'user_id', '3': 1, '4': 1, '5': 9, '10': 'userId'}, + const {'1': 'rev_id', '3': 2, '4': 1, '5': 3, '10': 'revId'}, + const {'1': 'doc_id', '3': 3, '4': 1, '5': 9, '10': 'docId'}, + ], +}; + +/// Descriptor for `NewDocUser`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List newDocUserDescriptor = $convert.base64Decode('CgpOZXdEb2NVc2VyEhcKB3VzZXJfaWQYASABKAlSBnVzZXJJZBIVCgZyZXZfaWQYAiABKANSBXJldklkEhUKBmRvY19pZBgDIAEoCVIFZG9jSWQ='); +@$core.Deprecated('Use textBlockIdDescriptor instead') +const TextBlockId$json = const { + '1': 'TextBlockId', + '2': const [ + const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'}, + ], +}; + +/// Descriptor for `TextBlockId`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List textBlockIdDescriptor = $convert.base64Decode('CgtUZXh0QmxvY2tJZBIUCgV2YWx1ZRgBIAEoCVIFdmFsdWU='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbserver.dart new file mode 100644 index 0000000000..5c81f4cb56 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/text_block_info.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: text_block_info.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'text_block_info.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pb.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pb.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pb.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pbenum.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pbenum.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pbenum.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pbjson.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pbjson.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pbjson.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pbserver.dart similarity index 100% rename from frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-collaboration/ws_data.pbserver.dart rename to frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-sync/ws_data.pbserver.dart diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pb.dart new file mode 100644 index 0000000000..bcd8d6051a --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pb.dart @@ -0,0 +1,137 @@ +/// +// Generated code. Do not modify. +// source: entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +import 'entities.pbenum.dart'; + +export 'entities.pbenum.dart'; + +class ExportPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ExportPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId') + ..e(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'exportType', $pb.PbFieldType.OE, defaultOrMaker: ExportType.Text, valueOf: ExportType.valueOf, enumValues: ExportType.values) + ..hasRequiredFields = false + ; + + ExportPayload._() : super(); + factory ExportPayload({ + $core.String? viewId, + ExportType? exportType, + }) { + final _result = create(); + if (viewId != null) { + _result.viewId = viewId; + } + if (exportType != null) { + _result.exportType = exportType; + } + return _result; + } + factory ExportPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory ExportPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + ExportPayload clone() => ExportPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + ExportPayload copyWith(void Function(ExportPayload) updates) => super.copyWith((message) => updates(message as ExportPayload)) as ExportPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static ExportPayload create() => ExportPayload._(); + ExportPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ExportPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static ExportPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get viewId => $_getSZ(0); + @$pb.TagNumber(1) + set viewId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasViewId() => $_has(0); + @$pb.TagNumber(1) + void clearViewId() => clearField(1); + + @$pb.TagNumber(2) + ExportType get exportType => $_getN(1); + @$pb.TagNumber(2) + set exportType(ExportType v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasExportType() => $_has(1); + @$pb.TagNumber(2) + void clearExportType() => clearField(2); +} + +class ExportData extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ExportData', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data') + ..e(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'exportType', $pb.PbFieldType.OE, defaultOrMaker: ExportType.Text, valueOf: ExportType.valueOf, enumValues: ExportType.values) + ..hasRequiredFields = false + ; + + ExportData._() : super(); + factory ExportData({ + $core.String? data, + ExportType? exportType, + }) { + final _result = create(); + if (data != null) { + _result.data = data; + } + if (exportType != null) { + _result.exportType = exportType; + } + return _result; + } + factory ExportData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory ExportData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + ExportData clone() => ExportData()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + ExportData copyWith(void Function(ExportData) updates) => super.copyWith((message) => updates(message as ExportData)) as ExportData; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static ExportData create() => ExportData._(); + ExportData createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static ExportData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static ExportData? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get data => $_getSZ(0); + @$pb.TagNumber(1) + set data($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasData() => $_has(0); + @$pb.TagNumber(1) + void clearData() => clearField(1); + + @$pb.TagNumber(2) + ExportType get exportType => $_getN(1); + @$pb.TagNumber(2) + set exportType(ExportType v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasExportType() => $_has(1); + @$pb.TagNumber(2) + void clearExportType() => clearField(2); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbenum.dart new file mode 100644 index 0000000000..f5413e61f2 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbenum.dart @@ -0,0 +1,28 @@ +/// +// Generated code. Do not modify. +// source: entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class ExportType extends $pb.ProtobufEnum { + static const ExportType Text = ExportType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Text'); + static const ExportType Markdown = ExportType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Markdown'); + static const ExportType Link = ExportType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Link'); + + static const $core.List values = [ + Text, + Markdown, + Link, + ]; + + static final $core.Map<$core.int, ExportType> _byValue = $pb.ProtobufEnum.initByValue(values); + static ExportType? valueOf($core.int value) => _byValue[value]; + + const ExportType._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbjson.dart new file mode 100644 index 0000000000..4935602b83 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbjson.dart @@ -0,0 +1,44 @@ +/// +// Generated code. Do not modify. +// source: entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use exportTypeDescriptor instead') +const ExportType$json = const { + '1': 'ExportType', + '2': const [ + const {'1': 'Text', '2': 0}, + const {'1': 'Markdown', '2': 1}, + const {'1': 'Link', '2': 2}, + ], +}; + +/// Descriptor for `ExportType`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List exportTypeDescriptor = $convert.base64Decode('CgpFeHBvcnRUeXBlEggKBFRleHQQABIMCghNYXJrZG93bhABEggKBExpbmsQAg=='); +@$core.Deprecated('Use exportPayloadDescriptor instead') +const ExportPayload$json = const { + '1': 'ExportPayload', + '2': const [ + const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'}, + const {'1': 'export_type', '3': 2, '4': 1, '5': 14, '6': '.ExportType', '10': 'exportType'}, + ], +}; + +/// Descriptor for `ExportPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List exportPayloadDescriptor = $convert.base64Decode('Cg1FeHBvcnRQYXlsb2FkEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBIsCgtleHBvcnRfdHlwZRgCIAEoDjILLkV4cG9ydFR5cGVSCmV4cG9ydFR5cGU='); +@$core.Deprecated('Use exportDataDescriptor instead') +const ExportData$json = const { + '1': 'ExportData', + '2': const [ + const {'1': 'data', '3': 1, '4': 1, '5': 9, '10': 'data'}, + const {'1': 'export_type', '3': 2, '4': 1, '5': 14, '6': '.ExportType', '10': 'exportType'}, + ], +}; + +/// Descriptor for `ExportData`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List exportDataDescriptor = $convert.base64Decode('CgpFeHBvcnREYXRhEhIKBGRhdGEYASABKAlSBGRhdGESLAoLZXhwb3J0X3R5cGUYAiABKA4yCy5FeHBvcnRUeXBlUgpleHBvcnRUeXBl'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbserver.dart new file mode 100644 index 0000000000..88741cd6c2 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/entities.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: entities.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'entities.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pb.dart new file mode 100644 index 0000000000..5bfad20674 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pb.dart @@ -0,0 +1,11 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +import 'dart:core' as $core; + +export 'event_map.pbenum.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbenum.dart new file mode 100644 index 0000000000..d88c52395c --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbenum.dart @@ -0,0 +1,28 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields + +// ignore_for_file: UNDEFINED_SHOWN_NAME +import 'dart:core' as $core; +import 'package:protobuf/protobuf.dart' as $pb; + +class BlockEvent extends $pb.ProtobufEnum { + static const BlockEvent GetBlockData = BlockEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetBlockData'); + static const BlockEvent ApplyDelta = BlockEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplyDelta'); + static const BlockEvent ExportDocument = BlockEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ExportDocument'); + + static const $core.List values = [ + GetBlockData, + ApplyDelta, + ExportDocument, + ]; + + static final $core.Map<$core.int, BlockEvent> _byValue = $pb.ProtobufEnum.initByValue(values); + static BlockEvent? valueOf($core.int value) => _byValue[value]; + + const BlockEvent._($core.int v, $core.String n) : super(v, n); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbjson.dart new file mode 100644 index 0000000000..ac0f243e6f --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbjson.dart @@ -0,0 +1,22 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +import 'dart:core' as $core; +import 'dart:convert' as $convert; +import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use blockEventDescriptor instead') +const BlockEvent$json = const { + '1': 'BlockEvent', + '2': const [ + const {'1': 'GetBlockData', '2': 0}, + const {'1': 'ApplyDelta', '2': 1}, + const {'1': 'ExportDocument', '2': 2}, + ], +}; + +/// Descriptor for `BlockEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List blockEventDescriptor = $convert.base64Decode('CgpCbG9ja0V2ZW50EhAKDEdldEJsb2NrRGF0YRAAEg4KCkFwcGx5RGVsdGEQARISCg5FeHBvcnREb2N1bWVudBAC'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbserver.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbserver.dart new file mode 100644 index 0000000000..e359d1146c --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/event_map.pbserver.dart @@ -0,0 +1,9 @@ +/// +// Generated code. Do not modify. +// source: event_map.proto +// +// @dart = 2.12 +// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package + +export 'event_map.pb.dart'; + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/protobuf.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/protobuf.dart new file mode 100644 index 0000000000..a2db1d12ab --- /dev/null +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-text-block/protobuf.dart @@ -0,0 +1,3 @@ +// Auto-generated, do not edit +export './entities.pb.dart'; +export './event_map.pb.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbenum.dart index bca822dca5..ffcdcc93ac 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbenum.dart @@ -12,10 +12,12 @@ import 'package:protobuf/protobuf.dart' as $pb; class WSChannel extends $pb.ProtobufEnum { static const WSChannel Document = WSChannel._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Document'); static const WSChannel Folder = WSChannel._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Folder'); + static const WSChannel Grid = WSChannel._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Grid'); static const $core.List values = [ Document, Folder, + Grid, ]; static final $core.Map<$core.int, WSChannel> _byValue = $pb.ProtobufEnum.initByValue(values); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbjson.dart index d1edecb666..0b878758fa 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/lib-ws/msg.pbjson.dart @@ -14,11 +14,12 @@ const WSChannel$json = const { '2': const [ const {'1': 'Document', '2': 0}, const {'1': 'Folder', '2': 1}, + const {'1': 'Grid', '2': 2}, ], }; /// Descriptor for `WSChannel`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List wSChannelDescriptor = $convert.base64Decode('CglXU0NoYW5uZWwSDAoIRG9jdW1lbnQQABIKCgZGb2xkZXIQAQ=='); +final $typed_data.Uint8List wSChannelDescriptor = $convert.base64Decode('CglXU0NoYW5uZWwSDAoIRG9jdW1lbnQQABIKCgZGb2xkZXIQARIICgRHcmlkEAI='); @$core.Deprecated('Use webSocketRawMessageDescriptor instead') const WebSocketRawMessage$json = const { '1': 'WebSocketRawMessage', diff --git a/frontend/app_flowy/packages/flowy_sdk/macos/flowy_sdk.podspec b/frontend/app_flowy/packages/flowy_sdk/macos/flowy_sdk.podspec index 4dd9a055f9..497388b99f 100644 --- a/frontend/app_flowy/packages/flowy_sdk/macos/flowy_sdk.podspec +++ b/frontend/app_flowy/packages/flowy_sdk/macos/flowy_sdk.podspec @@ -20,6 +20,6 @@ A new flutter plugin project. s.platform = :osx, '10.11' s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } s.swift_version = '5.0' - # s.static_framework = true - s.vendored_libraries = "libdart_ffi.dylib" + s.static_framework = true + s.vendored_libraries = "libdart_ffi.a" end diff --git a/frontend/app_flowy/packages/flowy_sdk/pubspec.lock b/frontend/app_flowy/packages/flowy_sdk/pubspec.lock index 5ece223a66..1f5af870d9 100644 --- a/frontend/app_flowy/packages/flowy_sdk/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_sdk/pubspec.lock @@ -214,6 +214,13 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.1+2" freezed_annotation: dependency: "direct main" description: @@ -394,6 +401,13 @@ packages: description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" source_span: dependency: transitive description: diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index 18bc260d4f..8f7e6d6db2 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -512,7 +512,7 @@ packages: name: fluttertoast url: "https://pub.dartlang.org" source: hosted - version: "8.0.8" + version: "8.0.9" freezed: dependency: "direct dev" description: @@ -645,7 +645,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.6.3" json_annotation: dependency: transitive description: @@ -653,6 +653,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.4.0" + linked_scroll_controller: + dependency: "direct main" + description: + name: linked_scroll_controller + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" lint: dependency: transitive description: @@ -799,7 +806,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.0" path_drawing: dependency: transitive description: @@ -947,6 +954,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1+1" + reorderables: + dependency: "direct main" + description: + name: reorderables + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.3" shared_preferences: dependency: transitive description: @@ -1031,6 +1045,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + simple_gesture_detector: + dependency: transitive + description: + name: simple_gesture_detector + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" sized_context: dependency: "direct main" description: @@ -1120,6 +1141,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.3.1+2" + table_calendar: + dependency: "direct main" + description: + name: table_calendar + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.5" term_glyph: dependency: transitive description: @@ -1133,21 +1161,28 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.20.1" + version: "1.19.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.8" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.11" + version: "0.4.9" + textfield_tags: + dependency: "direct main" + description: + name: textfield_tags + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" textstyle_extensions: dependency: transitive description: @@ -1322,7 +1357,7 @@ packages: path: "plugins/window_size" ref: e48abe7c3e9ebfe0b81622167c5201d4e783bb81 resolved-ref: e48abe7c3e9ebfe0b81622167c5201d4e783bb81 - url: "git://github.com/google/flutter-desktop-embedding.git" + url: "https://github.com/google/flutter-desktop-embedding.git" source: git version: "0.1.0" xdg_directories: @@ -1354,5 +1389,5 @@ packages: source: hosted version: "8.0.0" sdks: - dart: ">=2.16.0-100.0.dev <3.0.0" + dart: ">=2.15.0-116.0.dev <3.0.0" flutter: ">=2.5.0" diff --git a/frontend/app_flowy/pubspec.yaml b/frontend/app_flowy/pubspec.yaml index 67b4a8aaef..fd2b75b9e0 100644 --- a/frontend/app_flowy/pubspec.yaml +++ b/frontend/app_flowy/pubspec.yaml @@ -53,7 +53,7 @@ dependencies: path_provider: ^2.0.1 window_size: git: - url: git://github.com/google/flutter-desktop-embedding.git + url: https://github.com/google/flutter-desktop-embedding.git path: plugins/window_size ref: e48abe7c3e9ebfe0b81622167c5201d4e783bb81 sized_context: ^1.0.0+1 @@ -67,13 +67,15 @@ dependencies: clipboard: ^0.1.3 connectivity_plus: 2.2.0 easy_localization: ^3.0.0 - + textfield_tags: ^2.0.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 device_info_plus: ^3.2.1 fluttertoast: ^8.0.8 - reorderables: ^0.4.3 + table_calendar: ^3.0.5 + reorderables: + linked_scroll_controller: ^0.2.0 dev_dependencies: flutter_lints: ^1.0.0 @@ -112,6 +114,9 @@ flutter: - assets/images/ - assets/images/home/ - assets/images/editor/ + - assets/images/grid/ + - assets/images/grid/field/ + - assets/images/grid/setting/ - assets/translations/ # - images/a_dot_ham.jpeg diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 2ec1b6e3bd..a7c5f12665 100755 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -57,6 +57,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "async-stream" version = "0.3.2" @@ -78,17 +84,6 @@ dependencies = [ "syn", ] -[[package]] -name = "async-trait" -version = "0.1.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "atomic" version = "0.5.1" @@ -458,20 +453,6 @@ dependencies = [ "itertools", ] -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.2" @@ -506,16 +487,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.6" @@ -847,78 +818,6 @@ dependencies = [ "syn", ] -[[package]] -name = "flowy-block" -version = "0.1.0" -dependencies = [ - "async-stream", - "async-trait", - "bytecount", - "byteorder", - "bytes", - "chrono", - "color-eyre", - "criterion", - "dart-notify", - "dashmap", - "derive_more", - "diesel", - "diesel_derives", - "flowy-block", - "flowy-collaboration", - "flowy-database", - "flowy-derive", - "flowy-error", - "flowy-sync", - "flowy-test", - "futures", - "futures-util", - "lib-dispatch", - "lib-infra", - "lib-ot", - "lib-ws", - "log", - "parking_lot", - "pin-project", - "protobuf", - "rand 0.7.3", - "serde", - "serde_json", - "strum", - "strum_macros", - "tokio", - "tracing", - "unicode-segmentation", - "url", -] - -[[package]] -name = "flowy-collaboration" -version = "0.1.0" -dependencies = [ - "async-stream", - "bytes", - "chrono", - "dashmap", - "dissimilar", - "flowy-derive", - "flowy-folder-data-model", - "futures", - "lib-infra", - "lib-ot", - "log", - "md5", - "parking_lot", - "protobuf", - "serde", - "serde_json", - "strum", - "strum_macros", - "tokio", - "tracing", - "url", -] - [[package]] name = "flowy-database" version = "0.1.0" @@ -951,10 +850,10 @@ name = "flowy-error" version = "0.1.0" dependencies = [ "bytes", - "flowy-collaboration", "flowy-database", "flowy-derive", "flowy-error-code", + "flowy-sync", "http-flowy", "lib-dispatch", "lib-infra", @@ -979,38 +878,30 @@ dependencies = [ name = "flowy-folder" version = "0.1.0" dependencies = [ - "bincode", "bytes", - "chrono", - "crossbeam", - "crossbeam-utils", "dart-notify", - "derive_more", "diesel", "diesel_derives", - "flowy-block", - "flowy-collaboration", "flowy-database", "flowy-derive", "flowy-error", "flowy-folder", "flowy-folder-data-model", + "flowy-revision", "flowy-sync", "flowy-test", + "flowy-text-block", "futures", - "futures-core", "lazy_static", "lib-dispatch", "lib-infra", "lib-ot", - "lib-sqlite", "log", "parking_lot", "pin-project", "protobuf", "serde", "serde_json", - "serial_test", "strum", "strum_macros", "tokio", @@ -1028,6 +919,7 @@ dependencies = [ "flowy-error-code", "lib-infra", "log", + "nanoid", "protobuf", "serde", "serde_json", @@ -1035,7 +927,60 @@ dependencies = [ "strum", "strum_macros", "unicode-segmentation", - "uuid", +] + +[[package]] +name = "flowy-grid" +version = "0.1.0" +dependencies = [ + "bytes", + "chrono", + "dart-notify", + "dashmap", + "diesel", + "flowy-database", + "flowy-derive", + "flowy-error", + "flowy-grid", + "flowy-grid-data-model", + "flowy-revision", + "flowy-sync", + "flowy-test", + "indexmap", + "lazy_static", + "lib-dispatch", + "lib-infra", + "lib-ot", + "nanoid", + "protobuf", + "rayon", + "rust_decimal", + "rusty-money", + "serde", + "serde_json", + "serde_repr", + "strum", + "strum_macros", + "tokio", + "tracing", +] + +[[package]] +name = "flowy-grid-data-model" +version = "0.1.0" +dependencies = [ + "bytes", + "flowy-derive", + "flowy-error-code", + "indexmap", + "lib-infra", + "nanoid", + "protobuf", + "serde", + "serde_json", + "serde_repr", + "strum", + "strum_macros", ] [[package]] @@ -1047,12 +992,12 @@ dependencies = [ "bytes", "config", "dashmap", - "flowy-block", - "flowy-collaboration", "flowy-derive", "flowy-error", "flowy-folder", "flowy-folder-data-model", + "flowy-sync", + "flowy-text-block", "flowy-user", "flowy-user-data-model", "futures-util", @@ -1063,6 +1008,7 @@ dependencies = [ "lib-infra", "lib-ws", "log", + "nanoid", "parking_lot", "protobuf", "reqwest", @@ -1075,6 +1021,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "flowy-revision" +version = "0.1.0" +dependencies = [ + "async-stream", + "bytes", + "dashmap", + "diesel", + "diesel_derives", + "flowy-database", + "flowy-error", + "flowy-sync", + "futures-util", + "lib-infra", + "lib-ot", + "lib-ws", + "serde", + "strum", + "strum_macros", + "tokio", + "tracing", +] + [[package]] name = "flowy-sdk" version = "0.1.0" @@ -1083,12 +1052,14 @@ dependencies = [ "bytes", "claim 0.5.0", "color-eyre", - "flowy-block", - "flowy-collaboration", "flowy-database", "flowy-folder", + "flowy-grid", + "flowy-grid-data-model", "flowy-net", + "flowy-revision", "flowy-sync", + "flowy-text-block", "flowy-user", "futures-core", "futures-util", @@ -1109,18 +1080,18 @@ name = "flowy-sync" version = "0.1.0" dependencies = [ "async-stream", - "async-trait", "bytes", + "chrono", "dashmap", - "diesel", - "diesel_derives", - "flowy-collaboration", - "flowy-database", - "flowy-error", - "futures-util", + "dissimilar", + "flowy-derive", + "flowy-folder-data-model", + "flowy-grid-data-model", + "futures", "lib-infra", "lib-ot", - "lib-ws", + "log", + "md5", "parking_lot", "protobuf", "serde", @@ -1129,6 +1100,7 @@ dependencies = [ "strum_macros", "tokio", "tracing", + "url", ] [[package]] @@ -1140,10 +1112,10 @@ dependencies = [ "claim 0.4.0", "claim 0.5.0", "fake", - "flowy-collaboration", "flowy-folder", "flowy-net", "flowy-sdk", + "flowy-sync", "flowy-user", "futures", "futures-util", @@ -1151,6 +1123,7 @@ dependencies = [ "lib-infra", "lib-ot", "log", + "nanoid", "protobuf", "quickcheck", "quickcheck_macros", @@ -1162,10 +1135,14 @@ dependencies = [ ] [[package]] -name = "flowy-user" +name = "flowy-text-block" version = "0.1.0" dependencies = [ + "async-stream", "bytes", + "chrono", + "color-eyre", + "criterion", "dart-notify", "dashmap", "derive_more", @@ -1174,27 +1151,55 @@ dependencies = [ "flowy-database", "flowy-derive", "flowy-error", + "flowy-revision", + "flowy-sync", + "flowy-test", + "flowy-text-block", + "futures", + "futures-util", + "lib-dispatch", + "lib-infra", + "lib-ot", + "lib-ws", + "log", + "protobuf", + "rand 0.7.3", + "serde", + "serde_json", + "strum", + "strum_macros", + "tokio", + "tracing", + "unicode-segmentation", + "url", +] + +[[package]] +name = "flowy-user" +version = "0.1.0" +dependencies = [ + "bytes", + "dart-notify", + "diesel", + "diesel_derives", + "flowy-database", + "flowy-derive", + "flowy-error", "flowy-test", "flowy-user-data-model", "futures", - "futures-core", "lazy_static", "lib-dispatch", "lib-infra", - "lib-sqlite", "log", + "nanoid", "once_cell", "parking_lot", - "pin-project", "protobuf", - "r2d2", "serde", "serde_json", - "serial_test", "strum", "strum_macros", - "thread-id", - "thread_local", "tokio", "tracing", ] @@ -1611,12 +1616,13 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] @@ -1676,7 +1682,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags", "cfg-if", "ryu", @@ -1699,6 +1705,7 @@ dependencies = [ "futures-util", "lazy_static", "log", + "nanoid", "paste", "pin-project", "protobuf", @@ -1708,7 +1715,6 @@ dependencies = [ "thread-id", "tokio", "tracing", - "uuid", ] [[package]] @@ -1737,7 +1743,6 @@ dependencies = [ "tera", "tokio", "toml", - "uuid", "walkdir", ] @@ -1962,6 +1967,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand 0.8.4", +] + [[package]] name = "native-tls" version = "0.2.8" @@ -2726,6 +2740,27 @@ dependencies = [ "winreg", ] +[[package]] +name = "rust_decimal" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37baa70cf8662d2ba1c1868c5983dda16ef32b105cce41fb5c47e72936a90b3" +dependencies = [ + "arrayvec 0.7.2", + "num-traits", + "serde", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "184abaf7b434800e1a5a8aad3ebc8cd7498df33af72d65371d797a264713a59b" +dependencies = [ + "quote", + "rust_decimal", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -2747,6 +2782,16 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +[[package]] +name = "rusty-money" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b28f881005eac7ad8d46b6f075da5f322bd7f4f83a38720fc069694ddadd683" +dependencies = [ + "rust_decimal", + "rust_decimal_macros", +] + [[package]] name = "ryu" version = "1.0.9" @@ -3553,7 +3598,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ "getrandom 0.2.3", - "serde", ] [[package]] diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index ea37363bcc..d4cc70df5f 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -11,10 +11,22 @@ members = [ "flowy-database", "flowy-folder", "dart-notify", - "flowy-block", + "flowy-text-block", "flowy-error", - "flowy-sync", + "flowy-revision", + "flowy-grid", ] [profile.dev] +opt-level = 0 +#https://doc.rust-lang.org/rustc/codegen-options/index.html#debug-assertions split-debuginfo = "unpacked" + +[profile.release] +opt-level = 3 +## debuginfo — it makes ./target much bigger, which again harms caching. Depending on your preferred workflow, +## you might consider disabling debuginfo unconditionally, this brings some benefits for local builds as well. +#strip = "debuginfo" +## For from-scratch builds, incremental adds an extra dependency-tracking overhead. It also significantly increases +## the amount of IO and the size of ./target, which make caching less effective. +incremental = false \ No newline at end of file diff --git a/frontend/rust-lib/dart-ffi/Cargo.toml b/frontend/rust-lib/dart-ffi/Cargo.toml index 96755db623..bbc3c3f35b 100644 --- a/frontend/rust-lib/dart-ffi/Cargo.toml +++ b/frontend/rust-lib/dart-ffi/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [lib] name = "dart_ffi" # this value will change depending on the target os -# default staticlib +# default static lib crate-type = ["staticlib"] @@ -31,7 +31,7 @@ flowy-derive = {path = "../../../shared-lib/flowy-derive" } [features] default = ["flowy-sdk/dart", "dart-notify/dart", "flutter"] flutter = [] -http_server = ["flowy-sdk/http_server", "flowy-sdk/use_bunyan"] +http_sync = ["flowy-sdk/http_sync", "flowy-sdk/use_bunyan"] #use_serde = ["bincode"] #use_protobuf= ["protobuf"] diff --git a/frontend/rust-lib/flowy-block/src/lib.rs b/frontend/rust-lib/flowy-block/src/lib.rs deleted file mode 100644 index 018bd94599..0000000000 --- a/frontend/rust-lib/flowy-block/src/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub mod block_editor; -pub mod manager; -mod queue; -mod web_socket; - -pub use manager::*; -pub mod errors { - pub use flowy_error::{internal_error, ErrorCode, FlowyError}; -} - -pub const DOCUMENT_SYNC_INTERVAL_IN_MILLIS: u64 = 1000; - -use crate::errors::FlowyError; -use flowy_collaboration::entities::document_info::{BlockId, BlockInfo, CreateBlockParams, ResetDocumentParams}; -use lib_infra::future::FutureResult; - -pub trait BlockCloudService: Send + Sync { - fn create_block(&self, token: &str, params: CreateBlockParams) -> FutureResult<(), FlowyError>; - - fn read_block(&self, token: &str, params: BlockId) -> FutureResult, FlowyError>; - - fn update_block(&self, token: &str, params: ResetDocumentParams) -> FutureResult<(), FlowyError>; -} diff --git a/frontend/rust-lib/flowy-block/tests/document/mod.rs b/frontend/rust-lib/flowy-block/tests/document/mod.rs deleted file mode 100644 index 252787043a..0000000000 --- a/frontend/rust-lib/flowy-block/tests/document/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod document_test; -mod edit_script; diff --git a/frontend/rust-lib/flowy-database/migrations/2021-09-22-074638_flowy-doc-op/down.sql b/frontend/rust-lib/flowy-database/migrations/2021-09-22-074638_flowy-doc-op/down.sql index 291a97c5ce..3f706119bd 100644 --- a/frontend/rust-lib/flowy-database/migrations/2021-09-22-074638_flowy-doc-op/down.sql +++ b/frontend/rust-lib/flowy-database/migrations/2021-09-22-074638_flowy-doc-op/down.sql @@ -1 +1,2 @@ --- This file should undo anything in `up.sql` \ No newline at end of file +-- This file should undo anything in `up.sql` +DROP TABLE rev_table; \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-03-04-101530_flowy-grid/down.sql b/frontend/rust-lib/flowy-database/migrations/2022-03-04-101530_flowy-grid/down.sql new file mode 100644 index 0000000000..96473ec177 --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-03-04-101530_flowy-grid/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE kv_table; \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-03-04-101530_flowy-grid/up.sql b/frontend/rust-lib/flowy-database/migrations/2022-03-04-101530_flowy-grid/up.sql new file mode 100644 index 0000000000..edde5d7dfa --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-03-04-101530_flowy-grid/up.sql @@ -0,0 +1,5 @@ +-- Your SQL goes here +CREATE TABLE kv_table ( + key TEXT NOT NULL PRIMARY KEY, + value BLOB NOT NULL DEFAULT (x'') +); \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-03-11-025536_flowy-grid/down.sql b/frontend/rust-lib/flowy-database/migrations/2022-03-11-025536_flowy-grid/down.sql new file mode 100644 index 0000000000..9d48f0fb8a --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-03-11-025536_flowy-grid/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +DROP TABLE grid_rev_table; +DROP TABLE grid_meta_rev_table; \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-03-11-025536_flowy-grid/up.sql b/frontend/rust-lib/flowy-database/migrations/2022-03-11-025536_flowy-grid/up.sql new file mode 100644 index 0000000000..4ce278ec8f --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-03-11-025536_flowy-grid/up.sql @@ -0,0 +1,18 @@ +-- Your SQL goes here +CREATE TABLE grid_rev_table ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + object_id TEXT NOT NULL DEFAULT '', + base_rev_id BIGINT NOT NULL DEFAULT 0, + rev_id BIGINT NOT NULL DEFAULT 0, + data BLOB NOT NULL DEFAULT (x''), + state INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE grid_meta_rev_table ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + object_id TEXT NOT NULL DEFAULT '', + base_rev_id BIGINT NOT NULL DEFAULT 0, + rev_id BIGINT NOT NULL DEFAULT 0, + data BLOB NOT NULL DEFAULT (x''), + state INTEGER NOT NULL DEFAULT 0 +); \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-04-05-015536_flowy-grid-block-index/down.sql b/frontend/rust-lib/flowy-database/migrations/2022-04-05-015536_flowy-grid-block-index/down.sql new file mode 100644 index 0000000000..06daaca7de --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-04-05-015536_flowy-grid-block-index/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +DROP TABLE grid_block_index_table; +-- DROP TABLE grid_block_fts_table; \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-04-05-015536_flowy-grid-block-index/up.sql b/frontend/rust-lib/flowy-database/migrations/2022-04-05-015536_flowy-grid-block-index/up.sql new file mode 100644 index 0000000000..f55bc82f64 --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-04-05-015536_flowy-grid-block-index/up.sql @@ -0,0 +1,7 @@ +-- Your SQL goes here +CREATE TABLE grid_block_index_table ( + row_id TEXT NOT NULL PRIMARY KEY, + block_id TEXT NOT NULL +); + +-- CREATE VIRTUAL TABLE grid_block_fts_table USING FTS5(content, grid_id, block_id, row_id); \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/src/lib.rs b/frontend/rust-lib/flowy-database/src/lib.rs index bfdec920d4..e6c7d0b492 100644 --- a/frontend/rust-lib/flowy-database/src/lib.rs +++ b/frontend/rust-lib/flowy-database/src/lib.rs @@ -6,12 +6,10 @@ pub mod kv; use lib_sqlite::PoolConfig; pub use lib_sqlite::{ConnectionPool, DBConnection, Database}; - pub mod schema; #[macro_use] pub mod macros; - #[macro_use] extern crate diesel; #[macro_use] @@ -20,11 +18,11 @@ extern crate diesel_derives; extern crate diesel_migrations; pub type Error = diesel::result::Error; - pub mod prelude { - pub use diesel::{query_dsl::*, BelongingToDsl, ExpressionMethods, RunQueryDsl}; - pub use super::UserDatabaseConnection; + pub use crate::*; + pub use diesel::SqliteConnection; + pub use diesel::{query_dsl::*, BelongingToDsl, ExpressionMethods, RunQueryDsl}; } embed_migrations!("../flowy-database/migrations/"); diff --git a/frontend/rust-lib/flowy-database/src/macros.rs b/frontend/rust-lib/flowy-database/src/macros.rs index 9ef9740fee..e1534bf25f 100644 --- a/frontend/rust-lib/flowy-database/src/macros.rs +++ b/frontend/rust-lib/flowy-database/src/macros.rs @@ -160,3 +160,39 @@ macro_rules! impl_sql_integer_expression { } }; } + +#[macro_export] +macro_rules! impl_rev_state_map { + ($target:ident) => { + impl std::convert::From for $target { + fn from(value: i32) -> Self { + match value { + 0 => $target::Sync, + 1 => $target::Ack, + o => { + tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o); + $target::Sync + } + } + } + } + + impl std::convert::From<$target> for RevisionState { + fn from(s: $target) -> Self { + match s { + $target::Sync => RevisionState::Sync, + $target::Ack => RevisionState::Ack, + } + } + } + + impl std::convert::From for $target { + fn from(s: RevisionState) -> Self { + match s { + RevisionState::Sync => $target::Sync, + RevisionState::Ack => $target::Ack, + } + } + } + }; +} diff --git a/frontend/rust-lib/flowy-database/src/schema.rs b/frontend/rust-lib/flowy-database/src/schema.rs index 0bc8b99ef8..8fddd037e0 100644 --- a/frontend/rust-lib/flowy-database/src/schema.rs +++ b/frontend/rust-lib/flowy-database/src/schema.rs @@ -21,6 +21,42 @@ table! { } } +table! { + grid_block_index_table (row_id) { + row_id -> Text, + block_id -> Text, + } +} + +table! { + grid_meta_rev_table (id) { + id -> Integer, + object_id -> Text, + base_rev_id -> BigInt, + rev_id -> BigInt, + data -> Binary, + state -> Integer, + } +} + +table! { + grid_rev_table (id) { + id -> Integer, + object_id -> Text, + base_rev_id -> BigInt, + rev_id -> BigInt, + data -> Binary, + state -> Integer, + } +} + +table! { + kv_table (key) { + key -> Text, + value -> Binary, + } +} + table! { rev_table (id) { id -> Integer, @@ -84,6 +120,10 @@ table! { allow_tables_to_appear_in_same_query!( app_table, doc_table, + grid_block_index_table, + grid_meta_rev_table, + grid_rev_table, + kv_table, rev_table, trash_table, user_table, diff --git a/frontend/rust-lib/flowy-error/Cargo.toml b/frontend/rust-lib/flowy-error/Cargo.toml index b7a816b026..5041facaca 100644 --- a/frontend/rust-lib/flowy-error/Cargo.toml +++ b/frontend/rust-lib/flowy-error/Cargo.toml @@ -13,7 +13,7 @@ protobuf = {version = "2.20.0"} bytes = "1.0" -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration", optional = true} +flowy-sync = { path = "../../../shared-lib/flowy-sync", optional = true} lib-ot = { path = "../../../shared-lib/lib-ot", optional = true} serde_json = {version = "1.0", optional = true} http-flowy = { git = "https://github.com/AppFlowy-IO/AppFlowy-Server", optional = true} @@ -22,7 +22,7 @@ r2d2 = { version = "0.8", optional = true} lib-sqlite = { path = "../lib-sqlite", optional = true } [features] -collaboration = ["flowy-collaboration"] +collaboration = ["flowy-sync"] ot = ["lib-ot"] serde = ["serde_json"] http_server = ["http-flowy"] diff --git a/frontend/rust-lib/flowy-error/src/errors.rs b/frontend/rust-lib/flowy-error/src/errors.rs index 956df16fa5..cd890fd02e 100644 --- a/frontend/rust-lib/flowy-error/src/errors.rs +++ b/frontend/rust-lib/flowy-error/src/errors.rs @@ -64,6 +64,8 @@ impl FlowyError { static_flowy_error!(name_empty, ErrorCode::UserNameIsEmpty); static_flowy_error!(user_id, ErrorCode::UserIdInvalid); static_flowy_error!(user_not_exist, ErrorCode::UserNotExist); + static_flowy_error!(text_too_long, ErrorCode::TextTooLong); + static_flowy_error!(invalid_data, ErrorCode::InvalidData); } impl std::convert::From for FlowyError { diff --git a/frontend/rust-lib/flowy-error/src/ext/collaborate.rs b/frontend/rust-lib/flowy-error/src/ext/collaborate.rs index c4a6725794..f93b2b7bc3 100644 --- a/frontend/rust-lib/flowy-error/src/ext/collaborate.rs +++ b/frontend/rust-lib/flowy-error/src/ext/collaborate.rs @@ -1,9 +1,9 @@ use crate::FlowyError; -use flowy_collaboration::errors::ErrorCode; +use flowy_sync::errors::ErrorCode; -impl std::convert::From for FlowyError { - fn from(error: flowy_collaboration::errors::CollaborateError) -> Self { +impl std::convert::From for FlowyError { + fn from(error: flowy_sync::errors::CollaborateError) -> Self { match error.code { ErrorCode::RecordNotFound => FlowyError::record_not_found().context(error.msg), _ => FlowyError::internal().context(error.msg), diff --git a/frontend/rust-lib/flowy-folder/Cargo.toml b/frontend/rust-lib/flowy-folder/Cargo.toml index 45f7ffb3e7..ddc6f1f586 100644 --- a/frontend/rust-lib/flowy-folder/Cargo.toml +++ b/frontend/rust-lib/flowy-folder/Cargo.toml @@ -7,27 +7,23 @@ edition = "2018" [dependencies] flowy-folder-data-model = { path = "../../../shared-lib/flowy-folder-data-model" } -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" } +flowy-sync = { path = "../../../shared-lib/flowy-sync" } flowy-derive = { path = "../../../shared-lib/flowy-derive" } lib-ot = { path = "../../../shared-lib/lib-ot" } lib-infra = { path = "../../../shared-lib/lib-infra" } -flowy-block = { path = "../flowy-block" } +flowy-text-block = { path = "../flowy-text-block" } flowy-database = { path = "../flowy-database" } flowy-error = { path = "../flowy-error", features = ["db", "http_server"]} dart-notify = { path = "../dart-notify" } lib-dispatch = { path = "../lib-dispatch" } -lib-sqlite = { path = "../lib-sqlite" } -flowy-sync = { path = "../flowy-sync" } +flowy-revision = { path = "../flowy-revision" } parking_lot = "0.11" protobuf = {version = "2.18.0"} log = "0.4.14" diesel = {version = "1.4.8", features = ["sqlite"]} diesel_derives = {version = "1.4.1", features = ["sqlite"]} -#diesel = { git = "https://github.com/diesel-rs/diesel.git", branch = "master", features = ["sqlite"] } -#diesel_derives = { git = "https://github.com/diesel-rs/diesel.git", branch = "master",features = ["sqlite"] } -futures-core = { version = "0.3", default-features = false } futures = "0.3.15" pin-project = "1.0.0" strum = "0.21" @@ -35,25 +31,20 @@ strum_macros = "0.21" tokio = { version = "1", features = ["rt"] } lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } -derive_more = {version = "0.99", features = ["display"]} -bincode = { version = "1.3"} tracing = { version = "0.1", features = ["log"] } bytes = { version = "1.0" } -crossbeam = "0.8" -crossbeam-utils = "0.8" -chrono = "0.4" [dev-dependencies] -serial_test = "0.5.1" serde_json = "1.0" flowy-folder = { path = "../flowy-folder", features = ["flowy_unit_test"]} flowy-test = { path = "../flowy-test" } +[build-dependencies] +lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file_gen", "proto_gen"] } + [features] default = [] -http_server = [] -flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-sync/flowy_unit_test"] -dart = ["lib-infra/dart", "flowy-folder/dart", "flowy-folder/dart",] - -[build-dependencies] -lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file_gen", "proto_gen"] } \ No newline at end of file +sync = [] +cloud_sync = ["sync"] +flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-revision/flowy_unit_test"] +dart = ["lib-infra/dart"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-folder/build.rs b/frontend/rust-lib/flowy-folder/build.rs index 4ab7b9e23d..4d4d3b13da 100644 --- a/frontend/rust-lib/flowy-folder/build.rs +++ b/frontend/rust-lib/flowy-folder/build.rs @@ -3,5 +3,7 @@ use lib_infra::code_gen; fn main() { let crate_name = env!("CARGO_PKG_NAME"); code_gen::protobuf_file::gen(crate_name, "./src/protobuf/proto"); + + #[cfg(feature = "dart")] code_gen::dart_event::gen(crate_name); } diff --git a/frontend/rust-lib/flowy-folder/src/event_map.rs b/frontend/rust-lib/flowy-folder/src/event_map.rs index bd151f80b0..906e9406ce 100644 --- a/frontend/rust-lib/flowy-folder/src/event_map.rs +++ b/frontend/rust-lib/flowy-folder/src/event_map.rs @@ -1,5 +1,4 @@ use crate::{ - controller::FolderManager, entities::{ app::{App, AppId, CreateAppParams, UpdateAppParams}, trash::{RepeatedTrash, RepeatedTrashId}, @@ -7,16 +6,15 @@ use crate::{ workspace::{CreateWorkspaceParams, RepeatedWorkspace, UpdateWorkspaceParams, Workspace, WorkspaceId}, }, errors::FlowyError, + manager::FolderManager, services::{app::event_handler::*, trash::event_handler::*, view::event_handler::*, workspace::event_handler::*}, }; -use flowy_database::DBConnection; +use flowy_database::{ConnectionPool, DBConnection}; use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; -use strum_macros::Display; - use lib_dispatch::prelude::*; use lib_infra::future::FutureResult; -use lib_sqlite::ConnectionPool; use std::sync::Arc; +use strum_macros::Display; pub trait WorkspaceDeps: WorkspaceUser + WorkspaceDatabase {} @@ -63,9 +61,8 @@ pub fn create(folder: Arc) -> Module { .event(FolderEvent::UpdateView, update_view_handler) .event(FolderEvent::DeleteView, delete_view_handler) .event(FolderEvent::DuplicateView, duplicate_view_handler) - .event(FolderEvent::OpenView, open_view_handler) - .event(FolderEvent::CloseView, close_view_handler) - .event(FolderEvent::ApplyDocDelta, block_delta_handler); + .event(FolderEvent::SetLatestView, set_latest_view_handler) + .event(FolderEvent::CloseView, close_view_handler); module = module .event(FolderEvent::ReadTrash, read_trash_handler) @@ -74,8 +71,6 @@ pub fn create(folder: Arc) -> Module { .event(FolderEvent::RestoreAllTrash, restore_all_trash_handler) .event(FolderEvent::DeleteAllTrash, delete_all_trash_handler); - module = module.event(FolderEvent::ExportDocument, export_handler); - module } @@ -130,8 +125,8 @@ pub enum FolderEvent { #[event()] CopyLink = 206, - #[event(input = "ViewId", output = "BlockDelta")] - OpenView = 207, + #[event(input = "ViewId")] + SetLatestView = 207, #[event(input = "ViewId")] CloseView = 208, @@ -150,12 +145,6 @@ pub enum FolderEvent { #[event()] DeleteAllTrash = 304, - - #[event(input = "BlockDelta", output = "BlockDelta")] - ApplyDocDelta = 400, - - #[event(input = "ExportPayload", output = "ExportData")] - ExportDocument = 500, } pub trait FolderCouldServiceV1: Send + Sync { diff --git a/frontend/rust-lib/flowy-folder/src/lib.rs b/frontend/rust-lib/flowy-folder/src/lib.rs index 7ce085a8dd..0137664274 100644 --- a/frontend/rust-lib/flowy-folder/src/lib.rs +++ b/frontend/rust-lib/flowy-folder/src/lib.rs @@ -8,8 +8,8 @@ mod macros; #[macro_use] extern crate flowy_database; -pub mod controller; mod dart_notification; +pub mod manager; pub mod protobuf; mod util; diff --git a/frontend/rust-lib/flowy-folder/src/controller.rs b/frontend/rust-lib/flowy-folder/src/manager.rs similarity index 74% rename from frontend/rust-lib/flowy-folder/src/controller.rs rename to frontend/rust-lib/flowy-folder/src/manager.rs index a01a26b7d5..05847f8cc1 100644 --- a/frontend/rust-lib/flowy-folder/src/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -1,17 +1,3 @@ -use bytes::Bytes; -use chrono::Utc; -use flowy_collaboration::client_document::default::{initial_delta, initial_read_me}; -use flowy_folder_data_model::user_default; -use flowy_sync::RevisionWebSocket; -use lazy_static::lazy_static; - -use flowy_block::BlockManager; -use flowy_collaboration::{client_folder::FolderPad, entities::ws_data::ServerRevisionWSData}; - -use flowy_collaboration::entities::revision::{RepeatedRevision, Revision}; -use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc}; -use tokio::sync::RwLock as TokioRwLock; - use crate::{ dart_notification::{send_dart_notification, FolderNotification}, entities::workspace::RepeatedWorkspace, @@ -22,11 +8,22 @@ use crate::{ TrashController, ViewController, WorkspaceController, }, }; +use bytes::Bytes; +use flowy_sync::client_document::default::{initial_quill_delta_string, initial_read_me}; +use flowy_error::FlowyError; +use flowy_folder_data_model::entities::view::ViewDataType; +use flowy_folder_data_model::user_default; +use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; +use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_sync::{client_folder::FolderPad, entities::ws_data::ServerRevisionWSData}; +use lazy_static::lazy_static; +use lib_infra::future::FutureResult; +use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc}; +use tokio::sync::RwLock as TokioRwLock; lazy_static! { static ref INIT_FOLDER_FLAG: TokioRwLock> = TokioRwLock::new(HashMap::new()); } - const FOLDER_ID: &str = "folder"; const FOLDER_ID_SPLIT: &str = ":"; #[derive(Clone)] @@ -65,6 +62,7 @@ pub struct FolderManager { pub(crate) trash_controller: Arc, web_socket: Arc, folder_editor: Arc>>>, + data_processors: ViewDataProcessorMap, } impl FolderManager { @@ -72,7 +70,7 @@ impl FolderManager { user: Arc, cloud_service: Arc, database: Arc, - document_manager: Arc, + data_processors: ViewDataProcessorMap, web_socket: Arc, ) -> Self { if let Ok(user_id) = user.user_id() { @@ -95,7 +93,7 @@ impl FolderManager { persistence.clone(), cloud_service.clone(), trash_controller.clone(), - document_manager, + data_processors.clone(), )); let app_controller = Arc::new(AppController::new( @@ -122,6 +120,7 @@ impl FolderManager { trash_controller, web_socket, folder_editor, + data_processors, } } @@ -163,11 +162,21 @@ impl FolderManager { let _ = self.persistence.initialize(user_id, &folder_id).await?; let pool = self.persistence.db_pool()?; - let folder_editor = ClientFolderEditor::new(user_id, &folder_id, token, pool, self.web_socket.clone()).await?; + let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool)); + let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache)); + let rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence); + + let folder_editor = + ClientFolderEditor::new(user_id, &folder_id, token, rev_manager, self.web_socket.clone()).await?; *self.folder_editor.write().await = Some(Arc::new(folder_editor)); let _ = self.app_controller.initialize()?; let _ = self.view_controller.initialize()?; + + self.data_processors.iter().for_each(|(_, processor)| { + processor.initialize(); + }); + write_guard.insert(user_id.to_owned(), true); Ok(()) } @@ -191,21 +200,19 @@ impl DefaultFolderBuilder { view_controller: Arc, ) -> FlowyResult<()> { log::debug!("Create user default workspace"); - let time = Utc::now(); - let workspace = user_default::create_default_workspace(time); + let workspace = user_default::create_default_workspace(); set_current_workspace(&workspace.id); for app in workspace.apps.iter() { for (index, view) in app.belongings.iter().enumerate() { let view_data = if index == 0 { - initial_read_me().to_delta_json() + initial_read_me().to_delta_str() } else { - initial_delta().to_delta_json() + initial_quill_delta_string() }; - view_controller.set_latest_view(view); - let delta_data = Bytes::from(view_data); - let repeated_revision: RepeatedRevision = - Revision::initial_revision(user_id, &view.id, delta_data).into(); - let _ = view_controller.create_view(&view.id, repeated_revision).await?; + let _ = view_controller.set_latest_view(&view.id); + let _ = view_controller + .create_view(&view.id, ViewDataType::TextBlock, Bytes::from(view_data)) + .await?; } } let folder = FolderPad::new(vec![workspace.clone()], vec![])?; @@ -225,3 +232,23 @@ impl FolderManager { self.folder_editor.read().await.clone().unwrap() } } + +pub trait ViewDataProcessor { + fn initialize(&self) -> FutureResult<(), FlowyError>; + + fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError>; + + fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError>; + + fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>; + + fn delta_bytes(&self, view_id: &str) -> FutureResult; + + fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult; + + fn process_create_view_data(&self, user_id: &str, view_id: &str, data: Vec) -> FutureResult; + + fn data_type(&self) -> ViewDataType; +} + +pub type ViewDataProcessorMap = Arc>>; diff --git a/frontend/rust-lib/flowy-folder/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-folder/src/protobuf/model/event_map.rs index 58606cda0d..6dc25807d6 100644 --- a/frontend/rust-lib/flowy-folder/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-folder/src/protobuf/model/event_map.rs @@ -41,15 +41,13 @@ pub enum FolderEvent { DeleteView = 204, DuplicateView = 205, CopyLink = 206, - OpenView = 207, + SetLatestView = 207, CloseView = 208, ReadTrash = 300, PutbackTrash = 301, DeleteTrash = 302, RestoreAllTrash = 303, DeleteAllTrash = 304, - ApplyDocDelta = 400, - ExportDocument = 500, } impl ::protobuf::ProtobufEnum for FolderEvent { @@ -75,15 +73,13 @@ impl ::protobuf::ProtobufEnum for FolderEvent { 204 => ::std::option::Option::Some(FolderEvent::DeleteView), 205 => ::std::option::Option::Some(FolderEvent::DuplicateView), 206 => ::std::option::Option::Some(FolderEvent::CopyLink), - 207 => ::std::option::Option::Some(FolderEvent::OpenView), + 207 => ::std::option::Option::Some(FolderEvent::SetLatestView), 208 => ::std::option::Option::Some(FolderEvent::CloseView), 300 => ::std::option::Option::Some(FolderEvent::ReadTrash), 301 => ::std::option::Option::Some(FolderEvent::PutbackTrash), 302 => ::std::option::Option::Some(FolderEvent::DeleteTrash), 303 => ::std::option::Option::Some(FolderEvent::RestoreAllTrash), 304 => ::std::option::Option::Some(FolderEvent::DeleteAllTrash), - 400 => ::std::option::Option::Some(FolderEvent::ApplyDocDelta), - 500 => ::std::option::Option::Some(FolderEvent::ExportDocument), _ => ::std::option::Option::None } } @@ -106,15 +102,13 @@ impl ::protobuf::ProtobufEnum for FolderEvent { FolderEvent::DeleteView, FolderEvent::DuplicateView, FolderEvent::CopyLink, - FolderEvent::OpenView, + FolderEvent::SetLatestView, FolderEvent::CloseView, FolderEvent::ReadTrash, FolderEvent::PutbackTrash, FolderEvent::DeleteTrash, FolderEvent::RestoreAllTrash, FolderEvent::DeleteAllTrash, - FolderEvent::ApplyDocDelta, - FolderEvent::ExportDocument, ]; values } @@ -143,19 +137,18 @@ impl ::protobuf::reflect::ProtobufValue for FolderEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xd2\x03\n\x0bFolderEvent\x12\x13\n\x0fCreateWorks\ + \n\x0fevent_map.proto*\xae\x03\n\x0bFolderEvent\x12\x13\n\x0fCreateWorks\ pace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorksp\ aces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspa\ ce\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\r\n\tCreateApp\x10\ e\x12\r\n\tDeleteApp\x10f\x12\x0b\n\x07ReadApp\x10g\x12\r\n\tUpdateApp\ \x10h\x12\x0f\n\nCreateView\x10\xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\ \x12\x0f\n\nUpdateView\x10\xcb\x01\x12\x0f\n\nDeleteView\x10\xcc\x01\x12\ - \x12\n\rDuplicateView\x10\xcd\x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\r\ - \n\x08OpenView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\x0e\n\tR\ - eadTrash\x10\xac\x02\x12\x11\n\x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0b\ - DeleteTrash\x10\xae\x02\x12\x14\n\x0fRestoreAllTrash\x10\xaf\x02\x12\x13\ - \n\x0eDeleteAllTrash\x10\xb0\x02\x12\x12\n\rApplyDocDelta\x10\x90\x03\ - \x12\x13\n\x0eExportDocument\x10\xf4\x03b\x06proto3\ + \x12\n\rDuplicateView\x10\xcd\x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\ + \x12\n\rSetLatestView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\ + \x0e\n\tReadTrash\x10\xac\x02\x12\x11\n\x0cPutbackTrash\x10\xad\x02\x12\ + \x10\n\x0bDeleteTrash\x10\xae\x02\x12\x14\n\x0fRestoreAllTrash\x10\xaf\ + \x02\x12\x13\n\x0eDeleteAllTrash\x10\xb0\x02b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-folder/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-folder/src/protobuf/proto/event_map.proto index a21f0f92c7..67f2606664 100644 --- a/frontend/rust-lib/flowy-folder/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-folder/src/protobuf/proto/event_map.proto @@ -17,13 +17,11 @@ enum FolderEvent { DeleteView = 204; DuplicateView = 205; CopyLink = 206; - OpenView = 207; + SetLatestView = 207; CloseView = 208; ReadTrash = 300; PutbackTrash = 301; DeleteTrash = 302; RestoreAllTrash = 303; DeleteAllTrash = 304; - ApplyDocDelta = 400; - ExportDocument = 500; } diff --git a/frontend/rust-lib/flowy-folder/src/services/app/controller.rs b/frontend/rust-lib/flowy-folder/src/services/app/controller.rs index 8ecb4f79b6..ce8cc321a6 100644 --- a/frontend/rust-lib/flowy-folder/src/services/app/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/app/controller.rs @@ -221,7 +221,7 @@ async fn handle_trash_event( } } -#[tracing::instrument(skip(workspace_id, trash_controller, transaction), err)] +#[tracing::instrument(level = "debug", skip(workspace_id, trash_controller, transaction), err)] fn notify_apps_changed<'a>( workspace_id: &str, trash_controller: Arc, diff --git a/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs index f3f354d517..45034646b0 100644 --- a/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs @@ -36,7 +36,7 @@ pub(crate) async fn delete_app_handler( Ok(()) } -#[tracing::instrument(skip(data, controller))] +#[tracing::instrument(level = "debug", skip(data, controller))] pub(crate) async fn update_app_handler( data: Data, controller: AppData>, @@ -46,7 +46,7 @@ pub(crate) async fn update_app_handler( Ok(()) } -#[tracing::instrument(skip(data, app_controller, view_controller))] +#[tracing::instrument(level = "debug", skip(data, app_controller, view_controller))] pub(crate) async fn read_app_handler( data: Data, app_controller: AppData>, diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index 6f032964e8..6ea1a7e2ec 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -1,50 +1,49 @@ -use crate::services::web_socket::make_folder_ws_manager; -use flowy_collaboration::{ +use flowy_sync::{ client_folder::{FolderChange, FolderPad}, entities::{revision::Revision, ws_data::ServerRevisionWSData}, }; -use crate::controller::FolderId; -use flowy_collaboration::util::make_delta_from_revisions; +use crate::manager::FolderId; +use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; -use flowy_sync::{ - RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence, - RevisionWebSocket, RevisionWebSocketManager, +use flowy_sync::util::make_delta_from_revisions; + +use flowy_revision::{ + RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionWebSocket, }; use lib_infra::future::FutureResult; use lib_ot::core::PlainTextAttributes; -use lib_sqlite::ConnectionPool; + use parking_lot::RwLock; use std::sync::Arc; pub struct ClientFolderEditor { user_id: String, + #[allow(dead_code)] pub(crate) folder_id: FolderId, pub(crate) folder: Arc>, rev_manager: Arc, - ws_manager: Arc, + #[cfg(feature = "sync")] + ws_manager: Arc, } impl ClientFolderEditor { + #[allow(unused_variables)] pub async fn new( user_id: &str, folder_id: &FolderId, token: &str, - pool: Arc, + mut rev_manager: RevisionManager, web_socket: Arc, ) -> FlowyResult { - let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), pool)); - let mut rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence); let cloud = Arc::new(FolderRevisionCloudService { token: token.to_string(), }); - let folder = Arc::new(RwLock::new( - rev_manager - .load::(cloud) - .await?, - )); + let folder = Arc::new(RwLock::new(rev_manager.load::(Some(cloud)).await?)); let rev_manager = Arc::new(rev_manager); - let ws_manager = make_folder_ws_manager( + + #[cfg(feature = "sync")] + let ws_manager = crate::services::web_socket::make_folder_ws_manager( user_id, folder_id.as_ref(), rev_manager.clone(), @@ -60,22 +59,30 @@ impl ClientFolderEditor { folder_id, folder, rev_manager, + #[cfg(feature = "sync")] ws_manager, }) } + #[cfg(feature = "sync")] pub async fn receive_ws_data(&self, data: ServerRevisionWSData) -> FlowyResult<()> { let _ = self.ws_manager.ws_passthrough_tx.send(data).await.map_err(|e| { let err_msg = format!("{} passthrough error: {}", self.folder_id, e); FlowyError::internal().context(err_msg) })?; + + Ok(()) + } + + #[cfg(not(feature = "sync"))] + pub async fn receive_ws_data(&self, _data: ServerRevisionWSData) -> FlowyResult<()> { Ok(()) } pub(crate) fn apply_change(&self, change: FolderChange) -> FlowyResult<()> { let FolderChange { delta, md5 } = change; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_bytes(); + let delta_data = delta.to_delta_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -86,7 +93,7 @@ impl ClientFolderEditor { ); let _ = futures::executor::block_on(async { self.rev_manager - .add_local_revision::(&revision) + .add_local_revision(&revision, Box::new(FolderRevisionCompactor())) .await })?; Ok(()) @@ -128,24 +135,10 @@ impl ClientFolderEditor { } } -struct FolderRevisionCompact(); -impl RevisionCompact for FolderRevisionCompact { - fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec) -> FlowyResult { - if revisions.is_empty() { - return Err(FlowyError::internal().context("Can't compact the empty folder's revisions")); - } - - if revisions.len() == 1 { - return Ok(revisions.pop().unwrap()); - } - - let first_revision = revisions.first().unwrap(); - let last_revision = revisions.last().unwrap(); - - let (base_rev_id, rev_id) = first_revision.pair_rev_id(); - let md5 = last_revision.md5.clone(); +struct FolderRevisionCompactor(); +impl RevisionCompactor for FolderRevisionCompactor { + fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - let delta_data = delta.to_bytes(); - Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5)) + Ok(delta.to_delta_bytes()) } } diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs index 258b8a1e55..bc8838059a 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs @@ -1,9 +1,8 @@ -use crate::controller::FolderId; +use crate::manager::FolderId; use crate::{ event_map::WorkspaceDatabase, services::persistence::{AppTableSql, TrashTableSql, ViewTableSql, WorkspaceTableSql}, }; -use flowy_collaboration::{client_folder::FolderPad, entities::revision::md5}; use flowy_database::kv::KV; use flowy_error::{FlowyError, FlowyResult}; use flowy_folder_data_model::entities::{ @@ -11,7 +10,9 @@ use flowy_folder_data_model::entities::{ view::{RepeatedView, View}, workspace::Workspace, }; -use flowy_sync::{RevisionLoader, RevisionPersistence}; +use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; +use flowy_revision::{RevisionLoader, RevisionPersistence}; +use flowy_sync::{client_folder::FolderPad, entities::revision::md5}; use std::sync::Arc; const V1_MIGRATION: &str = "FOLDER_V1_MIGRATION"; @@ -87,7 +88,8 @@ impl FolderMigration { return Ok(None); } let pool = self.database.db_pool()?; - let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), pool.clone())); + let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool)); + let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache)); let (revisions, _) = RevisionLoader { object_id: folder_id.as_ref().to_owned(), user_id: self.user_id.clone(), diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index 77b6d2a6c4..89b7245da9 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -2,20 +2,12 @@ mod migration; pub mod version_1; mod version_2; -use flowy_collaboration::client_folder::initial_folder_delta; -use flowy_collaboration::{ - client_folder::FolderPad, - entities::revision::{Revision, RevisionState}, -}; -use std::sync::Arc; -use tokio::sync::RwLock; -pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*}; - use crate::{ - controller::FolderId, event_map::WorkspaceDatabase, + manager::FolderId, services::{folder_editor::ClientFolderEditor, persistence::migration::FolderMigration}, }; +use flowy_database::ConnectionPool; use flowy_error::{FlowyError, FlowyResult}; use flowy_folder_data_model::entities::{ app::App, @@ -23,8 +15,13 @@ use flowy_folder_data_model::entities::{ view::View, workspace::Workspace, }; -use flowy_sync::{mk_revision_disk_cache, RevisionRecord}; -use lib_sqlite::ConnectionPool; +use flowy_revision::disk::{RevisionRecord, RevisionState}; +use flowy_revision::mk_revision_disk_cache; +use flowy_sync::client_folder::initial_folder_delta; +use flowy_sync::{client_folder::FolderPad, entities::revision::Revision}; +use std::sync::Arc; +use tokio::sync::RwLock; +pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*}; pub trait FolderPersistenceTransaction { fn create_workspace(&self, user_id: &str, workspace: Workspace) -> FlowyResult<()>; @@ -118,7 +115,7 @@ impl FolderPersistence { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { let pool = self.database.db_pool()?; - let delta_data = initial_folder_delta(&folder)?.to_bytes(); + let delta_data = initial_folder_delta(&folder)?.to_delta_bytes(); let md5 = folder.md5(); let revision = Revision::new(folder_id.as_ref(), 0, 0, delta_data, user_id, md5); let record = RevisionRecord { diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs index 33b30a8656..46f351ff03 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs @@ -1,18 +1,14 @@ use crate::entities::{ - app::{App, ColorStyle, UpdateAppParams}, + app::{App, UpdateAppParams}, trash::{Trash, TrashType}, view::RepeatedView, }; -use diesel::sql_types::Binary; +use crate::{errors::FlowyError, services::persistence::version_1::workspace_sql::WorkspaceTable}; use flowy_database::{ prelude::*, schema::{app_table, app_table::dsl}, SqliteConnection, }; -use serde::{Deserialize, Serialize, __private::TryFrom}; -use std::convert::TryInto; - -use crate::{errors::FlowyError, services::persistence::version_1::workspace_sql::WorkspaceTable}; pub struct AppTableSql(); impl AppTableSql { @@ -86,7 +82,7 @@ pub(crate) struct AppTable { pub workspace_id: String, // equal to #[belongs_to(Workspace, foreign_key = "workspace_id")]. pub name: String, pub desc: String, - pub color_style: ColorStyleCol, + pub color_style: Vec, pub last_view_id: Option, pub modified_time: i64, pub create_time: i64, @@ -101,7 +97,7 @@ impl AppTable { workspace_id: app.workspace_id, name: app.name, desc: app.desc, - color_style: ColorStyleCol::default(), + color_style: Default::default(), last_view_id: None, modified_time: app.modified_time, create_time: app.create_time, @@ -123,38 +119,6 @@ impl std::convert::From for Trash { } } -#[derive(Clone, PartialEq, Serialize, Deserialize, Debug, Default, FromSqlRow, AsExpression)] -#[sql_type = "Binary"] -pub(crate) struct ColorStyleCol { - pub(crate) theme_color: String, -} - -impl std::convert::From for ColorStyleCol { - fn from(s: ColorStyle) -> Self { - Self { - theme_color: s.theme_color, - } - } -} - -impl std::convert::TryInto> for &ColorStyleCol { - type Error = String; - - fn try_into(self) -> Result, Self::Error> { - bincode::serialize(self).map_err(|e| format!("{:?}", e)) - } -} - -impl std::convert::TryFrom<&[u8]> for ColorStyleCol { - type Error = String; - - fn try_from(value: &[u8]) -> Result { - bincode::deserialize(value).map_err(|e| format!("{:?}", e)) - } -} - -impl_sql_binary_expression!(ColorStyleCol); - #[derive(AsChangeset, Identifiable, Default, Debug)] #[table_name = "app_table"] pub struct AppChangeset { diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/v1_impl.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/v1_impl.rs index 847fc8225a..c301c5a972 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/v1_impl.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/v1_impl.rs @@ -6,6 +6,7 @@ use crate::services::persistence::{ }, FolderPersistenceTransaction, TrashTableSql, }; +use flowy_database::DBConnection; use flowy_error::FlowyResult; use flowy_folder_data_model::entities::{ app::App, @@ -13,7 +14,6 @@ use flowy_folder_data_model::entities::{ view::View, workspace::Workspace, }; -use lib_sqlite::DBConnection; pub struct V1Transaction<'a>(pub &'a DBConnection); diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs index 955bf44818..a41f3c49c2 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs @@ -84,8 +84,8 @@ pub(crate) struct ViewTable { impl ViewTable { pub fn new(view: View) -> Self { let data_type = match view.data_type { - ViewDataType::RichText => SqlViewDataType::RichText, - ViewDataType::PlainText => SqlViewDataType::PlainText, + ViewDataType::TextBlock => SqlViewDataType::Block, + ViewDataType::Grid => SqlViewDataType::Grid, }; ViewTable { @@ -106,8 +106,8 @@ impl ViewTable { impl std::convert::From for View { fn from(table: ViewTable) -> Self { let data_type = match table.view_type { - SqlViewDataType::RichText => ViewDataType::RichText, - SqlViewDataType::PlainText => ViewDataType::PlainText, + SqlViewDataType::Block => ViewDataType::TextBlock, + SqlViewDataType::Grid => ViewDataType::Grid, }; View { @@ -177,24 +177,24 @@ impl ViewChangeset { #[repr(i32)] #[sql_type = "Integer"] pub enum SqlViewDataType { - RichText = 0, - PlainText = 1, + Block = 0, + Grid = 1, } impl std::default::Default for SqlViewDataType { fn default() -> Self { - SqlViewDataType::RichText + SqlViewDataType::Block } } impl std::convert::From for SqlViewDataType { fn from(value: i32) -> Self { match value { - 0 => SqlViewDataType::RichText, - 1 => SqlViewDataType::PlainText, + 0 => SqlViewDataType::Block, + 1 => SqlViewDataType::Grid, o => { - log::error!("Unsupported view type {}, fallback to ViewType::Docs", o); - SqlViewDataType::PlainText + log::error!("Unsupported view type {}, fallback to ViewType::Block", o); + SqlViewDataType::Block } } } diff --git a/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs b/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs index c4b433bc51..cdbabc1320 100644 --- a/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs @@ -274,7 +274,7 @@ impl TrashController { } } -#[tracing::instrument(skip(repeated_trash), fields(n_trash))] +#[tracing::instrument(level = "debug", skip(repeated_trash), fields(n_trash))] fn notify_trash_changed(repeated_trash: RepeatedTrash) { tracing::Span::current().record("n_trash", &repeated_trash.len()); send_anonymous_dart_notification(FolderNotification::TrashUpdated) diff --git a/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs index 1f7257a043..b1853faaf5 100644 --- a/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs @@ -6,7 +6,7 @@ use crate::{ use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::sync::Arc; -#[tracing::instrument(skip(controller), err)] +#[tracing::instrument(level = "debug", skip(controller), err)] pub(crate) async fn read_trash_handler( controller: AppData>, ) -> DataResult { @@ -14,7 +14,7 @@ pub(crate) async fn read_trash_handler( data_result(repeated_trash) } -#[tracing::instrument(skip(identifier, controller), err)] +#[tracing::instrument(level = "debug", skip(identifier, controller), err)] pub(crate) async fn putback_trash_handler( identifier: Data, controller: AppData>, @@ -23,7 +23,7 @@ pub(crate) async fn putback_trash_handler( Ok(()) } -#[tracing::instrument(skip(identifiers, controller), err)] +#[tracing::instrument(level = "debug", skip(identifiers, controller), err)] pub(crate) async fn delete_trash_handler( identifiers: Data, controller: AppData>, @@ -32,13 +32,13 @@ pub(crate) async fn delete_trash_handler( Ok(()) } -#[tracing::instrument(skip(controller), err)] +#[tracing::instrument(level = "debug", skip(controller), err)] pub(crate) async fn restore_all_trash_handler(controller: AppData>) -> Result<(), FlowyError> { let _ = controller.restore_all_trash().await?; Ok(()) } -#[tracing::instrument(skip(controller), err)] +#[tracing::instrument(level = "debug", skip(controller), err)] pub(crate) async fn delete_all_trash_handler(controller: AppData>) -> Result<(), FlowyError> { let _ = controller.delete_all_trash().await?; Ok(()) diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs index 72e29c1b60..c48203b74b 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs @@ -1,13 +1,4 @@ -use bytes::Bytes; -use flowy_collaboration::entities::{ - document_info::{BlockDelta, BlockId}, - revision::{RepeatedRevision, Revision}, -}; - -use flowy_collaboration::client_document::default::initial_delta_string; -use futures::{FutureExt, StreamExt}; -use std::{collections::HashSet, sync::Arc}; - +use crate::manager::{ViewDataProcessor, ViewDataProcessorMap}; use crate::{ dart_notification::{send_dart_notification, FolderNotification}, entities::{ @@ -21,11 +12,12 @@ use crate::{ TrashController, TrashEvent, }, }; -use flowy_block::BlockManager; +use bytes::Bytes; use flowy_database::kv::KV; -use flowy_folder_data_model::entities::share::{ExportData, ExportParams}; - -use lib_infra::uuid_string; +use flowy_folder_data_model::entities::view::{gen_view_id, ViewDataType}; +use flowy_sync::entities::text_block_info::TextBlockId; +use futures::{FutureExt, StreamExt}; +use std::{collections::HashSet, sync::Arc}; const LATEST_VIEW_ID: &str = "latest_view_id"; @@ -34,7 +26,7 @@ pub(crate) struct ViewController { cloud_service: Arc, persistence: Arc, trash_controller: Arc, - block_manager: Arc, + data_processors: ViewDataProcessorMap, } impl ViewController { @@ -42,52 +34,57 @@ impl ViewController { user: Arc, persistence: Arc, cloud_service: Arc, - trash_can: Arc, - document_manager: Arc, + trash_controller: Arc, + data_processors: ViewDataProcessorMap, ) -> Self { Self { user, cloud_service, persistence, - trash_controller: trash_can, - block_manager: document_manager, + trash_controller, + data_processors, } } pub(crate) fn initialize(&self) -> Result<(), FlowyError> { - let _ = self.block_manager.init()?; self.listen_trash_can_event(); Ok(()) } #[tracing::instrument(level = "trace", skip(self, params), fields(name = %params.name), err)] - pub(crate) async fn create_view_from_params(&self, params: CreateViewParams) -> Result { - let view_data = if params.data.is_empty() { - initial_delta_string() + pub(crate) async fn create_view_from_params(&self, mut params: CreateViewParams) -> Result { + let processor = self.get_data_processor(¶ms.data_type)?; + let user_id = self.user.user_id()?; + if params.data.is_empty() { + let view_data = processor.create_default_view(&user_id, ¶ms.view_id).await?; + params.data = view_data.to_vec(); } else { - params.data.clone() + let delta_data = processor + .process_create_view_data(&user_id, ¶ms.view_id, params.data.clone()) + .await?; + let _ = self + .create_view(¶ms.view_id, params.data_type.clone(), delta_data) + .await?; }; - let delta_data = Bytes::from(view_data); - let user_id = self.user.user_id()?; - let repeated_revision: RepeatedRevision = - Revision::initial_revision(&user_id, ¶ms.view_id, delta_data).into(); - let _ = self.create_view(¶ms.view_id, repeated_revision).await?; let view = self.create_view_on_server(params).await?; let _ = self.create_view_on_local(view.clone()).await?; Ok(view) } - #[tracing::instrument(level = "debug", skip(self, view_id, repeated_revision), err)] + #[tracing::instrument(level = "debug", skip(self, view_id, delta_data), err)] pub(crate) async fn create_view( &self, view_id: &str, - repeated_revision: RepeatedRevision, + data_type: ViewDataType, + delta_data: Bytes, ) -> Result<(), FlowyError> { - if repeated_revision.is_empty() { + if delta_data.is_empty() { return Err(FlowyError::internal().context("The content of the view should not be empty")); } - let _ = self.block_manager.create_block(view_id, repeated_revision).await?; + let user_id = self.user.user_id()?; + let processor = self.get_data_processor(&data_type)?; + let _ = processor.create_container(&user_id, view_id, delta_data).await?; Ok(()) } @@ -103,7 +100,7 @@ impl ViewController { .await } - #[tracing::instrument(skip(self, view_id), fields(view_id = %view_id.value), err)] + #[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)] pub(crate) async fn read_view(&self, view_id: ViewId) -> Result { let view = self .persistence @@ -133,30 +130,27 @@ impl ViewController { } #[tracing::instrument(level = "debug", skip(self), err)] - pub(crate) async fn open_view(&self, view_id: &str) -> Result { - let editor = self.block_manager.open_block(view_id).await?; + pub(crate) fn set_latest_view(&self, view_id: &str) -> Result<(), FlowyError> { KV::set_str(LATEST_VIEW_ID, view_id.to_owned()); - let document_json = editor.block_json().await?; - Ok(BlockDelta { - block_id: view_id.to_string(), - delta_json: document_json, - }) + Ok(()) } #[tracing::instrument(level = "debug", skip(self), err)] - pub(crate) async fn close_view(&self, doc_id: &str) -> Result<(), FlowyError> { - let _ = self.block_manager.close_block(doc_id)?; + pub(crate) async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> { + let processor = self.get_data_processor_from_view_id(view_id).await?; + let _ = processor.close_container(view_id).await?; Ok(()) } #[tracing::instrument(level = "debug", skip(self,params), fields(doc_id = %params.value), err)] - pub(crate) async fn delete_view(&self, params: BlockId) -> Result<(), FlowyError> { + pub(crate) async fn delete_view(&self, params: TextBlockId) -> Result<(), FlowyError> { if let Some(view_id) = KV::get_str(LATEST_VIEW_ID) { if view_id == params.value { let _ = KV::remove(LATEST_VIEW_ID); } } - let _ = self.block_manager.close_block(¶ms.value)?; + let processor = self.get_data_processor_from_view_id(¶ms.value).await?; + let _ = processor.delete_container(¶ms.value).await?; Ok(()) } @@ -167,17 +161,16 @@ impl ViewController { .begin_transaction(|transaction| transaction.read_view(view_id)) .await?; - let editor = self.block_manager.open_block(view_id).await?; - let document_json = editor.block_json().await?; + let processor = self.get_data_processor(&view.data_type)?; + let delta_bytes = processor.delta_bytes(view_id).await?; let duplicate_params = CreateViewParams { belong_to_id: view.belong_to_id.clone(), name: format!("{} (copy)", &view.name), desc: view.desc, thumbnail: view.thumbnail, data_type: view.data_type, - data: document_json, - view_id: uuid_string(), - ext_data: view.ext_data, + data: delta_bytes.to_vec(), + view_id: gen_view_id(), plugin_type: view.plugin_type, }; @@ -185,16 +178,6 @@ impl ViewController { Ok(()) } - #[tracing::instrument(level = "debug", skip(self, params), err)] - pub(crate) async fn export_view(&self, params: ExportParams) -> Result { - let editor = self.block_manager.open_block(¶ms.view_id).await?; - let delta_json = editor.block_json().await?; - Ok(ExportData { - data: delta_json, - export_type: params.export_type, - }) - } - // belong_to_id will be the app_id or view_id. #[tracing::instrument(level = "debug", skip(self), err)] pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result { @@ -226,11 +209,6 @@ impl ViewController { Ok(view) } - pub(crate) async fn receive_delta(&self, params: BlockDelta) -> Result { - let doc = self.block_manager.receive_local_delta(params).await?; - Ok(doc) - } - pub(crate) async fn latest_visit_view(&self) -> FlowyResult> { match KV::get_str(LATEST_VIEW_ID) { None => Ok(None), @@ -243,21 +221,17 @@ impl ViewController { } } } - - pub(crate) fn set_latest_view(&self, view: &View) { - KV::set_str(LATEST_VIEW_ID, view.id.clone()); - } } impl ViewController { - #[tracing::instrument(skip(self), err)] + #[tracing::instrument(level = "debug", skip(self), err)] async fn create_view_on_server(&self, params: CreateViewParams) -> Result { let token = self.user.token()?; let view = self.cloud_service.create_view(&token, params).await?; Ok(view) } - #[tracing::instrument(skip(self), err)] + #[tracing::instrument(level = "debug", skip(self), err)] fn update_view_on_server(&self, params: UpdateViewParams) -> Result<(), FlowyError> { let token = self.user.token()?; let server = self.cloud_service.clone(); @@ -273,7 +247,7 @@ impl ViewController { Ok(()) } - #[tracing::instrument(skip(self), err)] + #[tracing::instrument(level = "debug", skip(self), err)] fn read_view_on_server(&self, params: ViewId) -> Result<(), FlowyError> { let token = self.user.token()?; let server = self.cloud_service.clone(); @@ -304,7 +278,7 @@ impl ViewController { fn listen_trash_can_event(&self) { let mut rx = self.trash_controller.subscribe(); let persistence = self.persistence.clone(); - let document_manager = self.block_manager.clone(); + let data_processors = self.data_processors.clone(); let trash_controller = self.trash_controller.clone(); let _ = tokio::spawn(async move { loop { @@ -318,7 +292,7 @@ impl ViewController { if let Some(event) = stream.next().await { handle_trash_event( persistence.clone(), - document_manager.clone(), + data_processors.clone(), trash_controller.clone(), event, ) @@ -327,12 +301,34 @@ impl ViewController { } }); } + + async fn get_data_processor_from_view_id( + &self, + view_id: &str, + ) -> FlowyResult> { + let view = self + .persistence + .begin_transaction(|transaction| transaction.read_view(view_id)) + .await?; + self.get_data_processor(&view.data_type) + } + + #[inline] + fn get_data_processor(&self, data_type: &ViewDataType) -> FlowyResult> { + match self.data_processors.get(data_type) { + None => Err(FlowyError::internal().context(format!( + "Get data processor failed. Unknown view data type: {:?}", + data_type + ))), + Some(processor) => Ok(processor.clone()), + } + } } -#[tracing::instrument(level = "trace", skip(persistence, document_manager, trash_can))] +#[tracing::instrument(level = "trace", skip(persistence, data_processors, trash_can))] async fn handle_trash_event( persistence: Arc, - document_manager: Arc, + data_processors: ViewDataProcessorMap, trash_can: Arc, event: TrashEvent, ) { @@ -364,28 +360,54 @@ async fn handle_trash_event( let _ = ret.send(result).await; } TrashEvent::Delete(identifiers, ret) => { - let result = persistence - .begin_transaction(|transaction| { - let mut notify_ids = HashSet::new(); - for identifier in identifiers.items { - let view = transaction.read_view(&identifier.id)?; - let _ = transaction.delete_view(&identifier.id)?; - let _ = document_manager.delete(&identifier.id)?; - notify_ids.insert(view.belong_to_id); - } + let result = || async { + let views = persistence + .begin_transaction(|transaction| { + let mut notify_ids = HashSet::new(); + let mut views = vec![]; + for identifier in identifiers.items { + let view = transaction.read_view(&identifier.id)?; + let _ = transaction.delete_view(&view.id)?; + notify_ids.insert(view.belong_to_id.clone()); + views.push(view); + } + for notify_id in notify_ids { + let _ = notify_views_changed(¬ify_id, trash_can.clone(), &transaction)?; + } + Ok(views) + }) + .await?; - for notify_id in notify_ids { - let _ = notify_views_changed(¬ify_id, trash_can.clone(), &transaction)?; + for view in views { + match get_data_processor(data_processors.clone(), &view.data_type) { + Ok(processor) => { + let _ = processor.close_container(&view.id).await?; + } + Err(e) => { + tracing::error!("{}", e) + } } - - Ok(()) - }) - .await; - let _ = ret.send(result).await; + } + Ok(()) + }; + let _ = ret.send(result().await).await; } } } +fn get_data_processor( + data_processors: ViewDataProcessorMap, + data_type: &ViewDataType, +) -> FlowyResult> { + match data_processors.get(data_type) { + None => Err(FlowyError::internal().context(format!( + "Get data processor failed. Unknown view data type: {:?}", + data_type + ))), + Some(processor) => Ok(processor.clone()), + } +} + fn read_local_views_with_transaction<'a>( identifiers: RepeatedTrashId, transaction: &'a (dyn FolderPersistenceTransaction + 'a), @@ -402,7 +424,12 @@ fn notify_dart(view: View, notification: FolderNotification) { send_dart_notification(&view.id, notification).payload(view).send(); } -#[tracing::instrument(skip(belong_to_id, trash_controller, transaction), fields(view_count), err)] +#[tracing::instrument( + level = "debug", + skip(belong_to_id, trash_controller, transaction), + fields(view_count), + err +)] fn notify_views_changed<'a>( belong_to_id: &str, trash_controller: Arc, diff --git a/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs index 002a2ac24f..4f692d723d 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs @@ -8,8 +8,6 @@ use crate::{ errors::FlowyError, services::{TrashController, ViewController}, }; -use flowy_collaboration::entities::document_info::BlockDelta; -use flowy_folder_data_model::entities::share::{ExportData, ExportParams, ExportPayload}; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::{convert::TryInto, sync::Arc}; @@ -35,7 +33,7 @@ pub(crate) async fn read_view_handler( data_result(view) } -#[tracing::instrument(skip(data, controller), err)] +#[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn update_view_handler( data: Data, controller: AppData>, @@ -46,14 +44,6 @@ pub(crate) async fn update_view_handler( Ok(()) } -pub(crate) async fn block_delta_handler( - data: Data, - controller: AppData>, -) -> DataResult { - let block_delta = controller.receive_delta(data.into_inner()).await?; - data_result(block_delta) -} - pub(crate) async fn delete_view_handler( data: Data, view_controller: AppData>, @@ -75,13 +65,13 @@ pub(crate) async fn delete_view_handler( Ok(()) } -pub(crate) async fn open_view_handler( +pub(crate) async fn set_latest_view_handler( data: Data, controller: AppData>, -) -> DataResult { +) -> Result<(), FlowyError> { let view_id: ViewId = data.into_inner(); - let doc = controller.open_view(&view_id.value).await?; - data_result(doc) + let _ = controller.set_latest_view(&view_id.value)?; + Ok(()) } pub(crate) async fn close_view_handler( @@ -93,7 +83,7 @@ pub(crate) async fn close_view_handler( Ok(()) } -#[tracing::instrument(skip(data, controller), err)] +#[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn duplicate_view_handler( data: Data, controller: AppData>, @@ -102,13 +92,3 @@ pub(crate) async fn duplicate_view_handler( let _ = controller.duplicate_view(&view_id.value).await?; Ok(()) } - -#[tracing::instrument(skip(data, controller), err)] -pub(crate) async fn export_handler( - data: Data, - controller: AppData>, -) -> DataResult { - let params: ExportParams = data.into_inner().try_into()?; - let data = controller.export_view(params).await?; - data_result(data) -} diff --git a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs index 438b3f52d3..75db905d63 100644 --- a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs +++ b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs @@ -1,19 +1,20 @@ use crate::services::FOLDER_SYNC_INTERVAL_IN_MILLIS; use bytes::Bytes; -use flowy_collaboration::{ +use flowy_error::FlowyError; +use flowy_revision::*; +use flowy_sync::{ client_folder::FolderPad, entities::{ revision::RevisionRange, ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSDataType}, }, }; -use flowy_error::FlowyError; -use flowy_sync::*; use lib_infra::future::{BoxResultFuture, FutureResult}; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; +#[allow(dead_code)] pub(crate) async fn make_folder_ws_manager( user_id: &str, folder_id: &str, @@ -43,7 +44,7 @@ pub(crate) async fn make_folder_ws_manager( } pub(crate) struct FolderWSDataSink(Arc); -impl RevisionWSDataIterator for FolderWSDataSink { +impl RevisionWebSocketSink for FolderWSDataSink { fn next(&self) -> FutureResult, FlowyError> { let sink_provider = self.0.clone(); FutureResult::new(async move { sink_provider.next().await }) diff --git a/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs index 5b464f25e4..d274e42f7f 100644 --- a/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs @@ -1,7 +1,7 @@ use crate::{ - controller::FolderManager, dart_notification::{send_dart_notification, FolderNotification}, errors::FlowyError, + manager::FolderManager, services::{get_current_workspace, read_local_workspace_apps, WorkspaceController}, }; use flowy_folder_data_model::entities::{ @@ -13,7 +13,7 @@ use flowy_folder_data_model::entities::{ use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::{convert::TryInto, sync::Arc}; -#[tracing::instrument(skip(data, controller), err)] +#[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn create_workspace_handler( data: Data, controller: AppData>, @@ -24,7 +24,7 @@ pub(crate) async fn create_workspace_handler( data_result(detail) } -#[tracing::instrument(skip(controller), err)] +#[tracing::instrument(level = "debug", skip(controller), err)] pub(crate) async fn read_workspace_apps_handler( controller: AppData>, ) -> DataResult { @@ -32,7 +32,7 @@ pub(crate) async fn read_workspace_apps_handler( data_result(repeated_app) } -#[tracing::instrument(skip(data, controller), err)] +#[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn open_workspace_handler( data: Data, controller: AppData>, @@ -42,7 +42,7 @@ pub(crate) async fn open_workspace_handler( data_result(workspaces) } -#[tracing::instrument(skip(data, folder), err)] +#[tracing::instrument(level = "debug", skip(data, folder), err)] pub(crate) async fn read_workspaces_handler( data: Data, folder: AppData>, @@ -69,7 +69,7 @@ pub(crate) async fn read_workspaces_handler( data_result(workspaces) } -#[tracing::instrument(skip(folder), err)] +#[tracing::instrument(level = "debug", skip(folder), err)] pub async fn read_cur_workspace_handler( folder: AppData>, ) -> DataResult { diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs b/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs index 76b0aaf9c6..68a1bcea65 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs @@ -1,6 +1,8 @@ use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest}; -use flowy_collaboration::{client_document::default::initial_delta_string, entities::revision::RevisionState}; + use flowy_folder::entities::workspace::CreateWorkspacePayload; +use flowy_folder_data_model::entities::view::ViewDataType; +use flowy_revision::disk::RevisionState; use flowy_test::{event_builder::*, FlowySDKTest}; #[tokio::test] @@ -135,10 +137,12 @@ async fn app_create_with_view() { CreateView { name: "View A".to_owned(), desc: "View A description".to_owned(), + data_type: ViewDataType::TextBlock, }, CreateView { - name: "View B".to_owned(), - desc: "View B description".to_owned(), + name: "Grid".to_owned(), + desc: "Grid description".to_owned(), + data_type: ViewDataType::Grid, }, ReadApp(app.id), ]) @@ -147,7 +151,7 @@ async fn app_create_with_view() { app = test.app.clone(); assert_eq!(app.belongings.len(), 3); assert_eq!(app.belongings[1].name, "View A"); - assert_eq!(app.belongings[2].name, "View B") + assert_eq!(app.belongings[2].name, "Grid") } #[tokio::test] @@ -168,16 +172,6 @@ async fn view_update() { assert_eq!(test.view.name, new_name); } -#[tokio::test] -async fn open_document_view() { - let mut test = FolderTest::new().await; - assert_eq!(test.document_info, None); - - test.run_scripts(vec![OpenDocument]).await; - let document_info = test.document_info.unwrap(); - assert_eq!(document_info.text, initial_delta_string()); -} - #[tokio::test] #[should_panic] async fn view_delete() { @@ -207,10 +201,12 @@ async fn view_delete_all() { CreateView { name: "View A".to_owned(), desc: "View A description".to_owned(), + data_type: ViewDataType::TextBlock, }, CreateView { - name: "View B".to_owned(), - desc: "View B description".to_owned(), + name: "Grid".to_owned(), + desc: "Grid description".to_owned(), + data_type: ViewDataType::Grid, }, ReadApp(app.id.clone()), ]) @@ -238,6 +234,7 @@ async fn view_delete_all_permanent() { CreateView { name: "View A".to_owned(), desc: "View A description".to_owned(), + data_type: ViewDataType::TextBlock, }, ReadApp(app.id.clone()), ]) @@ -336,6 +333,7 @@ async fn folder_sync_revision_with_new_view() { CreateView { name: view_name.clone(), desc: view_desc.clone(), + data_type: ViewDataType::TextBlock, }, AssertCurrentRevId(3), AssertNextSyncRevId(Some(3)), diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/helper.rs b/frontend/rust-lib/flowy-folder/tests/workspace/helper.rs deleted file mode 100644 index 7d823749df..0000000000 --- a/frontend/rust-lib/flowy-folder/tests/workspace/helper.rs +++ /dev/null @@ -1,211 +0,0 @@ -use flowy_collaboration::entities::document_info::BlockInfo; -use flowy_folder::event_map::FolderEvent::*; -use flowy_folder_data_model::entities::view::{RepeatedViewId, ViewId}; -use flowy_folder_data_model::entities::workspace::WorkspaceId; -use flowy_folder_data_model::entities::{ - app::{App, AppId, CreateAppPayload, UpdateAppPayload}, - trash::{RepeatedTrash, TrashId, TrashType}, - view::{CreateViewPayload, UpdateViewPayload, View, ViewDataType}, - workspace::{CreateWorkspacePayload, RepeatedWorkspace, Workspace}, -}; -use flowy_test::{event_builder::*, FlowySDKTest}; - -pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Workspace { - let request = CreateWorkspacePayload { - name: name.to_owned(), - desc: desc.to_owned(), - }; - - let workspace = FolderEventBuilder::new(sdk.clone()) - .event(CreateWorkspace) - .payload(request) - .async_send() - .await - .parse::(); - workspace -} - -pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> Vec { - let request = WorkspaceId { value: workspace_id }; - let repeated_workspace = FolderEventBuilder::new(sdk.clone()) - .event(ReadWorkspaces) - .payload(request.clone()) - .async_send() - .await - .parse::(); - - let workspaces; - if let Some(workspace_id) = &request.value { - workspaces = repeated_workspace - .into_inner() - .into_iter() - .filter(|workspace| &workspace.id == workspace_id) - .collect::>(); - debug_assert_eq!(workspaces.len(), 1); - } else { - workspaces = repeated_workspace.items; - } - - workspaces -} - -pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc: &str) -> App { - let create_app_request = CreateAppPayload { - workspace_id: workspace_id.to_owned(), - name: name.to_string(), - desc: desc.to_string(), - color_style: Default::default(), - }; - - let app = FolderEventBuilder::new(sdk.clone()) - .event(CreateApp) - .payload(create_app_request) - .async_send() - .await - .parse::(); - app -} - -pub async fn read_app(sdk: &FlowySDKTest, app_id: &str) -> App { - let request = AppId { - value: app_id.to_owned(), - }; - - let app = FolderEventBuilder::new(sdk.clone()) - .event(ReadApp) - .payload(request) - .async_send() - .await - .parse::(); - - app -} - -pub async fn update_app(sdk: &FlowySDKTest, app_id: &str, name: Option, desc: Option) { - let request = UpdateAppPayload { - app_id: app_id.to_string(), - name, - desc, - color_style: None, - is_trash: None, - }; - - FolderEventBuilder::new(sdk.clone()) - .event(UpdateApp) - .payload(request) - .async_send() - .await; -} - -pub async fn delete_app(sdk: &FlowySDKTest, app_id: &str) { - let request = AppId { - value: app_id.to_string(), - }; - - FolderEventBuilder::new(sdk.clone()) - .event(DeleteApp) - .payload(request) - .async_send() - .await; -} - -pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &str, data_type: ViewDataType) -> View { - let request = CreateViewPayload { - belong_to_id: app_id.to_string(), - name: name.to_string(), - desc: desc.to_string(), - thumbnail: None, - data_type, - ext_data: "".to_string(), - plugin_type: 0, - }; - let view = FolderEventBuilder::new(sdk.clone()) - .event(CreateView) - .payload(request) - .async_send() - .await - .parse::(); - view -} - -pub async fn read_view(sdk: &FlowySDKTest, view_id: &str) -> View { - let view_id: ViewId = view_id.into(); - FolderEventBuilder::new(sdk.clone()) - .event(ReadView) - .payload(view_id) - .async_send() - .await - .parse::() -} - -pub async fn update_view(sdk: &FlowySDKTest, view_id: &str, name: Option, desc: Option) { - let request = UpdateViewPayload { - view_id: view_id.to_string(), - name, - desc, - thumbnail: None, - }; - FolderEventBuilder::new(sdk.clone()) - .event(UpdateView) - .payload(request) - .async_send() - .await; -} - -pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { - let request = RepeatedViewId { items: view_ids }; - FolderEventBuilder::new(sdk.clone()) - .event(DeleteView) - .payload(request) - .async_send() - .await; -} - -pub async fn open_document(sdk: &FlowySDKTest, view_id: &str) -> BlockInfo { - let view_id: ViewId = view_id.into(); - FolderEventBuilder::new(sdk.clone()) - .event(OpenView) - .payload(view_id) - .async_send() - .await - .parse::() -} - -pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrash { - FolderEventBuilder::new(sdk.clone()) - .event(ReadTrash) - .async_send() - .await - .parse::() -} - -pub async fn restore_app_from_trash(sdk: &FlowySDKTest, app_id: &str) { - let id = TrashId { - id: app_id.to_owned(), - ty: TrashType::TrashApp, - }; - FolderEventBuilder::new(sdk.clone()) - .event(PutbackTrash) - .payload(id) - .async_send() - .await; -} - -pub async fn restore_view_from_trash(sdk: &FlowySDKTest, view_id: &str) { - let id = TrashId { - id: view_id.to_owned(), - ty: TrashType::TrashView, - }; - FolderEventBuilder::new(sdk.clone()) - .event(PutbackTrash) - .payload(id) - .async_send() - .await; -} - -pub async fn delete_all_trash(sdk: &FlowySDKTest) { - FolderEventBuilder::new(sdk.clone()) - .event(DeleteAllTrash) - .async_send() - .await; -} diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/main.rs b/frontend/rust-lib/flowy-folder/tests/workspace/main.rs index 553449ee4b..ff48b349e1 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/main.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/main.rs @@ -1,3 +1,2 @@ mod folder_test; -mod helper; mod script; diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs index d4f0fe0fd8..a6fd1fbe29 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs @@ -1,38 +1,63 @@ -use crate::helper::*; -use flowy_collaboration::entities::{document_info::BlockInfo, revision::RevisionState}; +use flowy_folder::event_map::FolderEvent::*; use flowy_folder::{errors::ErrorCode, services::folder_editor::ClientFolderEditor}; +use flowy_folder_data_model::entities::view::{RepeatedViewId, ViewId}; +use flowy_folder_data_model::entities::workspace::WorkspaceId; use flowy_folder_data_model::entities::{ app::{App, RepeatedApp}, trash::Trash, view::{RepeatedView, View, ViewDataType}, workspace::Workspace, }; -use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_test::FlowySDKTest; +use flowy_folder_data_model::entities::{ + app::{AppId, CreateAppPayload, UpdateAppPayload}, + trash::{RepeatedTrash, TrashId, TrashType}, + view::{CreateViewPayload, UpdateViewPayload}, + workspace::{CreateWorkspacePayload, RepeatedWorkspace}, +}; +use flowy_revision::disk::RevisionState; +use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; +use flowy_sync::entities::text_block_info::TextBlockInfo; +use flowy_test::{event_builder::*, FlowySDKTest}; use std::{sync::Arc, time::Duration}; use tokio::time::sleep; pub enum FolderScript { // Workspace ReadAllWorkspaces, - CreateWorkspace { name: String, desc: String }, + CreateWorkspace { + name: String, + desc: String, + }, AssertWorkspaceJson(String), AssertWorkspace(Workspace), ReadWorkspace(Option), // App - CreateApp { name: String, desc: String }, + CreateApp { + name: String, + desc: String, + }, AssertAppJson(String), AssertApp(App), ReadApp(String), - UpdateApp { name: Option, desc: Option }, + UpdateApp { + name: Option, + desc: Option, + }, DeleteApp, // View - CreateView { name: String, desc: String }, + CreateView { + name: String, + desc: String, + data_type: ViewDataType, + }, AssertView(View), ReadView(String), - UpdateView { name: Option, desc: Option }, + UpdateView { + name: Option, + desc: Option, + }, DeleteView, DeleteViews(Vec), @@ -42,13 +67,13 @@ pub enum FolderScript { ReadTrash, DeleteAllTrash, - // Document - OpenDocument, - // Sync AssertCurrentRevId(i64), AssertNextSyncRevId(Option), - AssertRevisionState { rev_id: i64, state: RevisionState }, + AssertRevisionState { + rev_id: i64, + state: RevisionState, + }, } pub struct FolderTest { @@ -58,7 +83,6 @@ pub struct FolderTest { pub app: App, pub view: View, pub trash: Vec, - pub document_info: Option, // pub folder_editor: } @@ -68,7 +92,14 @@ impl FolderTest { let _ = sdk.init_user().await; let mut workspace = create_workspace(&sdk, "FolderWorkspace", "Folder test workspace").await; let mut app = create_app(&sdk, &workspace.id, "Folder App", "Folder test app").await; - let view = create_view(&sdk, &app.id, "Folder View", "Folder test view", ViewDataType::RichText).await; + let view = create_view( + &sdk, + &app.id, + "Folder View", + "Folder test view", + ViewDataType::TextBlock, + ) + .await; app.belongings = RepeatedView { items: vec![view.clone()], }; @@ -83,7 +114,6 @@ impl FolderTest { app, view, trash: vec![], - document_info: None, } } @@ -145,8 +175,8 @@ impl FolderTest { delete_app(sdk, &self.app.id).await; } - FolderScript::CreateView { name, desc } => { - let view = create_view(sdk, &self.app.id, &name, &desc, ViewDataType::RichText).await; + FolderScript::CreateView { name, desc, data_type } => { + let view = create_view(sdk, &self.app.id, &name, &desc, data_type).await; self.view = view; } FolderScript::AssertView(view) => { @@ -179,10 +209,6 @@ impl FolderTest { delete_all_trash(sdk).await; self.trash = vec![]; } - FolderScript::OpenDocument => { - let document_info = open_document(sdk, &self.view.id).await; - self.document_info = Some(document_info); - } FolderScript::AssertRevisionState { rev_id, state } => { let record = cache.get(rev_id).await.unwrap(); assert_eq!(record.state, state); @@ -217,3 +243,204 @@ pub fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> { ("1234".repeat(100), ErrorCode::WorkspaceNameTooLong), ] } + +pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Workspace { + let request = CreateWorkspacePayload { + name: name.to_owned(), + desc: desc.to_owned(), + }; + + let workspace = FolderEventBuilder::new(sdk.clone()) + .event(CreateWorkspace) + .payload(request) + .async_send() + .await + .parse::(); + workspace +} + +pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> Vec { + let request = WorkspaceId { value: workspace_id }; + let repeated_workspace = FolderEventBuilder::new(sdk.clone()) + .event(ReadWorkspaces) + .payload(request.clone()) + .async_send() + .await + .parse::(); + + let workspaces; + if let Some(workspace_id) = &request.value { + workspaces = repeated_workspace + .into_inner() + .into_iter() + .filter(|workspace| &workspace.id == workspace_id) + .collect::>(); + debug_assert_eq!(workspaces.len(), 1); + } else { + workspaces = repeated_workspace.items; + } + + workspaces +} + +pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc: &str) -> App { + let create_app_request = CreateAppPayload { + workspace_id: workspace_id.to_owned(), + name: name.to_string(), + desc: desc.to_string(), + color_style: Default::default(), + }; + + let app = FolderEventBuilder::new(sdk.clone()) + .event(CreateApp) + .payload(create_app_request) + .async_send() + .await + .parse::(); + app +} + +pub async fn read_app(sdk: &FlowySDKTest, app_id: &str) -> App { + let request = AppId { + value: app_id.to_owned(), + }; + + let app = FolderEventBuilder::new(sdk.clone()) + .event(ReadApp) + .payload(request) + .async_send() + .await + .parse::(); + + app +} + +pub async fn update_app(sdk: &FlowySDKTest, app_id: &str, name: Option, desc: Option) { + let request = UpdateAppPayload { + app_id: app_id.to_string(), + name, + desc, + color_style: None, + is_trash: None, + }; + + FolderEventBuilder::new(sdk.clone()) + .event(UpdateApp) + .payload(request) + .async_send() + .await; +} + +pub async fn delete_app(sdk: &FlowySDKTest, app_id: &str) { + let request = AppId { + value: app_id.to_string(), + }; + + FolderEventBuilder::new(sdk.clone()) + .event(DeleteApp) + .payload(request) + .async_send() + .await; +} + +pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &str, data_type: ViewDataType) -> View { + let request = CreateViewPayload { + belong_to_id: app_id.to_string(), + name: name.to_string(), + desc: desc.to_string(), + thumbnail: None, + data_type, + plugin_type: 0, + data: vec![], + }; + let view = FolderEventBuilder::new(sdk.clone()) + .event(CreateView) + .payload(request) + .async_send() + .await + .parse::(); + view +} + +pub async fn read_view(sdk: &FlowySDKTest, view_id: &str) -> View { + let view_id: ViewId = view_id.into(); + FolderEventBuilder::new(sdk.clone()) + .event(ReadView) + .payload(view_id) + .async_send() + .await + .parse::() +} + +pub async fn update_view(sdk: &FlowySDKTest, view_id: &str, name: Option, desc: Option) { + let request = UpdateViewPayload { + view_id: view_id.to_string(), + name, + desc, + thumbnail: None, + }; + FolderEventBuilder::new(sdk.clone()) + .event(UpdateView) + .payload(request) + .async_send() + .await; +} + +pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { + let request = RepeatedViewId { items: view_ids }; + FolderEventBuilder::new(sdk.clone()) + .event(DeleteView) + .payload(request) + .async_send() + .await; +} + +#[allow(dead_code)] +pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfo { + let view_id: ViewId = view_id.into(); + FolderEventBuilder::new(sdk.clone()) + .event(SetLatestView) + .payload(view_id) + .async_send() + .await + .parse::() +} + +pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrash { + FolderEventBuilder::new(sdk.clone()) + .event(ReadTrash) + .async_send() + .await + .parse::() +} + +pub async fn restore_app_from_trash(sdk: &FlowySDKTest, app_id: &str) { + let id = TrashId { + id: app_id.to_owned(), + ty: TrashType::TrashApp, + }; + FolderEventBuilder::new(sdk.clone()) + .event(PutbackTrash) + .payload(id) + .async_send() + .await; +} + +pub async fn restore_view_from_trash(sdk: &FlowySDKTest, view_id: &str) { + let id = TrashId { + id: view_id.to_owned(), + ty: TrashType::TrashView, + }; + FolderEventBuilder::new(sdk.clone()) + .event(PutbackTrash) + .payload(id) + .async_send() + .await; +} + +pub async fn delete_all_trash(sdk: &FlowySDKTest) { + FolderEventBuilder::new(sdk.clone()) + .event(DeleteAllTrash) + .async_send() + .await; +} diff --git a/frontend/rust-lib/flowy-grid/Cargo.toml b/frontend/rust-lib/flowy-grid/Cargo.toml new file mode 100644 index 0000000000..db94bebe2f --- /dev/null +++ b/frontend/rust-lib/flowy-grid/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "flowy-grid" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lib-dispatch = { path = "../lib-dispatch" } +dart-notify = { path = "../dart-notify" } +flowy-revision = { path = "../flowy-revision" } +flowy-error = { path = "../flowy-error", features = ["db"]} +flowy-derive = { path = "../../../shared-lib/flowy-derive" } +lib-ot = { path = "../../../shared-lib/lib-ot" } +lib-infra = { path = "../../../shared-lib/lib-infra" } +flowy-grid-data-model = { path = "../../../shared-lib/flowy-grid-data-model" } +flowy-sync = { path = "../../../shared-lib/flowy-sync" } +flowy-database = { path = "../flowy-database" } + +strum = "0.21" +strum_macros = "0.21" +tracing = { version = "0.1", features = ["log"] } +protobuf = {version = "2.18.0"} +rust_decimal = "1.8.1" +rusty-money = {version = "0.4.0", features = ["iso"]} +lazy_static = "1.4.0" +chrono = "0.4.19" +nanoid = "0.4.0" +bytes = { version = "1.0" } +diesel = {version = "1.4.8", features = ["sqlite"]} +dashmap = "4.0" +tokio = {version = "1", features = ["sync"]} +rayon = "1.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = {version = "1.0"} +serde_repr = "0.1" +indexmap = {version = "1.8.1", features = ["serde"]} + +[dev-dependencies] +flowy-test = { path = "../flowy-test" } +flowy-grid = { path = "../flowy-grid", features = ["flowy_unit_test"]} + +[build-dependencies] +lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file_gen", "proto_gen"] } + + +[features] +default = [] +dart = ["lib-infra/dart"] +flowy_unit_test = ["flowy-revision/flowy_unit_test"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-grid/Flowy.toml b/frontend/rust-lib/flowy-grid/Flowy.toml new file mode 100644 index 0000000000..1d0d2baea8 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/Flowy.toml @@ -0,0 +1,8 @@ + +proto_crates = [ + "src/event_map.rs", + "src/services/field/type_options", + "src/services/entities", + "src/dart_notification.rs" +] +event_files = ["src/event_map.rs"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-grid/build.rs b/frontend/rust-lib/flowy-grid/build.rs new file mode 100644 index 0000000000..4d4d3b13da --- /dev/null +++ b/frontend/rust-lib/flowy-grid/build.rs @@ -0,0 +1,9 @@ +use lib_infra::code_gen; + +fn main() { + let crate_name = env!("CARGO_PKG_NAME"); + code_gen::protobuf_file::gen(crate_name, "./src/protobuf/proto"); + + #[cfg(feature = "dart")] + code_gen::dart_event::gen(crate_name); +} diff --git a/frontend/rust-lib/flowy-grid/src/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/dart_notification.rs new file mode 100644 index 0000000000..92749da519 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/dart_notification.rs @@ -0,0 +1,36 @@ +use dart_notify::DartNotifyBuilder; +use flowy_derive::ProtoBuf_Enum; +const OBSERVABLE_CATEGORY: &str = "Grid"; + +#[derive(ProtoBuf_Enum, Debug)] +pub enum GridNotification { + Unknown = 0, + DidCreateBlock = 11, + DidUpdateGridRow = 20, + DidUpdateGridField = 21, + DidUpdateRow = 30, + DidUpdateCell = 40, + DidUpdateField = 50, +} + +impl std::default::Default for GridNotification { + fn default() -> Self { + GridNotification::Unknown + } +} + +impl std::convert::From for i32 { + fn from(notification: GridNotification) -> Self { + notification as i32 + } +} + +#[tracing::instrument(level = "trace")] +pub fn send_dart_notification(id: &str, ty: GridNotification) -> DartNotifyBuilder { + DartNotifyBuilder::new(id, ty, OBSERVABLE_CATEGORY) +} + +#[tracing::instrument(level = "trace")] +pub fn send_anonymous_dart_notification(ty: GridNotification) -> DartNotifyBuilder { + DartNotifyBuilder::new("", ty, OBSERVABLE_CATEGORY) +} diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs new file mode 100644 index 0000000000..2ef933f039 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -0,0 +1,348 @@ +use crate::manager::GridManager; +use crate::services::entities::*; +use crate::services::field::type_options::*; +use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str}; +use crate::services::grid_editor::ClientGridEditor; +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_grid_data_model::entities::*; +use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; +use std::sync::Arc; + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_grid_data_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let grid_id: GridId = data.into_inner(); + let editor = manager.open_grid(grid_id).await?; + let grid = editor.grid_data().await?; + data_result(grid) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_grid_blocks_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: QueryGridBlocksParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let block_ids = params + .block_orders + .into_iter() + .map(|block| block.block_id) + .collect::>(); + let repeated_grid_block = editor.get_blocks(Some(block_ids)).await?; + data_result(repeated_grid_block) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_fields_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: QueryFieldParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let field_orders = params.field_orders.items; + let field_metas = editor.get_field_metas(Some(field_orders)).await?; + let repeated_field: RepeatedField = field_metas.into_iter().map(Field::from).collect::>().into(); + data_result(repeated_field) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn update_field_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let changeset: FieldChangesetParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(&changeset.grid_id)?; + let _ = editor.update_field(changeset).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn insert_field_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: InsertFieldParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.insert_field(params).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn delete_field_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: FieldIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.delete_field(¶ms.field_id).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn switch_to_field_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: EditFieldParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + editor + .switch_to_field_type(¶ms.field_id, ¶ms.field_type) + .await?; + + let field_meta = editor.get_field_meta(¶ms.field_id).await; + let edit_context = make_field_edit_context( + ¶ms.grid_id, + Some(params.field_id), + params.field_type, + editor, + field_meta, + ) + .await?; + data_result(edit_context) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn duplicate_field_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: FieldIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.duplicate_field(¶ms.field_id).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_field_context_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params = data.into_inner(); + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let edit_context = + make_field_edit_context(¶ms.grid_id, params.field_id, params.field_type, editor, None).await?; + + data_result(edit_context) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn move_item_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: MoveItemParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.move_item(params).await?; + Ok(()) +} + +async fn make_field_edit_context( + grid_id: &str, + field_id: Option, + field_type: FieldType, + editor: Arc, + field_meta: Option, +) -> FlowyResult { + let field_meta = field_meta.unwrap_or(get_or_create_field_meta(field_id, &field_type, editor).await?); + let s = field_meta + .get_type_option_str(None) + .unwrap_or_else(|| default_type_option_builder_from_type(&field_type).entry().json_str()); + + let builder = type_option_builder_from_json_str(&s, &field_meta.field_type); + let type_option_data = builder.entry().protobuf_bytes().to_vec(); + let field: Field = field_meta.into(); + Ok(EditFieldContext { + grid_id: grid_id.to_string(), + grid_field: field, + type_option_data, + }) +} + +async fn get_or_create_field_meta( + field_id: Option, + field_type: &FieldType, + editor: Arc, +) -> FlowyResult { + match field_id { + None => editor.create_next_field_meta(field_type).await, + Some(field_id) => match editor.get_field_meta(&field_id).await { + None => editor.create_next_field_meta(field_type).await, + Some(field_meta) => Ok(field_meta), + }, + } +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_row_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: RowIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + match editor.get_row(¶ms.row_id).await? { + None => Err(FlowyError::record_not_found().context("Can not find the row")), + Some(row) => data_result(row), + } +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn delete_row_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: RowIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.delete_row(¶ms.row_id).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn duplicate_row_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: RowIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.duplicate_row(¶ms.row_id).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn create_row_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: CreateRowParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(params.grid_id.as_ref())?; + let _ = editor.create_row(params.start_row_id).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn get_cell_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: CellIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + match editor.get_cell(¶ms).await { + None => data_result(Cell::new(¶ms.field_id, "".to_owned())), + Some(cell) => data_result(cell), + } +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn update_cell_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let changeset: CellChangeset = data.into_inner(); + let editor = manager.get_grid_editor(&changeset.grid_id)?; + let _ = editor.update_cell(changeset).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn new_select_option_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: CreateSelectOptionParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + match editor.get_field_meta(¶ms.field_id).await { + None => Err(ErrorCode::InvalidData.into()), + Some(field_meta) => { + let type_option = select_option_operation(&field_meta)?; + let select_option = type_option.create_option(¶ms.option_name); + data_result(select_option) + } + } +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn update_select_option_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let changeset: SelectOptionChangeset = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(&changeset.cell_identifier.grid_id)?; + + if let Some(mut field_meta) = editor.get_field_meta(&changeset.cell_identifier.field_id).await { + let mut type_option = select_option_operation(&field_meta)?; + let mut cell_data = None; + + if let Some(option) = changeset.insert_option { + cell_data = Some(SelectOptionCellChangeset::from_insert(&option.id).cell_data()); + type_option.insert_option(option); + } + + if let Some(option) = changeset.update_option { + type_option.insert_option(option); + } + + if let Some(option) = changeset.delete_option { + cell_data = Some(SelectOptionCellChangeset::from_delete(&option.id).cell_data()); + type_option.delete_option(option); + } + + field_meta.insert_type_option_entry(&*type_option); + let _ = editor.replace_field(field_meta).await?; + + let changeset = CellChangeset { + grid_id: changeset.cell_identifier.grid_id, + row_id: changeset.cell_identifier.row_id, + field_id: changeset.cell_identifier.field_id, + data: cell_data, + }; + let _ = editor.update_cell(changeset).await?; + } + Ok(()) +} +// +// #[tracing::instrument(level = "debug", skip_all, err)] +// pub(crate) async fn update_date_option_handler( +// data: Data, +// manager: AppData>, +// ) -> Result<(), FlowyError> { +// let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?; +// let editor = manager.get_grid_editor(¶ms.grid_id)?; +// let changeset: CellChangeset = params.into(); +// let _ = editor.update_cell(changeset).await?; +// Ok(()) +// } + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_select_option_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: CellIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + match editor.get_field_meta(¶ms.field_id).await { + None => { + tracing::error!("Can't find the corresponding field with id: {}", params.field_id); + data_result(SelectOptionContext::default()) + } + Some(field_meta) => { + let cell_meta = editor.get_cell_meta(¶ms.row_id, ¶ms.field_id).await?; + let type_option = select_option_operation(&field_meta)?; + let option_context = type_option.option_context(&cell_meta); + data_result(option_context) + } + } +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn update_cell_select_option_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let changeset: CellChangeset = params.into(); + let _ = editor.update_cell(changeset).await?; + Ok(()) +} diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs new file mode 100644 index 0000000000..46513a43c9 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -0,0 +1,101 @@ +use crate::event_handler::*; +use crate::manager::GridManager; +use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; +use lib_dispatch::prelude::*; +use std::sync::Arc; +use strum_macros::Display; + +pub fn create(grid_manager: Arc) -> Module { + let mut module = Module::new().name(env!("CARGO_PKG_NAME")).data(grid_manager); + module = module + .event(GridEvent::GetGridData, get_grid_data_handler) + .event(GridEvent::GetGridBlocks, get_grid_blocks_handler) + // Field + .event(GridEvent::GetFields, get_fields_handler) + .event(GridEvent::UpdateField, update_field_handler) + .event(GridEvent::InsertField, insert_field_handler) + .event(GridEvent::DeleteField, delete_field_handler) + .event(GridEvent::SwitchToField, switch_to_field_handler) + .event(GridEvent::DuplicateField, duplicate_field_handler) + .event(GridEvent::GetEditFieldContext, get_field_context_handler) + .event(GridEvent::MoveItem, move_item_handler) + // Row + .event(GridEvent::CreateRow, create_row_handler) + .event(GridEvent::GetRow, get_row_handler) + .event(GridEvent::DeleteRow, delete_row_handler) + .event(GridEvent::DuplicateRow, duplicate_row_handler) + // Cell + .event(GridEvent::GetCell, get_cell_handler) + .event(GridEvent::UpdateCell, update_cell_handler) + // SelectOption + .event(GridEvent::NewSelectOption, new_select_option_handler) + .event(GridEvent::UpdateSelectOption, update_select_option_handler) + .event(GridEvent::GetSelectOptionContext, get_select_option_handler) + .event(GridEvent::UpdateCellSelectOption, update_cell_select_option_handler); + + module +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] +#[event_err = "FlowyError"] +pub enum GridEvent { + #[event(input = "GridId", output = "Grid")] + GetGridData = 0, + + #[event(input = "QueryGridBlocksPayload", output = "RepeatedGridBlock")] + GetGridBlocks = 1, + + #[event(input = "QueryFieldPayload", output = "RepeatedField")] + GetFields = 10, + + #[event(input = "FieldChangesetPayload")] + UpdateField = 11, + + #[event(input = "InsertFieldPayload")] + InsertField = 12, + + #[event(input = "FieldIdentifierPayload")] + DeleteField = 13, + + #[event(input = "EditFieldPayload", output = "EditFieldContext")] + SwitchToField = 14, + + #[event(input = "FieldIdentifierPayload")] + DuplicateField = 15, + + #[event(input = "GetEditFieldContextPayload", output = "EditFieldContext")] + GetEditFieldContext = 16, + + #[event(input = "MoveItemPayload")] + MoveItem = 17, + + #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] + NewSelectOption = 30, + + #[event(input = "CellIdentifierPayload", output = "SelectOptionContext")] + GetSelectOptionContext = 31, + + #[event(input = "SelectOptionChangesetPayload")] + UpdateSelectOption = 32, + + #[event(input = "CreateRowPayload", output = "Row")] + CreateRow = 50, + + #[event(input = "RowIdentifierPayload", output = "Row")] + GetRow = 51, + + #[event(input = "RowIdentifierPayload")] + DeleteRow = 52, + + #[event(input = "RowIdentifierPayload")] + DuplicateRow = 53, + + #[event(input = "CellIdentifierPayload", output = "Cell")] + GetCell = 70, + + #[event(input = "CellChangeset")] + UpdateCell = 71, + + #[event(input = "SelectOptionCellChangesetPayload")] + UpdateCellSelectOption = 72, +} diff --git a/frontend/rust-lib/flowy-grid/src/lib.rs b/frontend/rust-lib/flowy-grid/src/lib.rs new file mode 100644 index 0000000000..a3ac3411e2 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/lib.rs @@ -0,0 +1,11 @@ +#[macro_use] +mod macros; + +mod event_handler; +pub mod event_map; +pub mod manager; + +mod dart_notification; +mod protobuf; +pub mod services; +pub mod util; diff --git a/frontend/rust-lib/flowy-grid/src/macros.rs b/frontend/rust-lib/flowy-grid/src/macros.rs new file mode 100644 index 0000000000..79e0e106eb --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/macros.rs @@ -0,0 +1,82 @@ +#[macro_export] +macro_rules! impl_into_box_type_option_builder { + ($target: ident) => { + impl std::convert::From<$target> for BoxTypeOptionBuilder { + fn from(target: $target) -> BoxTypeOptionBuilder { + Box::new(target) + } + } + }; +} + +macro_rules! impl_builder_from_json_str_and_from_bytes { + ($target: ident,$type_option: ident) => { + impl $target { + pub fn from_protobuf_bytes(bytes: Bytes) -> $target { + let type_option = $type_option::from_protobuf_bytes(bytes); + $target(type_option) + } + + pub fn from_json_str(s: &str) -> $target { + let type_option = $type_option::from_json_str(s); + $target(type_option) + } + } + }; +} + +#[macro_export] +macro_rules! impl_type_option { + ($target: ident, $field_type:expr) => { + impl std::convert::From<&FieldMeta> for $target { + fn from(field_meta: &FieldMeta) -> $target { + match field_meta.get_type_option_entry::<$target>(&$field_type) { + None => $target::default(), + Some(target) => target, + } + } + } + + impl std::convert::From<$target> for String { + fn from(type_option: $target) -> String { + type_option.json_str() + } + } + + impl TypeOptionDataEntry for $target { + fn field_type(&self) -> FieldType { + $field_type + } + + fn json_str(&self) -> String { + match serde_json::to_string(&self) { + Ok(s) => s, + Err(e) => { + tracing::error!("Field type data serialize to json fail, error: {:?}", e); + serde_json::to_string(&$target::default()).unwrap() + } + } + } + + fn protobuf_bytes(&self) -> Bytes { + self.clone().try_into().unwrap() + } + } + + impl TypeOptionDataDeserializer for $target { + fn from_json_str(s: &str) -> $target { + match serde_json::from_str(s) { + Ok(obj) => obj, + Err(err) => { + tracing::error!("{} convert from any data failed, {:?}", stringify!($target), err); + $target::default() + } + } + } + + fn from_protobuf_bytes(bytes: Bytes) -> $target { + $target::try_from(bytes).unwrap_or($target::default()) + } + } + }; +} diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs new file mode 100644 index 0000000000..218dff8782 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -0,0 +1,210 @@ +use crate::services::grid_editor::ClientGridEditor; +use crate::services::persistence::block_index::BlockIndexPersistence; +use crate::services::persistence::kv::GridKVPersistence; +use crate::services::persistence::GridDatabase; +use bytes::Bytes; +use dashmap::DashMap; +use flowy_database::ConnectionPool; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_grid_data_model::entities::{BuildGridContext, GridMeta}; +use flowy_revision::disk::{SQLiteGridBlockMetaRevisionPersistence, SQLiteGridRevisionPersistence}; +use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_sync::client_grid::{make_block_meta_delta, make_grid_delta}; +use flowy_sync::entities::revision::{RepeatedRevision, Revision}; +use std::sync::Arc; + +pub trait GridUser: Send + Sync { + fn user_id(&self) -> Result; + fn token(&self) -> Result; + fn db_pool(&self) -> Result, FlowyError>; +} + +pub struct GridManager { + editor_map: Arc, + grid_user: Arc, + block_index_persistence: Arc, + #[allow(dead_code)] + kv_persistence: Arc, +} + +impl GridManager { + pub fn new( + grid_user: Arc, + _rev_web_socket: Arc, + database: Arc, + ) -> Self { + let grid_editors = Arc::new(GridEditorMap::new()); + let kv_persistence = Arc::new(GridKVPersistence::new(database.clone())); + let block_index_persistence = Arc::new(BlockIndexPersistence::new(database)); + Self { + editor_map: grid_editors, + grid_user, + kv_persistence, + block_index_persistence, + } + } + + #[tracing::instrument(level = "debug", skip_all, err)] + pub async fn create_grid>(&self, grid_id: T, revisions: RepeatedRevision) -> FlowyResult<()> { + let grid_id = grid_id.as_ref(); + let db_pool = self.grid_user.db_pool()?; + let rev_manager = self.make_grid_rev_manager(grid_id, db_pool)?; + let _ = rev_manager.reset_object(revisions).await?; + Ok(()) + } + + #[tracing::instrument(level = "debug", skip_all, err)] + pub async fn create_grid_block_meta>( + &self, + block_id: T, + revisions: RepeatedRevision, + ) -> FlowyResult<()> { + let block_id = block_id.as_ref(); + let db_pool = self.grid_user.db_pool()?; + let rev_manager = self.make_grid_block_meta_rev_manager(block_id, db_pool)?; + let _ = rev_manager.reset_object(revisions).await?; + Ok(()) + } + + #[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)] + pub async fn open_grid>(&self, grid_id: T) -> FlowyResult> { + let grid_id = grid_id.as_ref(); + tracing::Span::current().record("grid_id", &grid_id); + self.get_or_create_grid_editor(grid_id).await + } + + #[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)] + pub fn close_grid>(&self, grid_id: T) -> FlowyResult<()> { + let grid_id = grid_id.as_ref(); + tracing::Span::current().record("grid_id", &grid_id); + self.editor_map.remove(grid_id); + Ok(()) + } + + #[tracing::instrument(level = "debug", skip(self, grid_id), fields(doc_id), err)] + pub fn delete_grid>(&self, grid_id: T) -> FlowyResult<()> { + let grid_id = grid_id.as_ref(); + tracing::Span::current().record("grid_id", &grid_id); + self.editor_map.remove(grid_id); + Ok(()) + } + + // #[tracing::instrument(level = "debug", skip(self), err)] + pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult> { + match self.editor_map.get(grid_id) { + None => Err(FlowyError::internal().context("Should call open_grid function first")), + Some(editor) => Ok(editor), + } + } + + async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult> { + match self.editor_map.get(grid_id) { + None => { + tracing::trace!("Create grid editor with id: {}", grid_id); + let db_pool = self.grid_user.db_pool()?; + let editor = self.make_grid_editor(grid_id, db_pool).await?; + self.editor_map.insert(grid_id, &editor); + Ok(editor) + } + Some(editor) => Ok(editor), + } + } + + #[tracing::instrument(level = "trace", skip(self, pool), err)] + async fn make_grid_editor( + &self, + grid_id: &str, + pool: Arc, + ) -> Result, FlowyError> { + let user = self.grid_user.clone(); + let rev_manager = self.make_grid_rev_manager(grid_id, pool.clone())?; + let grid_editor = + ClientGridEditor::new(grid_id, user, rev_manager, self.block_index_persistence.clone()).await?; + Ok(grid_editor) + } + + pub fn make_grid_rev_manager(&self, grid_id: &str, pool: Arc) -> FlowyResult { + let user_id = self.grid_user.user_id()?; + + let disk_cache = Arc::new(SQLiteGridRevisionPersistence::new(&user_id, pool)); + let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, disk_cache)); + let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence); + Ok(rev_manager) + } + + fn make_grid_block_meta_rev_manager( + &self, + block_d: &str, + pool: Arc, + ) -> FlowyResult { + let user_id = self.grid_user.user_id()?; + let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool)); + let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_d, disk_cache)); + let rev_manager = RevisionManager::new(&user_id, block_d, rev_persistence); + Ok(rev_manager) + } +} + +pub struct GridEditorMap { + inner: DashMap>, +} + +impl GridEditorMap { + fn new() -> Self { + Self { inner: DashMap::new() } + } + + pub(crate) fn insert(&self, grid_id: &str, grid_editor: &Arc) { + if self.inner.contains_key(grid_id) { + tracing::warn!("Grid:{} already exists in cache", grid_id); + } + self.inner.insert(grid_id.to_string(), grid_editor.clone()); + } + + pub(crate) fn get(&self, grid_id: &str) -> Option> { + Some(self.inner.get(grid_id)?.clone()) + } + + pub(crate) fn remove(&self, grid_id: &str) { + self.inner.remove(grid_id); + } +} + +pub async fn make_grid_view_data( + user_id: &str, + view_id: &str, + grid_manager: Arc, + build_context: BuildGridContext, +) -> FlowyResult { + let block_id = build_context.block_meta.block_id.clone(); + let grid_meta = GridMeta { + grid_id: view_id.to_string(), + fields: build_context.field_metas, + blocks: vec![build_context.block_meta], + }; + + // Create grid + let grid_meta_delta = make_grid_delta(&grid_meta); + let grid_delta_data = grid_meta_delta.to_delta_bytes(); + let repeated_revision: RepeatedRevision = + Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into(); + let _ = grid_manager.create_grid(view_id, repeated_revision).await?; + + // Indexing the block's rows + build_context.block_meta_data.rows.iter().for_each(|row| { + let _ = grid_manager + .block_index_persistence + .insert_or_update(&row.block_id, &row.id); + }); + + // Create grid's block + let grid_block_meta_delta = make_block_meta_delta(&build_context.block_meta_data); + let block_meta_delta_data = grid_block_meta_delta.to_delta_bytes(); + let repeated_revision: RepeatedRevision = + Revision::initial_revision(user_id, &block_id, block_meta_delta_data).into(); + let _ = grid_manager + .create_grid_block_meta(&block_id, repeated_revision) + .await?; + + Ok(grid_delta_data) +} diff --git a/shared-lib/flowy-collaboration/src/protobuf/mod.rs b/frontend/rust-lib/flowy-grid/src/protobuf/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/protobuf/mod.rs rename to frontend/rust-lib/flowy-grid/src/protobuf/mod.rs diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/cell_entities.rs new file mode 100644 index 0000000000..08a0cb0c1d --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/cell_entities.rs @@ -0,0 +1,505 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `cell_entities.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct CreateSelectOptionPayload { + // message fields + pub field_identifier: ::protobuf::SingularPtrField, + pub option_name: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CreateSelectOptionPayload { + fn default() -> &'a CreateSelectOptionPayload { + ::default_instance() + } +} + +impl CreateSelectOptionPayload { + pub fn new() -> CreateSelectOptionPayload { + ::std::default::Default::default() + } + + // .FieldIdentifierPayload field_identifier = 1; + + + pub fn get_field_identifier(&self) -> &super::field_entities::FieldIdentifierPayload { + self.field_identifier.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_field_identifier(&mut self) { + self.field_identifier.clear(); + } + + pub fn has_field_identifier(&self) -> bool { + self.field_identifier.is_some() + } + + // Param is passed by value, moved + pub fn set_field_identifier(&mut self, v: super::field_entities::FieldIdentifierPayload) { + self.field_identifier = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_identifier(&mut self) -> &mut super::field_entities::FieldIdentifierPayload { + if self.field_identifier.is_none() { + self.field_identifier.set_default(); + } + self.field_identifier.as_mut().unwrap() + } + + // Take field + pub fn take_field_identifier(&mut self) -> super::field_entities::FieldIdentifierPayload { + self.field_identifier.take().unwrap_or_else(|| super::field_entities::FieldIdentifierPayload::new()) + } + + // string option_name = 2; + + + pub fn get_option_name(&self) -> &str { + &self.option_name + } + pub fn clear_option_name(&mut self) { + self.option_name.clear(); + } + + // Param is passed by value, moved + pub fn set_option_name(&mut self, v: ::std::string::String) { + self.option_name = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_option_name(&mut self) -> &mut ::std::string::String { + &mut self.option_name + } + + // Take field + pub fn take_option_name(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.option_name, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for CreateSelectOptionPayload { + fn is_initialized(&self) -> bool { + for v in &self.field_identifier { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.field_identifier)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.option_name)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.field_identifier.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if !self.option_name.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.option_name); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.field_identifier.as_ref() { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if !self.option_name.is_empty() { + os.write_string(2, &self.option_name)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CreateSelectOptionPayload { + CreateSelectOptionPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "field_identifier", + |m: &CreateSelectOptionPayload| { &m.field_identifier }, + |m: &mut CreateSelectOptionPayload| { &mut m.field_identifier }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "option_name", + |m: &CreateSelectOptionPayload| { &m.option_name }, + |m: &mut CreateSelectOptionPayload| { &mut m.option_name }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CreateSelectOptionPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CreateSelectOptionPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CreateSelectOptionPayload::new) + } +} + +impl ::protobuf::Clear for CreateSelectOptionPayload { + fn clear(&mut self) { + self.field_identifier.clear(); + self.option_name.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CreateSelectOptionPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CreateSelectOptionPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct CellIdentifierPayload { + // message fields + pub grid_id: ::std::string::String, + pub field_id: ::std::string::String, + pub row_id: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CellIdentifierPayload { + fn default() -> &'a CellIdentifierPayload { + ::default_instance() + } +} + +impl CellIdentifierPayload { + pub fn new() -> CellIdentifierPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string field_id = 2; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string row_id = 3; + + + pub fn get_row_id(&self) -> &str { + &self.row_id + } + pub fn clear_row_id(&mut self) { + self.row_id.clear(); + } + + // Param is passed by value, moved + pub fn set_row_id(&mut self, v: ::std::string::String) { + self.row_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_id(&mut self) -> &mut ::std::string::String { + &mut self.row_id + } + + // Take field + pub fn take_row_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for CellIdentifierPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.field_id); + } + if !self.row_id.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.row_id); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.field_id.is_empty() { + os.write_string(2, &self.field_id)?; + } + if !self.row_id.is_empty() { + os.write_string(3, &self.row_id)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CellIdentifierPayload { + CellIdentifierPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &CellIdentifierPayload| { &m.grid_id }, + |m: &mut CellIdentifierPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &CellIdentifierPayload| { &m.field_id }, + |m: &mut CellIdentifierPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "row_id", + |m: &CellIdentifierPayload| { &m.row_id }, + |m: &mut CellIdentifierPayload| { &mut m.row_id }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CellIdentifierPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CellIdentifierPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CellIdentifierPayload::new) + } +} + +impl ::protobuf::Clear for CellIdentifierPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.field_id.clear(); + self.row_id.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CellIdentifierPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CellIdentifierPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x13cell_entities.proto\x1a\x14field_entities.proto\"\x80\x01\n\x19Cre\ + ateSelectOptionPayload\x12B\n\x10field_identifier\x18\x01\x20\x01(\x0b2\ + \x17.FieldIdentifierPayloadR\x0ffieldIdentifier\x12\x1f\n\x0boption_name\ + \x18\x02\x20\x01(\tR\noptionName\"b\n\x15CellIdentifierPayload\x12\x17\n\ + \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\ + \x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\ + b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/checkbox_type_option.rs new file mode 100644 index 0000000000..95612e4765 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/checkbox_type_option.rs @@ -0,0 +1,193 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `checkbox_type_option.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct CheckboxTypeOption { + // message fields + pub is_selected: bool, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CheckboxTypeOption { + fn default() -> &'a CheckboxTypeOption { + ::default_instance() + } +} + +impl CheckboxTypeOption { + pub fn new() -> CheckboxTypeOption { + ::std::default::Default::default() + } + + // bool is_selected = 1; + + + pub fn get_is_selected(&self) -> bool { + self.is_selected + } + pub fn clear_is_selected(&mut self) { + self.is_selected = false; + } + + // Param is passed by value, moved + pub fn set_is_selected(&mut self, v: bool) { + self.is_selected = v; + } +} + +impl ::protobuf::Message for CheckboxTypeOption { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.is_selected = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if self.is_selected != false { + my_size += 2; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if self.is_selected != false { + os.write_bool(1, self.is_selected)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CheckboxTypeOption { + CheckboxTypeOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "is_selected", + |m: &CheckboxTypeOption| { &m.is_selected }, + |m: &mut CheckboxTypeOption| { &mut m.is_selected }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CheckboxTypeOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CheckboxTypeOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CheckboxTypeOption::new) + } +} + +impl ::protobuf::Clear for CheckboxTypeOption { + fn clear(&mut self) { + self.is_selected = false; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CheckboxTypeOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CheckboxTypeOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x1acheckbox_type_option.proto\"5\n\x12CheckboxTypeOption\x12\x1f\n\ + \x0bis_selected\x18\x01\x20\x01(\x08R\nisSelectedb\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs new file mode 100644 index 0000000000..ff60cbf9e7 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs @@ -0,0 +1,109 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `dart_notification.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum GridNotification { + Unknown = 0, + DidCreateBlock = 11, + DidUpdateGridRow = 20, + DidUpdateGridField = 21, + DidUpdateRow = 30, + DidUpdateCell = 40, + DidUpdateField = 50, +} + +impl ::protobuf::ProtobufEnum for GridNotification { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(GridNotification::Unknown), + 11 => ::std::option::Option::Some(GridNotification::DidCreateBlock), + 20 => ::std::option::Option::Some(GridNotification::DidUpdateGridRow), + 21 => ::std::option::Option::Some(GridNotification::DidUpdateGridField), + 30 => ::std::option::Option::Some(GridNotification::DidUpdateRow), + 40 => ::std::option::Option::Some(GridNotification::DidUpdateCell), + 50 => ::std::option::Option::Some(GridNotification::DidUpdateField), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [GridNotification] = &[ + GridNotification::Unknown, + GridNotification::DidCreateBlock, + GridNotification::DidUpdateGridRow, + GridNotification::DidUpdateGridField, + GridNotification::DidUpdateRow, + GridNotification::DidUpdateCell, + GridNotification::DidUpdateField, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("GridNotification", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for GridNotification { +} + +impl ::std::default::Default for GridNotification { + fn default() -> Self { + GridNotification::Unknown + } +} + +impl ::protobuf::reflect::ProtobufValue for GridNotification { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x17dart_notification.proto*\x9a\x01\n\x10GridNotification\x12\x0b\n\ + \x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x14\n\x10DidUp\ + dateGridRow\x10\x14\x12\x16\n\x12DidUpdateGridField\x10\x15\x12\x10\n\ + \x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUpdateCell\x10(\x12\x12\n\x0eDidU\ + pdateField\x102b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs new file mode 100644 index 0000000000..223d6f322c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs @@ -0,0 +1,366 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `date_type_option.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct DateTypeOption { + // message fields + pub date_format: DateFormat, + pub time_format: TimeFormat, + pub include_time: bool, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a DateTypeOption { + fn default() -> &'a DateTypeOption { + ::default_instance() + } +} + +impl DateTypeOption { + pub fn new() -> DateTypeOption { + ::std::default::Default::default() + } + + // .DateFormat date_format = 1; + + + pub fn get_date_format(&self) -> DateFormat { + self.date_format + } + pub fn clear_date_format(&mut self) { + self.date_format = DateFormat::Local; + } + + // Param is passed by value, moved + pub fn set_date_format(&mut self, v: DateFormat) { + self.date_format = v; + } + + // .TimeFormat time_format = 2; + + + pub fn get_time_format(&self) -> TimeFormat { + self.time_format + } + pub fn clear_time_format(&mut self) { + self.time_format = TimeFormat::TwelveHour; + } + + // Param is passed by value, moved + pub fn set_time_format(&mut self, v: TimeFormat) { + self.time_format = v; + } + + // bool include_time = 3; + + + pub fn get_include_time(&self) -> bool { + self.include_time + } + pub fn clear_include_time(&mut self) { + self.include_time = false; + } + + // Param is passed by value, moved + pub fn set_include_time(&mut self, v: bool) { + self.include_time = v; + } +} + +impl ::protobuf::Message for DateTypeOption { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.date_format, 1, &mut self.unknown_fields)? + }, + 2 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.time_format, 2, &mut self.unknown_fields)? + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.include_time = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if self.date_format != DateFormat::Local { + my_size += ::protobuf::rt::enum_size(1, self.date_format); + } + if self.time_format != TimeFormat::TwelveHour { + my_size += ::protobuf::rt::enum_size(2, self.time_format); + } + if self.include_time != false { + my_size += 2; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if self.date_format != DateFormat::Local { + os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.date_format))?; + } + if self.time_format != TimeFormat::TwelveHour { + os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.time_format))?; + } + if self.include_time != false { + os.write_bool(3, self.include_time)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> DateTypeOption { + DateTypeOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "date_format", + |m: &DateTypeOption| { &m.date_format }, + |m: &mut DateTypeOption| { &mut m.date_format }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "time_format", + |m: &DateTypeOption| { &m.time_format }, + |m: &mut DateTypeOption| { &mut m.time_format }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "include_time", + |m: &DateTypeOption| { &m.include_time }, + |m: &mut DateTypeOption| { &mut m.include_time }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "DateTypeOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static DateTypeOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(DateTypeOption::new) + } +} + +impl ::protobuf::Clear for DateTypeOption { + fn clear(&mut self) { + self.date_format = DateFormat::Local; + self.time_format = TimeFormat::TwelveHour; + self.include_time = false; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for DateTypeOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for DateTypeOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum DateFormat { + Local = 0, + US = 1, + ISO = 2, + Friendly = 3, +} + +impl ::protobuf::ProtobufEnum for DateFormat { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(DateFormat::Local), + 1 => ::std::option::Option::Some(DateFormat::US), + 2 => ::std::option::Option::Some(DateFormat::ISO), + 3 => ::std::option::Option::Some(DateFormat::Friendly), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [DateFormat] = &[ + DateFormat::Local, + DateFormat::US, + DateFormat::ISO, + DateFormat::Friendly, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("DateFormat", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for DateFormat { +} + +impl ::std::default::Default for DateFormat { + fn default() -> Self { + DateFormat::Local + } +} + +impl ::protobuf::reflect::ProtobufValue for DateFormat { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum TimeFormat { + TwelveHour = 0, + TwentyFourHour = 1, +} + +impl ::protobuf::ProtobufEnum for TimeFormat { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(TimeFormat::TwelveHour), + 1 => ::std::option::Option::Some(TimeFormat::TwentyFourHour), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [TimeFormat] = &[ + TimeFormat::TwelveHour, + TimeFormat::TwentyFourHour, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("TimeFormat", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for TimeFormat { +} + +impl ::std::default::Default for TimeFormat { + fn default() -> Self { + TimeFormat::TwelveHour + } +} + +impl ::protobuf::reflect::ProtobufValue for TimeFormat { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x16date_type_option.proto\"\x8f\x01\n\x0eDateTypeOption\x12,\n\x0bdat\ + e_format\x18\x01\x20\x01(\x0e2\x0b.DateFormatR\ndateFormat\x12,\n\x0btim\ + e_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormatR\ntimeFormat\x12!\n\x0cinc\ + lude_time\x18\x03\x20\x01(\x08R\x0bincludeTime*6\n\nDateFormat\x12\t\n\ + \x05Local\x10\0\x12\x06\n\x02US\x10\x01\x12\x07\n\x03ISO\x10\x02\x12\x0c\ + \n\x08Friendly\x10\x03*0\n\nTimeFormat\x12\x0e\n\nTwelveHour\x10\0\x12\ + \x12\n\x0eTwentyFourHour\x10\x01b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs new file mode 100644 index 0000000000..b4792931ae --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -0,0 +1,153 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `event_map.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum GridEvent { + GetGridData = 0, + GetGridBlocks = 1, + GetFields = 10, + UpdateField = 11, + InsertField = 12, + DeleteField = 13, + SwitchToField = 14, + DuplicateField = 15, + GetEditFieldContext = 16, + MoveItem = 17, + NewSelectOption = 30, + GetSelectOptionContext = 31, + UpdateSelectOption = 32, + CreateRow = 50, + GetRow = 51, + DeleteRow = 52, + DuplicateRow = 53, + GetCell = 70, + UpdateCell = 71, + UpdateCellSelectOption = 72, +} + +impl ::protobuf::ProtobufEnum for GridEvent { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(GridEvent::GetGridData), + 1 => ::std::option::Option::Some(GridEvent::GetGridBlocks), + 10 => ::std::option::Option::Some(GridEvent::GetFields), + 11 => ::std::option::Option::Some(GridEvent::UpdateField), + 12 => ::std::option::Option::Some(GridEvent::InsertField), + 13 => ::std::option::Option::Some(GridEvent::DeleteField), + 14 => ::std::option::Option::Some(GridEvent::SwitchToField), + 15 => ::std::option::Option::Some(GridEvent::DuplicateField), + 16 => ::std::option::Option::Some(GridEvent::GetEditFieldContext), + 17 => ::std::option::Option::Some(GridEvent::MoveItem), + 30 => ::std::option::Option::Some(GridEvent::NewSelectOption), + 31 => ::std::option::Option::Some(GridEvent::GetSelectOptionContext), + 32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption), + 50 => ::std::option::Option::Some(GridEvent::CreateRow), + 51 => ::std::option::Option::Some(GridEvent::GetRow), + 52 => ::std::option::Option::Some(GridEvent::DeleteRow), + 53 => ::std::option::Option::Some(GridEvent::DuplicateRow), + 70 => ::std::option::Option::Some(GridEvent::GetCell), + 71 => ::std::option::Option::Some(GridEvent::UpdateCell), + 72 => ::std::option::Option::Some(GridEvent::UpdateCellSelectOption), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [GridEvent] = &[ + GridEvent::GetGridData, + GridEvent::GetGridBlocks, + GridEvent::GetFields, + GridEvent::UpdateField, + GridEvent::InsertField, + GridEvent::DeleteField, + GridEvent::SwitchToField, + GridEvent::DuplicateField, + GridEvent::GetEditFieldContext, + GridEvent::MoveItem, + GridEvent::NewSelectOption, + GridEvent::GetSelectOptionContext, + GridEvent::UpdateSelectOption, + GridEvent::CreateRow, + GridEvent::GetRow, + GridEvent::DeleteRow, + GridEvent::DuplicateRow, + GridEvent::GetCell, + GridEvent::UpdateCell, + GridEvent::UpdateCellSelectOption, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("GridEvent", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for GridEvent { +} + +impl ::std::default::Default for GridEvent { + fn default() -> Self { + GridEvent::GetGridData + } +} + +impl ::protobuf::reflect::ProtobufValue for GridEvent { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x0fevent_map.proto*\xfd\x02\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ + \x0bUpdateField\x10\x0b\x12\x0f\n\x0bInsertField\x10\x0c\x12\x0f\n\x0bDe\ + leteField\x10\r\x12\x11\n\rSwitchToField\x10\x0e\x12\x12\n\x0eDuplicateF\ + ield\x10\x0f\x12\x17\n\x13GetEditFieldContext\x10\x10\x12\x0c\n\x08MoveI\ + tem\x10\x11\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1a\n\x16GetSelectO\ + ptionContext\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\x20\x12\r\n\tCr\ + eateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\x104\x12\x10\n\ + \x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\nUpdateCell\ + \x10G\x12\x1a\n\x16UpdateCellSelectOption\x10Hb\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/field_entities.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/field_entities.rs new file mode 100644 index 0000000000..fa4edcc070 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/field_entities.rs @@ -0,0 +1,243 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `field_entities.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct FieldIdentifierPayload { + // message fields + pub field_id: ::std::string::String, + pub grid_id: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a FieldIdentifierPayload { + fn default() -> &'a FieldIdentifierPayload { + ::default_instance() + } +} + +impl FieldIdentifierPayload { + pub fn new() -> FieldIdentifierPayload { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string grid_id = 2; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for FieldIdentifierPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.grid_id); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + if !self.grid_id.is_empty() { + os.write_string(2, &self.grid_id)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> FieldIdentifierPayload { + FieldIdentifierPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &FieldIdentifierPayload| { &m.field_id }, + |m: &mut FieldIdentifierPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &FieldIdentifierPayload| { &m.grid_id }, + |m: &mut FieldIdentifierPayload| { &mut m.grid_id }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "FieldIdentifierPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static FieldIdentifierPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(FieldIdentifierPayload::new) + } +} + +impl ::protobuf::Clear for FieldIdentifierPayload { + fn clear(&mut self) { + self.field_id.clear(); + self.grid_id.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for FieldIdentifierPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldIdentifierPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x14field_entities.proto\"L\n\x16FieldIdentifierPayload\x12\x19\n\x08f\ + ield_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_id\x18\x02\x20\ + \x01(\tR\x06gridIdb\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/mod.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/mod.rs new file mode 100644 index 0000000000..99d0ecd1b6 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/mod.rs @@ -0,0 +1,32 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +// Auto-generated, do not edit + +mod field_entities; +pub use field_entities::*; + +mod number_type_option; +pub use number_type_option::*; + +mod dart_notification; +pub use dart_notification::*; + +mod selection_type_option; +pub use selection_type_option::*; + +mod row_entities; +pub use row_entities::*; + +mod cell_entities; +pub use cell_entities::*; + +mod checkbox_type_option; +pub use checkbox_type_option::*; + +mod event_map; +pub use event_map::*; + +mod text_type_option; +pub use text_type_option::*; + +mod date_type_option; +pub use date_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/number_type_option.rs new file mode 100644 index 0000000000..8fd65bc20b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/number_type_option.rs @@ -0,0 +1,404 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `number_type_option.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct NumberTypeOption { + // message fields + pub format: NumberFormat, + pub scale: u32, + pub symbol: ::std::string::String, + pub sign_positive: bool, + pub name: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a NumberTypeOption { + fn default() -> &'a NumberTypeOption { + ::default_instance() + } +} + +impl NumberTypeOption { + pub fn new() -> NumberTypeOption { + ::std::default::Default::default() + } + + // .NumberFormat format = 1; + + + pub fn get_format(&self) -> NumberFormat { + self.format + } + pub fn clear_format(&mut self) { + self.format = NumberFormat::Number; + } + + // Param is passed by value, moved + pub fn set_format(&mut self, v: NumberFormat) { + self.format = v; + } + + // uint32 scale = 2; + + + pub fn get_scale(&self) -> u32 { + self.scale + } + pub fn clear_scale(&mut self) { + self.scale = 0; + } + + // Param is passed by value, moved + pub fn set_scale(&mut self, v: u32) { + self.scale = v; + } + + // string symbol = 3; + + + pub fn get_symbol(&self) -> &str { + &self.symbol + } + pub fn clear_symbol(&mut self) { + self.symbol.clear(); + } + + // Param is passed by value, moved + pub fn set_symbol(&mut self, v: ::std::string::String) { + self.symbol = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_symbol(&mut self) -> &mut ::std::string::String { + &mut self.symbol + } + + // Take field + pub fn take_symbol(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.symbol, ::std::string::String::new()) + } + + // bool sign_positive = 4; + + + pub fn get_sign_positive(&self) -> bool { + self.sign_positive + } + pub fn clear_sign_positive(&mut self) { + self.sign_positive = false; + } + + // Param is passed by value, moved + pub fn set_sign_positive(&mut self, v: bool) { + self.sign_positive = v; + } + + // string name = 5; + + + pub fn get_name(&self) -> &str { + &self.name + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + &mut self.name + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.name, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for NumberTypeOption { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.format, 1, &mut self.unknown_fields)? + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.scale = tmp; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.symbol)?; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.sign_positive = tmp; + }, + 5 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if self.format != NumberFormat::Number { + my_size += ::protobuf::rt::enum_size(1, self.format); + } + if self.scale != 0 { + my_size += ::protobuf::rt::value_size(2, self.scale, ::protobuf::wire_format::WireTypeVarint); + } + if !self.symbol.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.symbol); + } + if self.sign_positive != false { + my_size += 2; + } + if !self.name.is_empty() { + my_size += ::protobuf::rt::string_size(5, &self.name); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if self.format != NumberFormat::Number { + os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.format))?; + } + if self.scale != 0 { + os.write_uint32(2, self.scale)?; + } + if !self.symbol.is_empty() { + os.write_string(3, &self.symbol)?; + } + if self.sign_positive != false { + os.write_bool(4, self.sign_positive)?; + } + if !self.name.is_empty() { + os.write_string(5, &self.name)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> NumberTypeOption { + NumberTypeOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "format", + |m: &NumberTypeOption| { &m.format }, + |m: &mut NumberTypeOption| { &mut m.format }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "scale", + |m: &NumberTypeOption| { &m.scale }, + |m: &mut NumberTypeOption| { &mut m.scale }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "symbol", + |m: &NumberTypeOption| { &m.symbol }, + |m: &mut NumberTypeOption| { &mut m.symbol }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "sign_positive", + |m: &NumberTypeOption| { &m.sign_positive }, + |m: &mut NumberTypeOption| { &mut m.sign_positive }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &NumberTypeOption| { &m.name }, + |m: &mut NumberTypeOption| { &mut m.name }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "NumberTypeOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static NumberTypeOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(NumberTypeOption::new) + } +} + +impl ::protobuf::Clear for NumberTypeOption { + fn clear(&mut self) { + self.format = NumberFormat::Number; + self.scale = 0; + self.symbol.clear(); + self.sign_positive = false; + self.name.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for NumberTypeOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for NumberTypeOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum NumberFormat { + Number = 0, + USD = 1, + CNY = 2, + EUR = 3, +} + +impl ::protobuf::ProtobufEnum for NumberFormat { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(NumberFormat::Number), + 1 => ::std::option::Option::Some(NumberFormat::USD), + 2 => ::std::option::Option::Some(NumberFormat::CNY), + 3 => ::std::option::Option::Some(NumberFormat::EUR), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [NumberFormat] = &[ + NumberFormat::Number, + NumberFormat::USD, + NumberFormat::CNY, + NumberFormat::EUR, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("NumberFormat", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for NumberFormat { +} + +impl ::std::default::Default for NumberFormat { + fn default() -> Self { + NumberFormat::Number + } +} + +impl ::protobuf::reflect::ProtobufValue for NumberFormat { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x18number_type_option.proto\"\xa0\x01\n\x10NumberTypeOption\x12%\n\ + \x06format\x18\x01\x20\x01(\x0e2\r.NumberFormatR\x06format\x12\x14\n\x05\ + scale\x18\x02\x20\x01(\rR\x05scale\x12\x16\n\x06symbol\x18\x03\x20\x01(\ + \tR\x06symbol\x12#\n\rsign_positive\x18\x04\x20\x01(\x08R\x0csignPositiv\ + e\x12\x12\n\x04name\x18\x05\x20\x01(\tR\x04name*5\n\x0cNumberFormat\x12\ + \n\n\x06Number\x10\0\x12\x07\n\x03USD\x10\x01\x12\x07\n\x03CNY\x10\x02\ + \x12\x07\n\x03EUR\x10\x03b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/row_entities.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/row_entities.rs new file mode 100644 index 0000000000..0bcf1323c6 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/row_entities.rs @@ -0,0 +1,243 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `row_entities.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct RowIdentifierPayload { + // message fields + pub grid_id: ::std::string::String, + pub row_id: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RowIdentifierPayload { + fn default() -> &'a RowIdentifierPayload { + ::default_instance() + } +} + +impl RowIdentifierPayload { + pub fn new() -> RowIdentifierPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string row_id = 3; + + + pub fn get_row_id(&self) -> &str { + &self.row_id + } + pub fn clear_row_id(&mut self) { + self.row_id.clear(); + } + + // Param is passed by value, moved + pub fn set_row_id(&mut self, v: ::std::string::String) { + self.row_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_id(&mut self) -> &mut ::std::string::String { + &mut self.row_id + } + + // Take field + pub fn take_row_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for RowIdentifierPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.row_id.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.row_id); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.row_id.is_empty() { + os.write_string(3, &self.row_id)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RowIdentifierPayload { + RowIdentifierPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &RowIdentifierPayload| { &m.grid_id }, + |m: &mut RowIdentifierPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "row_id", + |m: &RowIdentifierPayload| { &m.row_id }, + |m: &mut RowIdentifierPayload| { &mut m.row_id }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RowIdentifierPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RowIdentifierPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RowIdentifierPayload::new) + } +} + +impl ::protobuf::Clear for RowIdentifierPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.row_id.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RowIdentifierPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RowIdentifierPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x12row_entities.proto\"F\n\x14RowIdentifierPayload\x12\x17\n\x07grid_\ + id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\ + \x05rowIdb\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs new file mode 100644 index 0000000000..fb945be12b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs @@ -0,0 +1,1834 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `selection_type_option.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct SingleSelectTypeOption { + // message fields + pub options: ::protobuf::RepeatedField, + pub disable_color: bool, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a SingleSelectTypeOption { + fn default() -> &'a SingleSelectTypeOption { + ::default_instance() + } +} + +impl SingleSelectTypeOption { + pub fn new() -> SingleSelectTypeOption { + ::std::default::Default::default() + } + + // repeated .SelectOption options = 1; + + + pub fn get_options(&self) -> &[SelectOption] { + &self.options + } + pub fn clear_options(&mut self) { + self.options.clear(); + } + + // Param is passed by value, moved + pub fn set_options(&mut self, v: ::protobuf::RepeatedField) { + self.options = v; + } + + // Mutable pointer to the field. + pub fn mut_options(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.options + } + + // Take field + pub fn take_options(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.options, ::protobuf::RepeatedField::new()) + } + + // bool disable_color = 2; + + + pub fn get_disable_color(&self) -> bool { + self.disable_color + } + pub fn clear_disable_color(&mut self) { + self.disable_color = false; + } + + // Param is passed by value, moved + pub fn set_disable_color(&mut self, v: bool) { + self.disable_color = v; + } +} + +impl ::protobuf::Message for SingleSelectTypeOption { + fn is_initialized(&self) -> bool { + for v in &self.options { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.options)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.disable_color = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.options { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if self.disable_color != false { + my_size += 2; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.options { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if self.disable_color != false { + os.write_bool(2, self.disable_color)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> SingleSelectTypeOption { + SingleSelectTypeOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "options", + |m: &SingleSelectTypeOption| { &m.options }, + |m: &mut SingleSelectTypeOption| { &mut m.options }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "disable_color", + |m: &SingleSelectTypeOption| { &m.disable_color }, + |m: &mut SingleSelectTypeOption| { &mut m.disable_color }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "SingleSelectTypeOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static SingleSelectTypeOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(SingleSelectTypeOption::new) + } +} + +impl ::protobuf::Clear for SingleSelectTypeOption { + fn clear(&mut self) { + self.options.clear(); + self.disable_color = false; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SingleSelectTypeOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SingleSelectTypeOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct MultiSelectTypeOption { + // message fields + pub options: ::protobuf::RepeatedField, + pub disable_color: bool, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a MultiSelectTypeOption { + fn default() -> &'a MultiSelectTypeOption { + ::default_instance() + } +} + +impl MultiSelectTypeOption { + pub fn new() -> MultiSelectTypeOption { + ::std::default::Default::default() + } + + // repeated .SelectOption options = 1; + + + pub fn get_options(&self) -> &[SelectOption] { + &self.options + } + pub fn clear_options(&mut self) { + self.options.clear(); + } + + // Param is passed by value, moved + pub fn set_options(&mut self, v: ::protobuf::RepeatedField) { + self.options = v; + } + + // Mutable pointer to the field. + pub fn mut_options(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.options + } + + // Take field + pub fn take_options(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.options, ::protobuf::RepeatedField::new()) + } + + // bool disable_color = 2; + + + pub fn get_disable_color(&self) -> bool { + self.disable_color + } + pub fn clear_disable_color(&mut self) { + self.disable_color = false; + } + + // Param is passed by value, moved + pub fn set_disable_color(&mut self, v: bool) { + self.disable_color = v; + } +} + +impl ::protobuf::Message for MultiSelectTypeOption { + fn is_initialized(&self) -> bool { + for v in &self.options { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.options)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.disable_color = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.options { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + if self.disable_color != false { + my_size += 2; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.options { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + if self.disable_color != false { + os.write_bool(2, self.disable_color)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> MultiSelectTypeOption { + MultiSelectTypeOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "options", + |m: &MultiSelectTypeOption| { &m.options }, + |m: &mut MultiSelectTypeOption| { &mut m.options }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "disable_color", + |m: &MultiSelectTypeOption| { &m.disable_color }, + |m: &mut MultiSelectTypeOption| { &mut m.disable_color }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "MultiSelectTypeOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static MultiSelectTypeOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(MultiSelectTypeOption::new) + } +} + +impl ::protobuf::Clear for MultiSelectTypeOption { + fn clear(&mut self) { + self.options.clear(); + self.disable_color = false; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for MultiSelectTypeOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for MultiSelectTypeOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct SelectOption { + // message fields + pub id: ::std::string::String, + pub name: ::std::string::String, + pub color: SelectOptionColor, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a SelectOption { + fn default() -> &'a SelectOption { + ::default_instance() + } +} + +impl SelectOption { + pub fn new() -> SelectOption { + ::std::default::Default::default() + } + + // string id = 1; + + + pub fn get_id(&self) -> &str { + &self.id + } + pub fn clear_id(&mut self) { + self.id.clear(); + } + + // Param is passed by value, moved + pub fn set_id(&mut self, v: ::std::string::String) { + self.id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_id(&mut self) -> &mut ::std::string::String { + &mut self.id + } + + // Take field + pub fn take_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.id, ::std::string::String::new()) + } + + // string name = 2; + + + pub fn get_name(&self) -> &str { + &self.name + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + &mut self.name + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.name, ::std::string::String::new()) + } + + // .SelectOptionColor color = 3; + + + pub fn get_color(&self) -> SelectOptionColor { + self.color + } + pub fn clear_color(&mut self) { + self.color = SelectOptionColor::Purple; + } + + // Param is passed by value, moved + pub fn set_color(&mut self, v: SelectOptionColor) { + self.color = v; + } +} + +impl ::protobuf::Message for SelectOption { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?; + }, + 3 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.color, 3, &mut self.unknown_fields)? + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.id); + } + if !self.name.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.name); + } + if self.color != SelectOptionColor::Purple { + my_size += ::protobuf::rt::enum_size(3, self.color); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.id.is_empty() { + os.write_string(1, &self.id)?; + } + if !self.name.is_empty() { + os.write_string(2, &self.name)?; + } + if self.color != SelectOptionColor::Purple { + os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.color))?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> SelectOption { + SelectOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "id", + |m: &SelectOption| { &m.id }, + |m: &mut SelectOption| { &mut m.id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &SelectOption| { &m.name }, + |m: &mut SelectOption| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "color", + |m: &SelectOption| { &m.color }, + |m: &mut SelectOption| { &mut m.color }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "SelectOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static SelectOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(SelectOption::new) + } +} + +impl ::protobuf::Clear for SelectOption { + fn clear(&mut self) { + self.id.clear(); + self.name.clear(); + self.color = SelectOptionColor::Purple; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SelectOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SelectOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct SelectOptionChangesetPayload { + // message fields + pub cell_identifier: ::protobuf::SingularPtrField, + // message oneof groups + pub one_of_insert_option: ::std::option::Option, + pub one_of_update_option: ::std::option::Option, + pub one_of_delete_option: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a SelectOptionChangesetPayload { + fn default() -> &'a SelectOptionChangesetPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum SelectOptionChangesetPayload_oneof_one_of_insert_option { + insert_option(SelectOption), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum SelectOptionChangesetPayload_oneof_one_of_update_option { + update_option(SelectOption), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum SelectOptionChangesetPayload_oneof_one_of_delete_option { + delete_option(SelectOption), +} + +impl SelectOptionChangesetPayload { + pub fn new() -> SelectOptionChangesetPayload { + ::std::default::Default::default() + } + + // .CellIdentifierPayload cell_identifier = 1; + + + pub fn get_cell_identifier(&self) -> &super::cell_entities::CellIdentifierPayload { + self.cell_identifier.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_cell_identifier(&mut self) { + self.cell_identifier.clear(); + } + + pub fn has_cell_identifier(&self) -> bool { + self.cell_identifier.is_some() + } + + // Param is passed by value, moved + pub fn set_cell_identifier(&mut self, v: super::cell_entities::CellIdentifierPayload) { + self.cell_identifier = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_cell_identifier(&mut self) -> &mut super::cell_entities::CellIdentifierPayload { + if self.cell_identifier.is_none() { + self.cell_identifier.set_default(); + } + self.cell_identifier.as_mut().unwrap() + } + + // Take field + pub fn take_cell_identifier(&mut self) -> super::cell_entities::CellIdentifierPayload { + self.cell_identifier.take().unwrap_or_else(|| super::cell_entities::CellIdentifierPayload::new()) + } + + // .SelectOption insert_option = 2; + + + pub fn get_insert_option(&self) -> &SelectOption { + match self.one_of_insert_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(ref v)) => v, + _ => ::default_instance(), + } + } + pub fn clear_insert_option(&mut self) { + self.one_of_insert_option = ::std::option::Option::None; + } + + pub fn has_insert_option(&self) -> bool { + match self.one_of_insert_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_insert_option(&mut self, v: SelectOption) { + self.one_of_insert_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(v)) + } + + // Mutable pointer to the field. + pub fn mut_insert_option(&mut self) -> &mut SelectOption { + if let ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(_)) = self.one_of_insert_option { + } else { + self.one_of_insert_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(SelectOption::new())); + } + match self.one_of_insert_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_insert_option(&mut self) -> SelectOption { + if self.has_insert_option() { + match self.one_of_insert_option.take() { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(v)) => v, + _ => panic!(), + } + } else { + SelectOption::new() + } + } + + // .SelectOption update_option = 3; + + + pub fn get_update_option(&self) -> &SelectOption { + match self.one_of_update_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(ref v)) => v, + _ => ::default_instance(), + } + } + pub fn clear_update_option(&mut self) { + self.one_of_update_option = ::std::option::Option::None; + } + + pub fn has_update_option(&self) -> bool { + match self.one_of_update_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_update_option(&mut self, v: SelectOption) { + self.one_of_update_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(v)) + } + + // Mutable pointer to the field. + pub fn mut_update_option(&mut self) -> &mut SelectOption { + if let ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(_)) = self.one_of_update_option { + } else { + self.one_of_update_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(SelectOption::new())); + } + match self.one_of_update_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_update_option(&mut self) -> SelectOption { + if self.has_update_option() { + match self.one_of_update_option.take() { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(v)) => v, + _ => panic!(), + } + } else { + SelectOption::new() + } + } + + // .SelectOption delete_option = 4; + + + pub fn get_delete_option(&self) -> &SelectOption { + match self.one_of_delete_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(ref v)) => v, + _ => ::default_instance(), + } + } + pub fn clear_delete_option(&mut self) { + self.one_of_delete_option = ::std::option::Option::None; + } + + pub fn has_delete_option(&self) -> bool { + match self.one_of_delete_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_delete_option(&mut self, v: SelectOption) { + self.one_of_delete_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(v)) + } + + // Mutable pointer to the field. + pub fn mut_delete_option(&mut self) -> &mut SelectOption { + if let ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(_)) = self.one_of_delete_option { + } else { + self.one_of_delete_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(SelectOption::new())); + } + match self.one_of_delete_option { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_delete_option(&mut self) -> SelectOption { + if self.has_delete_option() { + match self.one_of_delete_option.take() { + ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(v)) => v, + _ => panic!(), + } + } else { + SelectOption::new() + } + } +} + +impl ::protobuf::Message for SelectOptionChangesetPayload { + fn is_initialized(&self) -> bool { + for v in &self.cell_identifier { + if !v.is_initialized() { + return false; + } + }; + if let Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(ref v)) = self.one_of_insert_option { + if !v.is_initialized() { + return false; + } + } + if let Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(ref v)) = self.one_of_update_option { + if !v.is_initialized() { + return false; + } + } + if let Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(ref v)) = self.one_of_delete_option { + if !v.is_initialized() { + return false; + } + } + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.cell_identifier)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_insert_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(is.read_message()?)); + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_update_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(is.read_message()?)); + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_delete_option = ::std::option::Option::Some(SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(is.read_message()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.cell_identifier.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let ::std::option::Option::Some(ref v) = self.one_of_insert_option { + match v { + &SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(ref v) => { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_update_option { + match v { + &SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(ref v) => { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_delete_option { + match v { + &SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(ref v) => { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.cell_identifier.as_ref() { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_insert_option { + match v { + &SelectOptionChangesetPayload_oneof_one_of_insert_option::insert_option(ref v) => { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_update_option { + match v { + &SelectOptionChangesetPayload_oneof_one_of_update_option::update_option(ref v) => { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_delete_option { + match v { + &SelectOptionChangesetPayload_oneof_one_of_delete_option::delete_option(ref v) => { + os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> SelectOptionChangesetPayload { + SelectOptionChangesetPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "cell_identifier", + |m: &SelectOptionChangesetPayload| { &m.cell_identifier }, + |m: &mut SelectOptionChangesetPayload| { &mut m.cell_identifier }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, SelectOption>( + "insert_option", + SelectOptionChangesetPayload::has_insert_option, + SelectOptionChangesetPayload::get_insert_option, + )); + fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, SelectOption>( + "update_option", + SelectOptionChangesetPayload::has_update_option, + SelectOptionChangesetPayload::get_update_option, + )); + fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, SelectOption>( + "delete_option", + SelectOptionChangesetPayload::has_delete_option, + SelectOptionChangesetPayload::get_delete_option, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "SelectOptionChangesetPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static SelectOptionChangesetPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(SelectOptionChangesetPayload::new) + } +} + +impl ::protobuf::Clear for SelectOptionChangesetPayload { + fn clear(&mut self) { + self.cell_identifier.clear(); + self.one_of_insert_option = ::std::option::Option::None; + self.one_of_update_option = ::std::option::Option::None; + self.one_of_delete_option = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SelectOptionChangesetPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SelectOptionChangesetPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct SelectOptionCellChangesetPayload { + // message fields + pub grid_id: ::std::string::String, + pub row_id: ::std::string::String, + pub field_id: ::std::string::String, + // message oneof groups + pub one_of_insert_option_id: ::std::option::Option, + pub one_of_delete_option_id: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a SelectOptionCellChangesetPayload { + fn default() -> &'a SelectOptionCellChangesetPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id { + insert_option_id(::std::string::String), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id { + delete_option_id(::std::string::String), +} + +impl SelectOptionCellChangesetPayload { + pub fn new() -> SelectOptionCellChangesetPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string row_id = 2; + + + pub fn get_row_id(&self) -> &str { + &self.row_id + } + pub fn clear_row_id(&mut self) { + self.row_id.clear(); + } + + // Param is passed by value, moved + pub fn set_row_id(&mut self, v: ::std::string::String) { + self.row_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_id(&mut self) -> &mut ::std::string::String { + &mut self.row_id + } + + // Take field + pub fn take_row_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) + } + + // string field_id = 3; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string insert_option_id = 4; + + + pub fn get_insert_option_id(&self) -> &str { + match self.one_of_insert_option_id { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(ref v)) => v, + _ => "", + } + } + pub fn clear_insert_option_id(&mut self) { + self.one_of_insert_option_id = ::std::option::Option::None; + } + + pub fn has_insert_option_id(&self) -> bool { + match self.one_of_insert_option_id { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_insert_option_id(&mut self, v: ::std::string::String) { + self.one_of_insert_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(v)) + } + + // Mutable pointer to the field. + pub fn mut_insert_option_id(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(_)) = self.one_of_insert_option_id { + } else { + self.one_of_insert_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(::std::string::String::new())); + } + match self.one_of_insert_option_id { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_insert_option_id(&mut self) -> ::std::string::String { + if self.has_insert_option_id() { + match self.one_of_insert_option_id.take() { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } + + // string delete_option_id = 5; + + + pub fn get_delete_option_id(&self) -> &str { + match self.one_of_delete_option_id { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(ref v)) => v, + _ => "", + } + } + pub fn clear_delete_option_id(&mut self) { + self.one_of_delete_option_id = ::std::option::Option::None; + } + + pub fn has_delete_option_id(&self) -> bool { + match self.one_of_delete_option_id { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_delete_option_id(&mut self, v: ::std::string::String) { + self.one_of_delete_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(v)) + } + + // Mutable pointer to the field. + pub fn mut_delete_option_id(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(_)) = self.one_of_delete_option_id { + } else { + self.one_of_delete_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(::std::string::String::new())); + } + match self.one_of_delete_option_id { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_delete_option_id(&mut self) -> ::std::string::String { + if self.has_delete_option_id() { + match self.one_of_delete_option_id.take() { + ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } +} + +impl ::protobuf::Message for SelectOptionCellChangesetPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_insert_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(is.read_string()?)); + }, + 5 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_delete_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(is.read_string()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.row_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.row_id); + } + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.field_id); + } + if let ::std::option::Option::Some(ref v) = self.one_of_insert_option_id { + match v { + &SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(ref v) => { + my_size += ::protobuf::rt::string_size(4, &v); + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_delete_option_id { + match v { + &SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(ref v) => { + my_size += ::protobuf::rt::string_size(5, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.row_id.is_empty() { + os.write_string(2, &self.row_id)?; + } + if !self.field_id.is_empty() { + os.write_string(3, &self.field_id)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_insert_option_id { + match v { + &SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(ref v) => { + os.write_string(4, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_delete_option_id { + match v { + &SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(ref v) => { + os.write_string(5, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> SelectOptionCellChangesetPayload { + SelectOptionCellChangesetPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &SelectOptionCellChangesetPayload| { &m.grid_id }, + |m: &mut SelectOptionCellChangesetPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "row_id", + |m: &SelectOptionCellChangesetPayload| { &m.row_id }, + |m: &mut SelectOptionCellChangesetPayload| { &mut m.row_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &SelectOptionCellChangesetPayload| { &m.field_id }, + |m: &mut SelectOptionCellChangesetPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "insert_option_id", + SelectOptionCellChangesetPayload::has_insert_option_id, + SelectOptionCellChangesetPayload::get_insert_option_id, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "delete_option_id", + SelectOptionCellChangesetPayload::has_delete_option_id, + SelectOptionCellChangesetPayload::get_delete_option_id, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "SelectOptionCellChangesetPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static SelectOptionCellChangesetPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(SelectOptionCellChangesetPayload::new) + } +} + +impl ::protobuf::Clear for SelectOptionCellChangesetPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.row_id.clear(); + self.field_id.clear(); + self.one_of_insert_option_id = ::std::option::Option::None; + self.one_of_delete_option_id = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SelectOptionCellChangesetPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SelectOptionCellChangesetPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct SelectOptionContext { + // message fields + pub options: ::protobuf::RepeatedField, + pub select_options: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a SelectOptionContext { + fn default() -> &'a SelectOptionContext { + ::default_instance() + } +} + +impl SelectOptionContext { + pub fn new() -> SelectOptionContext { + ::std::default::Default::default() + } + + // repeated .SelectOption options = 1; + + + pub fn get_options(&self) -> &[SelectOption] { + &self.options + } + pub fn clear_options(&mut self) { + self.options.clear(); + } + + // Param is passed by value, moved + pub fn set_options(&mut self, v: ::protobuf::RepeatedField) { + self.options = v; + } + + // Mutable pointer to the field. + pub fn mut_options(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.options + } + + // Take field + pub fn take_options(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.options, ::protobuf::RepeatedField::new()) + } + + // repeated .SelectOption select_options = 2; + + + pub fn get_select_options(&self) -> &[SelectOption] { + &self.select_options + } + pub fn clear_select_options(&mut self) { + self.select_options.clear(); + } + + // Param is passed by value, moved + pub fn set_select_options(&mut self, v: ::protobuf::RepeatedField) { + self.select_options = v; + } + + // Mutable pointer to the field. + pub fn mut_select_options(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.select_options + } + + // Take field + pub fn take_select_options(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.select_options, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for SelectOptionContext { + fn is_initialized(&self) -> bool { + for v in &self.options { + if !v.is_initialized() { + return false; + } + }; + for v in &self.select_options { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.options)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.select_options)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.options { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.select_options { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.options { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.select_options { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> SelectOptionContext { + SelectOptionContext::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "options", + |m: &SelectOptionContext| { &m.options }, + |m: &mut SelectOptionContext| { &mut m.options }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "select_options", + |m: &SelectOptionContext| { &m.select_options }, + |m: &mut SelectOptionContext| { &mut m.select_options }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "SelectOptionContext", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static SelectOptionContext { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(SelectOptionContext::new) + } +} + +impl ::protobuf::Clear for SelectOptionContext { + fn clear(&mut self) { + self.options.clear(); + self.select_options.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for SelectOptionContext { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for SelectOptionContext { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum SelectOptionColor { + Purple = 0, + Pink = 1, + LightPink = 2, + Orange = 3, + Yellow = 4, + Lime = 5, + Green = 6, + Aqua = 7, + Blue = 8, +} + +impl ::protobuf::ProtobufEnum for SelectOptionColor { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(SelectOptionColor::Purple), + 1 => ::std::option::Option::Some(SelectOptionColor::Pink), + 2 => ::std::option::Option::Some(SelectOptionColor::LightPink), + 3 => ::std::option::Option::Some(SelectOptionColor::Orange), + 4 => ::std::option::Option::Some(SelectOptionColor::Yellow), + 5 => ::std::option::Option::Some(SelectOptionColor::Lime), + 6 => ::std::option::Option::Some(SelectOptionColor::Green), + 7 => ::std::option::Option::Some(SelectOptionColor::Aqua), + 8 => ::std::option::Option::Some(SelectOptionColor::Blue), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [SelectOptionColor] = &[ + SelectOptionColor::Purple, + SelectOptionColor::Pink, + SelectOptionColor::LightPink, + SelectOptionColor::Orange, + SelectOptionColor::Yellow, + SelectOptionColor::Lime, + SelectOptionColor::Green, + SelectOptionColor::Aqua, + SelectOptionColor::Blue, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("SelectOptionColor", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for SelectOptionColor { +} + +impl ::std::default::Default for SelectOptionColor { + fn default() -> Self { + SelectOptionColor::Purple + } +} + +impl ::protobuf::reflect::ProtobufValue for SelectOptionColor { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x1bselection_type_option.proto\x1a\x13cell_entities.proto\"f\n\x16Sin\ + gleSelectTypeOption\x12'\n\x07options\x18\x01\x20\x03(\x0b2\r.SelectOpti\ + onR\x07options\x12#\n\rdisable_color\x18\x02\x20\x01(\x08R\x0cdisableCol\ + or\"e\n\x15MultiSelectTypeOption\x12'\n\x07options\x18\x01\x20\x03(\x0b2\ + \r.SelectOptionR\x07options\x12#\n\rdisable_color\x18\x02\x20\x01(\x08R\ + \x0cdisableColor\"\\\n\x0cSelectOption\x12\x0e\n\x02id\x18\x01\x20\x01(\ + \tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12(\n\x05color\ + \x18\x03\x20\x01(\x0e2\x12.SelectOptionColorR\x05color\"\xc9\x02\n\x1cSe\ + lectOptionChangesetPayload\x12?\n\x0fcell_identifier\x18\x01\x20\x01(\ + \x0b2\x16.CellIdentifierPayloadR\x0ecellIdentifier\x124\n\rinsert_option\ + \x18\x02\x20\x01(\x0b2\r.SelectOptionH\0R\x0cinsertOption\x124\n\rupdate\ + _option\x18\x03\x20\x01(\x0b2\r.SelectOptionH\x01R\x0cupdateOption\x124\ + \n\rdelete_option\x18\x04\x20\x01(\x0b2\r.SelectOptionH\x02R\x0cdeleteOp\ + tionB\x16\n\x14one_of_insert_optionB\x16\n\x14one_of_update_optionB\x16\ + \n\x14one_of_delete_option\"\xfb\x01\n\x20SelectOptionCellChangesetPaylo\ + ad\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_i\ + d\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\ + \x07fieldId\x12*\n\x10insert_option_id\x18\x04\x20\x01(\tH\0R\x0einsertO\ + ptionId\x12*\n\x10delete_option_id\x18\x05\x20\x01(\tH\x01R\x0edeleteOpt\ + ionIdB\x19\n\x17one_of_insert_option_idB\x19\n\x17one_of_delete_option_i\ + d\"t\n\x13SelectOptionContext\x12'\n\x07options\x18\x01\x20\x03(\x0b2\r.\ + SelectOptionR\x07options\x124\n\x0eselect_options\x18\x02\x20\x03(\x0b2\ + \r.SelectOptionR\rselectOptions*y\n\x11SelectOptionColor\x12\n\n\x06Purp\ + le\x10\0\x12\x08\n\x04Pink\x10\x01\x12\r\n\tLightPink\x10\x02\x12\n\n\ + \x06Orange\x10\x03\x12\n\n\x06Yellow\x10\x04\x12\x08\n\x04Lime\x10\x05\ + \x12\t\n\x05Green\x10\x06\x12\x08\n\x04Aqua\x10\x07\x12\x08\n\x04Blue\ + \x10\x08b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/text_type_option.rs new file mode 100644 index 0000000000..febc180e03 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/text_type_option.rs @@ -0,0 +1,200 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `text_type_option.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct RichTextTypeOption { + // message fields + pub format: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RichTextTypeOption { + fn default() -> &'a RichTextTypeOption { + ::default_instance() + } +} + +impl RichTextTypeOption { + pub fn new() -> RichTextTypeOption { + ::std::default::Default::default() + } + + // string format = 1; + + + pub fn get_format(&self) -> &str { + &self.format + } + pub fn clear_format(&mut self) { + self.format.clear(); + } + + // Param is passed by value, moved + pub fn set_format(&mut self, v: ::std::string::String) { + self.format = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_format(&mut self) -> &mut ::std::string::String { + &mut self.format + } + + // Take field + pub fn take_format(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.format, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for RichTextTypeOption { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.format)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.format.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.format); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.format.is_empty() { + os.write_string(1, &self.format)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RichTextTypeOption { + RichTextTypeOption::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "format", + |m: &RichTextTypeOption| { &m.format }, + |m: &mut RichTextTypeOption| { &mut m.format }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RichTextTypeOption", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RichTextTypeOption { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RichTextTypeOption::new) + } +} + +impl ::protobuf::Clear for RichTextTypeOption { + fn clear(&mut self) { + self.format.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RichTextTypeOption { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RichTextTypeOption { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x16text_type_option.proto\",\n\x12RichTextTypeOption\x12\x16\n\x06for\ + mat\x18\x01\x20\x01(\tR\x06formatb\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/cell_entities.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/cell_entities.proto new file mode 100644 index 0000000000..558ed90034 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/cell_entities.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +import "field_entities.proto"; + +message CreateSelectOptionPayload { + FieldIdentifierPayload field_identifier = 1; + string option_name = 2; +} +message CellIdentifierPayload { + string grid_id = 1; + string field_id = 2; + string row_id = 3; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/checkbox_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/checkbox_type_option.proto new file mode 100644 index 0000000000..df721337c7 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/checkbox_type_option.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message CheckboxTypeOption { + bool is_selected = 1; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto new file mode 100644 index 0000000000..9a2899833f --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +enum GridNotification { + Unknown = 0; + DidCreateBlock = 11; + DidUpdateGridRow = 20; + DidUpdateGridField = 21; + DidUpdateRow = 30; + DidUpdateCell = 40; + DidUpdateField = 50; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto new file mode 100644 index 0000000000..6dbc5ae09b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +message DateTypeOption { + DateFormat date_format = 1; + TimeFormat time_format = 2; + bool include_time = 3; +} +enum DateFormat { + Local = 0; + US = 1; + ISO = 2; + Friendly = 3; +} +enum TimeFormat { + TwelveHour = 0; + TwentyFourHour = 1; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto new file mode 100644 index 0000000000..7f45db5761 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +enum GridEvent { + GetGridData = 0; + GetGridBlocks = 1; + GetFields = 10; + UpdateField = 11; + InsertField = 12; + DeleteField = 13; + SwitchToField = 14; + DuplicateField = 15; + GetEditFieldContext = 16; + MoveItem = 17; + NewSelectOption = 30; + GetSelectOptionContext = 31; + UpdateSelectOption = 32; + CreateRow = 50; + GetRow = 51; + DeleteRow = 52; + DuplicateRow = 53; + GetCell = 70; + UpdateCell = 71; + UpdateCellSelectOption = 72; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/field_entities.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/field_entities.proto new file mode 100644 index 0000000000..3c670c50af --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/field_entities.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; + +message FieldIdentifierPayload { + string field_id = 1; + string grid_id = 2; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/number_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/number_type_option.proto new file mode 100644 index 0000000000..8057b0c4a6 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/number_type_option.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +message NumberTypeOption { + NumberFormat format = 1; + uint32 scale = 2; + string symbol = 3; + bool sign_positive = 4; + string name = 5; +} +enum NumberFormat { + Number = 0; + USD = 1; + CNY = 2; + EUR = 3; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/row_entities.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/row_entities.proto new file mode 100644 index 0000000000..d09d76e960 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/row_entities.proto @@ -0,0 +1,6 @@ +syntax = "proto3"; + +message RowIdentifierPayload { + string grid_id = 1; + string row_id = 3; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto new file mode 100644 index 0000000000..9940c13e9c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; +import "cell_entities.proto"; + +message SingleSelectTypeOption { + repeated SelectOption options = 1; + bool disable_color = 2; +} +message MultiSelectTypeOption { + repeated SelectOption options = 1; + bool disable_color = 2; +} +message SelectOption { + string id = 1; + string name = 2; + SelectOptionColor color = 3; +} +message SelectOptionChangesetPayload { + CellIdentifierPayload cell_identifier = 1; + oneof one_of_insert_option { SelectOption insert_option = 2; }; + oneof one_of_update_option { SelectOption update_option = 3; }; + oneof one_of_delete_option { SelectOption delete_option = 4; }; +} +message SelectOptionCellChangesetPayload { + string grid_id = 1; + string row_id = 2; + string field_id = 3; + oneof one_of_insert_option_id { string insert_option_id = 4; }; + oneof one_of_delete_option_id { string delete_option_id = 5; }; +} +message SelectOptionContext { + repeated SelectOption options = 1; + repeated SelectOption select_options = 2; +} +enum SelectOptionColor { + Purple = 0; + Pink = 1; + LightPink = 2; + Orange = 3; + Yellow = 4; + Lime = 5; + Green = 6; + Aqua = 7; + Blue = 8; +} diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/text_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/text_type_option.proto new file mode 100644 index 0000000000..67cfb438ea --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/text_type_option.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message RichTextTypeOption { + string format = 1; +} diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs new file mode 100644 index 0000000000..b4d8bccbe5 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs @@ -0,0 +1,194 @@ +use bytes::Bytes; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_grid_data_model::entities::{CellMeta, RowMeta, RowMetaChangeset, RowOrder}; +use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; +use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockMetaPad}; +use flowy_sync::entities::revision::Revision; +use flowy_sync::util::make_delta_from_revisions; +use lib_infra::future::FutureResult; +use lib_ot::core::PlainTextAttributes; +use std::borrow::Cow; + +use std::sync::Arc; +use tokio::sync::RwLock; + +pub struct ClientGridBlockMetaEditor { + user_id: String, + pub block_id: String, + pad: Arc>, + rev_manager: Arc, +} + +impl ClientGridBlockMetaEditor { + pub async fn new( + user_id: &str, + token: &str, + block_id: &str, + mut rev_manager: RevisionManager, + ) -> FlowyResult { + let cloud = Arc::new(GridBlockMetaRevisionCloudService { + token: token.to_owned(), + }); + let block_meta_pad = rev_manager.load::(Some(cloud)).await?; + let pad = Arc::new(RwLock::new(block_meta_pad)); + let rev_manager = Arc::new(rev_manager); + let user_id = user_id.to_owned(); + let block_id = block_id.to_owned(); + Ok(Self { + user_id, + block_id, + pad, + rev_manager, + }) + } + + /// return current number of rows and the inserted index. The inserted index will be None if the start_row_id is None + pub(crate) async fn create_row( + &self, + row: RowMeta, + start_row_id: Option, + ) -> FlowyResult<(i32, Option)> { + let mut row_count = 0; + let mut row_index = None; + let _ = self + .modify(|block_pad| { + if let Some(start_row_id) = start_row_id.as_ref() { + match block_pad.index_of_row(start_row_id) { + None => {} + Some(index) => row_index = Some(index + 1), + } + } + + let change = block_pad.add_row_meta(row, start_row_id)?; + row_count = block_pad.number_of_rows(); + + if row_index.is_none() { + row_index = Some(row_count - 1); + } + Ok(change) + }) + .await?; + + Ok((row_count, row_index)) + } + + pub async fn delete_rows(&self, ids: Vec>) -> FlowyResult { + let mut row_count = 0; + let _ = self + .modify(|block_pad| { + let changeset = block_pad.delete_rows(ids)?; + row_count = block_pad.number_of_rows(); + Ok(changeset) + }) + .await?; + Ok(row_count) + } + + pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { + let _ = self.modify(|block_pad| Ok(block_pad.update_row(changeset)?)).await?; + Ok(()) + } + + pub async fn move_row(&self, row_id: &str, from: usize, to: usize) -> FlowyResult<()> { + let _ = self + .modify(|block_pad| Ok(block_pad.move_row(row_id, from, to)?)) + .await?; + Ok(()) + } + + pub async fn get_row_metas(&self, row_ids: Option>>) -> FlowyResult>> + where + T: AsRef + ToOwned + ?Sized, + { + let row_metas = self.pad.read().await.get_row_metas(row_ids)?; + Ok(row_metas) + } + + pub async fn get_cell_metas( + &self, + field_id: &str, + row_ids: Option>>, + ) -> FlowyResult> { + let cell_metas = self.pad.read().await.get_cell_metas(field_id, row_ids)?; + Ok(cell_metas) + } + + pub async fn get_row_orders(&self, row_ids: Option>>) -> FlowyResult> + where + T: AsRef + ToOwned + ?Sized, + { + let row_orders = self + .pad + .read() + .await + .get_row_metas(row_ids)? + .iter() + .map(RowOrder::from) + .collect::>(); + Ok(row_orders) + } + + async fn modify(&self, f: F) -> FlowyResult<()> + where + F: for<'a> FnOnce(&'a mut GridBlockMetaPad) -> FlowyResult>, + { + let mut write_guard = self.pad.write().await; + match f(&mut *write_guard)? { + None => {} + Some(change) => { + let _ = self.apply_change(change).await?; + } + } + Ok(()) + } + + async fn apply_change(&self, change: GridBlockMetaChange) -> FlowyResult<()> { + let GridBlockMetaChange { delta, md5 } = change; + let user_id = self.user_id.clone(); + let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); + let delta_data = delta.to_delta_bytes(); + let revision = Revision::new( + &self.rev_manager.object_id, + base_rev_id, + rev_id, + delta_data, + &user_id, + md5, + ); + let _ = self + .rev_manager + .add_local_revision(&revision, Box::new(GridBlockMetaRevisionCompactor())) + .await?; + Ok(()) + } +} + +struct GridBlockMetaRevisionCloudService { + #[allow(dead_code)] + token: String, +} + +impl RevisionCloudService for GridBlockMetaRevisionCloudService { + #[tracing::instrument(level = "trace", skip(self))] + fn fetch_object(&self, _user_id: &str, _object_id: &str) -> FutureResult, FlowyError> { + FutureResult::new(async move { Ok(vec![]) }) + } +} + +struct GridBlockMetaPadBuilder(); +impl RevisionObjectBuilder for GridBlockMetaPadBuilder { + type Output = GridBlockMetaPad; + + fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { + let pad = GridBlockMetaPad::from_revisions(object_id, revisions)?; + Ok(pad) + } +} + +struct GridBlockMetaRevisionCompactor(); +impl RevisionCompactor for GridBlockMetaRevisionCompactor { + fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { + let delta = make_delta_from_revisions::(revisions)?; + Ok(delta.to_delta_bytes()) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs new file mode 100644 index 0000000000..5e0927795b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs @@ -0,0 +1,284 @@ +use crate::dart_notification::{send_dart_notification, GridNotification}; +use crate::manager::GridUser; +use crate::services::block_meta_editor::ClientGridBlockMetaEditor; +use crate::services::persistence::block_index::BlockIndexPersistence; +use crate::services::row::{group_row_orders, GridBlockSnapshot}; +use std::borrow::Cow; + +use dashmap::DashMap; +use flowy_error::FlowyResult; +use flowy_grid_data_model::entities::{ + CellChangeset, CellMeta, CellNotificationData, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, + IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder, +}; +use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; +use flowy_revision::{RevisionManager, RevisionPersistence}; +use std::collections::HashMap; +use std::sync::Arc; + +pub(crate) struct GridBlockMetaEditorManager { + grid_id: String, + user: Arc, + // Key: block_id + editor_map: DashMap>, + persistence: Arc, +} + +impl GridBlockMetaEditorManager { + pub(crate) async fn new( + grid_id: &str, + user: &Arc, + blocks: Vec, + persistence: Arc, + ) -> FlowyResult { + let editor_map = make_block_meta_editor_map(user, blocks).await?; + let user = user.clone(); + let grid_id = grid_id.to_owned(); + let manager = Self { + grid_id, + user, + editor_map, + persistence, + }; + Ok(manager) + } + + // #[tracing::instrument(level = "trace", skip(self))] + pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult> { + debug_assert!(!block_id.is_empty()); + match self.editor_map.get(block_id) { + None => { + tracing::error!("The is a fatal error, block is not exist"); + let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?); + self.editor_map.insert(block_id.to_owned(), editor.clone()); + Ok(editor) + } + Some(editor) => Ok(editor.clone()), + } + } + + async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult> { + let block_id = self.persistence.get_block_id(row_id)?; + Ok(self.get_editor(&block_id).await?) + } + + pub(crate) async fn create_row( + &self, + block_id: &str, + row_meta: RowMeta, + start_row_id: Option, + ) -> FlowyResult { + let _ = self.persistence.insert_or_update(&row_meta.block_id, &row_meta.id)?; + let editor = self.get_editor(&row_meta.block_id).await?; + + let mut index_row_order = IndexRowOrder::from(&row_meta); + let (row_count, row_index) = editor.create_row(row_meta, start_row_id).await?; + index_row_order.index = row_index; + + let _ = self + .notify_did_update_block(GridRowsChangeset::insert(block_id, vec![index_row_order])) + .await?; + Ok(row_count) + } + + pub(crate) async fn insert_row( + &self, + rows_by_block_id: HashMap>, + ) -> FlowyResult> { + let mut changesets = vec![]; + for (block_id, row_metas) in rows_by_block_id { + let mut inserted_row_orders = vec![]; + let editor = self.get_editor(&block_id).await?; + let mut row_count = 0; + for row in row_metas { + let _ = self.persistence.insert_or_update(&row.block_id, &row.id)?; + let mut row_order = IndexRowOrder::from(&row); + let (count, index) = editor.create_row(row, None).await?; + row_count = count; + row_order.index = index; + inserted_row_orders.push(row_order); + } + changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count)); + + let _ = self + .notify_did_update_block(GridRowsChangeset::insert(&block_id, inserted_row_orders)) + .await?; + } + + Ok(changesets) + } + + pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { + let editor = self.get_editor_from_row_id(&changeset.row_id).await?; + let _ = editor.update_row(changeset.clone()).await?; + let _ = self.notify_did_update_block_row(&changeset.row_id).await?; + Ok(()) + } + + pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> { + let row_id = row_id.to_owned(); + let block_id = self.persistence.get_block_id(&row_id)?; + let editor = self.get_editor(&block_id).await?; + let row_orders = editor.get_row_orders(Some(vec![Cow::Borrowed(&row_id)])).await?; + let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; + let _ = self + .notify_did_update_block(GridRowsChangeset::delete(&block_id, row_orders)) + .await?; + + Ok(()) + } + + pub(crate) async fn delete_rows(&self, row_orders: Vec) -> FlowyResult> { + let mut changesets = vec![]; + for block_order in group_row_orders(row_orders) { + let editor = self.get_editor(&block_order.block_id).await?; + let row_ids = block_order + .row_orders + .into_iter() + .map(|row_order| Cow::Owned(row_order.row_id)) + .collect::>>(); + let row_count = editor.delete_rows(row_ids).await?; + let changeset = GridBlockMetaChangeset::from_row_count(&block_order.block_id, row_count); + changesets.push(changeset); + } + + Ok(changesets) + } + + pub(crate) async fn move_row(&self, row_id: &str, from: usize, to: usize) -> FlowyResult<()> { + let editor = self.get_editor_from_row_id(row_id).await?; + let _ = editor.move_row(row_id, from, to).await?; + + match editor.get_row_metas(Some(vec![Cow::Borrowed(row_id)])).await?.pop() { + None => {} + Some(row_meta) => { + let row_order = RowOrder::from(&row_meta); + let insert_row = IndexRowOrder { + row_order: row_order.clone(), + index: Some(to as i32), + }; + let notified_changeset = GridRowsChangeset { + block_id: editor.block_id.clone(), + inserted_rows: vec![insert_row], + deleted_rows: vec![row_order], + updated_rows: vec![], + }; + + let _ = self.notify_did_update_block(notified_changeset).await?; + } + } + + Ok(()) + } + + pub async fn update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> { + let row_changeset: RowMetaChangeset = changeset.clone().into(); + let _ = self.update_row(row_changeset).await?; + + let cell_notification_data = CellNotificationData { + grid_id: changeset.grid_id, + field_id: changeset.field_id, + row_id: changeset.row_id, + content: changeset.data, + }; + self.notify_did_update_cell(cell_notification_data).await?; + + Ok(()) + } + + pub async fn get_row_meta(&self, row_id: &str) -> FlowyResult>> { + let editor = self.get_editor_from_row_id(row_id).await?; + let row_ids = vec![Cow::Borrowed(row_id)]; + let mut row_metas = editor.get_row_metas(Some(row_ids)).await?; + if row_metas.is_empty() { + Ok(None) + } else { + Ok(row_metas.pop()) + } + } + + pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { + let editor = self.get_editor(block_id).await?; + editor.get_row_orders::<&str>(None).await + } + + pub(crate) async fn make_block_snapshots(&self, block_ids: Vec) -> FlowyResult> { + let mut snapshots = vec![]; + for block_id in block_ids { + let editor = self.get_editor(&block_id).await?; + let row_metas = editor.get_row_metas::<&str>(None).await?; + snapshots.push(GridBlockSnapshot { block_id, row_metas }); + } + Ok(snapshots) + } + + // Optimization: Using the shared memory(Arc, Cow,etc.) to reduce memory usage. + #[allow(dead_code)] + pub async fn get_cell_metas( + &self, + block_ids: Vec, + field_id: &str, + row_ids: Option>>, + ) -> FlowyResult> { + let mut block_cell_metas = vec![]; + for block_id in block_ids { + let editor = self.get_editor(&block_id).await?; + let cell_metas = editor.get_cell_metas(field_id, row_ids.clone()).await?; + block_cell_metas.extend(cell_metas); + } + Ok(block_cell_metas) + } + + async fn notify_did_update_block_row(&self, row_id: &str) -> FlowyResult<()> { + let editor = self.get_editor_from_row_id(row_id).await?; + let row_ids = Some(vec![Cow::Borrowed(&row_id)]); + match editor.get_row_orders(row_ids).await?.pop() { + None => {} + Some(row_order) => { + let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); + let _ = self.notify_did_update_block(block_order_changeset).await?; + } + } + + Ok(()) + } + + async fn notify_did_update_block(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { + send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridRow) + .payload(changeset) + .send(); + Ok(()) + } + + async fn notify_did_update_cell(&self, data: CellNotificationData) -> FlowyResult<()> { + let id = format!("{}:{}", data.row_id, data.field_id); + send_dart_notification(&id, GridNotification::DidUpdateCell) + .payload(data) + .send(); + Ok(()) + } +} + +async fn make_block_meta_editor_map( + user: &Arc, + blocks: Vec, +) -> FlowyResult>> { + let editor_map = DashMap::new(); + for block in blocks { + let editor = make_block_meta_editor(user, &block.block_id).await?; + editor_map.insert(block.block_id, Arc::new(editor)); + } + + Ok(editor_map) +} + +async fn make_block_meta_editor(user: &Arc, block_id: &str) -> FlowyResult { + let token = user.token()?; + let user_id = user.user_id()?; + let pool = user.db_pool()?; + + let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool)); + let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache)); + let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence); + ClientGridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await +} diff --git a/frontend/rust-lib/flowy-grid/src/services/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/services/entities/cell_entities.rs new file mode 100644 index 0000000000..2f408db992 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/entities/cell_entities.rs @@ -0,0 +1,72 @@ +use crate::services::entities::{FieldIdentifier, FieldIdentifierPayload}; +use flowy_derive::ProtoBuf; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; + +#[derive(ProtoBuf, Default)] +pub struct CreateSelectOptionPayload { + #[pb(index = 1)] + pub field_identifier: FieldIdentifierPayload, + + #[pb(index = 2)] + pub option_name: String, +} + +pub struct CreateSelectOptionParams { + pub field_identifier: FieldIdentifier, + pub option_name: String, +} + +impl std::ops::Deref for CreateSelectOptionParams { + type Target = FieldIdentifier; + + fn deref(&self) -> &Self::Target { + &self.field_identifier + } +} + +impl TryInto for CreateSelectOptionPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let option_name = NotEmptyStr::parse(self.option_name).map_err(|_| ErrorCode::SelectOptionNameIsEmpty)?; + let field_identifier = self.field_identifier.try_into()?; + Ok(CreateSelectOptionParams { + field_identifier, + option_name: option_name.0, + }) + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct CellIdentifierPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub row_id: String, +} + +pub struct CellIdentifier { + pub grid_id: String, + pub field_id: String, + pub row_id: String, +} + +impl TryInto for CellIdentifierPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; + Ok(CellIdentifier { + grid_id: grid_id.0, + field_id: field_id.0, + row_id: row_id.0, + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/services/entities/field_entities.rs new file mode 100644 index 0000000000..553c833fd6 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/entities/field_entities.rs @@ -0,0 +1,30 @@ +use flowy_derive::ProtoBuf; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldIdentifierPayload { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, +} + +pub struct FieldIdentifier { + pub field_id: String, + pub grid_id: String, +} + +impl TryInto for FieldIdentifierPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(FieldIdentifier { + grid_id: grid_id.0, + field_id: field_id.0, + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/entities/mod.rs b/frontend/rust-lib/flowy-grid/src/services/entities/mod.rs new file mode 100644 index 0000000000..61bcf6ebed --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/entities/mod.rs @@ -0,0 +1,7 @@ +mod cell_entities; +mod field_entities; +mod row_entities; + +pub use cell_entities::*; +pub use field_entities::*; +pub use row_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/entities/row_entities.rs b/frontend/rust-lib/flowy-grid/src/services/entities/row_entities.rs new file mode 100644 index 0000000000..c97becbd34 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/entities/row_entities.rs @@ -0,0 +1,31 @@ +use flowy_derive::ProtoBuf; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; + +#[derive(ProtoBuf, Default)] +pub struct RowIdentifierPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 3)] + pub row_id: String, +} + +pub struct RowIdentifier { + pub grid_id: String, + pub row_id: String, +} + +impl TryInto for RowIdentifierPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; + + Ok(RowIdentifier { + grid_id: grid_id.0, + row_id: row_id.0, + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs new file mode 100644 index 0000000000..5eaabb0294 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs @@ -0,0 +1,123 @@ +use crate::services::field::type_options::*; +use bytes::Bytes; +use flowy_grid_data_model::entities::{Field, FieldMeta, FieldType, TypeOptionDataEntry}; +use indexmap::IndexMap; + +pub struct FieldBuilder { + field_meta: FieldMeta, + type_option_builder: Box, +} + +pub type BoxTypeOptionBuilder = Box; + +impl FieldBuilder { + pub fn new>(type_option_builder: T) -> Self { + let type_option_builder = type_option_builder.into(); + let field_meta = FieldMeta::new("", "", type_option_builder.field_type(), false); + Self { + field_meta, + type_option_builder, + } + } + + pub fn from_field_type(field_type: &FieldType) -> Self { + let type_option_builder = default_type_option_builder_from_type(field_type); + Self::new(type_option_builder) + } + + pub fn from_field(field: Field, type_option_builder: Box) -> Self { + let field_meta = FieldMeta { + id: field.id, + name: field.name, + desc: field.desc, + field_type: field.field_type, + frozen: field.frozen, + visibility: field.visibility, + width: field.width, + type_options: IndexMap::default(), + is_primary: field.is_primary, + }; + Self { + field_meta, + type_option_builder, + } + } + + pub fn name(mut self, name: &str) -> Self { + self.field_meta.name = name.to_owned(); + self + } + + pub fn desc(mut self, desc: &str) -> Self { + self.field_meta.desc = desc.to_owned(); + self + } + + pub fn primary(mut self, is_primary: bool) -> Self { + self.field_meta.is_primary = is_primary; + self + } + + pub fn visibility(mut self, visibility: bool) -> Self { + self.field_meta.visibility = visibility; + self + } + + pub fn width(mut self, width: i32) -> Self { + self.field_meta.width = width; + self + } + + pub fn frozen(mut self, frozen: bool) -> Self { + self.field_meta.frozen = frozen; + self + } + + pub fn build(self) -> FieldMeta { + debug_assert_eq!(self.field_meta.field_type, self.type_option_builder.field_type()); + let mut field_meta = self.field_meta; + field_meta.insert_type_option_entry(self.type_option_builder.entry()); + field_meta + } +} + +pub trait TypeOptionBuilder { + fn field_type(&self) -> FieldType; + fn entry(&self) -> &dyn TypeOptionDataEntry; +} + +pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box { + let s: String = match field_type { + FieldType::RichText => RichTextTypeOption::default().into(), + FieldType::Number => NumberTypeOption::default().into(), + FieldType::DateTime => DateTypeOption::default().into(), + FieldType::SingleSelect => SingleSelectTypeOption::default().into(), + FieldType::MultiSelect => MultiSelectTypeOption::default().into(), + FieldType::Checkbox => CheckboxTypeOption::default().into(), + }; + + type_option_builder_from_json_str(&s, field_type) +} + +pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box { + match field_type { + FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_json_str(s)), + FieldType::Number => Box::new(NumberTypeOptionBuilder::from_json_str(s)), + FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_json_str(s)), + FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_json_str(s)), + FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)), + FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)), + } +} + +pub fn type_option_builder_from_bytes>(bytes: T, field_type: &FieldType) -> Box { + let bytes = bytes.into(); + match field_type { + FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_protobuf_bytes(bytes)), + FieldType::Number => Box::new(NumberTypeOptionBuilder::from_protobuf_bytes(bytes)), + FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_protobuf_bytes(bytes)), + FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_protobuf_bytes(bytes)), + FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)), + FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)), + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/mod.rs new file mode 100644 index 0000000000..c1b689fbf4 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/mod.rs @@ -0,0 +1,5 @@ +mod field_builder; +pub(crate) mod type_options; + +pub use field_builder::*; +pub use type_options::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs new file mode 100644 index 0000000000..994e82829a --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -0,0 +1,119 @@ +use crate::impl_type_option; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; +use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use bytes::Bytes; +use flowy_derive::ProtoBuf; +use flowy_error::FlowyError; +use flowy_grid_data_model::entities::{ + CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, +}; + +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +#[derive(Default)] +pub struct CheckboxTypeOptionBuilder(CheckboxTypeOption); +impl_into_box_type_option_builder!(CheckboxTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(CheckboxTypeOptionBuilder, CheckboxTypeOption); + +impl CheckboxTypeOptionBuilder { + pub fn set_selected(mut self, is_selected: bool) -> Self { + self.0.is_selected = is_selected; + self + } +} + +impl TypeOptionBuilder for CheckboxTypeOptionBuilder { + fn field_type(&self) -> FieldType { + self.0.field_type() + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] +pub struct CheckboxTypeOption { + #[pb(index = 1)] + pub is_selected: bool, +} +impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); + +const YES: &str = "Yes"; +const NO: &str = "No"; + +impl CellDataOperation for CheckboxTypeOption { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + if !type_option_cell_data.is_checkbox() { + return String::new(); + } + let cell_data = type_option_cell_data.data; + if cell_data == YES || cell_data == NO { + return cell_data; + } + } + + String::new() + } + + fn apply_changeset>( + &self, + changeset: T, + _cell_meta: Option, + ) -> Result { + let changeset = changeset.into(); + let s = match string_to_bool(&changeset) { + true => YES, + false => NO, + }; + Ok(TypeOptionCellData::new(s, self.field_type()).json()) + } +} + +fn string_to_bool(bool_str: &str) -> bool { + let lower_case_str: &str = &bool_str.to_lowercase(); + match lower_case_str { + "1" => true, + "true" => true, + "yes" => true, + "0" => false, + "false" => false, + "no" => false, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use crate::services::field::type_options::checkbox_type_option::{NO, YES}; + use crate::services::field::CheckboxTypeOption; + use crate::services::field::FieldBuilder; + use crate::services::row::CellDataOperation; + use flowy_grid_data_model::entities::FieldType; + + #[test] + fn checkout_box_description_test() { + let type_option = CheckboxTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + + let data = type_option.apply_changeset("true", None).unwrap(); + assert_eq!(type_option.decode_cell_data(data, &field_meta), YES); + + let data = type_option.apply_changeset("1", None).unwrap(); + assert_eq!(type_option.decode_cell_data(data, &field_meta), YES); + + let data = type_option.apply_changeset("yes", None).unwrap(); + assert_eq!(type_option.decode_cell_data(data, &field_meta), YES); + + let data = type_option.apply_changeset("false", None).unwrap(); + assert_eq!(type_option.decode_cell_data(data, &field_meta), NO); + + let data = type_option.apply_changeset("no", None).unwrap(); + assert_eq!(type_option.decode_cell_data(data, &field_meta), NO); + + let data = type_option.apply_changeset("123", None).unwrap(); + assert_eq!(type_option.decode_cell_data(data, &field_meta), NO); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs new file mode 100644 index 0000000000..81e77f2645 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -0,0 +1,296 @@ +use crate::impl_type_option; +use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use bytes::Bytes; +use chrono::format::strftime::StrftimeItems; +use chrono::NaiveDateTime; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::FlowyError; +use flowy_grid_data_model::entities::{ + CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, +}; + +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; +use strum_macros::EnumIter; + +// Date +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct DateTypeOption { + #[pb(index = 1)] + pub date_format: DateFormat, + + #[pb(index = 2)] + pub time_format: TimeFormat, + + #[pb(index = 3)] + pub include_time: bool, +} +impl_type_option!(DateTypeOption, FieldType::DateTime); + +impl DateTypeOption { + #[allow(dead_code)] + fn today_from_timestamp(&self, timestamp: i64) -> String { + let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); + self.today_from_native(native) + } + + fn today_from_native(&self, naive: chrono::NaiveDateTime) -> String { + let utc: chrono::DateTime = chrono::DateTime::from_utc(naive, chrono::Utc); + let local: chrono::DateTime = chrono::DateTime::from(utc); + let output = format!("{}", local.format_with_items(StrftimeItems::new(&self.fmt_str()))); + output + } + + fn fmt_str(&self) -> String { + if self.include_time { + format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) + } else { + self.date_format.format_str().to_string() + } + } +} + +impl CellDataOperation for DateTypeOption { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + if !type_option_cell_data.is_date() { + return String::new(); + } + + let cell_data = type_option_cell_data.data; + if let Ok(timestamp) = cell_data.parse::() { + let native = NaiveDateTime::from_timestamp(timestamp, 0); + return self.today_from_native(native); + } + + if NaiveDateTime::parse_from_str(&cell_data, &self.fmt_str()).is_ok() { + return cell_data; + } + } + + String::new() + } + + fn apply_changeset>( + &self, + changeset: T, + _cell_meta: Option, + ) -> Result { + let changeset = changeset.into(); + if changeset.parse::().is_err() || changeset.parse::().is_err() { + return Err(FlowyError::internal().context(format!("Parse {} failed", changeset))); + }; + + Ok(TypeOptionCellData::new(changeset, self.field_type()).json()) + } +} + +#[derive(Default)] +pub struct DateTypeOptionBuilder(DateTypeOption); +impl_into_box_type_option_builder!(DateTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(DateTypeOptionBuilder, DateTypeOption); + +impl DateTypeOptionBuilder { + pub fn date_format(mut self, date_format: DateFormat) -> Self { + self.0.date_format = date_format; + self + } + + pub fn time_format(mut self, time_format: TimeFormat) -> Self { + self.0.time_format = time_format; + self + } +} +impl TypeOptionBuilder for DateTypeOptionBuilder { + fn field_type(&self) -> FieldType { + self.0.field_type() + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +#[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)] +pub enum DateFormat { + Local = 0, + US = 1, + ISO = 2, + Friendly = 3, +} +impl std::default::Default for DateFormat { + fn default() -> Self { + DateFormat::Friendly + } +} + +impl std::convert::From for DateFormat { + fn from(value: i32) -> Self { + match value { + 0 => DateFormat::Local, + 1 => DateFormat::US, + 2 => DateFormat::ISO, + 3 => DateFormat::Friendly, + _ => { + tracing::error!("Unsupported date format, fallback to friendly"); + DateFormat::Friendly + } + } + } +} + +impl DateFormat { + pub fn value(&self) -> i32 { + *self as i32 + } + // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html + pub fn format_str(&self) -> &'static str { + match self { + DateFormat::Local => "%Y/%m/%d", + DateFormat::US => "%Y/%m/%d", + DateFormat::ISO => "%Y-%m-%d", + DateFormat::Friendly => "%b %d,%Y", + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, EnumIter, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)] +pub enum TimeFormat { + TwelveHour = 0, + TwentyFourHour = 1, +} + +impl std::convert::From for TimeFormat { + fn from(value: i32) -> Self { + match value { + 0 => TimeFormat::TwelveHour, + 1 => TimeFormat::TwentyFourHour, + _ => { + tracing::error!("Unsupported time format, fallback to TwentyFourHour"); + TimeFormat::TwentyFourHour + } + } + } +} + +impl TimeFormat { + pub fn value(&self) -> i32 { + *self as i32 + } + + // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html + pub fn format_str(&self) -> &'static str { + match self { + TimeFormat::TwelveHour => "%r", + TimeFormat::TwentyFourHour => "%R", + } + } +} + +impl std::default::Default for TimeFormat { + fn default() -> Self { + TimeFormat::TwentyFourHour + } +} + +#[cfg(test)] +mod tests { + use crate::services::field::FieldBuilder; + use crate::services::field::{DateFormat, DateTypeOption, TimeFormat}; + use crate::services::row::{CellDataOperation, TypeOptionCellData}; + use flowy_grid_data_model::entities::FieldType; + use strum::IntoEnumIterator; + + #[test] + fn date_description_invalid_input_test() { + let type_option = DateTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + assert_eq!( + "".to_owned(), + type_option.decode_cell_data("1e".to_owned(), &field_meta) + ); + } + + #[test] + fn date_description_date_format_test() { + let mut type_option = DateTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + for date_format in DateFormat::iter() { + type_option.date_format = date_format; + match date_format { + DateFormat::Friendly => { + assert_eq!( + "Mar 14,2022".to_owned(), + type_option.decode_cell_data(data("1647251762"), &field_meta) + ); + assert_eq!( + // "Mar 14,2022".to_owned(), + "".to_owned(), + type_option.decode_cell_data(data("Mar 14,2022 17:56"), &field_meta) + ); + } + DateFormat::US => { + assert_eq!( + "2022/03/14".to_owned(), + type_option.decode_cell_data(data("1647251762"), &field_meta) + ); + assert_eq!( + // "2022/03/14".to_owned(), + "".to_owned(), + type_option.decode_cell_data(data("2022/03/14 17:56"), &field_meta) + ); + } + DateFormat::ISO => { + assert_eq!( + "2022-03-14".to_owned(), + type_option.decode_cell_data(data("1647251762"), &field_meta) + ); + } + DateFormat::Local => { + assert_eq!( + "2022/03/14".to_owned(), + type_option.decode_cell_data(data("1647251762"), &field_meta) + ); + } + } + } + } + + #[test] + fn date_description_time_format_test() { + let mut type_option = DateTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + for time_format in TimeFormat::iter() { + type_option.time_format = time_format; + match time_format { + TimeFormat::TwentyFourHour => { + assert_eq!("Mar 14,2022".to_owned(), type_option.today_from_timestamp(1647251762)); + assert_eq!( + "Mar 14,2022".to_owned(), + type_option.decode_cell_data(data("1647251762"), &field_meta) + ); + } + TimeFormat::TwelveHour => { + assert_eq!("Mar 14,2022".to_owned(), type_option.today_from_timestamp(1647251762)); + assert_eq!( + "Mar 14,2022".to_owned(), + type_option.decode_cell_data(data("1647251762"), &field_meta) + ); + } + } + } + } + + #[test] + #[should_panic] + fn date_description_invalid_data_test() { + let type_option = DateTypeOption::default(); + type_option.apply_changeset("he", None).unwrap(); + } + + fn data(s: &str) -> String { + TypeOptionCellData::new(s, FieldType::DateTime).json() + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs new file mode 100644 index 0000000000..b5cab79b97 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs @@ -0,0 +1,12 @@ +mod checkbox_type_option; +mod date_type_option; +mod number_type_option; +mod selection_type_option; +mod text_type_option; +mod type_option_data; + +pub use checkbox_type_option::*; +pub use date_type_option::*; +pub use number_type_option::*; +pub use selection_type_option::*; +pub use text_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs new file mode 100644 index 0000000000..6f3cec4341 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs @@ -0,0 +1,350 @@ +use crate::impl_type_option; +use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::FlowyError; +use flowy_grid_data_model::entities::{ + CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, +}; + +use lazy_static::lazy_static; + +use rust_decimal::Decimal; +use rusty_money::iso::{Currency, CNY, EUR, USD}; +use serde::{Deserialize, Serialize}; + +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; +use bytes::Bytes; +use std::str::FromStr; +use strum::IntoEnumIterator; +use strum_macros::EnumIter; + +lazy_static! { + static ref STRIP_SYMBOL: Vec = make_strip_symbol(); +} + +#[derive(Default)] +pub struct NumberTypeOptionBuilder(NumberTypeOption); +impl_into_box_type_option_builder!(NumberTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(NumberTypeOptionBuilder, NumberTypeOption); + +impl NumberTypeOptionBuilder { + pub fn name(mut self, name: &str) -> Self { + self.0.name = name.to_string(); + self + } + + pub fn set_format(mut self, format: NumberFormat) -> Self { + self.0.set_format(format); + self + } + + pub fn scale(mut self, scale: u32) -> Self { + self.0.scale = scale; + self + } + + pub fn positive(mut self, positive: bool) -> Self { + self.0.sign_positive = positive; + self + } +} + +impl TypeOptionBuilder for NumberTypeOptionBuilder { + fn field_type(&self) -> FieldType { + self.0.field_type() + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +// Number +#[derive(Clone, Debug, Serialize, Deserialize, ProtoBuf)] +pub struct NumberTypeOption { + #[pb(index = 1)] + pub format: NumberFormat, + + #[pb(index = 2)] + pub scale: u32, + + #[pb(index = 3)] + pub symbol: String, + + #[pb(index = 4)] + pub sign_positive: bool, + + #[pb(index = 5)] + pub name: String, +} +impl_type_option!(NumberTypeOption, FieldType::Number); + +impl CellDataOperation for NumberTypeOption { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + if type_option_cell_data.is_date() { + return String::new(); + } + + let cell_data = type_option_cell_data.data; + match self.format { + NumberFormat::Number => { + if cell_data.parse::().is_ok() { + cell_data + } else { + String::new() + } + } + NumberFormat::USD => self.money_from_str(&cell_data, USD), + NumberFormat::CNY => self.money_from_str(&cell_data, CNY), + NumberFormat::EUR => self.money_from_str(&cell_data, EUR), + } + } else { + String::new() + } + } + + fn apply_changeset>( + &self, + changeset: T, + _cell_meta: Option, + ) -> Result { + let changeset = changeset.into(); + let data = self.strip_symbol(changeset); + + if !data.chars().all(char::is_numeric) { + return Err(FlowyError::invalid_data().context("Should only contain numbers")); + } + + Ok(TypeOptionCellData::new(&data, self.field_type()).json()) + } +} + +impl std::default::Default for NumberTypeOption { + fn default() -> Self { + let format = NumberFormat::default(); + let symbol = format.symbol(); + NumberTypeOption { + format, + scale: 0, + symbol, + sign_positive: true, + name: "Number".to_string(), + } + } +} + +impl NumberTypeOption { + pub fn set_format(&mut self, format: NumberFormat) { + self.format = format; + self.symbol = format.symbol(); + } + + fn money_from_str(&self, s: &str, currency: &'static Currency) -> String { + match Decimal::from_str(s) { + Ok(mut decimal) => { + match decimal.set_scale(self.scale) { + Ok(_) => {} + Err(e) => { + tracing::error!("Set decimal scale failed: {:?}", e); + } + } + decimal.set_sign_positive(self.sign_positive); + let money = rusty_money::Money::from_decimal(decimal, currency); + money.to_string() + } + Err(_) => String::new(), + } + } + + fn strip_symbol(&self, s: T) -> String { + let mut s = s.to_string(); + if !s.chars().all(char::is_numeric) { + s.retain(|c| !STRIP_SYMBOL.contains(&c.to_string())); + } + s + } +} + +#[derive(Clone, Copy, Debug, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)] +pub enum NumberFormat { + Number = 0, + USD = 1, + CNY = 2, + EUR = 3, +} + +impl std::default::Default for NumberFormat { + fn default() -> Self { + NumberFormat::Number + } +} + +impl NumberFormat { + pub fn symbol(&self) -> String { + match self { + NumberFormat::Number => "".to_string(), + NumberFormat::USD => USD.symbol.to_string(), + NumberFormat::CNY => CNY.symbol.to_string(), + NumberFormat::EUR => EUR.symbol.to_string(), + } + } + + #[allow(dead_code)] + pub fn code(&self) -> String { + match self { + NumberFormat::Number => "".to_string(), + NumberFormat::USD => USD.iso_alpha_code.to_string(), + NumberFormat::CNY => CNY.iso_alpha_code.to_string(), + NumberFormat::EUR => EUR.iso_alpha_code.to_string(), + } + } +} + +fn make_strip_symbol() -> Vec { + let mut symbols = vec![",".to_owned(), ".".to_owned()]; + for format in NumberFormat::iter() { + symbols.push(format.symbol()); + } + symbols +} + +#[cfg(test)] +mod tests { + use crate::services::field::FieldBuilder; + use crate::services::field::{NumberFormat, NumberTypeOption}; + use crate::services::row::{CellDataOperation, TypeOptionCellData}; + use flowy_grid_data_model::entities::FieldType; + use strum::IntoEnumIterator; + + #[test] + fn number_description_invalid_input_test() { + let type_option = NumberTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + assert_eq!("".to_owned(), type_option.decode_cell_data(data(""), &field_meta)); + assert_eq!("".to_owned(), type_option.decode_cell_data(data("abc"), &field_meta)); + } + + #[test] + fn number_description_test() { + let mut type_option = NumberTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + assert_eq!(type_option.strip_symbol("¥18,443"), "18443".to_owned()); + assert_eq!(type_option.strip_symbol("$18,443"), "18443".to_owned()); + assert_eq!(type_option.strip_symbol("€18.443"), "18443".to_owned()); + + for format in NumberFormat::iter() { + type_option.format = format; + match format { + NumberFormat::Number => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "18443".to_owned() + ); + } + NumberFormat::USD => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "$18,443".to_owned() + ); + assert_eq!(type_option.decode_cell_data(data(""), &field_meta), "".to_owned()); + assert_eq!(type_option.decode_cell_data(data("abc"), &field_meta), "".to_owned()); + } + NumberFormat::CNY => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "¥18,443".to_owned() + ); + } + NumberFormat::EUR => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "€18.443".to_owned() + ); + } + } + } + } + + fn data(s: &str) -> String { + TypeOptionCellData::new(s, FieldType::Number).json() + } + + #[test] + fn number_description_scale_test() { + let mut type_option = NumberTypeOption { + scale: 1, + ..Default::default() + }; + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + + for format in NumberFormat::iter() { + type_option.format = format; + match format { + NumberFormat::Number => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "18443".to_owned() + ); + } + NumberFormat::USD => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "$1,844.3".to_owned() + ); + } + NumberFormat::CNY => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "¥1,844.3".to_owned() + ); + } + NumberFormat::EUR => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "€1.844,3".to_owned() + ); + } + } + } + } + + #[test] + fn number_description_sign_test() { + let mut type_option = NumberTypeOption { + sign_positive: false, + ..Default::default() + }; + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + + for format in NumberFormat::iter() { + type_option.format = format; + match format { + NumberFormat::Number => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "18443".to_owned() + ); + } + NumberFormat::USD => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "-$18,443".to_owned() + ); + } + NumberFormat::CNY => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "-¥18,443".to_owned() + ); + } + NumberFormat::EUR => { + assert_eq!( + type_option.decode_cell_data(data("18443"), &field_meta), + "-€18.443".to_owned() + ); + } + } + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs new file mode 100644 index 0000000000..ecaf2344b8 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs @@ -0,0 +1,606 @@ +use crate::impl_type_option; +use crate::services::entities::{CellIdentifier, CellIdentifierPayload}; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; +use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use bytes::Bytes; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_grid_data_model::entities::{ + CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, +}; +use flowy_grid_data_model::parser::NotEmptyStr; +use nanoid::nanoid; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +pub const SELECTION_IDS_SEPARATOR: &str = ","; + +pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { + fn insert_option(&mut self, new_option: SelectOption) { + let options = self.mut_options(); + if let Some(index) = options + .iter() + .position(|option| option.id == new_option.id || option.name == new_option.name) + { + options.remove(index); + options.insert(index, new_option); + } else { + options.insert(0, new_option); + } + } + + fn delete_option(&mut self, delete_option: SelectOption) { + let options = self.mut_options(); + if let Some(index) = options.iter().position(|option| option.id == delete_option.id) { + options.remove(index); + } + } + + fn create_option(&self, name: &str) -> SelectOption { + let color = select_option_color_from_index(self.options().len()); + SelectOption::with_color(name, color) + } + + fn option_context(&self, cell_meta: &Option) -> SelectOptionContext; + + fn options(&self) -> &Vec; + + fn mut_options(&mut self) -> &mut Vec; +} + +pub fn select_option_operation(field_meta: &FieldMeta) -> FlowyResult> { + match &field_meta.field_type { + FieldType::SingleSelect => { + let type_option = SingleSelectTypeOption::from(field_meta); + Ok(Box::new(type_option)) + } + FieldType::MultiSelect => { + let type_option = MultiSelectTypeOption::from(field_meta); + Ok(Box::new(type_option)) + } + ty => { + tracing::error!("Unsupported field type: {:?} for this handler", ty); + Err(ErrorCode::FieldInvalidOperation.into()) + } + } +} + +// Single select +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct SingleSelectTypeOption { + #[pb(index = 1)] + pub options: Vec, + + #[pb(index = 2)] + pub disable_color: bool, +} +impl_type_option!(SingleSelectTypeOption, FieldType::SingleSelect); + +impl SelectOptionOperation for SingleSelectTypeOption { + fn option_context(&self, cell_meta: &Option) -> SelectOptionContext { + let select_options = make_select_context_from(cell_meta, &self.options); + SelectOptionContext { + options: self.options.clone(), + select_options, + } + } + + fn options(&self) -> &Vec { + &self.options + } + + fn mut_options(&mut self) -> &mut Vec { + &mut self.options + } +} + +impl CellDataOperation for SingleSelectTypeOption { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + if !type_option_cell_data.is_single_select() { + return String::new(); + } + + match select_option_ids(type_option_cell_data.data).first() { + None => String::new(), + Some(option_id) => match self.options.iter().find(|option| &option.id == option_id) { + None => String::new(), + Some(option) => option.name.clone(), + }, + } + } else { + String::new() + } + } + + fn apply_changeset>( + &self, + changeset: T, + _cell_meta: Option, + ) -> Result { + let changeset = changeset.into(); + let select_option_changeset: SelectOptionCellChangeset = serde_json::from_str(&changeset)?; + let new_cell_data: String; + if let Some(insert_option_id) = select_option_changeset.insert_option_id { + tracing::trace!("Insert single select option: {}", &insert_option_id); + new_cell_data = insert_option_id; + } else { + tracing::trace!("Delete single select option"); + new_cell_data = "".to_string() + } + + Ok(TypeOptionCellData::new(&new_cell_data, self.field_type()).json()) + } +} + +#[derive(Default)] +pub struct SingleSelectTypeOptionBuilder(SingleSelectTypeOption); +impl_into_box_type_option_builder!(SingleSelectTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(SingleSelectTypeOptionBuilder, SingleSelectTypeOption); + +impl SingleSelectTypeOptionBuilder { + pub fn option(mut self, opt: SelectOption) -> Self { + self.0.options.push(opt); + self + } +} + +impl TypeOptionBuilder for SingleSelectTypeOptionBuilder { + fn field_type(&self) -> FieldType { + self.0.field_type() + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +// Multiple select +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct MultiSelectTypeOption { + #[pb(index = 1)] + pub options: Vec, + + #[pb(index = 2)] + pub disable_color: bool, +} +impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect); + +impl MultiSelectTypeOption { + pub fn get_cell_data(&self, cell_meta: &CellMeta) -> String { + match TypeOptionCellData::from_str(&cell_meta.data) { + Ok(type_option) => type_option.data, + Err(_) => String::new(), + } + } +} + +impl SelectOptionOperation for MultiSelectTypeOption { + fn option_context(&self, cell_meta: &Option) -> SelectOptionContext { + let select_options = make_select_context_from(cell_meta, &self.options); + SelectOptionContext { + options: self.options.clone(), + select_options, + } + } + + fn options(&self) -> &Vec { + &self.options + } + + fn mut_options(&mut self) -> &mut Vec { + &mut self.options + } +} + +impl CellDataOperation for MultiSelectTypeOption { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + if !type_option_cell_data.is_multi_select() { + return String::new(); + } + let option_ids = select_option_ids(type_option_cell_data.data); + self.options + .iter() + .filter(|option| option_ids.contains(&option.id)) + .map(|option| option.name.clone()) + .collect::>() + .join(SELECTION_IDS_SEPARATOR) + } else { + String::new() + } + } + + fn apply_changeset>( + &self, + changeset: T, + cell_meta: Option, + ) -> Result { + let changeset = changeset.into(); + let select_option_changeset: SelectOptionCellChangeset = serde_json::from_str(&changeset)?; + let new_cell_data: String; + match cell_meta { + None => { + new_cell_data = select_option_changeset + .insert_option_id + .unwrap_or_else(|| "".to_owned()); + } + Some(cell_meta) => { + let cell_data = self.get_cell_data(&cell_meta); + let mut selected_options = select_option_ids(cell_data); + if let Some(insert_option_id) = select_option_changeset.insert_option_id { + tracing::trace!("Insert multi select option: {}", &insert_option_id); + if selected_options.contains(&insert_option_id) { + selected_options.retain(|id| id != &insert_option_id); + } else { + selected_options.push(insert_option_id); + } + } + + if let Some(delete_option_id) = select_option_changeset.delete_option_id { + tracing::trace!("Delete multi select option: {}", &delete_option_id); + selected_options.retain(|id| id != &delete_option_id); + } + + new_cell_data = selected_options.join(SELECTION_IDS_SEPARATOR); + tracing::trace!("Multi select cell data: {}", &new_cell_data); + } + } + + Ok(TypeOptionCellData::new(&new_cell_data, self.field_type()).json()) + } +} + +#[derive(Default)] +pub struct MultiSelectTypeOptionBuilder(MultiSelectTypeOption); +impl_into_box_type_option_builder!(MultiSelectTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(MultiSelectTypeOptionBuilder, MultiSelectTypeOption); +impl MultiSelectTypeOptionBuilder { + pub fn option(mut self, opt: SelectOption) -> Self { + self.0.options.push(opt); + self + } +} + +impl TypeOptionBuilder for MultiSelectTypeOptionBuilder { + fn field_type(&self) -> FieldType { + self.0.field_type() + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +fn select_option_ids(data: String) -> Vec { + data.split(SELECTION_IDS_SEPARATOR) + .map(|id| id.to_string()) + .collect::>() +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct SelectOption { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub name: String, + + #[pb(index = 3)] + pub color: SelectOptionColor, +} + +impl SelectOption { + pub fn new(name: &str) -> Self { + SelectOption { + id: nanoid!(4), + name: name.to_owned(), + color: SelectOptionColor::default(), + } + } + + pub fn with_color(name: &str, color: SelectOptionColor) -> Self { + SelectOption { + id: nanoid!(4), + name: name.to_owned(), + color, + } + } +} + +#[derive(Clone, Debug, Default, ProtoBuf)] +pub struct SelectOptionChangesetPayload { + #[pb(index = 1)] + pub cell_identifier: CellIdentifierPayload, + + #[pb(index = 2, one_of)] + pub insert_option: Option, + + #[pb(index = 3, one_of)] + pub update_option: Option, + + #[pb(index = 4, one_of)] + pub delete_option: Option, +} + +pub struct SelectOptionChangeset { + pub cell_identifier: CellIdentifier, + pub insert_option: Option, + pub update_option: Option, + pub delete_option: Option, +} + +impl TryInto for SelectOptionChangesetPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let cell_identifier = self.cell_identifier.try_into()?; + Ok(SelectOptionChangeset { + cell_identifier, + insert_option: self.insert_option, + update_option: self.update_option, + delete_option: self.delete_option, + }) + } +} + +#[derive(Clone, Debug, Default, ProtoBuf)] +pub struct SelectOptionCellChangesetPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub row_id: String, + + #[pb(index = 3)] + pub field_id: String, + + #[pb(index = 4, one_of)] + pub insert_option_id: Option, + + #[pb(index = 5, one_of)] + pub delete_option_id: Option, +} + +pub struct SelectOptionCellChangesetParams { + pub grid_id: String, + pub field_id: String, + pub row_id: String, + pub insert_option_id: Option, + + pub delete_option_id: Option, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct SelectOptionCellChangeset { + pub insert_option_id: Option, + pub delete_option_id: Option, +} + +impl SelectOptionCellChangeset { + pub fn from_insert(option_id: &str) -> Self { + SelectOptionCellChangeset { + insert_option_id: Some(option_id.to_string()), + delete_option_id: None, + } + } + + pub fn from_delete(option_id: &str) -> Self { + SelectOptionCellChangeset { + insert_option_id: None, + delete_option_id: Some(option_id.to_string()), + } + } + + pub fn cell_data(&self) -> String { + serde_json::to_string(self).unwrap() + } +} + +impl std::convert::From for CellChangeset { + fn from(params: SelectOptionCellChangesetParams) -> Self { + let changeset = SelectOptionCellChangeset { + insert_option_id: params.insert_option_id, + delete_option_id: params.delete_option_id, + }; + let s = serde_json::to_string(&changeset).unwrap(); + CellChangeset { + grid_id: params.grid_id, + row_id: params.row_id, + field_id: params.field_id, + data: Some(s), + } + } +} + +impl TryInto for SelectOptionCellChangesetPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + let insert_option_id = match self.insert_option_id { + None => None, + Some(insert_option_id) => Some( + NotEmptyStr::parse(insert_option_id) + .map_err(|_| ErrorCode::OptionIdIsEmpty)? + .0, + ), + }; + + let delete_option_id = match self.delete_option_id { + None => None, + Some(delete_option_id) => Some( + NotEmptyStr::parse(delete_option_id) + .map_err(|_| ErrorCode::OptionIdIsEmpty)? + .0, + ), + }; + + Ok(SelectOptionCellChangesetParams { + grid_id: grid_id.0, + row_id: row_id.0, + field_id: field_id.0, + insert_option_id, + delete_option_id, + }) + } +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct SelectOptionContext { + #[pb(index = 1)] + pub options: Vec, + + #[pb(index = 2)] + pub select_options: Vec, +} + +#[derive(ProtoBuf_Enum, Serialize, Deserialize, Debug, Clone)] +#[repr(u8)] +pub enum SelectOptionColor { + Purple = 0, + Pink = 1, + LightPink = 2, + Orange = 3, + Yellow = 4, + Lime = 5, + Green = 6, + Aqua = 7, + Blue = 8, +} + +pub fn select_option_color_from_index(index: usize) -> SelectOptionColor { + match index % 8 { + 0 => SelectOptionColor::Purple, + 1 => SelectOptionColor::Pink, + 2 => SelectOptionColor::LightPink, + 3 => SelectOptionColor::Orange, + 4 => SelectOptionColor::Yellow, + 5 => SelectOptionColor::Lime, + 6 => SelectOptionColor::Green, + 7 => SelectOptionColor::Aqua, + 8 => SelectOptionColor::Blue, + _ => SelectOptionColor::Purple, + } +} + +impl std::default::Default for SelectOptionColor { + fn default() -> Self { + SelectOptionColor::Purple + } +} + +fn make_select_context_from(cell_meta: &Option, options: &[SelectOption]) -> Vec { + match cell_meta { + None => vec![], + Some(cell_meta) => { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&cell_meta.data) { + select_option_ids(type_option_cell_data.data) + .into_iter() + .flat_map(|option_id| options.iter().find(|option| option.id == option_id).cloned()) + .collect() + } else { + vec![] + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::services::field::FieldBuilder; + use crate::services::field::{ + MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellChangeset, + SingleSelectTypeOption, SingleSelectTypeOptionBuilder, SELECTION_IDS_SEPARATOR, + }; + use crate::services::row::CellDataOperation; + + #[test] + fn single_select_test() { + let google_option = SelectOption::new("Google"); + let facebook_option = SelectOption::new("Facebook"); + let twitter_option = SelectOption::new("Twitter"); + let single_select = SingleSelectTypeOptionBuilder::default() + .option(google_option.clone()) + .option(facebook_option.clone()) + .option(twitter_option); + + let field_meta = FieldBuilder::new(single_select) + .name("Platform") + .visibility(true) + .build(); + + let type_option = SingleSelectTypeOption::from(&field_meta); + + let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR); + let data = SelectOptionCellChangeset::from_insert(&option_ids).cell_data(); + let cell_data = type_option.apply_changeset(data, None).unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,); + + let data = SelectOptionCellChangeset::from_insert(&google_option.id).cell_data(); + let cell_data = type_option.apply_changeset(data, None).unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,); + + // Invalid option id + let cell_data = type_option + .apply_changeset(SelectOptionCellChangeset::from_insert("").cell_data(), None) + .unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + + // Invalid option id + let cell_data = type_option + .apply_changeset(SelectOptionCellChangeset::from_insert("123").cell_data(), None) + .unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + + // Invalid changeset + assert!(type_option.apply_changeset("123", None).is_err()); + } + + #[test] + fn multi_select_test() { + let google_option = SelectOption::new("Google"); + let facebook_option = SelectOption::new("Facebook"); + let twitter_option = SelectOption::new("Twitter"); + let multi_select = MultiSelectTypeOptionBuilder::default() + .option(google_option.clone()) + .option(facebook_option.clone()) + .option(twitter_option); + + let field_meta = FieldBuilder::new(multi_select) + .name("Platform") + .visibility(true) + .build(); + + let type_option = MultiSelectTypeOption::from(&field_meta); + + let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); + let data = SelectOptionCellChangeset::from_insert(&option_ids).cell_data(); + let cell_data = type_option.apply_changeset(data, None).unwrap(); + assert_eq!( + type_option.decode_cell_data(cell_data, &field_meta), + vec![google_option.name.clone(), facebook_option.name].join(SELECTION_IDS_SEPARATOR), + ); + + let data = SelectOptionCellChangeset::from_insert(&google_option.id).cell_data(); + let cell_data = type_option.apply_changeset(data, None).unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,); + + // Invalid option id + let cell_data = type_option + .apply_changeset(SelectOptionCellChangeset::from_insert("").cell_data(), None) + .unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + + // Invalid option id + let cell_data = type_option + .apply_changeset(SelectOptionCellChangeset::from_insert("123,456").cell_data(), None) + .unwrap(); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + + // Invalid changeset + assert!(type_option.apply_changeset("123", None).is_err()); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs new file mode 100644 index 0000000000..08e61a57e9 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -0,0 +1,121 @@ +use crate::impl_type_option; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; +use crate::services::row::{decode_cell_data, CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use bytes::Bytes; +use flowy_derive::ProtoBuf; +use flowy_error::FlowyError; +use flowy_grid_data_model::entities::{ + CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, +}; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +#[derive(Default)] +pub struct RichTextTypeOptionBuilder(RichTextTypeOption); +impl_into_box_type_option_builder!(RichTextTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(RichTextTypeOptionBuilder, RichTextTypeOption); + +impl TypeOptionBuilder for RichTextTypeOptionBuilder { + fn field_type(&self) -> FieldType { + self.0.field_type() + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)] +pub struct RichTextTypeOption { + #[pb(index = 1)] + pub format: String, +} +impl_type_option!(RichTextTypeOption, FieldType::RichText); + +impl CellDataOperation for RichTextTypeOption { + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> String { + if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + if type_option_cell_data.is_date() + || type_option_cell_data.is_single_select() + || type_option_cell_data.is_multi_select() + || type_option_cell_data.is_number() + { + decode_cell_data(data, field_meta, &type_option_cell_data.field_type).unwrap_or_else(|| "".to_owned()) + } else { + type_option_cell_data.data + } + } else { + String::new() + } + } + + fn apply_changeset>( + &self, + changeset: T, + _cell_meta: Option, + ) -> Result { + let data = changeset.into(); + if data.len() > 10000 { + Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000")) + } else { + Ok(TypeOptionCellData::new(&data, self.field_type()).json()) + } + } +} + +#[cfg(test)] +mod tests { + use crate::services::field::FieldBuilder; + use crate::services::field::*; + use crate::services::row::{CellDataOperation, TypeOptionCellData}; + use flowy_grid_data_model::entities::FieldType; + + #[test] + fn text_description_test() { + let type_option = RichTextTypeOption::default(); + + // date + let date_time_field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + let data = TypeOptionCellData::new("1647251762", FieldType::DateTime).json(); + assert_eq!( + type_option.decode_cell_data(data, &date_time_field_meta), + "Mar 14,2022".to_owned() + ); + + // Single select + let done_option = SelectOption::new("Done"); + let done_option_id = done_option.id.clone(); + let single_select = SingleSelectTypeOptionBuilder::default().option(done_option); + let single_select_field_meta = FieldBuilder::new(single_select).build(); + let cell_data = TypeOptionCellData::new(&done_option_id, FieldType::SingleSelect).json(); + assert_eq!( + type_option.decode_cell_data(cell_data, &single_select_field_meta), + "Done".to_owned() + ); + + // Multiple select + let google_option = SelectOption::new("Google"); + let facebook_option = SelectOption::new("Facebook"); + let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); + let cell_data_changeset = SelectOptionCellChangeset::from_insert(&ids).cell_data(); + let multi_select = MultiSelectTypeOptionBuilder::default() + .option(google_option) + .option(facebook_option); + let multi_select_field_meta = FieldBuilder::new(multi_select).build(); + let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_meta); + let cell_data = multi_type_option.apply_changeset(cell_data_changeset, None).unwrap(); + assert_eq!( + type_option.decode_cell_data(cell_data, &multi_select_field_meta), + "Google,Facebook".to_owned() + ); + + //Number + let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); + let number_field_meta = FieldBuilder::new(number).build(); + let data = TypeOptionCellData::new("18443", FieldType::Number).json(); + assert_eq!( + type_option.decode_cell_data(data, &number_field_meta), + "$18,443".to_owned() + ); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs @@ -0,0 +1 @@ + diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs new file mode 100644 index 0000000000..8f30c0a7cd --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -0,0 +1,549 @@ +use crate::dart_notification::{send_dart_notification, GridNotification}; +use crate::manager::GridUser; +use crate::services::block_meta_manager::GridBlockMetaEditorManager; +use crate::services::entities::CellIdentifier; +use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; +use crate::services::persistence::block_index::BlockIndexPersistence; +use crate::services::row::*; +use bytes::Bytes; +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_grid_data_model::entities::*; +use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; +use flowy_sync::client_grid::{GridChangeset, GridMetaPad, JsonDeserializer}; +use flowy_sync::entities::revision::Revision; +use flowy_sync::errors::CollaborateResult; +use flowy_sync::util::make_delta_from_revisions; +use lib_infra::future::FutureResult; +use lib_ot::core::PlainTextAttributes; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub struct ClientGridEditor { + grid_id: String, + user: Arc, + grid_pad: Arc>, + rev_manager: Arc, + block_meta_manager: Arc, +} + +impl ClientGridEditor { + pub async fn new( + grid_id: &str, + user: Arc, + mut rev_manager: RevisionManager, + persistence: Arc, + ) -> FlowyResult> { + let token = user.token()?; + let cloud = Arc::new(GridRevisionCloudService { token }); + let grid_pad = rev_manager.load::(Some(cloud)).await?; + let rev_manager = Arc::new(rev_manager); + let grid_pad = Arc::new(RwLock::new(grid_pad)); + let blocks = grid_pad.read().await.get_block_metas(); + + let block_meta_manager = Arc::new(GridBlockMetaEditorManager::new(grid_id, &user, blocks, persistence).await?); + Ok(Arc::new(Self { + grid_id: grid_id.to_owned(), + user, + grid_pad, + rev_manager, + block_meta_manager, + })) + } + + pub async fn insert_field(&self, params: InsertFieldParams) -> FlowyResult<()> { + let InsertFieldParams { + field, + type_option_data, + start_field_id, + grid_id, + } = params; + let field_id = field.id.clone(); + if self.contain_field(&field_id).await { + let _ = self + .modify(|grid| { + let deserializer = TypeOptionJsonDeserializer(field.field_type.clone()); + let changeset = FieldChangesetParams { + field_id: field.id, + grid_id, + name: Some(field.name), + desc: Some(field.desc), + field_type: Some(field.field_type), + frozen: Some(field.frozen), + visibility: Some(field.visibility), + width: Some(field.width), + type_option_data: Some(type_option_data), + }; + Ok(grid.update_field_meta(changeset, deserializer)?) + }) + .await?; + let _ = self.notify_did_update_grid_field(&field_id).await?; + } else { + let _ = self + .modify(|grid| { + let builder = type_option_builder_from_bytes(type_option_data, &field.field_type); + let field_meta = FieldBuilder::from_field(field, builder).build(); + + Ok(grid.create_field_meta(field_meta, start_field_id)?) + }) + .await?; + let _ = self.notify_did_insert_grid_field(&field_id).await?; + } + + Ok(()) + } + + pub async fn create_next_field_meta(&self, field_type: &FieldType) -> FlowyResult { + let name = format!("Property {}", self.grid_pad.read().await.fields().len() + 1); + let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build(); + Ok(field_meta) + } + + pub async fn contain_field(&self, field_id: &str) -> bool { + self.grid_pad.read().await.contain_field(field_id) + } + + pub async fn update_field(&self, params: FieldChangesetParams) -> FlowyResult<()> { + let field_id = params.field_id.clone(); + let json_deserializer = match self.grid_pad.read().await.get_field_meta(params.field_id.as_str()) { + None => return Err(ErrorCode::FieldDoesNotExist.into()), + Some((_, field_meta)) => TypeOptionJsonDeserializer(field_meta.field_type.clone()), + }; + + let _ = self + .modify(|grid| Ok(grid.update_field_meta(params, json_deserializer)?)) + .await?; + + let _ = self.notify_did_update_grid_field(&field_id).await?; + Ok(()) + } + + pub async fn replace_field(&self, field_meta: FieldMeta) -> FlowyResult<()> { + let field_id = field_meta.id.clone(); + let _ = self.modify(|pad| Ok(pad.replace_field_meta(field_meta)?)).await?; + let _ = self.notify_did_update_grid_field(&field_id).await?; + Ok(()) + } + + pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> { + let _ = self.modify(|grid| Ok(grid.delete_field_meta(field_id)?)).await?; + let field_order = FieldOrder::from(field_id); + let notified_changeset = GridFieldChangeset::delete(&self.grid_id, vec![field_order]); + let _ = self.notify_did_update_grid(notified_changeset).await?; + Ok(()) + } + + pub async fn switch_to_field_type(&self, field_id: &str, field_type: &FieldType) -> FlowyResult<()> { + // let block_ids = self + // .get_block_metas() + // .await? + // .into_iter() + // .map(|block_meta| block_meta.block_id) + // .collect(); + // let cell_metas = self + // .block_meta_manager + // .get_cell_metas(block_ids, field_id, None) + // .await?; + + let type_option_json_builder = |field_type: &FieldType| -> String { + return default_type_option_builder_from_type(field_type).entry().json_str(); + }; + + let _ = self + .modify(|grid| Ok(grid.switch_to_field(field_id, field_type.clone(), type_option_json_builder)?)) + .await?; + + let _ = self.notify_did_update_grid_field(field_id).await?; + + Ok(()) + } + + pub async fn duplicate_field(&self, field_id: &str) -> FlowyResult<()> { + let duplicated_field_id = gen_field_id(); + let _ = self + .modify(|grid| Ok(grid.duplicate_field_meta(field_id, &duplicated_field_id)?)) + .await?; + + let _ = self.notify_did_insert_grid_field(&duplicated_field_id).await?; + Ok(()) + } + + pub async fn get_field_meta(&self, field_id: &str) -> Option { + let field_meta = self.grid_pad.read().await.get_field_meta(field_id)?.1.clone(); + Some(field_meta) + } + + pub async fn get_field_metas(&self, field_ids: Option>) -> FlowyResult> + where + T: Into, + { + if field_ids.is_none() { + let field_metas = self.grid_pad.read().await.get_field_metas(None)?; + return Ok(field_metas); + } + + let to_field_orders = |item: Vec| item.into_iter().map(|data| data.into()).collect(); + let field_orders = field_ids.map_or(vec![], to_field_orders); + let expected_len = field_orders.len(); + let field_metas = self.grid_pad.read().await.get_field_metas(Some(field_orders))?; + if expected_len != 0 && field_metas.len() != expected_len { + tracing::error!( + "This is a bug. The len of the field_metas should equal to {}", + expected_len + ); + debug_assert!(field_metas.len() == expected_len); + } + Ok(field_metas) + } + + pub async fn create_block(&self, grid_block: GridBlockMeta) -> FlowyResult<()> { + let _ = self.modify(|grid| Ok(grid.create_block_meta(grid_block)?)).await?; + Ok(()) + } + + pub async fn update_block(&self, changeset: GridBlockMetaChangeset) -> FlowyResult<()> { + let _ = self.modify(|grid| Ok(grid.update_block_meta(changeset)?)).await?; + Ok(()) + } + + pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { + let field_metas = self.grid_pad.read().await.get_field_metas(None)?; + let block_id = self.block_id().await?; + + // insert empty row below the row whose id is upper_row_id + let row_meta_ctx = CreateRowMetaBuilder::new(&field_metas).build(); + let row_meta = make_row_meta_from_context(&block_id, row_meta_ctx); + let row_order = RowOrder::from(&row_meta); + + // insert the row + let row_count = self + .block_meta_manager + .create_row(&block_id, row_meta, start_row_id) + .await?; + + // update block row count + let changeset = GridBlockMetaChangeset::from_row_count(&block_id, row_count); + let _ = self.update_block(changeset).await?; + Ok(row_order) + } + + pub async fn insert_rows(&self, contexts: Vec) -> FlowyResult> { + let block_id = self.block_id().await?; + let mut rows_by_block_id: HashMap> = HashMap::new(); + let mut row_orders = vec![]; + for ctx in contexts { + let row_meta = make_row_meta_from_context(&block_id, ctx); + row_orders.push(RowOrder::from(&row_meta)); + rows_by_block_id + .entry(block_id.clone()) + .or_insert_with(Vec::new) + .push(row_meta); + } + let changesets = self.block_meta_manager.insert_row(rows_by_block_id).await?; + for changeset in changesets { + let _ = self.update_block(changeset).await?; + } + Ok(row_orders) + } + + pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { + self.block_meta_manager.update_row(changeset).await + } + + pub async fn get_rows(&self, block_id: &str) -> FlowyResult { + let block_ids = vec![block_id.to_owned()]; + let mut grid_block_snapshot = self.grid_block_snapshots(Some(block_ids)).await?; + + // For the moment, we only support one block. + // We can save the rows into multiple blocks and load them asynchronously in the future. + debug_assert_eq!(grid_block_snapshot.len(), 1); + if grid_block_snapshot.len() == 1 { + let snapshot = grid_block_snapshot.pop().unwrap(); + let field_metas = self.get_field_metas::(None).await?; + let rows = make_rows_from_row_metas(&field_metas, &snapshot.row_metas); + Ok(rows.into()) + } else { + Ok(vec![].into()) + } + } + + pub async fn get_row(&self, row_id: &str) -> FlowyResult> { + match self.block_meta_manager.get_row_meta(row_id).await? { + None => Ok(None), + Some(row_meta) => { + let field_metas = self.get_field_metas::(None).await?; + let row_metas = vec![row_meta]; + let mut rows = make_rows_from_row_metas(&field_metas, &row_metas); + debug_assert!(rows.len() == 1); + Ok(rows.pop()) + } + } + } + pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> { + let _ = self.block_meta_manager.delete_row(row_id).await?; + Ok(()) + } + + pub async fn duplicate_row(&self, _row_id: &str) -> FlowyResult<()> { + Ok(()) + } + + pub async fn get_cell(&self, params: &CellIdentifier) -> Option { + let field_meta = self.get_field_meta(¶ms.field_id).await?; + let row_meta = self.block_meta_manager.get_row_meta(¶ms.row_id).await.ok()??; + make_cell(¶ms.field_id, &field_meta, &row_meta) + } + + pub async fn get_cell_meta(&self, row_id: &str, field_id: &str) -> FlowyResult> { + let row_meta = self.block_meta_manager.get_row_meta(row_id).await?; + match row_meta { + None => Ok(None), + Some(row_meta) => { + let cell_meta = row_meta.cells.get(field_id).cloned(); + Ok(cell_meta) + } + } + } + + #[tracing::instrument(level = "trace", skip_all, err)] + pub async fn update_cell(&self, mut changeset: CellChangeset) -> FlowyResult<()> { + if changeset.data.as_ref().is_none() { + return Ok(()); + } + + let cell_data_changeset = changeset.data.unwrap(); + let cell_meta = self.get_cell_meta(&changeset.row_id, &changeset.field_id).await?; + tracing::trace!("{}: {:?}", &changeset.field_id, cell_meta); + match self.grid_pad.read().await.get_field_meta(&changeset.field_id) { + None => { + let msg = format!("Field not found with id: {}", &changeset.field_id); + Err(FlowyError::internal().context(msg)) + } + Some((_, field_meta)) => { + // Update the changeset.data property with the return value. + changeset.data = Some(apply_cell_data_changeset(cell_data_changeset, cell_meta, field_meta)?); + let _ = self.block_meta_manager.update_cell(changeset).await?; + Ok(()) + } + } + } + + pub async fn get_blocks(&self, block_ids: Option>) -> FlowyResult { + let block_snapshots = self.grid_block_snapshots(block_ids.clone()).await?; + make_grid_blocks(block_ids, block_snapshots) + } + + pub async fn get_block_metas(&self) -> FlowyResult> { + let grid_blocks = self.grid_pad.read().await.get_block_metas(); + Ok(grid_blocks) + } + + pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { + let changesets = self.block_meta_manager.delete_rows(row_orders).await?; + for changeset in changesets { + let _ = self.update_block(changeset).await?; + } + Ok(()) + } + + pub async fn grid_data(&self) -> FlowyResult { + let pad_read_guard = self.grid_pad.read().await; + let field_orders = pad_read_guard.get_field_orders(); + let mut block_orders = vec![]; + for block_order in pad_read_guard.get_block_metas() { + let row_orders = self.block_meta_manager.get_row_orders(&block_order.block_id).await?; + let block_order = GridBlockOrder { + block_id: block_order.block_id, + row_orders, + }; + block_orders.push(block_order); + } + + Ok(Grid { + id: self.grid_id.clone(), + field_orders, + block_orders, + }) + } + + pub async fn grid_block_snapshots(&self, block_ids: Option>) -> FlowyResult> { + let block_ids = match block_ids { + None => self + .grid_pad + .read() + .await + .get_block_metas() + .into_iter() + .map(|block_meta| block_meta.block_id) + .collect::>(), + Some(block_ids) => block_ids, + }; + let snapshots = self.block_meta_manager.make_block_snapshots(block_ids).await?; + Ok(snapshots) + } + + pub async fn move_item(&self, params: MoveItemParams) -> FlowyResult<()> { + match params.ty { + MoveItemType::MoveField => { + self.move_field(¶ms.item_id, params.from_index, params.to_index) + .await + } + MoveItemType::MoveRow => self.move_row(¶ms.item_id, params.from_index, params.to_index).await, + } + } + + pub async fn move_field(&self, field_id: &str, from: i32, to: i32) -> FlowyResult<()> { + let _ = self + .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) + .await?; + if let Some((index, field_meta)) = self.grid_pad.read().await.get_field_meta(field_id) { + let delete_field_order = FieldOrder::from(field_id); + let insert_field = IndexField::from_field_meta(field_meta, index); + let notified_changeset = GridFieldChangeset { + grid_id: self.grid_id.clone(), + inserted_fields: vec![insert_field], + deleted_fields: vec![delete_field_order], + updated_fields: vec![], + }; + + let _ = self.notify_did_update_grid(notified_changeset).await?; + } + Ok(()) + } + + pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> { + let _ = self + .block_meta_manager + .move_row(row_id, from as usize, to as usize) + .await?; + Ok(()) + } + + pub async fn delta_bytes(&self) -> Bytes { + self.grid_pad.read().await.delta_bytes() + } + + async fn modify(&self, f: F) -> FlowyResult<()> + where + F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult>, + { + let mut write_guard = self.grid_pad.write().await; + if let Some(changeset) = f(&mut *write_guard)? { + let _ = self.apply_change(changeset).await?; + } + Ok(()) + } + + async fn apply_change(&self, change: GridChangeset) -> FlowyResult<()> { + let GridChangeset { delta, md5 } = change; + let user_id = self.user.user_id()?; + let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); + let delta_data = delta.to_delta_bytes(); + let revision = Revision::new( + &self.rev_manager.object_id, + base_rev_id, + rev_id, + delta_data, + &user_id, + md5, + ); + let _ = self + .rev_manager + .add_local_revision(&revision, Box::new(GridRevisionCompactor())) + .await?; + Ok(()) + } + + async fn block_id(&self) -> FlowyResult { + match self.grid_pad.read().await.get_block_metas().last() { + None => Err(FlowyError::internal().context("There is no grid block in this grid")), + Some(grid_block) => Ok(grid_block.block_id.clone()), + } + } + + #[tracing::instrument(level = "trace", skip_all, err)] + async fn notify_did_insert_grid_field(&self, field_id: &str) -> FlowyResult<()> { + if let Some((index, field_meta)) = self.grid_pad.read().await.get_field_meta(field_id) { + let index_field = IndexField::from_field_meta(field_meta, index); + let notified_changeset = GridFieldChangeset::insert(&self.grid_id, vec![index_field]); + let _ = self.notify_did_update_grid(notified_changeset).await?; + } + Ok(()) + } + + #[tracing::instrument(level = "trace", skip_all, err)] + async fn notify_did_update_grid_field(&self, field_id: &str) -> FlowyResult<()> { + if let Some((_, field_meta)) = self + .grid_pad + .read() + .await + .get_field_meta(field_id) + .map(|(index, field)| (index, field.clone())) + { + let updated_field = Field::from(field_meta); + let notified_changeset = GridFieldChangeset::update(&self.grid_id, vec![updated_field.clone()]); + let _ = self.notify_did_update_grid(notified_changeset).await?; + + send_dart_notification(field_id, GridNotification::DidUpdateField) + .payload(updated_field) + .send(); + } + + Ok(()) + } + + async fn notify_did_update_grid(&self, changeset: GridFieldChangeset) -> FlowyResult<()> { + send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridField) + .payload(changeset) + .send(); + Ok(()) + } +} + +#[cfg(feature = "flowy_unit_test")] +impl ClientGridEditor { + pub fn rev_manager(&self) -> Arc { + self.rev_manager.clone() + } +} + +pub struct GridPadBuilder(); +impl RevisionObjectBuilder for GridPadBuilder { + type Output = GridMetaPad; + + fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { + let pad = GridMetaPad::from_revisions(object_id, revisions)?; + Ok(pad) + } +} + +struct GridRevisionCloudService { + #[allow(dead_code)] + token: String, +} + +impl RevisionCloudService for GridRevisionCloudService { + #[tracing::instrument(level = "trace", skip(self))] + fn fetch_object(&self, _user_id: &str, _object_id: &str) -> FutureResult, FlowyError> { + FutureResult::new(async move { Ok(vec![]) }) + } +} + +struct GridRevisionCompactor(); +impl RevisionCompactor for GridRevisionCompactor { + fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { + let delta = make_delta_from_revisions::(revisions)?; + Ok(delta.to_delta_bytes()) + } +} + +struct TypeOptionJsonDeserializer(FieldType); +impl JsonDeserializer for TypeOptionJsonDeserializer { + fn deserialize(&self, type_option_data: Vec) -> CollaborateResult { + // The type_option_data sent from Dart is serialized by protobuf. + let builder = type_option_builder_from_bytes(type_option_data, &self.0); + let json = builder.entry().json_str(); + tracing::trace!("Deserialize type option data to: {}", json); + Ok(json) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/mod.rs b/frontend/rust-lib/flowy-grid/src/services/mod.rs new file mode 100644 index 0000000000..036efd6ada --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/mod.rs @@ -0,0 +1,9 @@ +mod util; + +pub mod block_meta_editor; +mod block_meta_manager; +pub mod entities; +pub mod field; +pub mod grid_editor; +pub mod persistence; +pub mod row; diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs new file mode 100644 index 0000000000..df75ec629c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs @@ -0,0 +1,48 @@ +use crate::services::persistence::GridDatabase; +use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; +use flowy_database::{ + prelude::*, + schema::{grid_block_index_table, grid_block_index_table::dsl}, +}; +use flowy_error::FlowyResult; +use std::sync::Arc; + +pub struct BlockIndexPersistence { + database: Arc, +} + +impl BlockIndexPersistence { + pub fn new(database: Arc) -> Self { + Self { database } + } + + pub fn get_block_id(&self, row_id: &str) -> FlowyResult { + let conn = self.database.db_connection()?; + let block_id = dsl::grid_block_index_table + .filter(grid_block_index_table::row_id.eq(row_id)) + .select(grid_block_index_table::block_id) + .first::(&*conn)?; + + Ok(block_id) + } + + pub fn insert_or_update(&self, block_id: &str, row_id: &str) -> FlowyResult<()> { + let conn = self.database.db_connection()?; + let item = IndexItem { + row_id: row_id.to_string(), + block_id: block_id.to_string(), + }; + let _ = diesel::replace_into(grid_block_index_table::table) + .values(item) + .execute(&*conn)?; + Ok(()) + } +} + +#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] +#[table_name = "grid_block_index_table"] +#[primary_key(row_id)] +struct IndexItem { + row_id: String, + block_id: String, +} diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/kv.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/kv.rs new file mode 100644 index 0000000000..06a5a2d68f --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/kv.rs @@ -0,0 +1,143 @@ +use crate::services::persistence::GridDatabase; +use ::diesel::{query_dsl::*, ExpressionMethods}; +use bytes::Bytes; +use diesel::SqliteConnection; +use flowy_database::{ + prelude::*, + schema::{kv_table, kv_table::dsl}, +}; +use flowy_error::{FlowyError, FlowyResult}; +use std::sync::Arc; + +#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] +#[table_name = "kv_table"] +#[primary_key(key)] +pub struct KeyValue { + key: String, + value: Vec, +} + +pub trait KVTransaction { + fn get>(&self, key: &str) -> FlowyResult>; + fn set>(&self, value: T) -> FlowyResult<()>; + fn remove(&self, key: &str) -> FlowyResult<()>; + + fn batch_get>(&self, keys: Vec) + -> FlowyResult>; + fn batch_set>(&self, values: Vec) -> FlowyResult<()>; + fn batch_remove(&self, keys: Vec) -> FlowyResult<()>; +} + +pub struct GridKVPersistence { + database: Arc, +} + +impl GridKVPersistence { + pub fn new(database: Arc) -> Self { + Self { database } + } + + pub fn begin_transaction(&self, f: F) -> FlowyResult + where + F: for<'a> FnOnce(SqliteTransaction<'a>) -> FlowyResult, + { + let conn = self.database.db_connection()?; + conn.immediate_transaction::<_, FlowyError, _>(|| { + let sql_transaction = SqliteTransaction { conn: &conn }; + f(sql_transaction) + }) + } +} + +impl KVTransaction for GridKVPersistence { + fn get>(&self, key: &str) -> FlowyResult> { + self.begin_transaction(|transaction| transaction.get(key)) + } + + fn set>(&self, value: T) -> FlowyResult<()> { + self.begin_transaction(|transaction| transaction.set(value)) + } + + fn remove(&self, key: &str) -> FlowyResult<()> { + self.begin_transaction(|transaction| transaction.remove(key)) + } + + fn batch_get>( + &self, + keys: Vec, + ) -> FlowyResult> { + self.begin_transaction(|transaction| transaction.batch_get(keys)) + } + + fn batch_set>(&self, values: Vec) -> FlowyResult<()> { + self.begin_transaction(|transaction| transaction.batch_set(values)) + } + + fn batch_remove(&self, keys: Vec) -> FlowyResult<()> { + self.begin_transaction(|transaction| transaction.batch_remove(keys)) + } +} + +pub struct SqliteTransaction<'a> { + conn: &'a SqliteConnection, +} + +impl<'a> KVTransaction for SqliteTransaction<'a> { + fn get>(&self, key: &str) -> FlowyResult> { + let item = dsl::kv_table + .filter(kv_table::key.eq(key)) + .first::(self.conn)?; + let value = T::try_from(Bytes::from(item.value)).unwrap(); + Ok(Some(value)) + } + + fn set>(&self, value: T) -> FlowyResult<()> { + let item: KeyValue = value.into(); + let _ = diesel::replace_into(kv_table::table).values(&item).execute(self.conn)?; + Ok(()) + } + + fn remove(&self, key: &str) -> FlowyResult<()> { + let sql = dsl::kv_table.filter(kv_table::key.eq(key)); + let _ = diesel::delete(sql).execute(self.conn)?; + Ok(()) + } + + fn batch_get>( + &self, + keys: Vec, + ) -> FlowyResult> { + let items = dsl::kv_table + .filter(kv_table::key.eq_any(&keys)) + .load::(self.conn)?; + let mut values = vec![]; + for item in items { + let value = T::try_from(Bytes::from(item.value)).unwrap(); + values.push(value); + } + Ok(values) + } + + fn batch_set>(&self, values: Vec) -> FlowyResult<()> { + let items = values.into_iter().map(|value| value.into()).collect::>(); + let _ = diesel::replace_into(kv_table::table) + .values(&items) + .execute(self.conn)?; + Ok(()) + } + + fn batch_remove(&self, keys: Vec) -> FlowyResult<()> { + let sql = dsl::kv_table.filter(kv_table::key.eq_any(keys)); + let _ = diesel::delete(sql).execute(self.conn)?; + Ok(()) + } +} + +// impl + GridIdentifiable> std::convert::From for KeyValue { +// fn from(value: T) -> Self { +// let key = value.id().to_string(); +// let bytes: Bytes = value.try_into().unwrap(); +// let value = bytes.to_vec(); +// KeyValue { key, value } +// } +// } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs new file mode 100644 index 0000000000..d6167cf8e6 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs @@ -0,0 +1,16 @@ +use flowy_database::{ConnectionPool, DBConnection}; +use flowy_error::FlowyError; +use std::sync::Arc; + +pub mod block_index; +pub mod kv; + +pub trait GridDatabase: Send + Sync { + fn db_pool(&self) -> Result, FlowyError>; + + fn db_connection(&self) -> Result { + let pool = self.db_pool()?; + let conn = pool.get().map_err(|e| FlowyError::internal().context(e))?; + Ok(conn) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs new file mode 100644 index 0000000000..7384173b60 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs @@ -0,0 +1,148 @@ +use crate::services::field::*; +use std::fmt::Formatter; + +use flowy_error::FlowyError; +use flowy_grid_data_model::entities::{CellMeta, FieldMeta, FieldType}; +use serde::{Deserialize, Serialize}; + +pub trait CellDataOperation { + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> String; + fn apply_changeset>( + &self, + changeset: T, + cell_meta: Option, + ) -> Result; +} + +#[derive(Debug)] +pub struct CellDataChangeset(String); + +impl std::fmt::Display for CellDataChangeset { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &self.0) + } +} + +impl> std::convert::From for CellDataChangeset { + fn from(s: T) -> Self { + let s = s.as_ref().to_owned(); + CellDataChangeset(s) + } +} + +impl std::ops::Deref for CellDataChangeset { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TypeOptionCellData { + pub data: String, + pub field_type: FieldType, +} + +impl std::str::FromStr for TypeOptionCellData { + type Err = FlowyError; + + fn from_str(s: &str) -> Result { + let type_option_cell_data: TypeOptionCellData = serde_json::from_str(s)?; + Ok(type_option_cell_data) + } +} + +impl TypeOptionCellData { + pub fn new(data: T, field_type: FieldType) -> Self { + TypeOptionCellData { + data: data.to_string(), + field_type, + } + } + + pub fn json(&self) -> String { + serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) + } + + pub fn is_number(&self) -> bool { + self.field_type == FieldType::Number + } + + pub fn is_text(&self) -> bool { + self.field_type == FieldType::RichText + } + + pub fn is_checkbox(&self) -> bool { + self.field_type == FieldType::Checkbox + } + + pub fn is_date(&self) -> bool { + self.field_type == FieldType::DateTime + } + + pub fn is_single_select(&self) -> bool { + self.field_type == FieldType::SingleSelect + } + + pub fn is_multi_select(&self) -> bool { + self.field_type == FieldType::MultiSelect + } +} + +/// The changeset will be deserialized into specific data base on the FieldType. +/// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect +pub fn apply_cell_data_changeset>( + changeset: T, + cell_meta: Option, + field_meta: &FieldMeta, +) -> Result { + match field_meta.field_type { + FieldType::RichText => RichTextTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), + FieldType::Number => NumberTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), + FieldType::DateTime => DateTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), + FieldType::SingleSelect => SingleSelectTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), + FieldType::MultiSelect => MultiSelectTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), + FieldType::Checkbox => CheckboxTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), + } +} +// +// #[tracing::instrument(level = "trace", skip(field_meta, data), fields(content), err)] +// pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Result { +// let s = match field_meta.field_type { +// FieldType::RichText => RichTextTypeOption::from(field_meta).decode_cell_data(data, field_meta), +// FieldType::Number => NumberTypeOption::from(field_meta).decode_cell_data(data, field_meta), +// FieldType::DateTime => DateTypeOption::from(field_meta).decode_cell_data(data, field_meta), +// FieldType::SingleSelect => SingleSelectTypeOption::from(field_meta).decode_cell_data(data, field_meta), +// FieldType::MultiSelect => MultiSelectTypeOption::from(field_meta).decode_cell_data(data, field_meta), +// FieldType::Checkbox => CheckboxTypeOption::from(field_meta).decode_cell_data(data, field_meta), +// }; +// tracing::Span::current().record("content", &format!("{:?}: {}", field_meta.field_type, s).as_str()); +// Ok(s) +// } + +#[tracing::instrument(level = "trace", skip(field_meta, data), fields(content))] +pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Option { + let s = match field_type { + FieldType::RichText => field_meta + .get_type_option_entry::(field_type)? + .decode_cell_data(data, field_meta), + FieldType::Number => field_meta + .get_type_option_entry::(field_type)? + .decode_cell_data(data, field_meta), + FieldType::DateTime => field_meta + .get_type_option_entry::(field_type)? + .decode_cell_data(data, field_meta), + FieldType::SingleSelect => field_meta + .get_type_option_entry::(field_type)? + .decode_cell_data(data, field_meta), + FieldType::MultiSelect => field_meta + .get_type_option_entry::(field_type)? + .decode_cell_data(data, field_meta), + FieldType::Checkbox => field_meta + .get_type_option_entry::(field_type)? + .decode_cell_data(data, field_meta), + }; + tracing::Span::current().record("content", &format!("{:?}: {}", field_meta.field_type, s).as_str()); + Some(s) +} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs new file mode 100644 index 0000000000..f9bf130e8b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs @@ -0,0 +1,8 @@ +mod cell_data_operation; +mod row_builder; +pub mod row_entities; +mod row_loader; + +pub use cell_data_operation::*; +pub use row_builder::*; +pub(crate) use row_loader::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs new file mode 100644 index 0000000000..fa5298fd39 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -0,0 +1,96 @@ +use crate::services::field::SelectOptionCellChangeset; +use crate::services::row::apply_cell_data_changeset; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_grid_data_model::entities::{gen_row_id, CellMeta, FieldMeta, RowMeta, DEFAULT_ROW_HEIGHT}; +use indexmap::IndexMap; +use std::collections::HashMap; + +pub struct CreateRowMetaBuilder<'a> { + field_meta_map: HashMap<&'a String, &'a FieldMeta>, + payload: CreateRowMetaPayload, +} + +impl<'a> CreateRowMetaBuilder<'a> { + pub fn new(fields: &'a [FieldMeta]) -> Self { + let field_meta_map = fields + .iter() + .map(|field| (&field.id, field)) + .collect::>(); + + let payload = CreateRowMetaPayload { + row_id: gen_row_id(), + cell_by_field_id: Default::default(), + height: DEFAULT_ROW_HEIGHT, + visibility: true, + }; + + Self { + field_meta_map, + payload, + } + } + + pub fn add_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> { + match self.field_meta_map.get(&field_id.to_owned()) { + None => { + let msg = format!("Invalid field_id: {}", field_id); + Err(FlowyError::internal().context(msg)) + } + Some(field_meta) => { + let data = apply_cell_data_changeset(&data, None, field_meta)?; + let cell = CellMeta::new(data); + self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); + Ok(()) + } + } + } + + pub fn add_select_option_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> { + match self.field_meta_map.get(&field_id.to_owned()) { + None => { + let msg = format!("Invalid field_id: {}", field_id); + Err(FlowyError::internal().context(msg)) + } + Some(field_meta) => { + let cell_data = SelectOptionCellChangeset::from_insert(&data).cell_data(); + let data = apply_cell_data_changeset(&cell_data, None, field_meta)?; + let cell = CellMeta::new(data); + self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); + Ok(()) + } + } + } + + #[allow(dead_code)] + pub fn height(mut self, height: i32) -> Self { + self.payload.height = height; + self + } + + #[allow(dead_code)] + pub fn visibility(mut self, visibility: bool) -> Self { + self.payload.visibility = visibility; + self + } + + pub fn build(self) -> CreateRowMetaPayload { + self.payload + } +} + +pub fn make_row_meta_from_context(block_id: &str, payload: CreateRowMetaPayload) -> RowMeta { + RowMeta { + id: payload.row_id, + block_id: block_id.to_owned(), + cells: payload.cell_by_field_id, + height: payload.height, + visibility: payload.visibility, + } +} + +pub struct CreateRowMetaPayload { + pub row_id: String, + pub cell_by_field_id: IndexMap, + pub height: i32, + pub visibility: bool, +} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_entities.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_entities.rs new file mode 100644 index 0000000000..c97becbd34 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_entities.rs @@ -0,0 +1,31 @@ +use flowy_derive::ProtoBuf; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; + +#[derive(ProtoBuf, Default)] +pub struct RowIdentifierPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 3)] + pub row_id: String, +} + +pub struct RowIdentifier { + pub grid_id: String, + pub row_id: String, +} + +impl TryInto for RowIdentifierPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; + + Ok(RowIdentifier { + grid_id: grid_id.0, + row_id: row_id.0, + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs new file mode 100644 index 0000000000..770ba758e9 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -0,0 +1,106 @@ +use crate::services::row::decode_cell_data; +use flowy_error::FlowyResult; +use flowy_grid_data_model::entities::{ + Cell, CellMeta, FieldMeta, GridBlock, GridBlockOrder, RepeatedGridBlock, Row, RowMeta, RowOrder, +}; +use std::collections::HashMap; +use std::sync::Arc; + +pub struct GridBlockSnapshot { + pub(crate) block_id: String, + pub row_metas: Vec>, +} + +pub(crate) fn group_row_orders(row_orders: Vec) -> Vec { + let mut map: HashMap = HashMap::new(); + row_orders.into_iter().for_each(|row_order| { + // Memory Optimization: escape clone block_id + let block_id = row_order.block_id.clone(); + map.entry(block_id) + .or_insert_with(|| GridBlockOrder::new(&row_order.block_id)) + .row_orders + .push(row_order); + }); + map.into_values().collect::>() +} + +#[inline(always)] +pub fn make_cell_by_field_id( + field_map: &HashMap<&String, &FieldMeta>, + field_id: String, + cell_meta: CellMeta, +) -> Option<(String, Cell)> { + let field_meta = field_map.get(&field_id)?; + let content = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?; + let cell = Cell::new(&field_id, content); + Some((field_id, cell)) +} + +#[allow(dead_code)] +pub fn make_cell(field_id: &str, field_meta: &FieldMeta, row_meta: &RowMeta) -> Option { + let cell_meta = row_meta.cells.get(field_id)?.clone(); + let content = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?; + Some(Cell::new(field_id, content)) +} + +pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc]) -> Vec { + row_metas.iter().map(RowOrder::from).collect::>() +} + +pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &[Arc]) -> Vec { + let field_meta_map = fields + .iter() + .map(|field_meta| (&field_meta.id, field_meta)) + .collect::>(); + + let make_row = |row_meta: &Arc| { + let cell_by_field_id = row_meta + .cells + .clone() + .into_iter() + .flat_map(|(field_id, cell_meta)| make_cell_by_field_id(&field_meta_map, field_id, cell_meta)) + .collect::>(); + + Row { + id: row_meta.id.clone(), + cell_by_field_id, + height: row_meta.height, + } + }; + + row_metas.iter().map(make_row).collect::>() +} + +pub(crate) fn make_grid_blocks( + block_ids: Option>, + block_snapshots: Vec, +) -> FlowyResult { + match block_ids { + None => Ok(block_snapshots + .into_iter() + .map(|snapshot| { + let row_orders = make_row_orders_from_row_metas(&snapshot.row_metas); + GridBlock::new(&snapshot.block_id, row_orders) + }) + .collect::>() + .into()), + Some(block_ids) => { + let block_meta_data_map: HashMap<&String, &Vec>> = block_snapshots + .iter() + .map(|data| (&data.block_id, &data.row_metas)) + .collect(); + + let mut grid_blocks = vec![]; + for block_id in block_ids { + match block_meta_data_map.get(&block_id) { + None => {} + Some(row_metas) => { + let row_orders = make_row_orders_from_row_metas(row_metas); + grid_blocks.push(GridBlock::new(&block_id, row_orders)); + } + } + } + Ok(grid_blocks.into()) + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/util.rs b/frontend/rust-lib/flowy-grid/src/services/util.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/util.rs @@ -0,0 +1 @@ + diff --git a/frontend/rust-lib/flowy-grid/src/util.rs b/frontend/rust-lib/flowy-grid/src/util.rs new file mode 100644 index 0000000000..f70d685c2d --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/util.rs @@ -0,0 +1,31 @@ +use crate::services::field::*; +use flowy_grid_data_model::entities::{BuildGridContext, FieldType}; +use flowy_sync::client_grid::GridBuilder; + +pub fn make_default_grid() -> BuildGridContext { + // text + let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .primary(true) + .build(); + + // single select + let single_select = SingleSelectTypeOptionBuilder::default(); + let single_select_field = FieldBuilder::new(single_select).name("Type").visibility(true).build(); + + // checkbox + let checkbox_field = FieldBuilder::from_field_type(&FieldType::Checkbox) + .name("Done") + .visibility(true) + .build(); + + GridBuilder::default() + .add_field(text_field) + .add_field(single_select_field) + .add_field(checkbox_field) + .add_empty_row() + .add_empty_row() + .add_empty_row() + .build() +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs new file mode 100644 index 0000000000..3c66f2355e --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs @@ -0,0 +1,361 @@ +use crate::grid::script::EditorScript::*; +use crate::grid::script::*; +use chrono::NaiveDateTime; +use flowy_grid::services::field::{ + MultiSelectTypeOption, SelectOption, SelectOptionCellChangeset, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, +}; +use flowy_grid::services::row::{decode_cell_data, CreateRowMetaBuilder}; +use flowy_grid_data_model::entities::{ + CellChangeset, FieldChangesetParams, FieldType, GridBlockMeta, GridBlockMetaChangeset, RowMetaChangeset, + TypeOptionDataEntry, +}; + +#[tokio::test] +async fn grid_create_field() { + let mut test = GridEditorTest::new().await; + let (text_field_params, text_field_meta) = create_text_field(&test.grid_id); + let (single_select_params, single_select_field) = create_single_select_field(&test.grid_id); + let scripts = vec![ + CreateField { + params: text_field_params, + }, + AssertFieldEqual { + field_index: test.field_count, + field_meta: text_field_meta, + }, + ]; + test.run_scripts(scripts).await; + + let scripts = vec![ + CreateField { + params: single_select_params, + }, + AssertFieldEqual { + field_index: test.field_count, + field_meta: single_select_field, + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_create_duplicate_field() { + let mut test = GridEditorTest::new().await; + let (params, _) = create_text_field(&test.grid_id); + let field_count = test.field_count; + let expected_field_count = field_count + 1; + let scripts = vec![ + CreateField { params: params.clone() }, + CreateField { params }, + AssertFieldCount(expected_field_count), + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_update_field_with_empty_change() { + let mut test = GridEditorTest::new().await; + let (params, field_meta) = create_single_select_field(&test.grid_id); + let changeset = FieldChangesetParams { + field_id: field_meta.id.clone(), + grid_id: test.grid_id.clone(), + ..Default::default() + }; + + let scripts = vec![ + CreateField { params }, + UpdateField { changeset }, + AssertFieldEqual { + field_index: test.field_count, + field_meta, + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_update_field() { + let mut test = GridEditorTest::new().await; + let (single_select_params, single_select_field) = create_single_select_field(&test.grid_id); + let mut cloned_field = single_select_field.clone(); + + let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field); + single_select_type_option.options.push(SelectOption::new("Unknown")); + let changeset = FieldChangesetParams { + field_id: single_select_field.id.clone(), + grid_id: test.grid_id.clone(), + frozen: Some(true), + width: Some(1000), + type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()), + ..Default::default() + }; + + cloned_field.frozen = true; + cloned_field.width = 1000; + cloned_field.insert_type_option_entry(&single_select_type_option); + + let scripts = vec![ + CreateField { + params: single_select_params, + }, + UpdateField { changeset }, + AssertFieldEqual { + field_index: test.field_count, + field_meta: cloned_field, + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_delete_field() { + let mut test = GridEditorTest::new().await; + let expected_field_count = test.field_count; + let (text_params, text_field) = create_text_field(&test.grid_id); + let scripts = vec![ + CreateField { params: text_params }, + DeleteField { field_meta: text_field }, + AssertFieldCount(expected_field_count), + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_create_block() { + let grid_block = GridBlockMeta::new(); + let scripts = vec![ + AssertBlockCount(1), + CreateBlock { block: grid_block }, + AssertBlockCount(2), + ]; + GridEditorTest::new().await.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_update_block() { + let grid_block = GridBlockMeta::new(); + let mut cloned_grid_block = grid_block.clone(); + let changeset = GridBlockMetaChangeset { + block_id: grid_block.block_id.clone(), + start_row_index: Some(2), + row_count: Some(10), + }; + + cloned_grid_block.start_row_index = 2; + cloned_grid_block.row_count = 10; + + let scripts = vec![ + AssertBlockCount(1), + CreateBlock { block: grid_block }, + UpdateBlock { changeset }, + AssertBlockCount(2), + AssertBlockEqual { + block_index: 1, + block: cloned_grid_block, + }, + ]; + GridEditorTest::new().await.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_create_row() { + let scripts = vec![AssertRowCount(3), CreateEmptyRow, CreateEmptyRow, AssertRowCount(5)]; + GridEditorTest::new().await.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_create_row2() { + let mut test = GridEditorTest::new().await; + let create_row_context = CreateRowMetaBuilder::new(&test.field_metas).build(); + let scripts = vec![ + AssertRowCount(3), + CreateRow { + context: create_row_context, + }, + AssertRowCount(4), + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_update_row() { + let mut test = GridEditorTest::new().await; + let context = CreateRowMetaBuilder::new(&test.field_metas).build(); + let changeset = RowMetaChangeset { + row_id: context.row_id.clone(), + height: None, + visibility: None, + cell_by_field_id: Default::default(), + }; + + let scripts = vec![ + AssertRowCount(3), + CreateRow { context }, + UpdateRow { + changeset: changeset.clone(), + }, + AssertRow { changeset }, + AssertRowCount(4), + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_delete_row() { + let mut test = GridEditorTest::new().await; + let context_1 = CreateRowMetaBuilder::new(&test.field_metas).build(); + let context_2 = CreateRowMetaBuilder::new(&test.field_metas).build(); + let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()]; + let scripts = vec![ + AssertRowCount(3), + CreateRow { context: context_1 }, + CreateRow { context: context_2 }, + AssertBlockCount(1), + AssertBlock { + block_index: 0, + row_count: 5, + start_row_index: 0, + }, + DeleteRow { row_ids }, + AssertBlock { + block_index: 0, + row_count: 3, + start_row_index: 0, + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_row_add_cells_test() { + let mut test = GridEditorTest::new().await; + let mut builder = CreateRowMetaBuilder::new(&test.field_metas); + for field in &test.field_metas { + match field.field_type { + FieldType::RichText => { + builder.add_cell(&field.id, "hello world".to_owned()).unwrap(); + } + FieldType::Number => { + builder.add_cell(&field.id, "18,443".to_owned()).unwrap(); + } + FieldType::DateTime => { + builder.add_cell(&field.id, "1647251762".to_owned()).unwrap(); + } + FieldType::SingleSelect => { + let type_option = SingleSelectTypeOption::from(field); + let option = type_option.options.first().unwrap(); + builder.add_select_option_cell(&field.id, option.id.clone()).unwrap(); + } + FieldType::MultiSelect => { + let type_option = MultiSelectTypeOption::from(field); + let ops_ids = type_option + .options + .iter() + .map(|option| option.id.clone()) + .collect::>() + .join(SELECTION_IDS_SEPARATOR); + builder.add_select_option_cell(&field.id, ops_ids).unwrap(); + } + FieldType::Checkbox => { + builder.add_cell(&field.id, "false".to_string()).unwrap(); + } + } + } + let context = builder.build(); + let scripts = vec![CreateRow { context }, AssertGridMetaPad]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_row_add_date_cell_test() { + let mut test = GridEditorTest::new().await; + let mut builder = CreateRowMetaBuilder::new(&test.field_metas); + let mut date_field = None; + let timestamp = 1647390674; + for field in &test.field_metas { + if field.field_type == FieldType::DateTime { + date_field = Some(field.clone()); + NaiveDateTime::from_timestamp(123, 0); + // The data should not be empty + assert!(builder.add_cell(&field.id, "".to_owned()).is_err()); + + assert!(builder.add_cell(&field.id, "123".to_owned()).is_ok()); + assert!(builder.add_cell(&field.id, format!("{}", timestamp)).is_ok()); + } + } + let context = builder.build(); + let date_field = date_field.unwrap(); + let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone(); + assert_eq!( + decode_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type).unwrap(), + "2022/03/16", + ); + let scripts = vec![CreateRow { context }]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn grid_cell_update() { + let mut test = GridEditorTest::new().await; + let field_metas = &test.field_metas; + let row_metas = &test.row_metas; + let grid_blocks = &test.grid_blocks; + assert_eq!(row_metas.len(), 3); + assert_eq!(grid_blocks.len(), 1); + + let block_id = &grid_blocks.first().unwrap().block_id; + let mut scripts = vec![]; + for (index, row_meta) in row_metas.iter().enumerate() { + for field_meta in field_metas { + if index == 0 { + let data = match field_meta.field_type { + FieldType::RichText => "".to_string(), + FieldType::Number => "123".to_string(), + FieldType::DateTime => "123".to_string(), + FieldType::SingleSelect => { + let type_option = SingleSelectTypeOption::from(field_meta); + SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).cell_data() + } + FieldType::MultiSelect => { + let type_option = MultiSelectTypeOption::from(field_meta); + SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).cell_data() + } + FieldType::Checkbox => "1".to_string(), + }; + + scripts.push(UpdateCell { + changeset: CellChangeset { + grid_id: block_id.to_string(), + row_id: row_meta.id.clone(), + field_id: field_meta.id.clone(), + data: Some(data), + }, + is_err: false, + }); + } + + if index == 1 { + let (data, is_err) = match field_meta.field_type { + FieldType::RichText => ("1".to_string().repeat(10001), true), + FieldType::Number => ("abc".to_string(), true), + FieldType::DateTime => ("abc".to_string(), true), + FieldType::SingleSelect => (SelectOptionCellChangeset::from_insert("abc").cell_data(), false), + FieldType::MultiSelect => (SelectOptionCellChangeset::from_insert("abc").cell_data(), false), + FieldType::Checkbox => ("2".to_string(), false), + }; + + scripts.push(UpdateCell { + changeset: CellChangeset { + grid_id: block_id.to_string(), + row_id: row_meta.id.clone(), + field_id: field_meta.id.clone(), + data: Some(data), + }, + is_err, + }); + } + } + } + + test.run_scripts(scripts).await; +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs new file mode 100644 index 0000000000..04b16720e5 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs @@ -0,0 +1,2 @@ +mod grid_test; +mod script; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs new file mode 100644 index 0000000000..611ee937e2 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -0,0 +1,368 @@ +use bytes::Bytes; +use flowy_grid::services::field::*; +use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder}; +use flowy_grid::services::row::CreateRowMetaPayload; +use flowy_grid_data_model::entities::{ + BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, + GridBlockMetaChangeset, InsertFieldParams, RowMeta, RowMetaChangeset, RowOrder, TypeOptionDataEntry, +}; +use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; +use flowy_sync::client_grid::GridBuilder; +use flowy_test::helper::ViewTest; +use flowy_test::FlowySDKTest; +use std::collections::HashMap; +use std::sync::Arc; +use std::time::Duration; +use strum::EnumCount; +use tokio::time::sleep; + +pub enum EditorScript { + CreateField { + params: InsertFieldParams, + }, + UpdateField { + changeset: FieldChangesetParams, + }, + DeleteField { + field_meta: FieldMeta, + }, + AssertFieldCount(usize), + AssertFieldEqual { + field_index: usize, + field_meta: FieldMeta, + }, + CreateBlock { + block: GridBlockMeta, + }, + UpdateBlock { + changeset: GridBlockMetaChangeset, + }, + AssertBlockCount(usize), + AssertBlock { + block_index: usize, + row_count: i32, + start_row_index: i32, + }, + AssertBlockEqual { + block_index: usize, + block: GridBlockMeta, + }, + CreateEmptyRow, + CreateRow { + context: CreateRowMetaPayload, + }, + UpdateRow { + changeset: RowMetaChangeset, + }, + AssertRow { + changeset: RowMetaChangeset, + }, + DeleteRow { + row_ids: Vec, + }, + UpdateCell { + changeset: CellChangeset, + is_err: bool, + }, + AssertRowCount(usize), + // AssertRowEqual{ row_index: usize, row: RowMeta}, + AssertGridMetaPad, +} + +pub struct GridEditorTest { + pub sdk: FlowySDKTest, + pub grid_id: String, + pub editor: Arc, + pub field_metas: Vec, + pub grid_blocks: Vec, + pub row_metas: Vec>, + pub field_count: usize, + + pub row_order_by_row_id: HashMap, +} + +impl GridEditorTest { + pub async fn new() -> Self { + let sdk = FlowySDKTest::default(); + let _ = sdk.init_user().await; + let build_context = make_template_1_grid(); + let view_data: Bytes = build_context.into(); + let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; + let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); + let field_metas = editor.get_field_metas::(None).await.unwrap(); + let grid_blocks = editor.get_block_metas().await.unwrap(); + let row_metas = get_row_metas(&editor).await; + + let grid_id = test.view.id; + Self { + sdk, + grid_id, + editor, + field_metas, + grid_blocks, + row_metas, + field_count: FieldType::COUNT, + row_order_by_row_id: HashMap::default(), + } + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub async fn run_script(&mut self, script: EditorScript) { + let grid_manager = self.sdk.grid_manager.clone(); + let pool = self.sdk.user_session.db_pool().unwrap(); + let rev_manager = self.editor.rev_manager(); + let _cache = rev_manager.revision_cache().await; + + match script { + EditorScript::CreateField { params } => { + if !self.editor.contain_field(¶ms.field.id).await { + self.field_count += 1; + } + + self.editor.insert_field(params).await.unwrap(); + self.field_metas = self.editor.get_field_metas::(None).await.unwrap(); + assert_eq!(self.field_count, self.field_metas.len()); + } + EditorScript::UpdateField { changeset: change } => { + self.editor.update_field(change).await.unwrap(); + self.field_metas = self.editor.get_field_metas::(None).await.unwrap(); + } + EditorScript::DeleteField { field_meta } => { + if self.editor.contain_field(&field_meta.id).await { + self.field_count -= 1; + } + + self.editor.delete_field(&field_meta.id).await.unwrap(); + self.field_metas = self.editor.get_field_metas::(None).await.unwrap(); + assert_eq!(self.field_count, self.field_metas.len()); + } + EditorScript::AssertFieldCount(count) => { + assert_eq!( + self.editor.get_field_metas::(None).await.unwrap().len(), + count + ); + } + EditorScript::AssertFieldEqual { + field_index, + field_meta, + } => { + let field_metas = self.editor.get_field_metas::(None).await.unwrap(); + assert_eq!(field_metas[field_index].clone(), field_meta); + } + EditorScript::CreateBlock { block } => { + self.editor.create_block(block).await.unwrap(); + self.grid_blocks = self.editor.get_block_metas().await.unwrap(); + } + EditorScript::UpdateBlock { changeset: change } => { + self.editor.update_block(change).await.unwrap(); + } + EditorScript::AssertBlockCount(count) => { + assert_eq!(self.editor.get_block_metas().await.unwrap().len(), count); + } + EditorScript::AssertBlock { + block_index, + row_count, + start_row_index, + } => { + assert_eq!(self.grid_blocks[block_index].row_count, row_count); + assert_eq!(self.grid_blocks[block_index].start_row_index, start_row_index); + } + EditorScript::AssertBlockEqual { block_index, block } => { + let blocks = self.editor.get_block_metas().await.unwrap(); + let compared_block = blocks[block_index].clone(); + assert_eq!(compared_block, block); + } + EditorScript::CreateEmptyRow => { + let row_order = self.editor.create_row(None).await.unwrap(); + self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order); + self.row_metas = self.get_row_metas().await; + self.grid_blocks = self.editor.get_block_metas().await.unwrap(); + } + EditorScript::CreateRow { context } => { + let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); + for row_order in row_orders { + self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order); + } + self.row_metas = self.get_row_metas().await; + self.grid_blocks = self.editor.get_block_metas().await.unwrap(); + } + EditorScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(), + EditorScript::DeleteRow { row_ids } => { + let row_orders = row_ids + .into_iter() + .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) + .collect::>(); + + self.editor.delete_rows(row_orders).await.unwrap(); + self.row_metas = self.get_row_metas().await; + self.grid_blocks = self.editor.get_block_metas().await.unwrap(); + } + EditorScript::AssertRow { changeset } => { + let row = self.row_metas.iter().find(|row| row.id == changeset.row_id).unwrap(); + + if let Some(visibility) = changeset.visibility { + assert_eq!(row.visibility, visibility); + } + + if let Some(height) = changeset.height { + assert_eq!(row.height, height); + } + } + EditorScript::UpdateCell { changeset, is_err } => { + let result = self.editor.update_cell(changeset).await; + if is_err { + assert!(result.is_err()) + } else { + let _ = result.unwrap(); + self.row_metas = self.get_row_metas().await; + } + } + EditorScript::AssertRowCount(count) => { + assert_eq!(self.row_metas.len(), count); + } + EditorScript::AssertGridMetaPad => { + sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; + let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap(); + let grid_pad = grid_rev_manager.load::(None).await.unwrap(); + println!("{}", grid_pad.delta_str()); + } + } + } + + async fn get_row_metas(&self) -> Vec> { + get_row_metas(&self.editor).await + } +} + +async fn get_row_metas(editor: &Arc) -> Vec> { + editor + .grid_block_snapshots(None) + .await + .unwrap() + .pop() + .unwrap() + .row_metas +} + +pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) { + let field_meta = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .build(); + + let cloned_field_meta = field_meta.clone(); + + let type_option_data = field_meta + .get_type_option_entry::(&field_meta.field_type) + .unwrap() + .protobuf_bytes() + .to_vec(); + + let field = Field { + id: field_meta.id, + name: field_meta.name, + desc: field_meta.desc, + field_type: field_meta.field_type, + frozen: field_meta.frozen, + visibility: field_meta.visibility, + width: field_meta.width, + is_primary: false, + }; + + let params = InsertFieldParams { + grid_id: grid_id.to_owned(), + field, + type_option_data, + start_field_id: None, + }; + (params, cloned_field_meta) +} + +pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) { + let single_select = SingleSelectTypeOptionBuilder::default() + .option(SelectOption::new("Done")) + .option(SelectOption::new("Progress")); + + let field_meta = FieldBuilder::new(single_select).name("Name").visibility(true).build(); + let cloned_field_meta = field_meta.clone(); + let type_option_data = field_meta + .get_type_option_entry::(&field_meta.field_type) + .unwrap() + .protobuf_bytes() + .to_vec(); + + let field = Field { + id: field_meta.id, + name: field_meta.name, + desc: field_meta.desc, + field_type: field_meta.field_type, + frozen: field_meta.frozen, + visibility: field_meta.visibility, + width: field_meta.width, + is_primary: false, + }; + + let params = InsertFieldParams { + grid_id: grid_id.to_owned(), + field, + type_option_data, + start_field_id: None, + }; + (params, cloned_field_meta) +} + +fn make_template_1_grid() -> BuildGridContext { + let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .build(); + + // Single Select + let single_select = SingleSelectTypeOptionBuilder::default() + .option(SelectOption::new("Live")) + .option(SelectOption::new("Completed")) + .option(SelectOption::new("Planned")) + .option(SelectOption::new("Paused")); + let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); + + // MultiSelect + let multi_select = MultiSelectTypeOptionBuilder::default() + .option(SelectOption::new("Google")) + .option(SelectOption::new("Facebook")) + .option(SelectOption::new("Twitter")); + let multi_select_field = FieldBuilder::new(multi_select) + .name("Platform") + .visibility(true) + .build(); + + // Number + let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); + let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); + + // Date + let date = DateTypeOptionBuilder::default() + .date_format(DateFormat::US) + .time_format(TimeFormat::TwentyFourHour); + let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); + + // Checkbox + let checkbox = CheckboxTypeOptionBuilder::default(); + let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); + + GridBuilder::default() + .add_field(text_field) + .add_field(single_select_field) + .add_field(multi_select_field) + .add_field(number_field) + .add_field(date_field) + .add_field(checkbox_field) + .add_empty_row() + .add_empty_row() + .add_empty_row() + .build() +} diff --git a/frontend/rust-lib/flowy-grid/tests/main.rs b/frontend/rust-lib/flowy-grid/tests/main.rs new file mode 100644 index 0000000000..ec055c3bb9 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/main.rs @@ -0,0 +1 @@ +mod grid; diff --git a/frontend/rust-lib/flowy-net/Cargo.toml b/frontend/rust-lib/flowy-net/Cargo.toml index e494f6f5d1..fe40f6981d 100644 --- a/frontend/rust-lib/flowy-net/Cargo.toml +++ b/frontend/rust-lib/flowy-net/Cargo.toml @@ -9,12 +9,12 @@ edition = "2018" lib-dispatch = { path = "../lib-dispatch" } flowy-error = { path = "../flowy-error", features = ["collaboration", "http_server"] } flowy-derive = { path = "../../../shared-lib/flowy-derive" } -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration"} +flowy-sync = { path = "../../../shared-lib/flowy-sync"} flowy-folder-data-model = { path = "../../../shared-lib/flowy-folder-data-model"} flowy-user-data-model = { path = "../../../shared-lib/flowy-user-data-model"} flowy-folder = { path = "../flowy-folder" } flowy-user = { path = "../flowy-user" } -flowy-block = { path = "../flowy-block" } +flowy-text-block = { path = "../flowy-text-block" } lazy_static = "1.4.0" lib-infra = { path = "../../../shared-lib/lib-infra" } protobuf = {version = "2.18.0"} @@ -37,13 +37,14 @@ config = { version = "0.10.1", default-features = false, features = ["yaml"] } log = "0.4.14" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +nanoid = "0.4.0" [features] http_server = [] dart = [ "lib-infra/dart", "flowy-user/dart", - "flowy-collaboration/dart", + "flowy-sync/dart", "flowy-error/dart", "flowy-user-data-model/dart", "flowy-folder-data-model/dart" diff --git a/frontend/rust-lib/flowy-net/build.rs b/frontend/rust-lib/flowy-net/build.rs index 4ab7b9e23d..4d4d3b13da 100644 --- a/frontend/rust-lib/flowy-net/build.rs +++ b/frontend/rust-lib/flowy-net/build.rs @@ -3,5 +3,7 @@ use lib_infra::code_gen; fn main() { let crate_name = env!("CARGO_PKG_NAME"); code_gen::protobuf_file::gen(crate_name, "./src/protobuf/proto"); + + #[cfg(feature = "dart")] code_gen::dart_event::gen(crate_name); } diff --git a/frontend/rust-lib/flowy-net/src/handlers/mod.rs b/frontend/rust-lib/flowy-net/src/handlers/mod.rs index bb2f58fb4c..3f77ba3a04 100644 --- a/frontend/rust-lib/flowy-net/src/handlers/mod.rs +++ b/frontend/rust-lib/flowy-net/src/handlers/mod.rs @@ -3,7 +3,7 @@ use flowy_error::FlowyError; use lib_dispatch::prelude::{AppData, Data}; use std::sync::Arc; -#[tracing::instrument(skip(data, ws_manager))] +#[tracing::instrument(level = "debug", skip(data, ws_manager))] pub async fn update_network_ty( data: Data, ws_manager: AppData>, diff --git a/frontend/rust-lib/flowy-net/src/http_server/document.rs b/frontend/rust-lib/flowy-net/src/http_server/document.rs index bbc5aa2824..f10c737a95 100644 --- a/frontend/rust-lib/flowy-net/src/http_server/document.rs +++ b/frontend/rust-lib/flowy-net/src/http_server/document.rs @@ -2,9 +2,9 @@ use crate::{ configuration::*, request::{HttpRequestBuilder, ResponseMiddleware}, }; -use flowy_block::BlockCloudService; -use flowy_collaboration::entities::document_info::{BlockId, BlockInfo, CreateBlockParams, ResetDocumentParams}; use flowy_error::FlowyError; +use flowy_sync::entities::text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; +use flowy_text_block::BlockCloudService; use http_flowy::response::FlowyResponse; use lazy_static::lazy_static; use lib_infra::future::FutureResult; @@ -21,26 +21,26 @@ impl BlockHttpCloudService { } impl BlockCloudService for BlockHttpCloudService { - fn create_block(&self, token: &str, params: CreateBlockParams) -> FutureResult<(), FlowyError> { + fn create_block(&self, token: &str, params: CreateTextBlockParams) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.doc_url(); FutureResult::new(async move { create_document_request(&token, params, &url).await }) } - fn read_block(&self, token: &str, params: BlockId) -> FutureResult, FlowyError> { + fn read_block(&self, token: &str, params: TextBlockId) -> FutureResult, FlowyError> { let token = token.to_owned(); let url = self.config.doc_url(); FutureResult::new(async move { read_document_request(&token, params, &url).await }) } - fn update_block(&self, token: &str, params: ResetDocumentParams) -> FutureResult<(), FlowyError> { + fn update_block(&self, token: &str, params: ResetTextBlockParams) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.doc_url(); FutureResult::new(async move { reset_doc_request(&token, params, &url).await }) } } -pub async fn create_document_request(token: &str, params: CreateBlockParams, url: &str) -> Result<(), FlowyError> { +pub async fn create_document_request(token: &str, params: CreateTextBlockParams, url: &str) -> Result<(), FlowyError> { let _ = request_builder() .post(&url.to_owned()) .header(HEADER_TOKEN, token) @@ -50,7 +50,11 @@ pub async fn create_document_request(token: &str, params: CreateBlockParams, url Ok(()) } -pub async fn read_document_request(token: &str, params: BlockId, url: &str) -> Result, FlowyError> { +pub async fn read_document_request( + token: &str, + params: TextBlockId, + url: &str, +) -> Result, FlowyError> { let doc = request_builder() .get(&url.to_owned()) .header(HEADER_TOKEN, token) @@ -61,7 +65,7 @@ pub async fn read_document_request(token: &str, params: BlockId, url: &str) -> R Ok(doc) } -pub async fn reset_doc_request(token: &str, params: ResetDocumentParams, url: &str) -> Result<(), FlowyError> { +pub async fn reset_doc_request(token: &str, params: ResetTextBlockParams, url: &str) -> Result<(), FlowyError> { let _ = request_builder() .patch(&url.to_owned()) .header(HEADER_TOKEN, token) diff --git a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs index db23fbf2ef..6d7dd9c342 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs @@ -1,5 +1,5 @@ -use flowy_collaboration::{ - entities::{document_info::BlockInfo, folder_info::FolderInfo}, +use flowy_sync::{ + entities::{folder_info::FolderInfo, text_block_info::TextBlockInfo}, errors::CollaborateError, protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::*, @@ -29,25 +29,25 @@ pub trait RevisionCloudStorage: Send + Sync { ) -> BoxResultFuture<(), CollaborateError>; } -pub(crate) struct LocalDocumentCloudPersistence { +pub(crate) struct LocalTextBlockCloudPersistence { storage: Arc, } -impl Debug for LocalDocumentCloudPersistence { +impl Debug for LocalTextBlockCloudPersistence { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str("LocalRevisionCloudPersistence") } } -impl std::default::Default for LocalDocumentCloudPersistence { +impl std::default::Default for LocalTextBlockCloudPersistence { fn default() -> Self { - LocalDocumentCloudPersistence { + LocalTextBlockCloudPersistence { storage: Arc::new(MemoryDocumentCloudStorage::default()), } } } -impl FolderCloudPersistence for LocalDocumentCloudPersistence { +impl FolderCloudPersistence for LocalTextBlockCloudPersistence { fn read_folder(&self, _user_id: &str, folder_id: &str) -> BoxResultFuture { let storage = self.storage.clone(); let folder_id = folder_id.to_owned(); @@ -110,8 +110,8 @@ impl FolderCloudPersistence for LocalDocumentCloudPersistence { } } -impl DocumentCloudPersistence for LocalDocumentCloudPersistence { - fn read_document(&self, doc_id: &str) -> BoxResultFuture { +impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { + fn read_text_block(&self, doc_id: &str) -> BoxResultFuture { let storage = self.storage.clone(); let doc_id = doc_id.to_owned(); Box::pin(async move { @@ -123,11 +123,11 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence { }) } - fn create_document( + fn create_text_block( &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { let doc_id = doc_id.to_owned(); let storage = self.storage.clone(); Box::pin(async move { @@ -136,7 +136,7 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence { }) } - fn read_document_revisions( + fn read_text_block_revisions( &self, doc_id: &str, rev_ids: Option>, @@ -150,7 +150,10 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence { }) } - fn save_document_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn save_text_block_revisions( + &self, + repeated_revision: RepeatedRevisionPB, + ) -> BoxResultFuture<(), CollaborateError> { let storage = self.storage.clone(); Box::pin(async move { let _ = storage.set_revisions(repeated_revision).await?; @@ -158,7 +161,7 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence { }) } - fn reset_document(&self, doc_id: &str, revisions: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn reset_text_block(&self, doc_id: &str, revisions: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { let storage = self.storage.clone(); let doc_id = doc_id.to_owned(); Box::pin(async move { diff --git a/frontend/rust-lib/flowy-net/src/local_server/server.rs b/frontend/rust-lib/flowy-net/src/local_server/server.rs index e81e08b80d..e2eaf7de95 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/server.rs @@ -1,10 +1,12 @@ -use crate::local_server::persistence::LocalDocumentCloudPersistence; +use crate::local_server::persistence::LocalTextBlockCloudPersistence; use async_stream::stream; use bytes::Bytes; -use flowy_collaboration::{ - client_document::default::initial_delta_string, +use flowy_error::{internal_error, FlowyError}; +use flowy_folder::event_map::FolderCouldServiceV1; +use flowy_sync::{ + client_document::default::initial_quill_delta_string, entities::{ - document_info::{BlockId, BlockInfo, CreateBlockParams, ResetDocumentParams}, + text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}, ws_data::{ClientRevisionWSData, ClientRevisionWSDataType}, }, errors::CollaborateError, @@ -13,10 +15,9 @@ use flowy_collaboration::{ server_folder::ServerFolderManager, synchronizer::{RevisionSyncResponse, RevisionUser}, }; -use flowy_error::{internal_error, FlowyError}; -use flowy_folder::event_map::FolderCouldServiceV1; use futures_util::stream::StreamExt; use lib_ws::{WSChannel, WebSocketRawMessage}; +use nanoid::nanoid; use parking_lot::RwLock; use std::{ convert::{TryFrom, TryInto}, @@ -38,7 +39,7 @@ impl LocalServer { client_ws_sender: mpsc::UnboundedSender, client_ws_receiver: broadcast::Sender, ) -> Self { - let persistence = Arc::new(LocalDocumentCloudPersistence::default()); + let persistence = Arc::new(LocalTextBlockCloudPersistence::default()); let doc_manager = Arc::new(ServerDocumentManager::new(persistence.clone())); let folder_manager = Arc::new(ServerFolderManager::new(persistence)); let stop_tx = RwLock::new(None); @@ -122,6 +123,9 @@ impl LocalWebSocketRunner { let _ = self.handle_folder_client_data(client_data, "".to_owned()).await?; Ok(()) } + WSChannel::Grid => { + todo!("Implement grid web socket channel") + } } } @@ -248,18 +252,20 @@ impl RevisionUser for LocalRevisionUser { } } -use flowy_block::BlockCloudService; +use flowy_folder_data_model::entities::app::gen_app_id; +use flowy_folder_data_model::entities::workspace::gen_workspace_id; use flowy_folder_data_model::entities::{ app::{App, AppId, CreateAppParams, RepeatedApp, UpdateAppParams}, trash::{RepeatedTrash, RepeatedTrashId}, view::{CreateViewParams, RepeatedView, RepeatedViewId, UpdateViewParams, View, ViewId}, workspace::{CreateWorkspaceParams, RepeatedWorkspace, UpdateWorkspaceParams, Workspace, WorkspaceId}, }; +use flowy_text_block::BlockCloudService; use flowy_user::event_map::UserCloudService; use flowy_user_data_model::entities::{ SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserProfile, }; -use lib_infra::{future::FutureResult, timestamp, uuid_string}; +use lib_infra::{future::FutureResult, timestamp}; impl FolderCouldServiceV1 for LocalServer { fn init(&self) {} @@ -267,7 +273,7 @@ impl FolderCouldServiceV1 for LocalServer { fn create_workspace(&self, _token: &str, params: CreateWorkspaceParams) -> FutureResult { let time = timestamp(); let workspace = Workspace { - id: uuid_string(), + id: gen_workspace_id(), name: params.name, desc: params.desc, apps: RepeatedApp::default(), @@ -305,7 +311,7 @@ impl FolderCouldServiceV1 for LocalServer { belongings: RepeatedView::default(), modified_time: time, create_time: time, - ext_data: params.ext_data, + ext_data: "".to_string(), thumbnail: params.thumbnail, plugin_type: params.plugin_type, }; @@ -327,7 +333,7 @@ impl FolderCouldServiceV1 for LocalServer { fn create_app(&self, _token: &str, params: CreateAppParams) -> FutureResult { let time = timestamp(); let app = App { - id: uuid_string(), + id: gen_app_id(), workspace_id: params.workspace_id, name: params.name, desc: params.desc, @@ -369,7 +375,7 @@ impl FolderCouldServiceV1 for LocalServer { impl UserCloudService for LocalServer { fn sign_up(&self, params: SignUpParams) -> FutureResult { - let uid = uuid_string(); + let uid = nanoid!(10); FutureResult::new(async move { Ok(SignUpResponse { user_id: uid.clone(), @@ -381,7 +387,7 @@ impl UserCloudService for LocalServer { } fn sign_in(&self, params: SignInParams) -> FutureResult { - let user_id = uuid_string(); + let user_id = nanoid!(10); FutureResult::new(async { Ok(SignInResponse { user_id: user_id.clone(), @@ -410,21 +416,21 @@ impl UserCloudService for LocalServer { } impl BlockCloudService for LocalServer { - fn create_block(&self, _token: &str, _params: CreateBlockParams) -> FutureResult<(), FlowyError> { + fn create_block(&self, _token: &str, _params: CreateTextBlockParams) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } - fn read_block(&self, _token: &str, params: BlockId) -> FutureResult, FlowyError> { - let doc = BlockInfo { - doc_id: params.value, - text: initial_delta_string(), + fn read_block(&self, _token: &str, params: TextBlockId) -> FutureResult, FlowyError> { + let doc = TextBlockInfo { + block_id: params.value, + text: initial_quill_delta_string(), rev_id: 0, base_rev_id: 0, }; FutureResult::new(async { Ok(Some(doc)) }) } - fn update_block(&self, _token: &str, _params: ResetDocumentParams) -> FutureResult<(), FlowyError> { + fn update_block(&self, _token: &str, _params: ResetTextBlockParams) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } } diff --git a/frontend/rust-lib/flowy-sync/Cargo.toml b/frontend/rust-lib/flowy-revision/Cargo.toml similarity index 81% rename from frontend/rust-lib/flowy-sync/Cargo.toml rename to frontend/rust-lib/flowy-revision/Cargo.toml index 0d7476eda3..504e05a2ce 100644 --- a/frontend/rust-lib/flowy-sync/Cargo.toml +++ b/frontend/rust-lib/flowy-revision/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "flowy-sync" +name = "flowy-revision" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" } +flowy-sync = { path = "../../../shared-lib/flowy-sync" } lib-ot = { path = "../../../shared-lib/lib-ot" } lib-ws = { path = "../../../shared-lib/lib-ws" } lib-infra = { path = "../../../shared-lib/lib-infra" } @@ -14,19 +14,15 @@ flowy-database = { path = "../flowy-database" } flowy-error = { path = "../flowy-error", features = ["collaboration", "ot", "http_server", "serde", "db"] } diesel = {version = "1.4.8", features = ["sqlite"]} diesel_derives = {version = "1.4.1", features = ["sqlite"]} -protobuf = {version = "2.18.0"} tracing = { version = "0.1", features = ["log"] } tokio = {version = "1", features = ["sync"]} bytes = { version = "1.1" } strum = "0.21" strum_macros = "0.21" dashmap = "4.0" -parking_lot = "0.11" serde = { version = "1.0", features = ["derive"] } -serde_json = {version = "1.0"} futures-util = "0.3.15" async-stream = "0.3.2" -async-trait = "0.1.52" [features] flowy_unit_test = ["lib-ot/flowy_unit_test"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/folder_rev_impl.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/folder_rev_impl.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/folder_rev_impl.rs @@ -0,0 +1 @@ + diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/grid_meta_rev_impl.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_meta_rev_impl.rs new file mode 100644 index 0000000000..e850119c30 --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_meta_rev_impl.rs @@ -0,0 +1,235 @@ +use crate::cache::disk::RevisionDiskCache; +use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState}; + +use bytes::Bytes; +use diesel::{sql_types::Integer, update, SqliteConnection}; +use flowy_database::{ + impl_sql_integer_expression, insert_or_ignore_into, + prelude::*, + schema::{grid_meta_rev_table, grid_meta_rev_table::dsl}, + ConnectionPool, +}; +use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_sync::{ + entities::revision::{Revision, RevisionRange}, + util::md5, +}; +use std::sync::Arc; + +pub struct SQLiteGridBlockMetaRevisionPersistence { + user_id: String, + pub(crate) pool: Arc, +} + +impl RevisionDiskCache for SQLiteGridBlockMetaRevisionPersistence { + type Error = FlowyError; + + fn create_revision_records(&self, revision_records: Vec) -> Result<(), Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + let _ = GridMetaRevisionSql::create(revision_records, &*conn)?; + Ok(()) + } + + fn read_revision_records( + &self, + object_id: &str, + rev_ids: Option>, + ) -> Result, Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + let records = GridMetaRevisionSql::read(&self.user_id, object_id, rev_ids, &*conn)?; + Ok(records) + } + + fn read_revision_records_with_range( + &self, + object_id: &str, + range: &RevisionRange, + ) -> Result, Self::Error> { + let conn = &*self.pool.get().map_err(internal_error)?; + let revisions = GridMetaRevisionSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?; + Ok(revisions) + } + + fn update_revision_record(&self, changesets: Vec) -> FlowyResult<()> { + let conn = &*self.pool.get().map_err(internal_error)?; + let _ = conn.immediate_transaction::<_, FlowyError, _>(|| { + for changeset in changesets { + let _ = GridMetaRevisionSql::update(changeset, conn)?; + } + Ok(()) + })?; + Ok(()) + } + + fn delete_revision_records(&self, object_id: &str, rev_ids: Option>) -> Result<(), Self::Error> { + let conn = &*self.pool.get().map_err(internal_error)?; + let _ = GridMetaRevisionSql::delete(object_id, rev_ids, conn)?; + Ok(()) + } + + fn delete_and_insert_records( + &self, + object_id: &str, + deleted_rev_ids: Option>, + inserted_records: Vec, + ) -> Result<(), Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + conn.immediate_transaction::<_, FlowyError, _>(|| { + let _ = GridMetaRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?; + let _ = GridMetaRevisionSql::create(inserted_records, &*conn)?; + Ok(()) + }) + } +} + +impl SQLiteGridBlockMetaRevisionPersistence { + pub fn new(user_id: &str, pool: Arc) -> Self { + Self { + user_id: user_id.to_owned(), + pool, + } + } +} + +struct GridMetaRevisionSql(); +impl GridMetaRevisionSql { + fn create(revision_records: Vec, conn: &SqliteConnection) -> Result<(), FlowyError> { + // Batch insert: https://diesel.rs/guides/all-about-inserts.html + + let records = revision_records + .into_iter() + .map(|record| { + tracing::trace!( + "[GridMetaRevisionSql] create revision: {}:{:?}", + record.revision.object_id, + record.revision.rev_id + ); + let rev_state: GridMetaRevisionState = record.state.into(); + ( + dsl::object_id.eq(record.revision.object_id), + dsl::base_rev_id.eq(record.revision.base_rev_id), + dsl::rev_id.eq(record.revision.rev_id), + dsl::data.eq(record.revision.delta_data), + dsl::state.eq(rev_state), + ) + }) + .collect::>(); + + let _ = insert_or_ignore_into(dsl::grid_meta_rev_table) + .values(&records) + .execute(conn)?; + Ok(()) + } + + fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> { + let state: GridMetaRevisionState = changeset.state.clone().into(); + let filter = dsl::grid_meta_rev_table + .filter(dsl::rev_id.eq(changeset.rev_id.as_ref())) + .filter(dsl::object_id.eq(changeset.object_id)); + let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?; + tracing::debug!( + "[GridMetaRevisionSql] update revision:{} state:to {:?}", + changeset.rev_id, + changeset.state + ); + Ok(()) + } + + fn read( + user_id: &str, + object_id: &str, + rev_ids: Option>, + conn: &SqliteConnection, + ) -> Result, FlowyError> { + let mut sql = dsl::grid_meta_rev_table + .filter(dsl::object_id.eq(object_id)) + .into_boxed(); + if let Some(rev_ids) = rev_ids { + sql = sql.filter(dsl::rev_id.eq_any(rev_ids)); + } + let rows = sql.order(dsl::rev_id.asc()).load::(conn)?; + let records = rows + .into_iter() + .map(|row| mk_revision_record_from_table(user_id, row)) + .collect::>(); + + Ok(records) + } + + fn read_with_range( + user_id: &str, + object_id: &str, + range: RevisionRange, + conn: &SqliteConnection, + ) -> Result, FlowyError> { + let rev_tables = dsl::grid_meta_rev_table + .filter(dsl::rev_id.ge(range.start)) + .filter(dsl::rev_id.le(range.end)) + .filter(dsl::object_id.eq(object_id)) + .order(dsl::rev_id.asc()) + .load::(conn)?; + + let revisions = rev_tables + .into_iter() + .map(|table| mk_revision_record_from_table(user_id, table)) + .collect::>(); + Ok(revisions) + } + + fn delete(object_id: &str, rev_ids: Option>, conn: &SqliteConnection) -> Result<(), FlowyError> { + let mut sql = diesel::delete(dsl::grid_meta_rev_table).into_boxed(); + sql = sql.filter(dsl::object_id.eq(object_id)); + + if let Some(rev_ids) = rev_ids { + tracing::trace!("[GridMetaRevisionSql] Delete revision: {}:{:?}", object_id, rev_ids); + sql = sql.filter(dsl::rev_id.eq_any(rev_ids)); + } + + let affected_row = sql.execute(conn)?; + tracing::trace!("[GridMetaRevisionSql] Delete {} rows", affected_row); + Ok(()) + } +} + +#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] +#[table_name = "grid_meta_rev_table"] +struct GridMetaRevisionTable { + id: i32, + object_id: String, + base_rev_id: i64, + rev_id: i64, + data: Vec, + state: GridMetaRevisionState, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)] +#[repr(i32)] +#[sql_type = "Integer"] +pub enum GridMetaRevisionState { + Sync = 0, + Ack = 1, +} +impl_sql_integer_expression!(GridMetaRevisionState); +impl_rev_state_map!(GridMetaRevisionState); +impl std::default::Default for GridMetaRevisionState { + fn default() -> Self { + GridMetaRevisionState::Sync + } +} + +fn mk_revision_record_from_table(user_id: &str, table: GridMetaRevisionTable) -> RevisionRecord { + let md5 = md5(&table.data); + let revision = Revision::new( + &table.object_id, + table.base_rev_id, + table.rev_id, + Bytes::from(table.data), + user_id, + md5, + ); + RevisionRecord { + revision, + state: table.state.into(), + write_to_disk: false, + } +} diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs new file mode 100644 index 0000000000..d51ea8e48c --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs @@ -0,0 +1,234 @@ +use crate::cache::disk::RevisionDiskCache; +use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState}; + +use bytes::Bytes; +use diesel::{sql_types::Integer, update, SqliteConnection}; +use flowy_database::{ + impl_sql_integer_expression, insert_or_ignore_into, + prelude::*, + schema::{grid_rev_table, grid_rev_table::dsl}, + ConnectionPool, +}; +use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_sync::{ + entities::revision::{Revision, RevisionRange}, + util::md5, +}; +use std::sync::Arc; + +pub struct SQLiteGridRevisionPersistence { + user_id: String, + pub(crate) pool: Arc, +} + +impl RevisionDiskCache for SQLiteGridRevisionPersistence { + type Error = FlowyError; + + fn create_revision_records(&self, revision_records: Vec) -> Result<(), Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + let _ = GridRevisionSql::create(revision_records, &*conn)?; + Ok(()) + } + + fn read_revision_records( + &self, + object_id: &str, + rev_ids: Option>, + ) -> Result, Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + let records = GridRevisionSql::read(&self.user_id, object_id, rev_ids, &*conn)?; + Ok(records) + } + + fn read_revision_records_with_range( + &self, + object_id: &str, + range: &RevisionRange, + ) -> Result, Self::Error> { + let conn = &*self.pool.get().map_err(internal_error)?; + let revisions = GridRevisionSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?; + Ok(revisions) + } + + fn update_revision_record(&self, changesets: Vec) -> FlowyResult<()> { + let conn = &*self.pool.get().map_err(internal_error)?; + let _ = conn.immediate_transaction::<_, FlowyError, _>(|| { + for changeset in changesets { + let _ = GridRevisionSql::update(changeset, conn)?; + } + Ok(()) + })?; + Ok(()) + } + + fn delete_revision_records(&self, object_id: &str, rev_ids: Option>) -> Result<(), Self::Error> { + let conn = &*self.pool.get().map_err(internal_error)?; + let _ = GridRevisionSql::delete(object_id, rev_ids, conn)?; + Ok(()) + } + + fn delete_and_insert_records( + &self, + object_id: &str, + deleted_rev_ids: Option>, + inserted_records: Vec, + ) -> Result<(), Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + conn.immediate_transaction::<_, FlowyError, _>(|| { + let _ = GridRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?; + let _ = GridRevisionSql::create(inserted_records, &*conn)?; + Ok(()) + }) + } +} + +impl SQLiteGridRevisionPersistence { + pub fn new(user_id: &str, pool: Arc) -> Self { + Self { + user_id: user_id.to_owned(), + pool, + } + } +} + +struct GridRevisionSql(); +impl GridRevisionSql { + fn create(revision_records: Vec, conn: &SqliteConnection) -> Result<(), FlowyError> { + // Batch insert: https://diesel.rs/guides/all-about-inserts.html + + let records = revision_records + .into_iter() + .map(|record| { + tracing::trace!( + "[GridRevisionSql] create revision: {}:{:?}", + record.revision.object_id, + record.revision.rev_id + ); + let rev_state: GridRevisionState = record.state.into(); + ( + dsl::object_id.eq(record.revision.object_id), + dsl::base_rev_id.eq(record.revision.base_rev_id), + dsl::rev_id.eq(record.revision.rev_id), + dsl::data.eq(record.revision.delta_data), + dsl::state.eq(rev_state), + ) + }) + .collect::>(); + + let _ = insert_or_ignore_into(dsl::grid_rev_table) + .values(&records) + .execute(conn)?; + Ok(()) + } + + fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> { + let state: GridRevisionState = changeset.state.clone().into(); + let filter = dsl::grid_rev_table + .filter(dsl::rev_id.eq(changeset.rev_id.as_ref())) + .filter(dsl::object_id.eq(changeset.object_id)); + let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?; + tracing::debug!( + "[GridRevisionSql] update revision:{} state:to {:?}", + changeset.rev_id, + changeset.state + ); + Ok(()) + } + + fn read( + user_id: &str, + object_id: &str, + rev_ids: Option>, + conn: &SqliteConnection, + ) -> Result, FlowyError> { + let mut sql = dsl::grid_rev_table.filter(dsl::object_id.eq(object_id)).into_boxed(); + if let Some(rev_ids) = rev_ids { + sql = sql.filter(dsl::rev_id.eq_any(rev_ids)); + } + let rows = sql.order(dsl::rev_id.asc()).load::(conn)?; + let records = rows + .into_iter() + .map(|row| mk_revision_record_from_table(user_id, row)) + .collect::>(); + + Ok(records) + } + + fn read_with_range( + user_id: &str, + object_id: &str, + range: RevisionRange, + conn: &SqliteConnection, + ) -> Result, FlowyError> { + let rev_tables = dsl::grid_rev_table + .filter(dsl::rev_id.ge(range.start)) + .filter(dsl::rev_id.le(range.end)) + .filter(dsl::object_id.eq(object_id)) + .order(dsl::rev_id.asc()) + .load::(conn)?; + + let revisions = rev_tables + .into_iter() + .map(|table| mk_revision_record_from_table(user_id, table)) + .collect::>(); + Ok(revisions) + } + + fn delete(object_id: &str, rev_ids: Option>, conn: &SqliteConnection) -> Result<(), FlowyError> { + let mut sql = diesel::delete(dsl::grid_rev_table).into_boxed(); + sql = sql.filter(dsl::object_id.eq(object_id)); + + if let Some(rev_ids) = rev_ids { + tracing::trace!("[GridRevisionSql] Delete revision: {}:{:?}", object_id, rev_ids); + sql = sql.filter(dsl::rev_id.eq_any(rev_ids)); + } + + let affected_row = sql.execute(conn)?; + tracing::trace!("[GridRevisionSql] Delete {} rows", affected_row); + Ok(()) + } +} + +#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] +#[table_name = "grid_rev_table"] +struct GridRevisionTable { + id: i32, + object_id: String, + base_rev_id: i64, + rev_id: i64, + data: Vec, + state: GridRevisionState, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)] +#[repr(i32)] +#[sql_type = "Integer"] +pub enum GridRevisionState { + Sync = 0, + Ack = 1, +} +impl_sql_integer_expression!(GridRevisionState); +impl_rev_state_map!(GridRevisionState); + +impl std::default::Default for GridRevisionState { + fn default() -> Self { + GridRevisionState::Sync + } +} + +fn mk_revision_record_from_table(user_id: &str, table: GridRevisionTable) -> RevisionRecord { + let md5 = md5(&table.data); + let revision = Revision::new( + &table.object_id, + table.base_rev_id, + table.rev_id, + Bytes::from(table.data), + user_id, + md5, + ); + RevisionRecord { + revision, + state: table.state.into(), + write_to_disk: false, + } +} diff --git a/frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs similarity index 51% rename from frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs rename to frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs index 7bcbc30fdd..945c6d707f 100644 --- a/frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs @@ -1,19 +1,20 @@ -mod sql_impl; -use crate::RevisionRecord; -use diesel::SqliteConnection; -use flowy_collaboration::entities::revision::RevisionRange; -pub use sql_impl::*; +mod folder_rev_impl; +mod grid_meta_rev_impl; +mod grid_rev_impl; +mod text_rev_impl; + +pub use folder_rev_impl::*; +pub use grid_meta_rev_impl::*; +pub use grid_rev_impl::*; +pub use text_rev_impl::*; use flowy_error::FlowyResult; +use flowy_sync::entities::revision::{RevId, Revision, RevisionRange}; use std::fmt::Debug; pub trait RevisionDiskCache: Sync + Send { type Error: Debug; - fn create_revision_records( - &self, - revision_records: Vec, - conn: &SqliteConnection, - ) -> Result<(), Self::Error>; + fn create_revision_records(&self, revision_records: Vec) -> Result<(), Self::Error>; // Read all the records if the rev_ids is None fn read_revision_records( @@ -43,3 +44,43 @@ pub trait RevisionDiskCache: Sync + Send { inserted_records: Vec, ) -> Result<(), Self::Error>; } + +#[derive(Clone, Debug)] +pub struct RevisionRecord { + pub revision: Revision, + pub state: RevisionState, + pub write_to_disk: bool, +} + +impl RevisionRecord { + pub fn ack(&mut self) { + self.state = RevisionState::Ack; + } +} + +pub struct RevisionChangeset { + pub(crate) object_id: String, + pub(crate) rev_id: RevId, + pub(crate) state: RevisionState, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum RevisionState { + Sync = 0, + Ack = 1, +} + +impl RevisionState { + pub fn is_need_sync(&self) -> bool { + match self { + RevisionState::Sync => true, + RevisionState::Ack => false, + } + } +} + +impl AsRef for RevisionState { + fn as_ref(&self) -> &RevisionState { + self + } +} diff --git a/frontend/rust-lib/flowy-sync/src/cache/disk/sql_impl.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/text_rev_impl.rs similarity index 63% rename from frontend/rust-lib/flowy-sync/src/cache/disk/sql_impl.rs rename to frontend/rust-lib/flowy-revision/src/cache/disk/text_rev_impl.rs index e985a98bd8..165864d5db 100644 --- a/frontend/rust-lib/flowy-sync/src/cache/disk/sql_impl.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/text_rev_impl.rs @@ -1,10 +1,8 @@ -use crate::{cache::disk::RevisionDiskCache, RevisionRecord}; +use crate::cache::disk::RevisionDiskCache; +use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState}; + use bytes::Bytes; use diesel::{sql_types::Integer, update, SqliteConnection}; -use flowy_collaboration::{ - entities::revision::{RevId, RevType, Revision, RevisionRange, RevisionState}, - util::md5, -}; use flowy_database::{ impl_sql_integer_expression, insert_or_ignore_into, prelude::*, @@ -12,22 +10,23 @@ use flowy_database::{ ConnectionPool, }; use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_sync::{ + entities::revision::{RevType, Revision, RevisionRange}, + util::md5, +}; use std::sync::Arc; -pub struct SQLitePersistence { +pub struct SQLiteTextBlockRevisionPersistence { user_id: String, pub(crate) pool: Arc, } -impl RevisionDiskCache for SQLitePersistence { +impl RevisionDiskCache for SQLiteTextBlockRevisionPersistence { type Error = FlowyError; - fn create_revision_records( - &self, - revision_records: Vec, - conn: &SqliteConnection, - ) -> Result<(), Self::Error> { - let _ = RevisionTableSql::create(revision_records, conn)?; + fn create_revision_records(&self, revision_records: Vec) -> Result<(), Self::Error> { + let conn = self.pool.get().map_err(internal_error)?; + let _ = TextRevisionSql::create(revision_records, &*conn)?; Ok(()) } @@ -37,7 +36,7 @@ impl RevisionDiskCache for SQLitePersistence { rev_ids: Option>, ) -> Result, Self::Error> { let conn = self.pool.get().map_err(internal_error)?; - let records = RevisionTableSql::read(&self.user_id, object_id, rev_ids, &*conn)?; + let records = TextRevisionSql::read(&self.user_id, object_id, rev_ids, &*conn)?; Ok(records) } @@ -47,7 +46,7 @@ impl RevisionDiskCache for SQLitePersistence { range: &RevisionRange, ) -> Result, Self::Error> { let conn = &*self.pool.get().map_err(internal_error)?; - let revisions = RevisionTableSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?; + let revisions = TextRevisionSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?; Ok(revisions) } @@ -55,7 +54,7 @@ impl RevisionDiskCache for SQLitePersistence { let conn = &*self.pool.get().map_err(internal_error)?; let _ = conn.immediate_transaction::<_, FlowyError, _>(|| { for changeset in changesets { - let _ = RevisionTableSql::update(changeset, conn)?; + let _ = TextRevisionSql::update(changeset, conn)?; } Ok(()) })?; @@ -64,7 +63,7 @@ impl RevisionDiskCache for SQLitePersistence { fn delete_revision_records(&self, object_id: &str, rev_ids: Option>) -> Result<(), Self::Error> { let conn = &*self.pool.get().map_err(internal_error)?; - let _ = RevisionTableSql::delete(object_id, rev_ids, conn)?; + let _ = TextRevisionSql::delete(object_id, rev_ids, conn)?; Ok(()) } @@ -76,15 +75,15 @@ impl RevisionDiskCache for SQLitePersistence { ) -> Result<(), Self::Error> { let conn = self.pool.get().map_err(internal_error)?; conn.immediate_transaction::<_, FlowyError, _>(|| { - let _ = RevisionTableSql::delete(object_id, deleted_rev_ids, &*conn)?; - let _ = self.create_revision_records(inserted_records, &*conn)?; + let _ = TextRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?; + let _ = TextRevisionSql::create(inserted_records, &*conn)?; Ok(()) }) } } -impl SQLitePersistence { - pub(crate) fn new(user_id: &str, pool: Arc) -> Self { +impl SQLiteTextBlockRevisionPersistence { + pub fn new(user_id: &str, pool: Arc) -> Self { Self { user_id: user_id.to_owned(), pool, @@ -92,21 +91,21 @@ impl SQLitePersistence { } } -pub struct RevisionTableSql {} +struct TextRevisionSql {} -impl RevisionTableSql { - pub(crate) fn create(revision_records: Vec, conn: &SqliteConnection) -> Result<(), FlowyError> { +impl TextRevisionSql { + fn create(revision_records: Vec, conn: &SqliteConnection) -> Result<(), FlowyError> { // Batch insert: https://diesel.rs/guides/all-about-inserts.html let records = revision_records .into_iter() .map(|record| { tracing::trace!( - "[RevisionTable] create revision: {}:{:?}", + "[TextRevisionSql] create revision: {}:{:?}", record.revision.object_id, record.revision.rev_id ); - let rev_state: RevisionTableState = record.state.into(); + let rev_state: TextRevisionState = record.state.into(); ( dsl::doc_id.eq(record.revision.object_id), dsl::base_rev_id.eq(record.revision.base_rev_id), @@ -122,20 +121,21 @@ impl RevisionTableSql { Ok(()) } - pub(crate) fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> { + fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> { + let state: TextRevisionState = changeset.state.clone().into(); let filter = dsl::rev_table .filter(dsl::rev_id.eq(changeset.rev_id.as_ref())) .filter(dsl::doc_id.eq(changeset.object_id)); - let _ = update(filter).set(dsl::state.eq(changeset.state)).execute(conn)?; + let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?; tracing::debug!( - "[RevisionTable] update revision:{} state:to {:?}", + "[TextRevisionSql] update revision:{} state:to {:?}", changeset.rev_id, changeset.state ); Ok(()) } - pub(crate) fn read( + fn read( user_id: &str, object_id: &str, rev_ids: Option>, @@ -154,7 +154,7 @@ impl RevisionTableSql { Ok(records) } - pub(crate) fn read_with_range( + fn read_with_range( user_id: &str, object_id: &str, range: RevisionRange, @@ -174,90 +174,50 @@ impl RevisionTableSql { Ok(revisions) } - pub(crate) fn delete( - object_id: &str, - rev_ids: Option>, - conn: &SqliteConnection, - ) -> Result<(), FlowyError> { + fn delete(object_id: &str, rev_ids: Option>, conn: &SqliteConnection) -> Result<(), FlowyError> { let mut sql = diesel::delete(dsl::rev_table).into_boxed(); sql = sql.filter(dsl::doc_id.eq(object_id)); if let Some(rev_ids) = rev_ids { - tracing::trace!("[RevisionTable] Delete revision: {}:{:?}", object_id, rev_ids); + tracing::trace!("[TextRevisionSql] Delete revision: {}:{:?}", object_id, rev_ids); sql = sql.filter(dsl::rev_id.eq_any(rev_ids)); } let affected_row = sql.execute(conn)?; - tracing::trace!("[RevisionTable] Delete {} rows", affected_row); + tracing::trace!("[TextRevisionSql] Delete {} rows", affected_row); Ok(()) } } #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] #[table_name = "rev_table"] -pub(crate) struct RevisionTable { +struct RevisionTable { id: i32, - pub(crate) doc_id: String, - pub(crate) base_rev_id: i64, - pub(crate) rev_id: i64, - pub(crate) data: Vec, - pub(crate) state: RevisionTableState, - pub(crate) ty: RevTableType, // Deprecated + doc_id: String, + base_rev_id: i64, + rev_id: i64, + data: Vec, + state: TextRevisionState, + ty: RevTableType, // Deprecated } #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)] #[repr(i32)] #[sql_type = "Integer"] -pub enum RevisionTableState { +enum TextRevisionState { Sync = 0, Ack = 1, } +impl_sql_integer_expression!(TextRevisionState); +impl_rev_state_map!(TextRevisionState); -impl std::default::Default for RevisionTableState { +impl std::default::Default for TextRevisionState { fn default() -> Self { - RevisionTableState::Sync + TextRevisionState::Sync } } -impl std::convert::From for RevisionTableState { - fn from(value: i32) -> Self { - match value { - 0 => RevisionTableState::Sync, - 1 => RevisionTableState::Ack, - o => { - tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o); - RevisionTableState::Sync - } - } - } -} - -impl RevisionTableState { - pub fn value(&self) -> i32 { - *self as i32 - } -} -impl_sql_integer_expression!(RevisionTableState); - -impl std::convert::From for RevisionState { - fn from(s: RevisionTableState) -> Self { - match s { - RevisionTableState::Sync => RevisionState::Sync, - RevisionTableState::Ack => RevisionState::Ack, - } - } -} - -impl std::convert::From for RevisionTableState { - fn from(s: RevisionState) -> Self { - match s { - RevisionState::Sync => RevisionTableState::Sync, - RevisionState::Ack => RevisionTableState::Ack, - } - } -} - -pub(crate) fn mk_revision_record_from_table(user_id: &str, table: RevisionTable) -> RevisionRecord { +fn mk_revision_record_from_table(user_id: &str, table: RevisionTable) -> RevisionRecord { let md5 = md5(&table.data); let revision = Revision::new( &table.doc_id, @@ -281,6 +241,7 @@ pub enum RevTableType { Local = 0, Remote = 1, } +impl_sql_integer_expression!(RevTableType); impl std::default::Default for RevTableType { fn default() -> Self { @@ -300,12 +261,6 @@ impl std::convert::From for RevTableType { } } } -impl RevTableType { - pub fn value(&self) -> i32 { - *self as i32 - } -} -impl_sql_integer_expression!(RevTableType); impl std::convert::From for RevTableType { fn from(ty: RevType) -> Self { @@ -324,9 +279,3 @@ impl std::convert::From for RevType { } } } - -pub struct RevisionChangeset { - pub(crate) object_id: String, - pub(crate) rev_id: RevId, - pub(crate) state: RevisionTableState, -} diff --git a/frontend/rust-lib/flowy-sync/src/cache/memory.rs b/frontend/rust-lib/flowy-revision/src/cache/memory.rs similarity index 97% rename from frontend/rust-lib/flowy-sync/src/cache/memory.rs rename to frontend/rust-lib/flowy-revision/src/cache/memory.rs index 2c99c3f08c..6120c3f224 100644 --- a/frontend/rust-lib/flowy-sync/src/cache/memory.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/memory.rs @@ -1,7 +1,8 @@ -use crate::{RevisionRecord, REVISION_WRITE_INTERVAL_IN_MILLIS}; +use crate::disk::RevisionRecord; +use crate::REVISION_WRITE_INTERVAL_IN_MILLIS; use dashmap::DashMap; -use flowy_collaboration::entities::revision::RevisionRange; use flowy_error::{FlowyError, FlowyResult}; +use flowy_sync::entities::revision::RevisionRange; use std::{borrow::Cow, sync::Arc, time::Duration}; use tokio::{sync::RwLock, task::JoinHandle}; diff --git a/frontend/rust-lib/flowy-revision/src/cache/mod.rs b/frontend/rust-lib/flowy-revision/src/cache/mod.rs new file mode 100644 index 0000000000..3e592c49b1 --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/cache/mod.rs @@ -0,0 +1,2 @@ +pub mod disk; +pub(crate) mod memory; diff --git a/frontend/rust-lib/flowy-sync/src/conflict_resolve.rs b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs similarity index 98% rename from frontend/rust-lib/flowy-sync/src/conflict_resolve.rs rename to frontend/rust-lib/flowy-revision/src/conflict_resolve.rs index 817b77bd88..0a63f37f3e 100644 --- a/frontend/rust-lib/flowy-sync/src/conflict_resolve.rs +++ b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs @@ -1,13 +1,13 @@ use crate::RevisionManager; use bytes::Bytes; -use flowy_collaboration::{ +use flowy_error::{FlowyError, FlowyResult}; +use flowy_sync::{ entities::{ revision::{RepeatedRevision, Revision, RevisionRange}, ws_data::ServerRevisionWSDataType, }, util::make_delta_from_revisions, }; -use flowy_error::{FlowyError, FlowyResult}; use lib_infra::future::BoxResultFuture; use lib_ot::core::{Attributes, Delta, PlainTextAttributes}; use lib_ot::rich_text::RichTextAttributes; @@ -154,7 +154,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - client_delta.to_bytes(), + client_delta.to_delta_bytes(), user_id, md5.clone(), ); @@ -166,7 +166,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - server_delta.to_bytes(), + server_delta.to_delta_bytes(), user_id, md5, ); diff --git a/frontend/rust-lib/flowy-sync/src/lib.rs b/frontend/rust-lib/flowy-revision/src/lib.rs similarity index 80% rename from frontend/rust-lib/flowy-sync/src/lib.rs rename to frontend/rust-lib/flowy-revision/src/lib.rs index 16cc05d2c7..05e60c00e0 100644 --- a/frontend/rust-lib/flowy-sync/src/lib.rs +++ b/frontend/rust-lib/flowy-revision/src/lib.rs @@ -1,11 +1,13 @@ mod cache; mod conflict_resolve; mod rev_manager; +mod rev_persistence; mod ws_manager; pub use cache::*; pub use conflict_resolve::*; pub use rev_manager::*; +pub use rev_persistence::*; pub use ws_manager::*; #[macro_use] diff --git a/frontend/rust-lib/flowy-sync/src/rev_manager.rs b/frontend/rust-lib/flowy-revision/src/rev_manager.rs similarity index 80% rename from frontend/rust-lib/flowy-sync/src/rev_manager.rs rename to frontend/rust-lib/flowy-revision/src/rev_manager.rs index 5583690913..68d8db6f27 100644 --- a/frontend/rust-lib/flowy-sync/src/rev_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_manager.rs @@ -1,9 +1,11 @@ +use crate::disk::RevisionState; use crate::{RevisionPersistence, WSDataProviderDataSource}; -use flowy_collaboration::{ - entities::revision::{RepeatedRevision, Revision, RevisionRange, RevisionState}, +use bytes::Bytes; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_sync::{ + entities::revision::{RepeatedRevision, Revision, RevisionRange}, util::{pair_rev_id_from_revisions, RevIdCounter}, }; -use flowy_error::{FlowyError, FlowyResult}; use lib_infra::future::FutureResult; use std::sync::Arc; @@ -16,8 +18,26 @@ pub trait RevisionObjectBuilder: Send + Sync { fn build_object(object_id: &str, revisions: Vec) -> FlowyResult; } -pub trait RevisionCompact: Send + Sync { - fn compact_revisions(user_id: &str, object_id: &str, revisions: Vec) -> FlowyResult; +pub trait RevisionCompactor: Send + Sync { + fn compact(&self, user_id: &str, object_id: &str, mut revisions: Vec) -> FlowyResult { + if revisions.is_empty() { + return Err(FlowyError::internal().context("Can't compact the empty folder's revisions")); + } + + if revisions.len() == 1 { + return Ok(revisions.pop().unwrap()); + } + + let first_revision = revisions.first().unwrap(); + let last_revision = revisions.last().unwrap(); + + let (base_rev_id, rev_id) = first_revision.pair_rev_id(); + let md5 = last_revision.md5.clone(); + let delta_data = self.bytes_from_revisions(revisions)?; + Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5)) + } + + fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult; } pub struct RevisionManager { @@ -47,20 +67,21 @@ impl RevisionManager { } } - pub async fn load(&mut self, cloud: Arc) -> FlowyResult + #[tracing::instrument(level = "debug", skip_all, fields(object_id) err)] + pub async fn load(&mut self, cloud: Option>) -> FlowyResult where B: RevisionObjectBuilder, - C: RevisionCompact, { let (revisions, rev_id) = RevisionLoader { object_id: self.object_id.clone(), user_id: self.user_id.clone(), - cloud: Some(cloud), + cloud, rev_persistence: self.rev_persistence.clone(), } .load() .await?; self.rev_id_counter.set(rev_id); + tracing::Span::current().record("object_id", &self.object_id.as_str()); B::build_object(&self.object_id, revisions) } @@ -83,15 +104,16 @@ impl RevisionManager { Ok(()) } - #[tracing::instrument(level = "debug", skip(self, revision))] - pub async fn add_local_revision(&self, revision: &Revision) -> Result<(), FlowyError> - where - C: RevisionCompact, - { + #[tracing::instrument(level = "debug", skip_all, err)] + pub async fn add_local_revision<'a>( + &'a self, + revision: &Revision, + compactor: Box, + ) -> Result<(), FlowyError> { if revision.delta_data.is_empty() { return Err(FlowyError::internal().context("Delta data should be empty")); } - let rev_id = self.rev_persistence.add_sync_revision::(revision).await?; + let rev_id = self.rev_persistence.add_sync_revision(revision, compactor).await?; self.rev_id_counter.set(rev_id); Ok(()) } diff --git a/frontend/rust-lib/flowy-sync/src/cache/mod.rs b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs similarity index 86% rename from frontend/rust-lib/flowy-sync/src/cache/mod.rs rename to frontend/rust-lib/flowy-revision/src/rev_persistence.rs index a6b5be4102..6412b26ec6 100644 --- a/frontend/rust-lib/flowy-sync/src/cache/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs @@ -1,16 +1,13 @@ -mod disk; -mod memory; - use crate::cache::{ - disk::{RevisionChangeset, RevisionDiskCache, RevisionTableState, SQLitePersistence}, - memory::{RevisionMemoryCache, RevisionMemoryCacheDelegate}, + disk::{RevisionChangeset, RevisionDiskCache, SQLiteTextBlockRevisionPersistence}, + memory::RevisionMemoryCacheDelegate, }; - -use flowy_collaboration::entities::revision::{Revision, RevisionRange, RevisionState}; +use crate::disk::{RevisionRecord, RevisionState}; +use crate::memory::RevisionMemoryCache; +use crate::RevisionCompactor; use flowy_database::ConnectionPool; use flowy_error::{internal_error, FlowyError, FlowyResult}; - -use crate::RevisionCompact; +use flowy_sync::entities::revision::{Revision, RevisionRange}; use std::collections::VecDeque; use std::{borrow::Cow, sync::Arc}; use tokio::sync::RwLock; @@ -25,13 +22,17 @@ pub struct RevisionPersistence { memory_cache: Arc, sync_seq: RwLock, } + impl RevisionPersistence { - pub fn new(user_id: &str, object_id: &str, pool: Arc) -> RevisionPersistence { - let disk_cache = Arc::new(SQLitePersistence::new(user_id, pool)); - let memory_cache = Arc::new(RevisionMemoryCache::new(object_id, Arc::new(disk_cache.clone()))); + pub fn new( + user_id: &str, + object_id: &str, + disk_cache: Arc>, + ) -> RevisionPersistence { let object_id = object_id.to_owned(); let user_id = user_id.to_owned(); let sync_seq = RwLock::new(RevisionSyncSequence::new()); + let memory_cache = Arc::new(RevisionMemoryCache::new(&object_id, Arc::new(disk_cache.clone()))); Self { user_id, object_id, @@ -58,11 +59,12 @@ impl RevisionPersistence { } /// Save the revision to disk and append it to the end of the sync sequence. - #[tracing::instrument(level = "trace", skip(self, revision), fields(rev_id, compact_range, object_id=%self.object_id), err)] - pub(crate) async fn add_sync_revision(&self, revision: &Revision) -> FlowyResult - where - C: RevisionCompact, - { + #[tracing::instrument(level = "trace", skip_all, fields(rev_id, compact_range, object_id=%self.object_id), err)] + pub(crate) async fn add_sync_revision<'a>( + &'a self, + revision: &'a Revision, + compactor: Box, + ) -> FlowyResult { let result = self.sync_seq.read().await.compact(); match result { None => { @@ -82,7 +84,7 @@ impl RevisionPersistence { revisions.push(revision.clone()); // compact multiple revisions into one - let compact_revision = C::compact_revisions(&self.user_id, &self.object_id, revisions)?; + let compact_revision = compactor.compact(&self.user_id, &self.object_id, revisions)?; let rev_id = compact_revision.rev_id; tracing::Span::current().record("rev_id", &rev_id); @@ -216,20 +218,18 @@ pub fn mk_revision_disk_cache( user_id: &str, pool: Arc, ) -> Arc> { - Arc::new(SQLitePersistence::new(user_id, pool)) + Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool)) } -impl RevisionMemoryCacheDelegate for Arc { - #[tracing::instrument(level = "trace", skip(self, records), fields(checkpoint_result), err)] +impl RevisionMemoryCacheDelegate for Arc> { fn checkpoint_tick(&self, mut records: Vec) -> FlowyResult<()> { - let conn = &*self.pool.get().map_err(internal_error)?; records.retain(|record| record.write_to_disk); if !records.is_empty() { tracing::Span::current().record( "checkpoint_result", &format!("{} records were saved", records.len()).as_str(), ); - let _ = self.create_revision_records(records, conn)?; + let _ = self.create_revision_records(records)?; } Ok(()) } @@ -238,7 +238,7 @@ impl RevisionMemoryCacheDelegate for Arc { let changeset = RevisionChangeset { object_id: object_id.to_string(), rev_id: rev_id.into(), - state: RevisionTableState::Ack, + state: RevisionState::Ack, }; match self.update_revision_record(vec![changeset]) { Ok(_) => {} @@ -247,19 +247,6 @@ impl RevisionMemoryCacheDelegate for Arc { } } -#[derive(Clone, Debug)] -pub struct RevisionRecord { - pub revision: Revision, - pub state: RevisionState, - pub write_to_disk: bool, -} - -impl RevisionRecord { - pub fn ack(&mut self) { - self.state = RevisionState::Ack; - } -} - #[derive(Default)] struct RevisionSyncSequence(VecDeque); impl RevisionSyncSequence { diff --git a/frontend/rust-lib/flowy-sync/src/ws_manager.rs b/frontend/rust-lib/flowy-revision/src/ws_manager.rs similarity index 98% rename from frontend/rust-lib/flowy-sync/src/ws_manager.rs rename to frontend/rust-lib/flowy-revision/src/ws_manager.rs index a151a58038..42ad39c617 100644 --- a/frontend/rust-lib/flowy-sync/src/ws_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/ws_manager.rs @@ -2,11 +2,11 @@ use crate::ConflictRevisionSink; use async_stream::stream; use bytes::Bytes; -use flowy_collaboration::entities::{ +use flowy_error::{FlowyError, FlowyResult}; +use flowy_sync::entities::{ revision::{RevId, Revision, RevisionRange}, ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSData, ServerRevisionWSDataType}, }; -use flowy_error::{FlowyError, FlowyResult}; use futures_util::{future::BoxFuture, stream::StreamExt}; use lib_infra::future::{BoxResultFuture, FutureResult}; use lib_ws::WSConnectState; @@ -30,7 +30,7 @@ pub trait RevisionWSDataStream: Send + Sync { // The sink provides the data that will be sent through the web socket to the // backend. -pub trait RevisionWSDataIterator: Send + Sync { +pub trait RevisionWebSocketSink: Send + Sync { fn next(&self) -> FutureResult, FlowyError>; } @@ -43,7 +43,7 @@ pub trait RevisionWebSocket: Send + Sync + 'static { pub struct RevisionWebSocketManager { pub object_name: String, pub object_id: String, - ws_data_sink: Arc, + ws_data_sink: Arc, ws_data_stream: Arc, rev_web_socket: Arc, pub ws_passthrough_tx: Sender, @@ -62,7 +62,7 @@ impl RevisionWebSocketManager { object_name: &str, object_id: &str, rev_web_socket: Arc, - ws_data_sink: Arc, + ws_data_sink: Arc, ws_data_stream: Arc, ping_duration: Duration, ) -> Self { @@ -246,7 +246,7 @@ type SinkStopTx = broadcast::Sender<()>; pub struct RevisionWSSink { object_id: String, object_name: String, - provider: Arc, + provider: Arc, rev_web_socket: Arc, stop_rx: Option, ping_duration: Duration, @@ -256,7 +256,7 @@ impl RevisionWSSink { pub fn new( object_id: &str, object_name: &str, - provider: Arc, + provider: Arc, rev_web_socket: Arc, stop_rx: SinkStopRx, ping_duration: Duration, diff --git a/frontend/rust-lib/flowy-sdk/Cargo.toml b/frontend/rust-lib/flowy-sdk/Cargo.toml index d7dcd58789..2ffb444962 100644 --- a/frontend/rust-lib/flowy-sdk/Cargo.toml +++ b/frontend/rust-lib/flowy-sdk/Cargo.toml @@ -11,9 +11,11 @@ lib-log = { path = "../lib-log" } flowy-user = { path = "../flowy-user" } flowy-net = { path = "../flowy-net" } flowy-folder = { path = "../flowy-folder", default-features = false } +flowy-grid = { path = "../flowy-grid", default-features = false } +flowy-grid-data-model = { path = "../../../shared-lib/flowy-grid-data-model" } flowy-database = { path = "../flowy-database" } -flowy-block = { path = "../flowy-block" } -flowy-sync = { path = "../flowy-sync" } +flowy-text-block = { path = "../flowy-text-block", default-features = false } +flowy-revision = { path = "../flowy-revision" } tracing = { version = "0.1" } log = "0.4.14" @@ -23,8 +25,7 @@ bytes = "1.0" tokio = { version = "1", features = ["rt"] } parking_lot = "0.11" - -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" } +flowy-sync = { path = "../../../shared-lib/flowy-sync" } lib-ws = { path = "../../../shared-lib/lib-ws" } lib-infra = { path = "../../../shared-lib/lib-infra" } @@ -37,6 +38,7 @@ tokio = { version = "1", features = ["full"]} futures-util = "0.3.15" [features] -http_server = ["flowy-user/http_server", "flowy-folder/http_server", "flowy-block/http_server"] +http_sync = ["flowy-folder/cloud_sync", "flowy-text-block/cloud_sync"] +native_sync = ["flowy-folder/cloud_sync", "flowy-text-block/cloud_sync"] use_bunyan = ["lib-log/use_bunyan"] -dart = ["flowy-user/dart", "flowy-net/dart", "flowy-folder/dart", "flowy-collaboration/dart"] +dart = ["flowy-user/dart", "flowy-net/dart", "flowy-folder/dart", "flowy-sync/dart", "flowy-grid/dart", "flowy-text-block/dart"] diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs index 3a791888ff..41835804af 100644 --- a/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs @@ -1,21 +1,33 @@ use bytes::Bytes; -use flowy_block::BlockManager; -use flowy_collaboration::entities::ws_data::ClientRevisionWSData; use flowy_database::ConnectionPool; +use flowy_sync::client_document::default::initial_quill_delta_string; +use flowy_sync::entities::revision::{RepeatedRevision, Revision}; +use flowy_sync::entities::ws_data::ClientRevisionWSData; +use flowy_text_block::TextBlockManager; + +use flowy_folder::manager::{ViewDataProcessor, ViewDataProcessorMap}; +use flowy_folder::prelude::ViewDataType; use flowy_folder::{ - controller::FolderManager, errors::{internal_error, FlowyError}, event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser}, + manager::FolderManager, }; +use flowy_grid::manager::{make_grid_view_data, GridManager}; +use flowy_grid::util::make_default_grid; + use flowy_net::ClientServerConfiguration; use flowy_net::{ http_server::folder::FolderHttpCloudService, local_server::LocalServer, ws::connection::FlowyWebSocketConnect, }; -use flowy_sync::{RevisionWebSocket, WSStateReceiver}; +use flowy_revision::{RevisionWebSocket, WSStateReceiver}; use flowy_user::services::UserSession; use futures_core::future::BoxFuture; -use lib_infra::future::BoxResultFuture; +use lib_infra::future::{BoxResultFuture, FutureResult}; use lib_ws::{WSChannel, WSMessageReceiver, WebSocketRawMessage}; +use std::collections::HashMap; + +use flowy_grid_data_model::entities::BuildGridContext; +use std::convert::TryFrom; use std::{convert::TryInto, sync::Arc}; pub struct FolderDepsResolver(); @@ -24,8 +36,9 @@ impl FolderDepsResolver { local_server: Option>, user_session: Arc, server_config: &ClientServerConfiguration, - document_manager: &Arc, - ws_conn: Arc, + ws_conn: &Arc, + text_block_manager: &Arc, + grid_manager: &Arc, ) -> Arc { let user: Arc = Arc::new(WorkspaceUserImpl(user_session.clone())); let database: Arc = Arc::new(WorkspaceDatabaseImpl(user_session)); @@ -35,16 +48,9 @@ impl FolderDepsResolver { Some(local_server) => local_server, }; - let folder_manager = Arc::new( - FolderManager::new( - user.clone(), - cloud_service, - database, - document_manager.clone(), - web_socket, - ) - .await, - ); + let view_data_processor = make_view_data_processor(text_block_manager.clone(), grid_manager.clone()); + let folder_manager = + Arc::new(FolderManager::new(user.clone(), cloud_service, database, view_data_processor, web_socket).await); if let (Ok(user_id), Ok(token)) = (user.user_id(), user.token()) { match folder_manager.initialize(&user_id, &token).await { @@ -55,11 +61,25 @@ impl FolderDepsResolver { let receiver = Arc::new(FolderWSMessageReceiverImpl(folder_manager.clone())); ws_conn.add_ws_message_receiver(receiver).unwrap(); - folder_manager } } +fn make_view_data_processor( + text_block_manager: Arc, + grid_manager: Arc, +) -> ViewDataProcessorMap { + let mut map: HashMap> = HashMap::new(); + + let block_data_impl = TextBlockViewDataProcessor(text_block_manager); + map.insert(block_data_impl.data_type(), Arc::new(block_data_impl)); + + let grid_data_impl = GridViewDataProcessor(grid_manager); + map.insert(grid_data_impl.data_type(), Arc::new(grid_data_impl)); + + Arc::new(map) +} + struct WorkspaceDatabaseImpl(Arc); impl WorkspaceDatabase for WorkspaceDatabaseImpl { fn db_pool(&self) -> Result, FlowyError> { @@ -117,3 +137,146 @@ impl WSMessageReceiver for FolderWSMessageReceiverImpl { }); } } + +struct TextBlockViewDataProcessor(Arc); +impl ViewDataProcessor for TextBlockViewDataProcessor { + fn initialize(&self) -> FutureResult<(), FlowyError> { + let manager = self.0.clone(); + FutureResult::new(async move { manager.init() }) + } + + fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError> { + let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, delta_data).into(); + let view_id = view_id.to_string(); + let manager = self.0.clone(); + FutureResult::new(async move { + let _ = manager.create_block(view_id, repeated_revision).await?; + Ok(()) + }) + } + + fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> { + let manager = self.0.clone(); + let view_id = view_id.to_string(); + FutureResult::new(async move { + let _ = manager.delete_block(view_id)?; + Ok(()) + }) + } + + fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> { + let manager = self.0.clone(); + let view_id = view_id.to_string(); + FutureResult::new(async move { + let _ = manager.close_block(view_id)?; + Ok(()) + }) + } + + fn delta_bytes(&self, view_id: &str) -> FutureResult { + let view_id = view_id.to_string(); + let manager = self.0.clone(); + FutureResult::new(async move { + let editor = manager.open_block(view_id).await?; + let delta_bytes = Bytes::from(editor.delta_str().await?); + Ok(delta_bytes) + }) + } + + fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult { + let user_id = user_id.to_string(); + let view_id = view_id.to_string(); + let manager = self.0.clone(); + FutureResult::new(async move { + let view_data = initial_quill_delta_string(); + let delta_data = Bytes::from(view_data); + let repeated_revision: RepeatedRevision = + Revision::initial_revision(&user_id, &view_id, delta_data.clone()).into(); + let _ = manager.create_block(view_id, repeated_revision).await?; + Ok(delta_data) + }) + } + + fn process_create_view_data( + &self, + _user_id: &str, + _view_id: &str, + data: Vec, + ) -> FutureResult { + FutureResult::new(async move { Ok(Bytes::from(data)) }) + } + + fn data_type(&self) -> ViewDataType { + ViewDataType::TextBlock + } +} + +struct GridViewDataProcessor(Arc); +impl ViewDataProcessor for GridViewDataProcessor { + fn initialize(&self) -> FutureResult<(), FlowyError> { + FutureResult::new(async { Ok(()) }) + } + + fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError> { + let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, delta_data).into(); + let view_id = view_id.to_string(); + let grid_manager = self.0.clone(); + FutureResult::new(async move { + let _ = grid_manager.create_grid(view_id, repeated_revision).await?; + Ok(()) + }) + } + + fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> { + let grid_manager = self.0.clone(); + let view_id = view_id.to_string(); + FutureResult::new(async move { + let _ = grid_manager.delete_grid(view_id)?; + Ok(()) + }) + } + + fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> { + let grid_manager = self.0.clone(); + let view_id = view_id.to_string(); + FutureResult::new(async move { + let _ = grid_manager.close_grid(view_id)?; + Ok(()) + }) + } + + fn delta_bytes(&self, view_id: &str) -> FutureResult { + let view_id = view_id.to_string(); + let grid_manager = self.0.clone(); + FutureResult::new(async move { + let editor = grid_manager.open_grid(view_id).await?; + let delta_bytes = editor.delta_bytes().await; + Ok(delta_bytes) + }) + } + + fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult { + let build_context = make_default_grid(); + let user_id = user_id.to_string(); + let view_id = view_id.to_string(); + let grid_manager = self.0.clone(); + + FutureResult::new(async move { make_grid_view_data(&user_id, &view_id, grid_manager, build_context).await }) + } + + fn process_create_view_data(&self, user_id: &str, view_id: &str, data: Vec) -> FutureResult { + let user_id = user_id.to_string(); + let view_id = view_id.to_string(); + let grid_manager = self.0.clone(); + + FutureResult::new(async move { + let bytes = Bytes::from(data); + let build_context = BuildGridContext::try_from(bytes)?; + make_grid_view_data(&user_id, &view_id, grid_manager, build_context).await + }) + } + + fn data_type(&self) -> ViewDataType { + ViewDataType::Grid + } +} diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs new file mode 100644 index 0000000000..88073a3107 --- /dev/null +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs @@ -0,0 +1,77 @@ +use crate::FlowyError; +use bytes::Bytes; +use flowy_database::ConnectionPool; +use flowy_grid::manager::{GridManager, GridUser}; +use flowy_grid::services::persistence::GridDatabase; +use flowy_net::ws::connection::FlowyWebSocketConnect; +use flowy_revision::{RevisionWebSocket, WSStateReceiver}; +use flowy_sync::entities::ws_data::ClientRevisionWSData; +use flowy_user::services::UserSession; +use futures_core::future::BoxFuture; +use lib_infra::future::BoxResultFuture; +use lib_ws::{WSChannel, WebSocketRawMessage}; +use std::convert::TryInto; +use std::sync::Arc; + +pub struct GridDepsResolver(); + +impl GridDepsResolver { + pub fn resolve(ws_conn: Arc, user_session: Arc) -> Arc { + let user = Arc::new(GridUserImpl(user_session.clone())); + let rev_web_socket = Arc::new(GridWebSocket(ws_conn)); + Arc::new(GridManager::new( + user, + rev_web_socket, + Arc::new(GridDatabaseImpl(user_session)), + )) + } +} + +struct GridDatabaseImpl(Arc); +impl GridDatabase for GridDatabaseImpl { + fn db_pool(&self) -> Result, FlowyError> { + self.0.db_pool().map_err(|e| FlowyError::internal().context(e)) + } +} + +struct GridUserImpl(Arc); +impl GridUser for GridUserImpl { + fn user_id(&self) -> Result { + self.0.user_id() + } + + fn token(&self) -> Result { + self.0.token() + } + + fn db_pool(&self) -> Result, FlowyError> { + self.0.db_pool() + } +} + +struct GridWebSocket(Arc); +impl RevisionWebSocket for GridWebSocket { + fn send(&self, data: ClientRevisionWSData) -> BoxResultFuture<(), FlowyError> { + let bytes: Bytes = data.try_into().unwrap(); + let msg = WebSocketRawMessage { + channel: WSChannel::Grid, + data: bytes.to_vec(), + }; + + let ws_conn = self.0.clone(); + Box::pin(async move { + match ws_conn.web_socket().await? { + None => {} + Some(sender) => { + sender.send(msg).map_err(|e| FlowyError::internal().context(e))?; + } + } + Ok(()) + }) + } + + fn subscribe_state_changed(&self) -> BoxFuture { + let ws_conn = self.0.clone(); + Box::pin(async move { ws_conn.subscribe_websocket_state().await }) + } +} diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/mod.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/mod.rs index 569c32b8de..cac82f9c56 100644 --- a/frontend/rust-lib/flowy-sdk/src/deps_resolve/mod.rs +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/mod.rs @@ -1,7 +1,10 @@ -mod block_deps; mod folder_deps; +mod grid_deps; +mod text_block_deps; mod user_deps; +mod util; -pub use block_deps::*; pub use folder_deps::*; +pub use grid_deps::*; +pub use text_block_deps::*; pub use user_deps::*; diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/block_deps.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/text_block_deps.rs similarity index 81% rename from frontend/rust-lib/flowy-sdk/src/deps_resolve/block_deps.rs rename to frontend/rust-lib/flowy-sdk/src/deps_resolve/text_block_deps.rs index c7e77e252c..7b80e637ab 100644 --- a/frontend/rust-lib/flowy-sdk/src/deps_resolve/block_deps.rs +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/text_block_deps.rs @@ -1,37 +1,37 @@ use bytes::Bytes; -use flowy_block::{ - errors::{internal_error, FlowyError}, - BlockCloudService, BlockManager, BlockUser, -}; -use flowy_collaboration::entities::ws_data::ClientRevisionWSData; use flowy_database::ConnectionPool; use flowy_net::ClientServerConfiguration; use flowy_net::{ http_server::document::BlockHttpCloudService, local_server::LocalServer, ws::connection::FlowyWebSocketConnect, }; -use flowy_sync::{RevisionWebSocket, WSStateReceiver}; +use flowy_revision::{RevisionWebSocket, WSStateReceiver}; +use flowy_sync::entities::ws_data::ClientRevisionWSData; +use flowy_text_block::{ + errors::{internal_error, FlowyError}, + BlockCloudService, TextBlockManager, TextBlockUser, +}; use flowy_user::services::UserSession; use futures_core::future::BoxFuture; use lib_infra::future::BoxResultFuture; use lib_ws::{WSChannel, WSMessageReceiver, WebSocketRawMessage}; use std::{convert::TryInto, path::Path, sync::Arc}; -pub struct BlockDepsResolver(); -impl BlockDepsResolver { +pub struct TextBlockDepsResolver(); +impl TextBlockDepsResolver { pub fn resolve( local_server: Option>, ws_conn: Arc, user_session: Arc, server_config: &ClientServerConfiguration, - ) -> Arc { + ) -> Arc { let user = Arc::new(BlockUserImpl(user_session)); - let ws_sender = Arc::new(BlockWebSocket(ws_conn.clone())); + let rev_web_socket = Arc::new(TextBlockWebSocket(ws_conn.clone())); let cloud_service: Arc = match local_server { None => Arc::new(BlockHttpCloudService::new(server_config.clone())), Some(local_server) => local_server, }; - let manager = Arc::new(BlockManager::new(cloud_service, user, ws_sender)); + let manager = Arc::new(TextBlockManager::new(cloud_service, user, rev_web_socket)); let receiver = Arc::new(DocumentWSMessageReceiverImpl(manager.clone())); ws_conn.add_ws_message_receiver(receiver).unwrap(); @@ -40,7 +40,7 @@ impl BlockDepsResolver { } struct BlockUserImpl(Arc); -impl BlockUser for BlockUserImpl { +impl TextBlockUser for BlockUserImpl { fn user_dir(&self) -> Result { let dir = self.0.user_dir().map_err(|e| FlowyError::unauthorized().context(e))?; @@ -64,8 +64,8 @@ impl BlockUser for BlockUserImpl { } } -struct BlockWebSocket(Arc); -impl RevisionWebSocket for BlockWebSocket { +struct TextBlockWebSocket(Arc); +impl RevisionWebSocket for TextBlockWebSocket { fn send(&self, data: ClientRevisionWSData) -> BoxResultFuture<(), FlowyError> { let bytes: Bytes = data.try_into().unwrap(); let msg = WebSocketRawMessage { @@ -90,7 +90,7 @@ impl RevisionWebSocket for BlockWebSocket { } } -struct DocumentWSMessageReceiverImpl(Arc); +struct DocumentWSMessageReceiverImpl(Arc); impl WSMessageReceiver for DocumentWSMessageReceiverImpl { fn source(&self) -> WSChannel { WSChannel::Document diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/util.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/util.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/util.rs @@ -0,0 +1 @@ + diff --git a/frontend/rust-lib/flowy-sdk/src/lib.rs b/frontend/rust-lib/flowy-sdk/src/lib.rs index 16e3c37def..b426b40550 100644 --- a/frontend/rust-lib/flowy-sdk/src/lib.rs +++ b/frontend/rust-lib/flowy-sdk/src/lib.rs @@ -3,14 +3,15 @@ pub mod module; pub use flowy_net::get_client_server_configuration; use crate::deps_resolve::*; -use flowy_block::BlockManager; -use flowy_folder::{controller::FolderManager, errors::FlowyError}; +use flowy_folder::{errors::FlowyError, manager::FolderManager}; +use flowy_grid::manager::GridManager; use flowy_net::ClientServerConfiguration; use flowy_net::{ entities::NetworkType, local_server::LocalServer, ws::connection::{listen_on_websocket, FlowyWebSocketConnect}, }; +use flowy_text_block::TextBlockManager; use flowy_user::services::{notifier::UserStatus, UserSession, UserSessionConfig}; use lib_dispatch::prelude::*; use lib_dispatch::util::tokio_default_runtime; @@ -54,8 +55,8 @@ impl FlowySDKConfig { } } - pub fn log_filter(mut self, filter: &str) -> Self { - self.log_filter = crate_log_filter(filter.to_owned()); + pub fn log_filter(mut self, level: &str) -> Self { + self.log_filter = crate_log_filter(level.to_owned()); self } } @@ -66,17 +67,18 @@ fn crate_log_filter(level: String) -> String { filters.push(format!("flowy_sdk={}", level)); filters.push(format!("flowy_folder={}", level)); filters.push(format!("flowy_user={}", level)); - filters.push(format!("flowy_document={}", level)); - filters.push(format!("flowy_collaboration={}", "debug")); + filters.push(format!("flowy_text_block={}", level)); + filters.push(format!("flowy_grid={}", level)); + filters.push(format!("flowy_collaboration={}", "info")); filters.push(format!("dart_notify={}", level)); filters.push(format!("lib_ot={}", level)); filters.push(format!("lib_ws={}", level)); filters.push(format!("lib_infra={}", level)); + filters.push(format!("flowy_sync={}", level)); filters.push(format!("dart_ffi={}", "info")); filters.push(format!("flowy_database={}", "info")); filters.push(format!("flowy_net={}", "info")); - filters.push(format!("flowy_sync={}", "trace")); filters.join(",") } @@ -85,8 +87,9 @@ pub struct FlowySDK { #[allow(dead_code)] config: FlowySDKConfig, pub user_session: Arc, - pub document_manager: Arc, + pub text_block_manager: Arc, pub folder_manager: Arc, + pub grid_manager: Arc, pub dispatcher: Arc, pub ws_conn: Arc, pub local_server: Option>, @@ -99,21 +102,24 @@ impl FlowySDK { tracing::debug!("🔥 {:?}", config); let runtime = tokio_default_runtime().unwrap(); let (local_server, ws_conn) = mk_local_server(&config.server_config); - let (user_session, document_manager, folder_manager, local_server) = runtime.block_on(async { + let (user_session, text_block_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async { let user_session = mk_user_session(&config, &local_server, &config.server_config); - let document_manager = BlockDepsResolver::resolve( + let text_block_manager = TextBlockDepsResolver::resolve( local_server.clone(), ws_conn.clone(), user_session.clone(), &config.server_config, ); + let grid_manager = GridDepsResolver::resolve(ws_conn.clone(), user_session.clone()); + let folder_manager = FolderDepsResolver::resolve( local_server.clone(), user_session.clone(), &config.server_config, - &document_manager, - ws_conn.clone(), + &ws_conn, + &text_block_manager, + &grid_manager, ) .await; @@ -121,11 +127,23 @@ impl FlowySDK { local_server.run(); } ws_conn.init().await; - (user_session, document_manager, folder_manager, local_server) + ( + user_session, + text_block_manager, + folder_manager, + local_server, + grid_manager, + ) }); let dispatcher = Arc::new(EventDispatcher::construct(runtime, || { - mk_modules(&ws_conn, &folder_manager, &user_session) + mk_modules( + &ws_conn, + &folder_manager, + &grid_manager, + &user_session, + &text_block_manager, + ) })); _start_listening(&dispatcher, &ws_conn, &user_session, &folder_manager); @@ -133,8 +151,9 @@ impl FlowySDK { Self { config, user_session, - document_manager, + text_block_manager, folder_manager, + grid_manager, dispatcher, ws_conn, local_server, @@ -174,7 +193,7 @@ fn mk_local_server( server_config: &ClientServerConfiguration, ) -> (Option>, Arc) { let ws_addr = server_config.ws_addr(); - if cfg!(feature = "http_server") { + if cfg!(feature = "http_sync") { let ws_conn = Arc::new(FlowyWebSocketConnect::new(ws_addr)); (None, ws_conn) } else { diff --git a/frontend/rust-lib/flowy-sdk/src/module.rs b/frontend/rust-lib/flowy-sdk/src/module.rs index b88300d529..cbb1673a17 100644 --- a/frontend/rust-lib/flowy-sdk/src/module.rs +++ b/frontend/rust-lib/flowy-sdk/src/module.rs @@ -1,5 +1,7 @@ -use flowy_folder::controller::FolderManager; +use flowy_folder::manager::FolderManager; +use flowy_grid::manager::GridManager; use flowy_net::ws::connection::FlowyWebSocketConnect; +use flowy_text_block::TextBlockManager; use flowy_user::services::UserSession; use lib_dispatch::prelude::Module; use std::sync::Arc; @@ -7,22 +9,40 @@ use std::sync::Arc; pub fn mk_modules( ws_conn: &Arc, folder_manager: &Arc, + grid_manager: &Arc, user_session: &Arc, + text_block_manager: &Arc, ) -> Vec { let user_module = mk_user_module(user_session.clone()); let folder_module = mk_folder_module(folder_manager.clone()); let network_module = mk_network_module(ws_conn.clone()); - vec![user_module, folder_module, network_module] + let grid_module = mk_grid_module(grid_manager.clone()); + let text_block_module = mk_text_block_module(text_block_manager.clone()); + vec![ + user_module, + folder_module, + network_module, + grid_module, + text_block_module, + ] } fn mk_user_module(user_session: Arc) -> Module { flowy_user::event_map::create(user_session) } -fn mk_folder_module(core: Arc) -> Module { - flowy_folder::event_map::create(core) +fn mk_folder_module(folder_manager: Arc) -> Module { + flowy_folder::event_map::create(folder_manager) } fn mk_network_module(ws_conn: Arc) -> Module { flowy_net::event_map::create(ws_conn) } + +fn mk_grid_module(grid_manager: Arc) -> Module { + flowy_grid::event_map::create(grid_manager) +} + +fn mk_text_block_module(text_block_manager: Arc) -> Module { + flowy_text_block::event_map::create(text_block_manager) +} diff --git a/frontend/rust-lib/flowy-test/Cargo.toml b/frontend/rust-lib/flowy-test/Cargo.toml index 0a04c1d5f6..a9d2826295 100644 --- a/frontend/rust-lib/flowy-test/Cargo.toml +++ b/frontend/rust-lib/flowy-test/Cargo.toml @@ -12,7 +12,7 @@ flowy-net = { path = "../flowy-net"} flowy-folder = { path = "../flowy-folder", default-features = false} lib-dispatch = { path = "../lib-dispatch" } -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" } +flowy-sync = { path = "../../../shared-lib/flowy-sync" } lib-ot = { path = "../../../shared-lib/lib-ot" } lib-infra = { path = "../../../shared-lib/lib-infra" } @@ -26,6 +26,7 @@ futures-util = "0.3.15" thread-id = "3.3.0" log = "0.4" bytes = "1.0" +nanoid = "0.4.0" [dev-dependencies] quickcheck = "0.9.2" diff --git a/frontend/rust-lib/flowy-test/src/helper.rs b/frontend/rust-lib/flowy-test/src/helper.rs index 7b090792f3..d840069ca0 100644 --- a/frontend/rust-lib/flowy-test/src/helper.rs +++ b/frontend/rust-lib/flowy-test/src/helper.rs @@ -14,7 +14,6 @@ use flowy_user::{ event_map::UserEvent::{InitUser, SignIn, SignOut, SignUp}, }; use lib_dispatch::prelude::{EventDispatcher, ModuleRequest, ToBytes}; -use lib_infra::uuid_string; use std::{fs, path::PathBuf, sync::Arc}; pub struct ViewTest { @@ -25,11 +24,12 @@ pub struct ViewTest { } impl ViewTest { - pub async fn new(sdk: &FlowySDKTest) -> Self { + #[allow(dead_code)] + pub async fn new(sdk: &FlowySDKTest, data_type: ViewDataType, data: Vec) -> Self { let workspace = create_workspace(sdk, "Workspace", "").await; open_workspace(sdk, &workspace.id).await; let app = create_app(sdk, "App", "AppFlowy GitHub Project", &workspace.id).await; - let view = create_view(sdk, &app.id).await; + let view = create_view(sdk, &app.id, data_type, data).await; Self { sdk: sdk.clone(), workspace, @@ -37,6 +37,14 @@ impl ViewTest { view, } } + + pub async fn new_grid_view(sdk: &FlowySDKTest, data: Vec) -> Self { + Self::new(sdk, ViewDataType::Grid, data).await + } + + pub async fn new_text_block_view(sdk: &FlowySDKTest) -> Self { + Self::new(sdk, ViewDataType::TextBlock, vec![]).await + } } async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Workspace { @@ -82,15 +90,15 @@ async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &s app } -async fn create_view(sdk: &FlowySDKTest, app_id: &str) -> View { +async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType, data: Vec) -> View { let request = CreateViewPayload { belong_to_id: app_id.to_string(), name: "View A".to_string(), desc: "".to_string(), thumbnail: Some("http://1.png".to_string()), - data_type: ViewDataType::RichText, - ext_data: "".to_string(), + data_type, plugin_type: 0, + data, }; let view = FolderEventBuilder::new(sdk.clone()) @@ -118,7 +126,7 @@ pub fn root_dir() -> String { } pub fn random_email() -> String { - format!("{}@appflowy.io", uuid_string()) + format!("{}@appflowy.io", nanoid!(10)) } pub fn login_email() -> String { diff --git a/frontend/rust-lib/flowy-test/src/lib.rs b/frontend/rust-lib/flowy-test/src/lib.rs index 6d02f4f973..70159edf19 100644 --- a/frontend/rust-lib/flowy-test/src/lib.rs +++ b/frontend/rust-lib/flowy-test/src/lib.rs @@ -5,7 +5,7 @@ use crate::helper::*; use flowy_net::{get_client_server_configuration, ClientServerConfiguration}; use flowy_sdk::{FlowySDK, FlowySDKConfig}; use flowy_user::entities::UserProfile; -use lib_infra::uuid_string; +use nanoid::nanoid; pub mod prelude { pub use crate::{event_builder::*, helper::*, *}; @@ -36,7 +36,7 @@ impl std::default::Default for FlowySDKTest { impl FlowySDKTest { pub fn new(server_config: ClientServerConfiguration) -> Self { - let config = FlowySDKConfig::new(&root_dir(), server_config, &uuid_string()).log_filter("trace"); + let config = FlowySDKConfig::new(&root_dir(), server_config, &nanoid!(6)).log_filter("info"); let sdk = std::thread::spawn(|| FlowySDK::new(config)).join().unwrap(); std::mem::forget(sdk.dispatcher()); Self { inner: sdk } diff --git a/frontend/rust-lib/flowy-block/Cargo.toml b/frontend/rust-lib/flowy-text-block/Cargo.toml similarity index 74% rename from frontend/rust-lib/flowy-block/Cargo.toml rename to frontend/rust-lib/flowy-text-block/Cargo.toml index 330e70a61a..d9180a97bf 100644 --- a/frontend/rust-lib/flowy-block/Cargo.toml +++ b/frontend/rust-lib/flowy-text-block/Cargo.toml @@ -1,22 +1,21 @@ [package] -name = "flowy-block" +name = "flowy-text-block" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration"} +flowy-sync = { path = "../../../shared-lib/flowy-sync"} flowy-derive = { path = "../../../shared-lib/flowy-derive" } lib-ot = { path = "../../../shared-lib/lib-ot" } lib-ws = { path = "../../../shared-lib/lib-ws" } lib-infra = { path = "../../../shared-lib/lib-infra" } -derive_more = {version = "0.99", features = ["display"]} lib-dispatch = { path = "../lib-dispatch" } flowy-database = { path = "../flowy-database" } -flowy-sync = { path = "../flowy-sync" } +flowy-revision = { path = "../flowy-revision" } flowy-error = { path = "../flowy-error", features = ["collaboration", "ot", "http_server", "serde", "db"] } dart-notify = { path = "../dart-notify" } @@ -31,27 +30,28 @@ bytes = { version = "1.1" } strum = "0.21" strum_macros = "0.21" dashmap = "4.0" -parking_lot = "0.11" -bytecount = "0.6.0" url = "2.2" serde = { version = "1.0", features = ["derive"] } serde_json = {version = "1.0"} chrono = "0.4.19" futures-util = "0.3.15" -byteorder = {version = "1.3.4"} async-stream = "0.3.2" -async-trait = "0.1.52" futures = "0.3.15" -pin-project = "1.0.0" [dev-dependencies] flowy-test = { path = "../flowy-test" } -flowy-block = { path = "../flowy-block", features = ["flowy_unit_test"]} +flowy-text-block = { path = "../flowy-text-block", features = ["flowy_unit_test"]} +derive_more = {version = "0.99", features = ["display"]} color-eyre = { version = "0.5", default-features = false } criterion = "0.3" rand = "0.7.3" +[build-dependencies] +lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file_gen", "proto_gen"] } + [features] -http_server = [] -flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-sync/flowy_unit_test"] \ No newline at end of file +sync = [] +cloud_sync = ["sync"] +flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-revision/flowy_unit_test"] +dart = ["lib-infra/dart"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-text-block/Flowy.toml b/frontend/rust-lib/flowy-text-block/Flowy.toml new file mode 100644 index 0000000000..e6a5c4bd8f --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/Flowy.toml @@ -0,0 +1,3 @@ + +proto_crates = ["src/event_map.rs", "src/entities.rs"] +event_files = ["src/event_map.rs"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-text-block/build.rs b/frontend/rust-lib/flowy-text-block/build.rs new file mode 100644 index 0000000000..4d4d3b13da --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/build.rs @@ -0,0 +1,9 @@ +use lib_infra::code_gen; + +fn main() { + let crate_name = env!("CARGO_PKG_NAME"); + code_gen::protobuf_file::gen(crate_name, "./src/protobuf/proto"); + + #[cfg(feature = "dart")] + code_gen::dart_event::gen(crate_name); +} diff --git a/frontend/rust-lib/flowy-block/src/block_editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs similarity index 79% rename from frontend/rust-lib/flowy-block/src/block_editor.rs rename to frontend/rust-lib/flowy-text-block/src/editor.rs index 1ac0b99284..d43fc24f1c 100644 --- a/frontend/rust-lib/flowy-block/src/block_editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -1,21 +1,18 @@ -use crate::queue::BlockRevisionCompact; -use crate::web_socket::{make_block_ws_manager, EditorCommandSender}; +use crate::web_socket::EditorCommandSender; use crate::{ errors::FlowyError, queue::{EditBlockQueue, EditorCommand}, - BlockUser, + TextBlockUser, }; use bytes::Bytes; -use flowy_collaboration::entities::ws_data::ServerRevisionWSData; -use flowy_collaboration::{ - entities::{document_info::BlockInfo, revision::Revision}, +use flowy_error::{internal_error, FlowyResult}; +use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket}; +use flowy_sync::entities::ws_data::ServerRevisionWSData; +use flowy_sync::{ + entities::{revision::Revision, text_block_info::TextBlockInfo}, errors::CollaborateResult, util::make_delta_from_revisions, }; -use flowy_error::{internal_error, FlowyResult}; -use flowy_sync::{ - RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket, RevisionWebSocketManager, -}; use lib_ot::{ core::{Interval, Operation}, rich_text::{RichTextAttribute, RichTextDelta}, @@ -24,32 +21,33 @@ use lib_ws::WSConnectState; use std::sync::Arc; use tokio::sync::{mpsc, oneshot}; -pub struct ClientBlockEditor { +pub struct ClientTextBlockEditor { pub doc_id: String, #[allow(dead_code)] rev_manager: Arc, - ws_manager: Arc, + #[cfg(feature = "sync")] + ws_manager: Arc, edit_cmd_tx: EditorCommandSender, } -impl ClientBlockEditor { +impl ClientTextBlockEditor { + #[allow(unused_variables)] pub(crate) async fn new( doc_id: &str, - user: Arc, + user: Arc, mut rev_manager: RevisionManager, rev_web_socket: Arc, cloud_service: Arc, ) -> FlowyResult> { - let document_info = rev_manager - .load::(cloud_service) - .await?; + let document_info = rev_manager.load::(Some(cloud_service)).await?; let delta = document_info.delta()?; let rev_manager = Arc::new(rev_manager); let doc_id = doc_id.to_string(); let user_id = user.user_id()?; let edit_cmd_tx = spawn_edit_queue(user, rev_manager.clone(), delta); - let ws_manager = make_block_ws_manager( + #[cfg(feature = "sync")] + let ws_manager = crate::web_socket::make_block_ws_manager( doc_id.clone(), user_id.clone(), edit_cmd_tx.clone(), @@ -60,6 +58,7 @@ impl ClientBlockEditor { let editor = Arc::new(Self { doc_id, rev_manager, + #[cfg(feature = "sync")] ws_manager, edit_cmd_tx, }); @@ -140,9 +139,9 @@ impl ClientBlockEditor { Ok(()) } - pub async fn block_json(&self) -> FlowyResult { + pub async fn delta_str(&self) -> FlowyResult { let (ret, rx) = oneshot::channel::>(); - let msg = EditorCommand::ReadBlockJson { ret }; + let msg = EditorCommand::ReadDeltaStr { ret }; let _ = self.edit_cmd_tx.send(msg).await; let json = rx.await.map_err(internal_error)??; Ok(json) @@ -161,20 +160,32 @@ impl ClientBlockEditor { Ok(()) } + #[cfg(feature = "sync")] pub fn stop(&self) { self.ws_manager.stop(); } + #[cfg(not(feature = "sync"))] + pub fn stop(&self) {} + + #[cfg(feature = "sync")] pub(crate) async fn receive_ws_data(&self, data: ServerRevisionWSData) -> Result<(), FlowyError> { self.ws_manager.receive_ws_data(data).await } + #[cfg(not(feature = "sync"))] + pub(crate) async fn receive_ws_data(&self, _data: ServerRevisionWSData) -> Result<(), FlowyError> { + Ok(()) + } + #[cfg(feature = "sync")] pub(crate) fn receive_ws_state(&self, state: &WSConnectState) { self.ws_manager.connect_state_changed(state.clone()); } + #[cfg(not(feature = "sync"))] + pub(crate) fn receive_ws_state(&self, _state: &WSConnectState) {} } -impl std::ops::Drop for ClientBlockEditor { +impl std::ops::Drop for ClientTextBlockEditor { fn drop(&mut self) { tracing::trace!("{} ClientBlockEditor was dropped", self.doc_id) } @@ -182,7 +193,7 @@ impl std::ops::Drop for ClientBlockEditor { // The edit queue will exit after the EditorCommandSender was dropped. fn spawn_edit_queue( - user: Arc, + user: Arc, rev_manager: Arc, delta: RichTextDelta, ) -> EditorCommandSender { @@ -193,18 +204,10 @@ fn spawn_edit_queue( } #[cfg(feature = "flowy_unit_test")] -impl ClientBlockEditor { - pub async fn doc_json(&self) -> FlowyResult { - let (ret, rx) = oneshot::channel::>(); - let msg = EditorCommand::ReadBlockJson { ret }; - let _ = self.edit_cmd_tx.send(msg).await; - let s = rx.await.map_err(internal_error)??; - Ok(s) - } - - pub async fn doc_delta(&self) -> FlowyResult { +impl ClientTextBlockEditor { + pub async fn text_block_delta(&self) -> FlowyResult { let (ret, rx) = oneshot::channel::>(); - let msg = EditorCommand::ReadBlockDelta { ret }; + let msg = EditorCommand::ReadDelta { ret }; let _ = self.edit_cmd_tx.send(msg).await; let delta = rx.await.map_err(internal_error)??; Ok(delta) @@ -215,18 +218,18 @@ impl ClientBlockEditor { } } -struct BlockInfoBuilder(); -impl RevisionObjectBuilder for BlockInfoBuilder { - type Output = BlockInfo; +struct TextBlockInfoBuilder(); +impl RevisionObjectBuilder for TextBlockInfoBuilder { + type Output = TextBlockInfo; fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id(); let mut delta = make_delta_from_revisions(revisions)?; correct_delta(&mut delta); - Result::::Ok(BlockInfo { - doc_id: object_id.to_owned(), - text: delta.to_delta_json(), + Result::::Ok(TextBlockInfo { + block_id: object_id.to_owned(), + text: delta.to_delta_str(), rev_id, base_rev_id, }) diff --git a/shared-lib/flowy-folder-data-model/src/entities/share.rs b/frontend/rust-lib/flowy-text-block/src/entities.rs similarity index 100% rename from shared-lib/flowy-folder-data-model/src/entities/share.rs rename to frontend/rust-lib/flowy-text-block/src/entities.rs diff --git a/frontend/rust-lib/flowy-text-block/src/event_handler.rs b/frontend/rust-lib/flowy-text-block/src/event_handler.rs new file mode 100644 index 0000000000..183103b73e --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/event_handler.rs @@ -0,0 +1,42 @@ +use crate::entities::{ExportData, ExportParams, ExportPayload}; +use crate::TextBlockManager; +use flowy_error::FlowyError; +use flowy_sync::entities::text_block_info::{TextBlockDelta, TextBlockId}; +use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; +use std::convert::TryInto; +use std::sync::Arc; + +pub(crate) async fn get_block_data_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let block_id: TextBlockId = data.into_inner(); + let editor = manager.open_block(&block_id).await?; + let delta_str = editor.delta_str().await?; + data_result(TextBlockDelta { + block_id: block_id.into(), + delta_str, + }) +} + +pub(crate) async fn apply_delta_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let block_delta = manager.receive_local_delta(data.into_inner()).await?; + data_result(block_delta) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn export_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: ExportParams = data.into_inner().try_into()?; + let editor = manager.open_block(¶ms.view_id).await?; + let delta_json = editor.delta_str().await?; + data_result(ExportData { + data: delta_json, + export_type: params.export_type, + }) +} diff --git a/frontend/rust-lib/flowy-text-block/src/event_map.rs b/frontend/rust-lib/flowy-text-block/src/event_map.rs new file mode 100644 index 0000000000..a355af8bc3 --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/event_map.rs @@ -0,0 +1,30 @@ +use crate::event_handler::*; +use crate::TextBlockManager; +use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; +use lib_dispatch::prelude::Module; +use std::sync::Arc; +use strum_macros::Display; + +pub fn create(block_manager: Arc) -> Module { + let mut module = Module::new().name(env!("CARGO_PKG_NAME")).data(block_manager); + + module = module + .event(BlockEvent::GetBlockData, get_block_data_handler) + .event(BlockEvent::ApplyDelta, apply_delta_handler) + .event(BlockEvent::ExportDocument, export_handler); + + module +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] +#[event_err = "FlowyError"] +pub enum BlockEvent { + #[event(input = "TextBlockId", output = "TextBlockDelta")] + GetBlockData = 0, + + #[event(input = "TextBlockDelta", output = "TextBlockDelta")] + ApplyDelta = 1, + + #[event(input = "ExportPayload", output = "ExportData")] + ExportDocument = 2, +} diff --git a/frontend/rust-lib/flowy-text-block/src/lib.rs b/frontend/rust-lib/flowy-text-block/src/lib.rs new file mode 100644 index 0000000000..991fed8f38 --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/lib.rs @@ -0,0 +1,27 @@ +pub mod editor; +mod entities; +mod event_handler; +pub mod event_map; +pub mod manager; +mod queue; +mod web_socket; + +pub mod protobuf; +pub use manager::*; +pub mod errors { + pub use flowy_error::{internal_error, ErrorCode, FlowyError}; +} + +pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000; + +use crate::errors::FlowyError; +use flowy_sync::entities::text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; +use lib_infra::future::FutureResult; + +pub trait BlockCloudService: Send + Sync { + fn create_block(&self, token: &str, params: CreateTextBlockParams) -> FutureResult<(), FlowyError>; + + fn read_block(&self, token: &str, params: TextBlockId) -> FutureResult, FlowyError>; + + fn update_block(&self, token: &str, params: ResetTextBlockParams) -> FutureResult<(), FlowyError>; +} diff --git a/frontend/rust-lib/flowy-block/src/manager.rs b/frontend/rust-lib/flowy-text-block/src/manager.rs similarity index 65% rename from frontend/rust-lib/flowy-block/src/manager.rs rename to frontend/rust-lib/flowy-text-block/src/manager.rs index 6f6ecf15c5..8a34c6916d 100644 --- a/frontend/rust-lib/flowy-block/src/manager.rs +++ b/frontend/rust-lib/flowy-text-block/src/manager.rs @@ -1,54 +1,54 @@ -use crate::{block_editor::ClientBlockEditor, errors::FlowyError, BlockCloudService}; +use crate::{editor::ClientTextBlockEditor, errors::FlowyError, BlockCloudService}; use bytes::Bytes; use dashmap::DashMap; -use flowy_collaboration::entities::{ - document_info::{BlockDelta, BlockId}, - revision::{md5, RepeatedRevision, Revision}, - ws_data::ServerRevisionWSData, -}; use flowy_database::ConnectionPool; use flowy_error::FlowyResult; -use flowy_sync::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; +use flowy_revision::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_sync::entities::{ + revision::{md5, RepeatedRevision, Revision}, + text_block_info::{TextBlockDelta, TextBlockId}, + ws_data::ServerRevisionWSData, +}; use lib_infra::future::FutureResult; use std::{convert::TryInto, sync::Arc}; -pub trait BlockUser: Send + Sync { +pub trait TextBlockUser: Send + Sync { fn user_dir(&self) -> Result; fn user_id(&self) -> Result; fn token(&self) -> Result; fn db_pool(&self) -> Result, FlowyError>; } -pub struct BlockManager { +pub struct TextBlockManager { cloud_service: Arc, rev_web_socket: Arc, - block_editors: Arc, - block_user: Arc, + editor_map: Arc, + user: Arc, } -impl BlockManager { +impl TextBlockManager { pub fn new( cloud_service: Arc, - block_user: Arc, + text_block_user: Arc, rev_web_socket: Arc, ) -> Self { - let block_handlers = Arc::new(BlockEditors::new()); Self { cloud_service, rev_web_socket, - block_editors: block_handlers, - block_user, + editor_map: Arc::new(TextBlockEditorMap::new()), + user: text_block_user, } } pub fn init(&self) -> FlowyResult<()> { - listen_ws_state_changed(self.rev_web_socket.clone(), self.block_editors.clone()); + listen_ws_state_changed(self.rev_web_socket.clone(), self.editor_map.clone()); Ok(()) } #[tracing::instrument(level = "debug", skip(self, block_id), fields(block_id), err)] - pub async fn open_block>(&self, block_id: T) -> Result, FlowyError> { + pub async fn open_block>(&self, block_id: T) -> Result, FlowyError> { let block_id = block_id.as_ref(); tracing::Span::current().record("block_id", &block_id); self.get_block_editor(block_id).await @@ -58,32 +58,32 @@ impl BlockManager { pub fn close_block>(&self, block_id: T) -> Result<(), FlowyError> { let block_id = block_id.as_ref(); tracing::Span::current().record("block_id", &block_id); - self.block_editors.remove(block_id); + self.editor_map.remove(block_id); Ok(()) } #[tracing::instrument(level = "debug", skip(self, doc_id), fields(doc_id), err)] - pub fn delete>(&self, doc_id: T) -> Result<(), FlowyError> { + pub fn delete_block>(&self, doc_id: T) -> Result<(), FlowyError> { let doc_id = doc_id.as_ref(); tracing::Span::current().record("doc_id", &doc_id); - self.block_editors.remove(doc_id); + self.editor_map.remove(doc_id); Ok(()) } #[tracing::instrument(level = "debug", skip(self, delta), fields(doc_id = %delta.block_id), err)] - pub async fn receive_local_delta(&self, delta: BlockDelta) -> Result { + pub async fn receive_local_delta(&self, delta: TextBlockDelta) -> Result { let editor = self.get_block_editor(&delta.block_id).await?; - let _ = editor.compose_local_delta(Bytes::from(delta.delta_json)).await?; - let document_json = editor.block_json().await?; - Ok(BlockDelta { + let _ = editor.compose_local_delta(Bytes::from(delta.delta_str)).await?; + let document_json = editor.delta_str().await?; + Ok(TextBlockDelta { block_id: delta.block_id.clone(), - delta_json: document_json, + delta_str: document_json, }) } pub async fn create_block>(&self, doc_id: T, revisions: RepeatedRevision) -> FlowyResult<()> { let doc_id = doc_id.as_ref().to_owned(); - let db_pool = self.block_user.db_pool()?; + let db_pool = self.user.db_pool()?; // Maybe we could save the block to disk without creating the RevisionManager let rev_manager = self.make_rev_manager(&doc_id, db_pool)?; let _ = rev_manager.reset_object(revisions).await?; @@ -93,9 +93,9 @@ impl BlockManager { pub async fn receive_ws_data(&self, data: Bytes) { let result: Result = data.try_into(); match result { - Ok(data) => match self.block_editors.get(&data.object_id) { + Ok(data) => match self.editor_map.get(&data.object_id) { None => tracing::error!("Can't find any source handler for {:?}-{:?}", data.object_id, data.ty), - Some(block_editor) => match block_editor.receive_ws_data(data).await { + Some(editor) => match editor.receive_ws_data(data).await { Ok(_) => {} Err(e) => tracing::error!("{}", e), }, @@ -107,51 +107,53 @@ impl BlockManager { } } -impl BlockManager { - async fn get_block_editor(&self, block_id: &str) -> FlowyResult> { - match self.block_editors.get(block_id) { +impl TextBlockManager { + async fn get_block_editor(&self, block_id: &str) -> FlowyResult> { + match self.editor_map.get(block_id) { None => { - let db_pool = self.block_user.db_pool()?; - self.make_block_editor(block_id, db_pool).await + let db_pool = self.user.db_pool()?; + self.make_text_block_editor(block_id, db_pool).await } Some(editor) => Ok(editor), } } - async fn make_block_editor( + #[tracing::instrument(level = "trace", skip(self, pool), err)] + async fn make_text_block_editor( &self, block_id: &str, pool: Arc, - ) -> Result, FlowyError> { - let user = self.block_user.clone(); - let token = self.block_user.token()?; + ) -> Result, FlowyError> { + let user = self.user.clone(); + let token = self.user.token()?; let rev_manager = self.make_rev_manager(block_id, pool.clone())?; - let cloud_service = Arc::new(BlockRevisionCloudService { + let cloud_service = Arc::new(TextBlockRevisionCloudService { token, server: self.cloud_service.clone(), }); let doc_editor = - ClientBlockEditor::new(block_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service).await?; - self.block_editors.insert(block_id, &doc_editor); + ClientTextBlockEditor::new(block_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service).await?; + self.editor_map.insert(block_id, &doc_editor); Ok(doc_editor) } fn make_rev_manager(&self, doc_id: &str, pool: Arc) -> Result { - let user_id = self.block_user.user_id()?; - let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, pool)); + let user_id = self.user.user_id()?; + let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool)); + let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, disk_cache)); Ok(RevisionManager::new(&user_id, doc_id, rev_persistence)) } } -struct BlockRevisionCloudService { +struct TextBlockRevisionCloudService { token: String, server: Arc, } -impl RevisionCloudService for BlockRevisionCloudService { +impl RevisionCloudService for TextBlockRevisionCloudService { #[tracing::instrument(level = "trace", skip(self))] fn fetch_object(&self, user_id: &str, object_id: &str) -> FutureResult, FlowyError> { - let params: BlockId = object_id.to_string().into(); + let params: TextBlockId = object_id.to_string().into(); let server = self.server.clone(); let token = self.token.clone(); let user_id = user_id.to_string(); @@ -162,8 +164,14 @@ impl RevisionCloudService for BlockRevisionCloudService { Some(doc) => { let delta_data = Bytes::from(doc.text.clone()); let doc_md5 = md5(&delta_data); - let revision = - Revision::new(&doc.doc_id, doc.base_rev_id, doc.rev_id, delta_data, &user_id, doc_md5); + let revision = Revision::new( + &doc.block_id, + doc.base_rev_id, + doc.rev_id, + delta_data, + &user_id, + doc_md5, + ); Ok(vec![revision]) } } @@ -171,32 +179,24 @@ impl RevisionCloudService for BlockRevisionCloudService { } } -pub struct BlockEditors { - inner: DashMap>, +pub struct TextBlockEditorMap { + inner: DashMap>, } -impl BlockEditors { +impl TextBlockEditorMap { fn new() -> Self { Self { inner: DashMap::new() } } - pub(crate) fn insert(&self, block_id: &str, doc: &Arc) { + pub(crate) fn insert(&self, block_id: &str, doc: &Arc) { if self.inner.contains_key(block_id) { log::warn!("Doc:{} already exists in cache", block_id); } self.inner.insert(block_id.to_string(), doc.clone()); } - pub(crate) fn contains(&self, block_id: &str) -> bool { - self.inner.get(block_id).is_some() - } - - pub(crate) fn get(&self, block_id: &str) -> Option> { - if !self.contains(block_id) { - return None; - } - let opened_doc = self.inner.get(block_id).unwrap(); - Some(opened_doc.clone()) + pub(crate) fn get(&self, block_id: &str) -> Option> { + Some(self.inner.get(block_id)?.clone()) } pub(crate) fn remove(&self, block_id: &str) { @@ -208,7 +208,7 @@ impl BlockEditors { } #[tracing::instrument(level = "trace", skip(web_socket, handlers))] -fn listen_ws_state_changed(web_socket: Arc, handlers: Arc) { +fn listen_ws_state_changed(web_socket: Arc, handlers: Arc) { tokio::spawn(async move { let mut notify = web_socket.subscribe_state_changed().await; while let Ok(state) = notify.recv().await { diff --git a/frontend/rust-lib/flowy-text-block/src/protobuf/mod.rs b/frontend/rust-lib/flowy-text-block/src/protobuf/mod.rs new file mode 100644 index 0000000000..da97aad28a --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/protobuf/mod.rs @@ -0,0 +1,4 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +// Auto-generated, do not edit +mod model; +pub use model::*; \ No newline at end of file diff --git a/shared-lib/flowy-folder-data-model/src/protobuf/model/share.rs b/frontend/rust-lib/flowy-text-block/src/protobuf/model/entities.rs similarity index 96% rename from shared-lib/flowy-folder-data-model/src/protobuf/model/share.rs rename to frontend/rust-lib/flowy-text-block/src/protobuf/model/entities.rs index a020837fb0..3846f9c76f 100644 --- a/shared-lib/flowy-folder-data-model/src/protobuf/model/share.rs +++ b/frontend/rust-lib/flowy-text-block/src/protobuf/model/entities.rs @@ -17,7 +17,7 @@ #![allow(trivial_casts)] #![allow(unused_imports)] #![allow(unused_results)] -//! Generated file from `share.proto` +//! Generated file from `entities.proto` /// Generated files are compatible only with the same version /// of protobuf runtime. @@ -457,12 +457,12 @@ impl ::protobuf::reflect::ProtobufValue for ExportType { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0bshare.proto\"V\n\rExportPayload\x12\x17\n\x07view_id\x18\x01\x20\ - \x01(\tR\x06viewId\x12,\n\x0bexport_type\x18\x02\x20\x01(\x0e2\x0b.Expor\ - tTypeR\nexportType\"N\n\nExportData\x12\x12\n\x04data\x18\x01\x20\x01(\t\ - R\x04data\x12,\n\x0bexport_type\x18\x02\x20\x01(\x0e2\x0b.ExportTypeR\ne\ - xportType*.\n\nExportType\x12\x08\n\x04Text\x10\0\x12\x0c\n\x08Markdown\ - \x10\x01\x12\x08\n\x04Link\x10\x02b\x06proto3\ + \n\x0eentities.proto\"V\n\rExportPayload\x12\x17\n\x07view_id\x18\x01\ + \x20\x01(\tR\x06viewId\x12,\n\x0bexport_type\x18\x02\x20\x01(\x0e2\x0b.E\ + xportTypeR\nexportType\"N\n\nExportData\x12\x12\n\x04data\x18\x01\x20\ + \x01(\tR\x04data\x12,\n\x0bexport_type\x18\x02\x20\x01(\x0e2\x0b.ExportT\ + ypeR\nexportType*.\n\nExportType\x12\x08\n\x04Text\x10\0\x12\x0c\n\x08Ma\ + rkdown\x10\x01\x12\x08\n\x04Link\x10\x02b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-text-block/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-text-block/src/protobuf/model/event_map.rs new file mode 100644 index 0000000000..ab1a5da855 --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/protobuf/model/event_map.rs @@ -0,0 +1,95 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `event_map.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum BlockEvent { + GetBlockData = 0, + ApplyDelta = 1, + ExportDocument = 2, +} + +impl ::protobuf::ProtobufEnum for BlockEvent { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(BlockEvent::GetBlockData), + 1 => ::std::option::Option::Some(BlockEvent::ApplyDelta), + 2 => ::std::option::Option::Some(BlockEvent::ExportDocument), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [BlockEvent] = &[ + BlockEvent::GetBlockData, + BlockEvent::ApplyDelta, + BlockEvent::ExportDocument, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("BlockEvent", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for BlockEvent { +} + +impl ::std::default::Default for BlockEvent { + fn default() -> Self { + BlockEvent::GetBlockData + } +} + +impl ::protobuf::reflect::ProtobufValue for BlockEvent { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x0fevent_map.proto*B\n\nBlockEvent\x12\x10\n\x0cGetBlockData\x10\0\ + \x12\x0e\n\nApplyDelta\x10\x01\x12\x12\n\x0eExportDocument\x10\x02b\x06p\ + roto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/frontend/rust-lib/flowy-text-block/src/protobuf/model/mod.rs b/frontend/rust-lib/flowy-text-block/src/protobuf/model/mod.rs new file mode 100644 index 0000000000..a8012019d4 --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/protobuf/model/mod.rs @@ -0,0 +1,8 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +// Auto-generated, do not edit + +mod entities; +pub use entities::*; + +mod event_map; +pub use event_map::*; diff --git a/shared-lib/flowy-folder-data-model/src/protobuf/proto/share.proto b/frontend/rust-lib/flowy-text-block/src/protobuf/proto/entities.proto similarity index 100% rename from shared-lib/flowy-folder-data-model/src/protobuf/proto/share.proto rename to frontend/rust-lib/flowy-text-block/src/protobuf/proto/entities.proto diff --git a/frontend/rust-lib/flowy-text-block/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-text-block/src/protobuf/proto/event_map.proto new file mode 100644 index 0000000000..3ebf0755d3 --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/src/protobuf/proto/event_map.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +enum BlockEvent { + GetBlockData = 0; + ApplyDelta = 1; + ExportDocument = 2; +} diff --git a/frontend/rust-lib/flowy-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs similarity index 85% rename from frontend/rust-lib/flowy-block/src/queue.rs rename to frontend/rust-lib/flowy-text-block/src/queue.rs index 8ce74ce591..7c11afd0ff 100644 --- a/frontend/rust-lib/flowy-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -1,14 +1,15 @@ use crate::web_socket::EditorCommandReceiver; -use crate::BlockUser; +use crate::TextBlockUser; use async_stream::stream; -use flowy_collaboration::util::make_delta_from_revisions; -use flowy_collaboration::{ +use bytes::Bytes; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_revision::{DeltaMD5, RevisionCompactor, RevisionManager, RichTextTransformDeltas, TransformDeltas}; +use flowy_sync::util::make_delta_from_revisions; +use flowy_sync::{ client_document::{history::UndoResult, ClientDocument}, entities::revision::{RevId, Revision}, errors::CollaborateError, }; -use flowy_error::{FlowyError, FlowyResult}; -use flowy_sync::{DeltaMD5, RevisionCompact, RevisionManager, RichTextTransformDeltas, TransformDeltas}; use futures::stream::StreamExt; use lib_ot::{ core::{Interval, OperationTransformable}, @@ -21,14 +22,14 @@ use tokio::sync::{oneshot, RwLock}; // serial. pub(crate) struct EditBlockQueue { document: Arc>, - user: Arc, + user: Arc, rev_manager: Arc, receiver: Option, } impl EditBlockQueue { pub(crate) fn new( - user: Arc, + user: Arc, rev_manager: Arc, delta: RichTextDelta, receiver: EditorCommandReceiver, @@ -161,11 +162,11 @@ impl EditBlockQueue { let _ = self.save_local_delta(delta, md5).await?; let _ = ret.send(Ok(())); } - EditorCommand::ReadBlockJson { ret } => { - let data = self.document.read().await.to_json(); + EditorCommand::ReadDeltaStr { ret } => { + let data = self.document.read().await.delta_str(); let _ = ret.send(Ok(data)); } - EditorCommand::ReadBlockDelta { ret } => { + EditorCommand::ReadDelta { ret } => { let delta = self.document.read().await.delta().clone(); let _ = ret.send(Ok(delta)); } @@ -174,7 +175,7 @@ impl EditBlockQueue { } async fn save_local_delta(&self, delta: RichTextDelta, md5: String) -> Result { - let delta_data = delta.to_bytes(); + let delta_data = delta.to_delta_bytes(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let user_id = self.user.user_id()?; let revision = Revision::new( @@ -187,31 +188,17 @@ impl EditBlockQueue { ); let _ = self .rev_manager - .add_local_revision::(&revision) + .add_local_revision(&revision, Box::new(TextBlockRevisionCompactor())) .await?; Ok(rev_id.into()) } } -pub(crate) struct BlockRevisionCompact(); -impl RevisionCompact for BlockRevisionCompact { - fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec) -> FlowyResult { - if revisions.is_empty() { - return Err(FlowyError::internal().context("Can't compact the empty block's revisions")); - } - - if revisions.len() == 1 { - return Ok(revisions.pop().unwrap()); - } - - let first_revision = revisions.first().unwrap(); - let last_revision = revisions.last().unwrap(); - - let (base_rev_id, rev_id) = first_revision.pair_rev_id(); - let md5 = last_revision.md5.clone(); +pub(crate) struct TextBlockRevisionCompactor(); +impl RevisionCompactor for TextBlockRevisionCompactor { + fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - let delta_data = delta.to_bytes(); - Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5)) + Ok(delta.to_delta_bytes()) } } @@ -265,11 +252,11 @@ pub(crate) enum EditorCommand { Redo { ret: Ret<()>, }, - ReadBlockJson { + ReadDeltaStr { ret: Ret, }, #[allow(dead_code)] - ReadBlockDelta { + ReadDelta { ret: Ret, }, } @@ -289,8 +276,8 @@ impl std::fmt::Debug for EditorCommand { EditorCommand::CanRedo { .. } => "CanRedo", EditorCommand::Undo { .. } => "Undo", EditorCommand::Redo { .. } => "Redo", - EditorCommand::ReadBlockJson { .. } => "ReadDocumentAsJson", - EditorCommand::ReadBlockDelta { .. } => "ReadDocumentAsDelta", + EditorCommand::ReadDeltaStr { .. } => "ReadDeltaStr", + EditorCommand::ReadDelta { .. } => "ReadDocumentAsDelta", }; f.write_str(s) } diff --git a/frontend/rust-lib/flowy-block/src/web_socket.rs b/frontend/rust-lib/flowy-text-block/src/web_socket.rs similarity index 84% rename from frontend/rust-lib/flowy-block/src/web_socket.rs rename to frontend/rust-lib/flowy-text-block/src/web_socket.rs index ee8db49cf4..a44214f4f2 100644 --- a/frontend/rust-lib/flowy-block/src/web_socket.rs +++ b/frontend/rust-lib/flowy-text-block/src/web_socket.rs @@ -1,14 +1,14 @@ -use crate::{queue::EditorCommand, DOCUMENT_SYNC_INTERVAL_IN_MILLIS}; +use crate::{queue::EditorCommand, TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS}; use bytes::Bytes; -use flowy_collaboration::{ +use flowy_error::{internal_error, FlowyError}; +use flowy_revision::*; +use flowy_sync::{ entities::{ revision::RevisionRange, ws_data::{ClientRevisionWSData, NewDocumentUser, ServerRevisionWSDataType}, }, errors::CollaborateResult, }; -use flowy_error::{internal_error, FlowyError}; -use flowy_sync::*; use lib_infra::future::{BoxResultFuture, FutureResult}; use lib_ot::rich_text::RichTextAttributes; use lib_ot::rich_text::RichTextDelta; @@ -23,6 +23,7 @@ use tokio::sync::{ pub(crate) type EditorCommandSender = Sender; pub(crate) type EditorCommandReceiver = Receiver; +#[allow(dead_code)] pub(crate) async fn make_block_ws_manager( doc_id: String, user_id: String, @@ -31,12 +32,12 @@ pub(crate) async fn make_block_ws_manager( rev_web_socket: Arc, ) -> Arc { let ws_data_provider = Arc::new(WSDataProvider::new(&doc_id, Arc::new(rev_manager.clone()))); - let resolver = Arc::new(BlockConflictResolver { edit_cmd_tx }); + let resolver = Arc::new(TextBlockConflictResolver { edit_cmd_tx }); let conflict_controller = RichTextConflictController::new(&user_id, resolver, Arc::new(ws_data_provider.clone()), rev_manager); - let ws_data_stream = Arc::new(BlockRevisionWSDataStream::new(conflict_controller)); - let ws_data_sink = Arc::new(BlockWSDataSink(ws_data_provider)); - let ping_duration = Duration::from_millis(DOCUMENT_SYNC_INTERVAL_IN_MILLIS); + let ws_data_stream = Arc::new(TextBlockRevisionWSDataStream::new(conflict_controller)); + let ws_data_sink = Arc::new(TextBlockWSDataSink(ws_data_provider)); + let ping_duration = Duration::from_millis(TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS); let ws_manager = Arc::new(RevisionWebSocketManager::new( "Block", &doc_id, @@ -49,6 +50,7 @@ pub(crate) async fn make_block_ws_manager( ws_manager } +#[allow(dead_code)] fn listen_document_ws_state(_user_id: &str, _doc_id: &str, mut subscriber: broadcast::Receiver) { tokio::spawn(async move { while let Ok(state) = subscriber.recv().await { @@ -62,11 +64,12 @@ fn listen_document_ws_state(_user_id: &str, _doc_id: &str, mut subscriber: broad }); } -pub(crate) struct BlockRevisionWSDataStream { +pub(crate) struct TextBlockRevisionWSDataStream { conflict_controller: Arc, } -impl BlockRevisionWSDataStream { +impl TextBlockRevisionWSDataStream { + #[allow(dead_code)] pub fn new(conflict_controller: RichTextConflictController) -> Self { Self { conflict_controller: Arc::new(conflict_controller), @@ -74,7 +77,7 @@ impl BlockRevisionWSDataStream { } } -impl RevisionWSDataStream for BlockRevisionWSDataStream { +impl RevisionWSDataStream for TextBlockRevisionWSDataStream { fn receive_push_revision(&self, bytes: Bytes) -> BoxResultFuture<(), FlowyError> { let resolver = self.conflict_controller.clone(); Box::pin(async move { resolver.receive_bytes(bytes).await }) @@ -96,19 +99,19 @@ impl RevisionWSDataStream for BlockRevisionWSDataStream { } } -pub(crate) struct BlockWSDataSink(pub(crate) Arc); -impl RevisionWSDataIterator for BlockWSDataSink { +pub(crate) struct TextBlockWSDataSink(pub(crate) Arc); +impl RevisionWebSocketSink for TextBlockWSDataSink { fn next(&self) -> FutureResult, FlowyError> { let sink_provider = self.0.clone(); FutureResult::new(async move { sink_provider.next().await }) } } -struct BlockConflictResolver { +struct TextBlockConflictResolver { edit_cmd_tx: EditorCommandSender, } -impl ConflictResolver for BlockConflictResolver { +impl ConflictResolver for TextBlockConflictResolver { fn compose_delta(&self, delta: RichTextDelta) -> BoxResultFuture { let tx = self.edit_cmd_tx.clone(); Box::pin(async move { @@ -129,7 +132,7 @@ impl ConflictResolver for BlockConflictResolver { fn transform_delta( &self, delta: RichTextDelta, - ) -> BoxResultFuture { + ) -> BoxResultFuture { let tx = self.edit_cmd_tx.clone(); Box::pin(async move { let (ret, rx) = oneshot::channel::>(); diff --git a/frontend/rust-lib/flowy-text-block/tests/document/mod.rs b/frontend/rust-lib/flowy-text-block/tests/document/mod.rs new file mode 100644 index 0000000000..8aa4c774ed --- /dev/null +++ b/frontend/rust-lib/flowy-text-block/tests/document/mod.rs @@ -0,0 +1,2 @@ +mod script; +mod text_block_test; diff --git a/frontend/rust-lib/flowy-block/tests/document/edit_script.rs b/frontend/rust-lib/flowy-text-block/tests/document/script.rs similarity index 80% rename from frontend/rust-lib/flowy-block/tests/document/edit_script.rs rename to frontend/rust-lib/flowy-text-block/tests/document/script.rs index 441b4cd104..5511896fc2 100644 --- a/frontend/rust-lib/flowy-block/tests/document/edit_script.rs +++ b/frontend/rust-lib/flowy-text-block/tests/document/script.rs @@ -1,7 +1,7 @@ -use flowy_block::block_editor::ClientBlockEditor; -use flowy_block::DOCUMENT_SYNC_INTERVAL_IN_MILLIS; -use flowy_collaboration::entities::revision::RevisionState; +use flowy_revision::disk::RevisionState; use flowy_test::{helper::ViewTest, FlowySDKTest}; +use flowy_text_block::editor::ClientTextBlockEditor; +use flowy_text_block::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS; use lib_ot::{core::Interval, rich_text::RichTextDelta}; use std::sync::Arc; use tokio::time::{sleep, Duration}; @@ -17,17 +17,17 @@ pub enum EditorScript { AssertJson(&'static str), } -pub struct EditorTest { +pub struct TextBlockEditorTest { pub sdk: FlowySDKTest, - pub editor: Arc, + pub editor: Arc, } -impl EditorTest { +impl TextBlockEditorTest { pub async fn new() -> Self { let sdk = FlowySDKTest::default(); let _ = sdk.init_user().await; - let test = ViewTest::new(&sdk).await; - let editor = sdk.document_manager.open_block(&test.view.id).await.unwrap(); + let test = ViewTest::new_text_block_view(&sdk).await; + let editor = sdk.text_block_manager.open_block(&test.view.id).await.unwrap(); Self { sdk, editor } } @@ -41,8 +41,6 @@ impl EditorTest { let rev_manager = self.editor.rev_manager(); let cache = rev_manager.revision_cache().await; let _user_id = self.sdk.user_session.user_id().unwrap(); - // let ws_manager = self.sdk.ws_conn.clone(); - // let token = self.sdk.user_session.token().unwrap(); match script { EditorScript::InsertText(s, offset) => { @@ -74,14 +72,14 @@ impl EditorTest { } EditorScript::AssertJson(expected) => { let expected_delta: RichTextDelta = serde_json::from_str(expected).unwrap(); - let delta = self.editor.doc_delta().await.unwrap(); + let delta = self.editor.text_block_delta().await.unwrap(); if expected_delta != delta { eprintln!("✅ expect: {}", expected,); - eprintln!("❌ receive: {}", delta.to_delta_json()); + eprintln!("❌ receive: {}", delta.to_delta_str()); } assert_eq!(expected_delta, delta); } } - sleep(Duration::from_millis(DOCUMENT_SYNC_INTERVAL_IN_MILLIS)).await; + sleep(Duration::from_millis(TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS)).await; } } diff --git a/frontend/rust-lib/flowy-block/tests/document/document_test.rs b/frontend/rust-lib/flowy-text-block/tests/document/text_block_test.rs similarity index 68% rename from frontend/rust-lib/flowy-block/tests/document/document_test.rs rename to frontend/rust-lib/flowy-text-block/tests/document/text_block_test.rs index 86fd1d4a2e..30a926c3f9 100644 --- a/frontend/rust-lib/flowy-block/tests/document/document_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/document/text_block_test.rs @@ -1,9 +1,9 @@ -use crate::document::edit_script::{EditorScript::*, *}; -use flowy_collaboration::entities::revision::RevisionState; +use crate::document::script::{EditorScript::*, *}; +use flowy_revision::disk::RevisionState; use lib_ot::core::{count_utf16_code_units, Interval}; #[tokio::test] -async fn document_sync_current_rev_id_check() { +async fn text_block_sync_current_rev_id_check() { let scripts = vec![ InsertText("1", 0), AssertCurrentRevId(1), @@ -14,11 +14,11 @@ async fn document_sync_current_rev_id_check() { AssertNextSyncRevId(None), AssertJson(r#"[{"insert":"123\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_state_check() { +async fn text_block_sync_state_check() { let scripts = vec![ InsertText("1", 0), InsertText("2", 1), @@ -28,11 +28,11 @@ async fn document_sync_state_check() { AssertRevisionState(3, RevisionState::Ack), AssertJson(r#"[{"insert":"123\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_insert_test() { +async fn text_block_sync_insert_test() { let scripts = vec![ InsertText("1", 0), InsertText("2", 1), @@ -40,11 +40,11 @@ async fn document_sync_insert_test() { AssertJson(r#"[{"insert":"123\n"}]"#), AssertNextSyncRevId(None), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_insert_in_chinese() { +async fn text_block_sync_insert_in_chinese() { let s = "好".to_owned(); let offset = count_utf16_code_units(&s); let scripts = vec![ @@ -52,11 +52,11 @@ async fn document_sync_insert_in_chinese() { InsertText("好", offset), AssertJson(r#"[{"insert":"你好\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_insert_with_emoji() { +async fn text_block_sync_insert_with_emoji() { let s = "😁".to_owned(); let offset = count_utf16_code_units(&s); let scripts = vec![ @@ -64,11 +64,11 @@ async fn document_sync_insert_with_emoji() { InsertText("☺️", offset), AssertJson(r#"[{"insert":"😁☺️\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_delete_in_english() { +async fn text_block_sync_delete_in_english() { let scripts = vec![ InsertText("1", 0), InsertText("2", 1), @@ -76,11 +76,11 @@ async fn document_sync_delete_in_english() { Delete(Interval::new(0, 2)), AssertJson(r#"[{"insert":"3\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_delete_in_chinese() { +async fn text_block_sync_delete_in_chinese() { let s = "好".to_owned(); let offset = count_utf16_code_units(&s); let scripts = vec![ @@ -89,11 +89,11 @@ async fn document_sync_delete_in_chinese() { Delete(Interval::new(0, offset)), AssertJson(r#"[{"insert":"好\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } #[tokio::test] -async fn document_sync_replace_test() { +async fn text_block_sync_replace_test() { let scripts = vec![ InsertText("1", 0), InsertText("2", 1), @@ -101,5 +101,5 @@ async fn document_sync_replace_test() { Replace(Interval::new(0, 3), "abc"), AssertJson(r#"[{"insert":"abc\n"}]"#), ]; - EditorTest::new().await.run_scripts(scripts).await; + TextBlockEditorTest::new().await.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-block/tests/editor/attribute_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs similarity index 97% rename from frontend/rust-lib/flowy-block/tests/editor/attribute_test.rs rename to frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs index 261ce60b6c..037b36970b 100644 --- a/frontend/rust-lib/flowy-block/tests/editor/attribute_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs @@ -1,6 +1,6 @@ #![cfg_attr(rustfmt, rustfmt::skip)] use crate::editor::{TestBuilder, TestOp::*}; -use flowy_collaboration::client_document::{NewlineDoc, PlainDoc}; +use flowy_sync::client_document::{NewlineDoc, PlainDoc}; use lib_ot::core::{Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr}; use unicode_segmentation::UnicodeSegmentation; use lib_ot::rich_text::RichTextDelta; @@ -762,19 +762,19 @@ fn attributes_preserve_list_format_on_merge() { #[test] fn delta_compose() { - let mut delta = RichTextDelta::from_json(r#"[{"insert":"\n"}]"#).unwrap(); + let mut delta = RichTextDelta::from_delta_str(r#"[{"insert":"\n"}]"#).unwrap(); let deltas = vec![ - RichTextDelta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_json(r#"[{"insert":"a"}]"#).unwrap(), - RichTextDelta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), + RichTextDelta::from_delta_str(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_delta_str(r#"[{"insert":"a"}]"#).unwrap(), + RichTextDelta::from_delta_str(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_delta_str(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), ]; for d in deltas { delta = delta.compose(&d).unwrap(); } assert_eq!( - delta.to_delta_json(), + delta.to_delta_str(), r#"[{"insert":"a"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\n"}]"# ); diff --git a/frontend/rust-lib/flowy-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs similarity index 96% rename from frontend/rust-lib/flowy-block/tests/editor/mod.rs rename to frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index 151652262f..f463a0932a 100644 --- a/frontend/rust-lib/flowy-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -5,7 +5,7 @@ mod serde_test; mod undo_redo_test; use derive_more::Display; -use flowy_collaboration::client_document::{ClientDocument, InitialDocumentText}; +use flowy_sync::client_document::{ClientDocument, InitialDocumentText}; use lib_ot::{ core::*, rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta}, @@ -13,7 +13,7 @@ use lib_ot::{ use rand::{prelude::*, Rng as WrappedRng}; use std::{sync::Once, time::Duration}; -const LEVEL: &str = "debug"; +const LEVEL: &str = "info"; #[derive(Clone, Debug, Display)] pub enum TestOp { @@ -108,20 +108,20 @@ impl TestBuilder { TestOp::Insert(delta_i, s, index) => { let document = &mut self.documents[*delta_i]; let delta = document.insert(*index, s).unwrap(); - tracing::debug!("Insert delta: {}", delta.to_delta_json()); + tracing::debug!("Insert delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Delete(delta_i, iv) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, "").unwrap(); - tracing::trace!("Delete delta: {}", delta.to_delta_json()); + tracing::trace!("Delete delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Replace(delta_i, iv, s) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, s).unwrap(); - tracing::trace!("Replace delta: {}", delta.to_delta_json()); + tracing::trace!("Replace delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::InsertBold(delta_i, s, iv) => { @@ -133,7 +133,7 @@ impl TestBuilder { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bold(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Bold delta: {}", delta.to_delta_json()); + tracing::trace!("Bold delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Italic(delta_i, iv, enable) => { @@ -143,28 +143,28 @@ impl TestBuilder { false => RichTextAttribute::Italic(false), }; let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Italic delta: {}", delta.to_delta_json()); + tracing::trace!("Italic delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Header(delta_i, iv, level) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Header(*level); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Header delta: {}", delta.to_delta_json()); + tracing::trace!("Header delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Link(delta_i, iv, link) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Link(link.to_owned()); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Link delta: {}", delta.to_delta_json()); + tracing::trace!("Link delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Bullet(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bullet(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::debug!("Bullet delta: {}", delta.to_delta_json()); + tracing::debug!("Bullet delta: {}", delta.to_delta_str()); self.deltas.insert(*delta_i, Some(delta)); } @@ -194,15 +194,15 @@ impl TestBuilder { let delta_a = &self.documents[*delta_a_i].delta(); let delta_b = &self.documents[*delta_b_i].delta(); tracing::debug!("Invert: "); - tracing::debug!("a: {}", delta_a.to_delta_json()); - tracing::debug!("b: {}", delta_b.to_delta_json()); + tracing::debug!("a: {}", delta_a.to_delta_str()); + tracing::debug!("b: {}", delta_b.to_delta_str()); let (_, b_prime) = delta_a.transform(delta_b).unwrap(); let undo = b_prime.invert(delta_a); let new_delta = delta_a.compose(&b_prime).unwrap(); - tracing::debug!("new delta: {}", new_delta.to_delta_json()); - tracing::debug!("undo delta: {}", undo.to_delta_json()); + tracing::debug!("new delta: {}", new_delta.to_delta_str()); + tracing::debug!("undo delta: {}", undo.to_delta_str()); let new_delta_after_undo = new_delta.compose(&undo).unwrap(); @@ -226,7 +226,7 @@ impl TestBuilder { } TestOp::AssertDocJson(delta_i, expected) => { - let delta_json = self.documents[*delta_i].to_json(); + let delta_json = self.documents[*delta_i].delta_str(); let expected_delta: RichTextDelta = serde_json::from_str(expected).unwrap(); let target_delta: RichTextDelta = serde_json::from_str(&delta_json).unwrap(); @@ -238,7 +238,7 @@ impl TestBuilder { } TestOp::AssertPrimeJson(doc_i, expected) => { - let prime_json = self.primes[*doc_i].as_ref().unwrap().to_delta_json(); + let prime_json = self.primes[*doc_i].as_ref().unwrap().to_delta_str(); let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap(); let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap(); diff --git a/frontend/rust-lib/flowy-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs similarity index 99% rename from frontend/rust-lib/flowy-block/tests/editor/op_test.rs rename to frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index 7745d4b098..3f174fa3bc 100644 --- a/frontend/rust-lib/flowy-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] use crate::editor::{Rng, TestBuilder, TestOp::*}; -use flowy_collaboration::client_document::{NewlineDoc, PlainDoc}; +use flowy_sync::client_document::{NewlineDoc, PlainDoc}; use lib_ot::{ core::*, rich_text::{AttributeBuilder, RichTextAttribute, RichTextAttributes, RichTextDelta}, diff --git a/frontend/rust-lib/flowy-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs similarity index 88% rename from frontend/rust-lib/flowy-block/tests/editor/serde_test.rs rename to frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index 32366d667a..87d425901b 100644 --- a/frontend/rust-lib/flowy-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -1,4 +1,4 @@ -use flowy_collaboration::client_document::{ClientDocument, PlainDoc}; +use flowy_sync::client_document::{ClientDocument, PlainDoc}; use lib_ot::rich_text::RichTextOperation; use lib_ot::{ core::*, @@ -65,7 +65,7 @@ fn delta_serialize_multi_attribute_test() { let json = serde_json::to_string(&delta).unwrap(); eprintln!("{}", json); - let delta_from_json = Delta::from_json(&json).unwrap(); + let delta_from_json = Delta::from_delta_str(&json).unwrap(); assert_eq!(delta_from_json, delta); } @@ -77,7 +77,7 @@ fn delta_deserialize_test() { {"retain":2,"attributes":{"italic":"true","bold":"true"}}, {"retain":2,"attributes":{"italic":true,"bold":true}} ]"#; - let delta = RichTextDelta::from_json(json).unwrap(); + let delta = RichTextDelta::from_delta_str(json).unwrap(); eprintln!("{}", delta); } @@ -86,13 +86,13 @@ fn delta_deserialize_null_test() { let json = r#"[ {"retain":7,"attributes":{"bold":null}} ]"#; - let delta1 = RichTextDelta::from_json(json).unwrap(); + let delta1 = RichTextDelta::from_delta_str(json).unwrap(); let mut attribute = RichTextAttribute::Bold(true); attribute.value = RichTextAttributeValue(None); let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); - assert_eq!(delta2.to_delta_json(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); + assert_eq!(delta2.to_delta_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); assert_eq!(delta1, delta2); } @@ -108,10 +108,10 @@ fn document_insert_serde_test() { let mut document = ClientDocument::new::(); document.insert(0, "\n").unwrap(); document.insert(0, "123").unwrap(); - let json = document.to_json(); + let json = document.delta_str(); assert_eq!(r#"[{"insert":"123\n"}]"#, json); assert_eq!( r#"[{"insert":"123\n"}]"#, - ClientDocument::from_json(&json).unwrap().to_json() + ClientDocument::from_json(&json).unwrap().delta_str() ); } diff --git a/frontend/rust-lib/flowy-block/tests/editor/undo_redo_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs similarity index 99% rename from frontend/rust-lib/flowy-block/tests/editor/undo_redo_test.rs rename to frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs index 1b08b5ca2d..e6ea9200ab 100644 --- a/frontend/rust-lib/flowy-block/tests/editor/undo_redo_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs @@ -1,5 +1,5 @@ use crate::editor::{TestBuilder, TestOp::*}; -use flowy_collaboration::client_document::{NewlineDoc, PlainDoc, RECORD_THRESHOLD}; +use flowy_sync::client_document::{NewlineDoc, PlainDoc, RECORD_THRESHOLD}; use lib_ot::core::{Interval, NEW_LINE, WHITESPACE}; #[test] diff --git a/frontend/rust-lib/flowy-block/tests/main.rs b/frontend/rust-lib/flowy-text-block/tests/main.rs similarity index 100% rename from frontend/rust-lib/flowy-block/tests/main.rs rename to frontend/rust-lib/flowy-text-block/tests/main.rs diff --git a/frontend/rust-lib/flowy-user/Cargo.toml b/frontend/rust-lib/flowy-user/Cargo.toml index 307c59d62c..96e6141ed6 100644 --- a/frontend/rust-lib/flowy-user/Cargo.toml +++ b/frontend/rust-lib/flowy-user/Cargo.toml @@ -8,14 +8,12 @@ edition = "2018" [dependencies] flowy-user-data-model = { path = "../../../shared-lib/flowy-user-data-model" } flowy-derive = { path = "../../../shared-lib/flowy-derive" } -lib-infra = { path = "../../../shared-lib/lib-infra" } - -derive_more = {version = "0.99", features = ["display"]} flowy-database = { path = "../flowy-database" } +flowy-error = { path = "../flowy-error", features = ["db", "http_server"] } + +lib-infra = { path = "../../../shared-lib/lib-infra" } dart-notify = { path = "../dart-notify" } lib-dispatch = { path = "../lib-dispatch" } -flowy-error = { path = "../flowy-error", features = ["db", "http_server"] } -lib-sqlite = { path = "../lib-sqlite" } tracing = { version = "0.1", features = ["log"] } bytes = "1.0" @@ -26,25 +24,19 @@ protobuf = {version = "2.18.0"} lazy_static = "1.4.0" diesel = {version = "1.4.8", features = ["sqlite"]} diesel_derives = {version = "1.4.1", features = ["sqlite"]} -thread_local = "1.1.3" -thread-id = "3.3.0" once_cell = "1.7.2" parking_lot = "0.11" strum = "0.21" strum_macros = "0.21" tokio = { version = "1", features = ["rt"] } -pin-project = "1.0.0" -futures-core = { version = "0.3", default-features = false } -r2d2 = "0.8.9" -dashmap = "4.0" + [dev-dependencies] flowy-test = { path = "../flowy-test" } futures = "0.3.15" -serial_test = "0.5.1" +nanoid = "0.4.0" [features] -http_server = [] dart = ["lib-infra/dart"] [build-dependencies] diff --git a/frontend/rust-lib/flowy-user/build.rs b/frontend/rust-lib/flowy-user/build.rs index 4ab7b9e23d..4d4d3b13da 100644 --- a/frontend/rust-lib/flowy-user/build.rs +++ b/frontend/rust-lib/flowy-user/build.rs @@ -3,5 +3,7 @@ use lib_infra::code_gen; fn main() { let crate_name = env!("CARGO_PKG_NAME"); code_gen::protobuf_file::gen(crate_name, "./src/protobuf/proto"); + + #[cfg(feature = "dart")] code_gen::dart_event::gen(crate_name); } diff --git a/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs b/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs index 0285b2a442..b5d667bcbe 100644 --- a/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs +++ b/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs @@ -5,7 +5,7 @@ use lib_dispatch::prelude::*; use std::{convert::TryInto, sync::Arc}; // tracing instrument 👉🏻 https://docs.rs/tracing/0.1.26/tracing/attr.instrument.html -#[tracing::instrument(name = "sign_in", skip(data, session), fields(email = %data.email), err)] +#[tracing::instrument(level = "debug", name = "sign_in", skip(data, session), fields(email = %data.email), err)] pub async fn sign_in( data: Data, session: AppData>, @@ -16,6 +16,7 @@ pub async fn sign_in( } #[tracing::instrument( + level = "debug", name = "sign_up", skip(data, session), fields( diff --git a/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs b/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs index 1692faa9ac..a13f7187f7 100644 --- a/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs +++ b/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs @@ -6,31 +6,31 @@ use flowy_user_data_model::entities::{ use lib_dispatch::prelude::*; use std::{convert::TryInto, sync::Arc}; -#[tracing::instrument(skip(session))] +#[tracing::instrument(level = "debug", skip(session))] pub async fn init_user_handler(session: AppData>) -> Result<(), FlowyError> { let _ = session.init_user().await?; Ok(()) } -#[tracing::instrument(skip(session))] +#[tracing::instrument(level = "debug", skip(session))] pub async fn check_user_handler(session: AppData>) -> DataResult { let user_profile = session.check_user().await?; data_result(user_profile) } -#[tracing::instrument(skip(session))] +#[tracing::instrument(level = "debug", skip(session))] pub async fn get_user_profile_handler(session: AppData>) -> DataResult { let user_profile = session.user_profile().await?; data_result(user_profile) } -#[tracing::instrument(name = "sign_out", skip(session))] +#[tracing::instrument(level = "debug", name = "sign_out", skip(session))] pub async fn sign_out(session: AppData>) -> Result<(), FlowyError> { let _ = session.sign_out().await?; Ok(()) } -#[tracing::instrument(name = "update_user", skip(data, session))] +#[tracing::instrument(level = "debug", name = "update_user", skip(data, session))] pub async fn update_user_handler( data: Data, session: AppData>, @@ -42,7 +42,7 @@ pub async fn update_user_handler( const APPEARANCE_SETTING_CACHE_KEY: &str = "appearance_settings"; -#[tracing::instrument(skip(data), err)] +#[tracing::instrument(level = "debug", skip(data), err)] pub async fn set_appearance_setting(data: Data) -> Result<(), FlowyError> { let mut setting = data.into_inner(); if setting.theme.is_empty() { diff --git a/frontend/rust-lib/flowy-user/src/lib.rs b/frontend/rust-lib/flowy-user/src/lib.rs index 6d55e0c32f..18ef8e72e0 100644 --- a/frontend/rust-lib/flowy-user/src/lib.rs +++ b/frontend/rust-lib/flowy-user/src/lib.rs @@ -9,7 +9,7 @@ pub mod services; extern crate flowy_database; pub mod errors { - pub use flowy_error::{internal_error, ErrorCode, FlowyError}; + pub use flowy_error::*; } pub mod entities { diff --git a/frontend/rust-lib/flowy-user/src/services/database.rs b/frontend/rust-lib/flowy-user/src/services/database.rs index f7a8e9a85c..f3ddf48fa5 100644 --- a/frontend/rust-lib/flowy-user/src/services/database.rs +++ b/frontend/rust-lib/flowy-user/src/services/database.rs @@ -1,8 +1,8 @@ +use flowy_database::ConnectionPool; use flowy_database::{schema::user_table, DBConnection, Database}; -use flowy_error::FlowyError; +use flowy_error::{ErrorCode, FlowyError}; use flowy_user_data_model::entities::{SignInResponse, SignUpResponse, UpdateUserParams, UserProfile}; use lazy_static::lazy_static; -use lib_sqlite::ConnectionPool; use once_cell::sync::Lazy; use parking_lot::{Mutex, RwLock}; use std::{collections::HashMap, sync::Arc, time::Duration}; @@ -24,10 +24,10 @@ impl UserDB { fn open_user_db(&self, user_id: &str) -> Result<(), FlowyError> { if user_id.is_empty() { - return Err(FlowyError::internal().context("user id is empty")); + return Err(ErrorCode::UserIdIsEmpty.into()); } - tracing::info!("open user db {}", user_id); + tracing::trace!("open user db {}", user_id); let dir = format!("{}/{}", self.db_dir, user_id); let db = flowy_database::init(&dir).map_err(|e| { log::error!("init user db failed, {:?}, user_id: {}", e, user_id); diff --git a/frontend/rust-lib/flowy-user/src/services/user_session.rs b/frontend/rust-lib/flowy-user/src/services/user_session.rs index d8657ad01a..05eea59f87 100644 --- a/frontend/rust-lib/flowy-user/src/services/user_session.rs +++ b/frontend/rust-lib/flowy-user/src/services/user_session.rs @@ -7,6 +7,7 @@ use crate::{ notifier::UserNotifier, }, }; +use flowy_database::ConnectionPool; use flowy_database::{ kv::KV, query_dsl::*, @@ -16,7 +17,6 @@ use flowy_database::{ use flowy_user_data_model::entities::{ SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserProfile, }; -use lib_sqlite::ConnectionPool; use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use std::sync::Arc; diff --git a/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs b/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs index 1f29a87a71..9485e1f730 100644 --- a/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs +++ b/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs @@ -2,8 +2,9 @@ use crate::helper::*; use flowy_test::{event_builder::UserModuleEventBuilder, FlowySDKTest}; use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; use flowy_user_data_model::entities::{UpdateUserPayload, UserProfile}; -use lib_infra::uuid_string; -use serial_test::*; +use nanoid::nanoid; + +// use serial_test::*; #[tokio::test] async fn user_profile_get_failed() { @@ -17,7 +18,6 @@ async fn user_profile_get_failed() { } #[tokio::test] -#[serial] async fn user_profile_get() { let test = FlowySDKTest::default(); let user_profile = test.init_user().await; @@ -29,7 +29,6 @@ async fn user_profile_get() { } #[tokio::test] -#[serial] async fn user_update_with_name() { let sdk = FlowySDKTest::default(); let user = sdk.init_user().await; @@ -50,11 +49,10 @@ async fn user_update_with_name() { } #[tokio::test] -#[serial] async fn user_update_with_email() { let sdk = FlowySDKTest::default(); let user = sdk.init_user().await; - let new_email = format!("{}@gmail.com", uuid_string()); + let new_email = format!("{}@gmail.com", nanoid!(6)); let request = UpdateUserPayload::new(&user.id).email(&new_email); let _ = UserModuleEventBuilder::new(sdk.clone()) .event(UpdateUser) @@ -70,7 +68,6 @@ async fn user_update_with_email() { } #[tokio::test] -#[serial] async fn user_update_with_password() { let sdk = FlowySDKTest::default(); let user = sdk.init_user().await; @@ -85,7 +82,6 @@ async fn user_update_with_password() { } #[tokio::test] -#[serial] async fn user_update_with_invalid_email() { let test = FlowySDKTest::default(); let user = test.init_user().await; @@ -104,7 +100,6 @@ async fn user_update_with_invalid_email() { } #[tokio::test] -#[serial] async fn user_update_with_invalid_password() { let test = FlowySDKTest::default(); let user = test.init_user().await; @@ -120,7 +115,6 @@ async fn user_update_with_invalid_password() { } #[tokio::test] -#[serial] async fn user_update_with_invalid_name() { let test = FlowySDKTest::default(); let user = test.init_user().await; diff --git a/frontend/rust-lib/lib-dispatch/Cargo.toml b/frontend/rust-lib/lib-dispatch/Cargo.toml index b681ee15df..fd09f53956 100644 --- a/frontend/rust-lib/lib-dispatch/Cargo.toml +++ b/frontend/rust-lib/lib-dispatch/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.15" futures-util = "0.3.15" bytes = {version = "1.0", features = ["serde"]} tokio = { version = "1", features = ["full"] } -uuid = { version = "0.8", features = ["serde", "v4"] } +nanoid = "0.4.0" log = "0.4.14" env_logger = "0.8" serde_with = "1.9.4" diff --git a/frontend/rust-lib/lib-dispatch/src/module/module.rs b/frontend/rust-lib/lib-dispatch/src/module/module.rs index 22369197a0..d8fe647fdf 100644 --- a/frontend/rust-lib/lib-dispatch/src/module/module.rs +++ b/frontend/rust-lib/lib-dispatch/src/module/module.rs @@ -22,6 +22,7 @@ use crate::{ }, }; use futures_core::future::BoxFuture; +use nanoid::nanoid; use std::sync::Arc; pub type ModuleMap = Arc>>; @@ -118,7 +119,7 @@ impl ModuleRequest { E: Into, { Self { - id: uuid::Uuid::new_v4().to_string(), + id: nanoid!(6), event: event.into(), payload: Payload::None, } diff --git a/frontend/rust-lib/lib-log/src/lib.rs b/frontend/rust-lib/lib-log/src/lib.rs index c667f33344..d2e0310906 100644 --- a/frontend/rust-lib/lib-log/src/lib.rs +++ b/frontend/rust-lib/lib-log/src/lib.rs @@ -94,7 +94,7 @@ mod tests { say("hello world"); } - #[tracing::instrument(name = "say")] + #[tracing::instrument(level = "trace", name = "say")] fn say(s: &str) { tracing::info!("{}", s); } diff --git a/frontend/scripts/makefile/flutter.toml b/frontend/scripts/makefile/flutter.toml index 8e21a4d85c..fcf599af9e 100644 --- a/frontend/scripts/makefile/flutter.toml +++ b/frontend/scripts/makefile/flutter.toml @@ -5,16 +5,16 @@ linux_alias = "appflowy-linux" [tasks.appflowy-macos] dependencies = ["flowy-sdk-release"] -run_task = { name = ["code_generation", "flutter-build", "copy-to-product"] } +run_task = { name = ["code_generation", "set-app-version", "flutter-build", "copy-to-product"] } script_runner = "@shell" [tasks.appflowy-windows] dependencies = ["flowy-sdk-release"] -run_task = { name = ["code_generation", "flutter-build", "copy-to-product"] } +run_task = { name = ["code_generation", "set-app-version", "flutter-build", "copy-to-product"] } [tasks.appflowy-linux] dependencies = ["flowy-sdk-release"] -run_task = { name = ["code_generation", "flutter-build", "copy-to-product", "create-release-archive"] } +run_task = { name = ["code_generation", "set-app-version", "flutter-build", "copy-to-product", "create-release-archive"] } script_runner = "@shell" [tasks.appflowy-dev] @@ -24,16 +24,16 @@ linux_alias = "appflowy-linux-dev" [tasks.appflowy-macos-dev] dependencies = ["flowy-sdk-dev"] -run_task = { name = ["code_generation", "flutter-build", "copy-to-product"] } +run_task = { name = ["code_generation", "set-app-version", "flutter-build", "copy-to-product"] } script_runner = "@shell" [tasks.appflowy-windows-dev] dependencies = ["flowy-sdk-dev"] -run_task = { name = ["code_generation", "flutter-build", "copy-to-product"] } +run_task = { name = ["code_generation", "set-app-version", "flutter-build", "copy-to-product"] } [tasks.appflowy-linux-dev] dependencies = ["flowy-sdk-dev"] -run_task = { name = ["code_generation", "flutter-build", "copy-to-product"] } +run_task = { name = ["code_generation", "set-app-version", "flutter-build", "copy-to-product"] } script_runner = "@shell" [tasks.copy-to-product] @@ -44,7 +44,7 @@ linux_alias = "copy-to-product-linux" [tasks.copy-to-product-macos] script = [ """ - product_path=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${VERSION} + product_path=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${APP_VERSION} output_path=${product_path}/${TARGET_OS}/${FLUTTER_OUTPUT_DIR} if [ -d "${output_path}" ]; then rm -rf ${output_path}/ @@ -61,7 +61,7 @@ script_runner = "@shell" [tasks.copy-to-product-linux] script = [ """ - product_path=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${VERSION} + product_path=${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${APP_VERSION} output_path=${product_path}/${TARGET_OS}/${FLUTTER_OUTPUT_DIR} if [ -d "${output_path}" ]; then rm -rf ${output_path}/ @@ -81,7 +81,7 @@ script_runner = "@shell" [tasks.copy-to-product-windows] script = [ """ - product_path= set ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${VERSION} + product_path= set ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${APP_VERSION} output_path= set ${product_path}/${TARGET_OS} if is_path_exists ${output_path} rm -r ${output_path}/ @@ -95,6 +95,18 @@ script = [ ] script_runner = "@duckscript" +[tasks.set-app-version] +script = [ + """ + if is_empty ${APP_VERSION} + APP_VERSION = set ${CURRENT_APP_VERSION} + set_env APP_VERSION ${CURRENT_APP_VERSION} + end + echo APP_VERSION: ${APP_VERSION} + """, +] +script_runner = "@duckscript" + # The following tasks will create an archive that will be used on the GitHub Releases section # The archives are created using different compression programs depending on the target OS # The archive will be composed of all files that are located in the /Release/AppFlowy directory @@ -105,7 +117,7 @@ linux_alias = "create-release-archive-linux" [tasks.create-release-archive-linux] script = [ - "cd ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${VERSION}/${TARGET_OS}/Release", + "cd ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/app_flowy/product/${APP_VERSION}/${TARGET_OS}/Release", "tar -czf ${PRODUCT_NAME}-${TARGET_OS}-x86.tar.gz *" ] @@ -129,7 +141,7 @@ script = [ cd app_flowy/ flutter clean flutter pub get - flutter build ${TARGET_OS} --${BUILD_FLAG} --build-name=${VERSION} + flutter build ${TARGET_OS} --${BUILD_FLAG} --build-name=${APP_VERSION} """, ] script_runner = "@shell" diff --git a/shared-lib/Cargo.lock b/shared-lib/Cargo.lock index 18ade8da40..5465e58c21 100644 --- a/shared-lib/Cargo.lock +++ b/shared-lib/Cargo.lock @@ -402,33 +402,6 @@ dependencies = [ "syn", ] -[[package]] -name = "flowy-collaboration" -version = "0.1.0" -dependencies = [ - "async-stream", - "bytes", - "chrono", - "dashmap", - "dissimilar", - "flowy-derive", - "flowy-folder-data-model", - "futures", - "lib-infra", - "lib-ot", - "log", - "md5", - "parking_lot", - "protobuf", - "serde", - "serde_json", - "strum", - "strum_macros", - "tokio", - "tracing", - "url", -] - [[package]] name = "flowy-derive" version = "0.1.0" @@ -468,6 +441,7 @@ dependencies = [ "flowy-error-code", "lib-infra", "log", + "nanoid", "protobuf", "serde", "serde_json", @@ -475,7 +449,52 @@ dependencies = [ "strum", "strum_macros", "unicode-segmentation", - "uuid", +] + +[[package]] +name = "flowy-grid-data-model" +version = "0.1.0" +dependencies = [ + "bytes", + "flowy-derive", + "flowy-error-code", + "indexmap", + "lib-infra", + "nanoid", + "protobuf", + "serde", + "serde_json", + "serde_repr", + "strum", + "strum_macros", +] + +[[package]] +name = "flowy-sync" +version = "0.1.0" +dependencies = [ + "async-stream", + "bytes", + "chrono", + "dashmap", + "dissimilar", + "flowy-derive", + "flowy-folder-data-model", + "flowy-grid-data-model", + "futures", + "lib-infra", + "lib-ot", + "log", + "md5", + "parking_lot", + "protobuf", + "serde", + "serde_json", + "strum", + "strum_macros", + "tokio", + "tracing", + "url", ] [[package]] @@ -683,6 +702,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + [[package]] name = "heck" version = "0.3.3" @@ -759,6 +784,17 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", + "serde", +] + [[package]] name = "instant" version = "0.1.12" @@ -815,7 +851,6 @@ dependencies = [ "tera", "tokio", "toml", - "uuid", "walkdir", ] @@ -936,6 +971,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand 0.8.4", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -2061,16 +2105,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.3", - "serde", -] - [[package]] name = "validator" version = "0.12.0" diff --git a/shared-lib/Cargo.toml b/shared-lib/Cargo.toml index 0a4b9c7069..370c4d7f31 100644 --- a/shared-lib/Cargo.toml +++ b/shared-lib/Cargo.toml @@ -2,13 +2,14 @@ members = [ "flowy-user-data-model", "flowy-folder-data-model", - "flowy-collaboration", + "flowy-sync", "lib-ot", "lib-ws", "lib-infra", "flowy-derive", "flowy-ast", "flowy-error-code", + "flowy-grid-data-model", ] [profile.dev] diff --git a/shared-lib/flowy-derive/src/proto_buf/deserialize.rs b/shared-lib/flowy-derive/src/proto_buf/deserialize.rs index 8971d326c2..e09f7ea847 100644 --- a/shared-lib/flowy-derive/src/proto_buf/deserialize.rs +++ b/shared-lib/flowy-derive/src/proto_buf/deserialize.rs @@ -55,14 +55,11 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option } }?; let bracketed_ty_info = ty_info.bracket_ty_info.as_ref().as_ref(); - let has_func = format_ident!("has_{}", ident.to_string()); - // eprintln!("😁{:#?}", ty_info.primitive_ty); - // eprintln!("{:#?}", ty_info.bracket_ty_info); match ident_category(bracketed_ty_info.unwrap().ident) { TypeCategory::Enum => { let get_func = format_ident!("get_{}", ident.to_string()); - let ty = ty_info.ty; + let ty = bracketed_ty_info.unwrap().ty; Some(quote! { if pb.#has_func() { let enum_de_from_pb = #ty::try_from(&pb.#get_func()).unwrap(); @@ -207,13 +204,12 @@ fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, bracketed_type: &TyIn } } -fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, bracketed_type: &TyInfo) -> Option { +fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty_info: &TyInfo) -> Option { let ident = get_member_ident(ctxt, member)?; - let take_ident = format_ident!("take_{}", ident.to_string()); - let ty = bracketed_type.ty; + let ty = ty_info.ty; - match ident_category(bracketed_type.ident) { + match ident_category(ty_info.ident) { TypeCategory::Protobuf => Some(quote! { let mut m: std::collections::HashMap = std::collections::HashMap::new(); pb.#take_ident().into_iter().for_each(|(k,v)| { diff --git a/shared-lib/flowy-derive/src/proto_buf/serialize.rs b/shared-lib/flowy-derive/src/proto_buf/serialize.rs index d0162c90d3..324c26651b 100644 --- a/shared-lib/flowy-derive/src/proto_buf/serialize.rs +++ b/shared-lib/flowy-derive/src/proto_buf/serialize.rs @@ -71,6 +71,12 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option None => {} } }), + TypeCategory::Enum => Some(quote! { + match self.#member { + Some(s) => { pb.#set_func(s.try_into().unwrap()) } + None => {} + } + }), _ => Some(quote! { match self.#member { Some(ref s) => { pb.#set_func(s.clone()) } @@ -89,7 +95,7 @@ fn gen_token_stream(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option } }?; match ident_category(ty_info.ident) { - TypeCategory::Array => token_stream_for_vec(ctxt, member, ty_info.ty), + TypeCategory::Array => token_stream_for_vec(ctxt, member, ty_info.bracket_ty_info.unwrap().ty), TypeCategory::Map => token_stream_for_map(ctxt, member, ty_info.bracket_ty_info.unwrap().ty), TypeCategory::Str => { if is_option { @@ -149,7 +155,6 @@ fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op // e.g. pub cells: HashMap fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Option { // The key of the hashmap must be string - let flowy_protobuf = format_ident!("flowy_protobuf"); let ty_info = match parse_ty(ctxt, ty) { Ok(ty_info) => ty_info, Err(e) => { @@ -157,27 +162,21 @@ fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op panic!(); } }?; + let value_ty = ty_info.ty; match ident_category(ty_info.ident) { - TypeCategory::Protobuf => { - let value_type = ty_info.ident; - Some(quote! { - let mut m: std::collections::HashMap = std::collections::HashMap::new(); - self.#member.iter().for_each(|(k,v)| { - m.insert(k.clone(), v.try_into().unwrap()); - }); - pb.#member = m; - }) - } - - _ => { - let value_type = ty_info.ident; - Some(quote! { - let mut m: std::collections::HashMap = std::collections::HashMap::new(); - self.#member.iter().for_each(|(k,v)| { - m.insert(k.clone(), v.clone()); - }); - pb.#member = m; - }) - } + TypeCategory::Protobuf => Some(quote! { + let mut m: std::collections::HashMap = std::collections::HashMap::new(); + self.#member.into_iter().for_each(|(k,v)| { + m.insert(k.clone(), v.try_into().unwrap()); + }); + pb.#member = m; + }), + _ => Some(quote! { + let mut m: std::collections::HashMap = std::collections::HashMap::new(); + self.#member.iter().for_each(|(k,v)| { + m.insert(k.clone(), v.clone()); + }); + pb.#member = m; + }), } } diff --git a/shared-lib/flowy-derive/src/proto_buf/util.rs b/shared-lib/flowy-derive/src/proto_buf/util.rs index 49a5ee1605..ef9391fa0d 100644 --- a/shared-lib/flowy-derive/src/proto_buf/util.rs +++ b/shared-lib/flowy-derive/src/proto_buf/util.rs @@ -74,14 +74,14 @@ pub fn category_from_str(type_str: String) -> TypeCategory { } } - if let Some(protobuf) = CACHE_INFO.get(&TypeCategory::Protobuf) { - if protobuf.contains(&type_str) { + if let Some(protobuf_tys) = CACHE_INFO.get(&TypeCategory::Protobuf) { + if protobuf_tys.contains(&type_str) { return TypeCategory::Protobuf; } } - if let Some(protobuf) = CACHE_INFO.get(&TypeCategory::Enum) { - if protobuf.contains(&type_str) { + if let Some(enum_tys) = CACHE_INFO.get(&TypeCategory::Enum) { + if enum_tys.contains(&type_str) { return TypeCategory::Enum; } } diff --git a/shared-lib/flowy-error-code/src/code.rs b/shared-lib/flowy-error-code/src/code.rs index c47d4fd8d4..0315306871 100644 --- a/shared-lib/flowy-error-code/src/code.rs +++ b/shared-lib/flowy-error-code/src/code.rs @@ -15,6 +15,9 @@ pub enum ErrorCode { #[display(fmt = "RecordNotFound")] RecordNotFound = 3, + #[display(fmt = "User id is empty")] + UserIdIsEmpty = 4, + #[display(fmt = "Workspace name can not be empty or whitespace")] WorkspaceNameInvalid = 100, @@ -83,6 +86,33 @@ pub enum ErrorCode { UserIdInvalid = 311, #[display(fmt = "User not exist")] UserNotExist = 312, + #[display(fmt = "Text is too long")] + TextTooLong = 400, + + #[display(fmt = "Grid id is empty")] + GridIdIsEmpty = 410, + #[display(fmt = "Grid block id is empty")] + BlockIdIsEmpty = 420, + #[display(fmt = "Row id is empty")] + RowIdIsEmpty = 430, + #[display(fmt = "Select option id is empty")] + OptionIdIsEmpty = 431, + #[display(fmt = "Field id is empty")] + FieldIdIsEmpty = 440, + #[display(fmt = "Field doesn't exist")] + FieldDoesNotExist = 441, + #[display(fmt = "The name of the option should not be empty")] + SelectOptionNameIsEmpty = 442, + #[display(fmt = "Field not exists")] + FieldNotExists = 443, + #[display(fmt = "The operation in this field is invalid")] + FieldInvalidOperation = 444, + + #[display(fmt = "Field's type option data should not be empty")] + TypeOptionDataIsEmpty = 450, + + #[display(fmt = "Invalid data")] + InvalidData = 500, } impl ErrorCode { diff --git a/shared-lib/flowy-error-code/src/protobuf/model/code.rs b/shared-lib/flowy-error-code/src/protobuf/model/code.rs index f70c1eb49d..5653852147 100644 --- a/shared-lib/flowy-error-code/src/protobuf/model/code.rs +++ b/shared-lib/flowy-error-code/src/protobuf/model/code.rs @@ -28,6 +28,7 @@ pub enum ErrorCode { Internal = 0, UserUnauthorized = 2, RecordNotFound = 3, + UserIdIsEmpty = 4, WorkspaceNameInvalid = 100, WorkspaceIdInvalid = 101, AppColorStyleInvalid = 102, @@ -55,6 +56,18 @@ pub enum ErrorCode { UserNameIsEmpty = 310, UserIdInvalid = 311, UserNotExist = 312, + TextTooLong = 400, + GridIdIsEmpty = 410, + BlockIdIsEmpty = 420, + RowIdIsEmpty = 430, + OptionIdIsEmpty = 431, + FieldIdIsEmpty = 440, + FieldDoesNotExist = 441, + SelectOptionNameIsEmpty = 442, + FieldNotExists = 443, + FieldInvalidOperation = 444, + TypeOptionDataIsEmpty = 450, + InvalidData = 500, } impl ::protobuf::ProtobufEnum for ErrorCode { @@ -67,6 +80,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode { 0 => ::std::option::Option::Some(ErrorCode::Internal), 2 => ::std::option::Option::Some(ErrorCode::UserUnauthorized), 3 => ::std::option::Option::Some(ErrorCode::RecordNotFound), + 4 => ::std::option::Option::Some(ErrorCode::UserIdIsEmpty), 100 => ::std::option::Option::Some(ErrorCode::WorkspaceNameInvalid), 101 => ::std::option::Option::Some(ErrorCode::WorkspaceIdInvalid), 102 => ::std::option::Option::Some(ErrorCode::AppColorStyleInvalid), @@ -94,6 +108,18 @@ impl ::protobuf::ProtobufEnum for ErrorCode { 310 => ::std::option::Option::Some(ErrorCode::UserNameIsEmpty), 311 => ::std::option::Option::Some(ErrorCode::UserIdInvalid), 312 => ::std::option::Option::Some(ErrorCode::UserNotExist), + 400 => ::std::option::Option::Some(ErrorCode::TextTooLong), + 410 => ::std::option::Option::Some(ErrorCode::GridIdIsEmpty), + 420 => ::std::option::Option::Some(ErrorCode::BlockIdIsEmpty), + 430 => ::std::option::Option::Some(ErrorCode::RowIdIsEmpty), + 431 => ::std::option::Option::Some(ErrorCode::OptionIdIsEmpty), + 440 => ::std::option::Option::Some(ErrorCode::FieldIdIsEmpty), + 441 => ::std::option::Option::Some(ErrorCode::FieldDoesNotExist), + 442 => ::std::option::Option::Some(ErrorCode::SelectOptionNameIsEmpty), + 443 => ::std::option::Option::Some(ErrorCode::FieldNotExists), + 444 => ::std::option::Option::Some(ErrorCode::FieldInvalidOperation), + 450 => ::std::option::Option::Some(ErrorCode::TypeOptionDataIsEmpty), + 500 => ::std::option::Option::Some(ErrorCode::InvalidData), _ => ::std::option::Option::None } } @@ -103,6 +129,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode { ErrorCode::Internal, ErrorCode::UserUnauthorized, ErrorCode::RecordNotFound, + ErrorCode::UserIdIsEmpty, ErrorCode::WorkspaceNameInvalid, ErrorCode::WorkspaceIdInvalid, ErrorCode::AppColorStyleInvalid, @@ -130,6 +157,18 @@ impl ::protobuf::ProtobufEnum for ErrorCode { ErrorCode::UserNameIsEmpty, ErrorCode::UserIdInvalid, ErrorCode::UserNotExist, + ErrorCode::TextTooLong, + ErrorCode::GridIdIsEmpty, + ErrorCode::BlockIdIsEmpty, + ErrorCode::RowIdIsEmpty, + ErrorCode::OptionIdIsEmpty, + ErrorCode::FieldIdIsEmpty, + ErrorCode::FieldDoesNotExist, + ErrorCode::SelectOptionNameIsEmpty, + ErrorCode::FieldNotExists, + ErrorCode::FieldInvalidOperation, + ErrorCode::TypeOptionDataIsEmpty, + ErrorCode::InvalidData, ]; values } @@ -158,24 +197,31 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\ncode.proto*\xc4\x05\n\tErrorCode\x12\x0c\n\x08Internal\x10\0\x12\x14\ + \n\ncode.proto*\xe5\x07\n\tErrorCode\x12\x0c\n\x08Internal\x10\0\x12\x14\ \n\x10UserUnauthorized\x10\x02\x12\x12\n\x0eRecordNotFound\x10\x03\x12\ - \x18\n\x14WorkspaceNameInvalid\x10d\x12\x16\n\x12WorkspaceIdInvalid\x10e\ - \x12\x18\n\x14AppColorStyleInvalid\x10f\x12\x18\n\x14WorkspaceDescTooLon\ - g\x10g\x12\x18\n\x14WorkspaceNameTooLong\x10h\x12\x10\n\x0cAppIdInvalid\ - \x10n\x12\x12\n\x0eAppNameInvalid\x10o\x12\x13\n\x0fViewNameInvalid\x10x\ - \x12\x18\n\x14ViewThumbnailInvalid\x10y\x12\x11\n\rViewIdInvalid\x10z\ - \x12\x13\n\x0fViewDescTooLong\x10{\x12\x13\n\x0fViewDataInvalid\x10|\x12\ - \x13\n\x0fViewNameTooLong\x10}\x12\x11\n\x0cConnectError\x10\xc8\x01\x12\ - \x11\n\x0cEmailIsEmpty\x10\xac\x02\x12\x17\n\x12EmailFormatInvalid\x10\ - \xad\x02\x12\x17\n\x12EmailAlreadyExists\x10\xae\x02\x12\x14\n\x0fPasswo\ - rdIsEmpty\x10\xaf\x02\x12\x14\n\x0fPasswordTooLong\x10\xb0\x02\x12%\n\ - \x20PasswordContainsForbidCharacters\x10\xb1\x02\x12\x1a\n\x15PasswordFo\ - rmatInvalid\x10\xb2\x02\x12\x15\n\x10PasswordNotMatch\x10\xb3\x02\x12\ - \x14\n\x0fUserNameTooLong\x10\xb4\x02\x12'\n\"UserNameContainForbiddenCh\ - aracters\x10\xb5\x02\x12\x14\n\x0fUserNameIsEmpty\x10\xb6\x02\x12\x12\n\ - \rUserIdInvalid\x10\xb7\x02\x12\x11\n\x0cUserNotExist\x10\xb8\x02b\x06pr\ - oto3\ + \x11\n\rUserIdIsEmpty\x10\x04\x12\x18\n\x14WorkspaceNameInvalid\x10d\x12\ + \x16\n\x12WorkspaceIdInvalid\x10e\x12\x18\n\x14AppColorStyleInvalid\x10f\ + \x12\x18\n\x14WorkspaceDescTooLong\x10g\x12\x18\n\x14WorkspaceNameTooLon\ + g\x10h\x12\x10\n\x0cAppIdInvalid\x10n\x12\x12\n\x0eAppNameInvalid\x10o\ + \x12\x13\n\x0fViewNameInvalid\x10x\x12\x18\n\x14ViewThumbnailInvalid\x10\ + y\x12\x11\n\rViewIdInvalid\x10z\x12\x13\n\x0fViewDescTooLong\x10{\x12\ + \x13\n\x0fViewDataInvalid\x10|\x12\x13\n\x0fViewNameTooLong\x10}\x12\x11\ + \n\x0cConnectError\x10\xc8\x01\x12\x11\n\x0cEmailIsEmpty\x10\xac\x02\x12\ + \x17\n\x12EmailFormatInvalid\x10\xad\x02\x12\x17\n\x12EmailAlreadyExists\ + \x10\xae\x02\x12\x14\n\x0fPasswordIsEmpty\x10\xaf\x02\x12\x14\n\x0fPassw\ + ordTooLong\x10\xb0\x02\x12%\n\x20PasswordContainsForbidCharacters\x10\ + \xb1\x02\x12\x1a\n\x15PasswordFormatInvalid\x10\xb2\x02\x12\x15\n\x10Pas\ + swordNotMatch\x10\xb3\x02\x12\x14\n\x0fUserNameTooLong\x10\xb4\x02\x12'\ + \n\"UserNameContainForbiddenCharacters\x10\xb5\x02\x12\x14\n\x0fUserName\ + IsEmpty\x10\xb6\x02\x12\x12\n\rUserIdInvalid\x10\xb7\x02\x12\x11\n\x0cUs\ + erNotExist\x10\xb8\x02\x12\x10\n\x0bTextTooLong\x10\x90\x03\x12\x12\n\rG\ + ridIdIsEmpty\x10\x9a\x03\x12\x13\n\x0eBlockIdIsEmpty\x10\xa4\x03\x12\x11\ + \n\x0cRowIdIsEmpty\x10\xae\x03\x12\x14\n\x0fOptionIdIsEmpty\x10\xaf\x03\ + \x12\x13\n\x0eFieldIdIsEmpty\x10\xb8\x03\x12\x16\n\x11FieldDoesNotExist\ + \x10\xb9\x03\x12\x1c\n\x17SelectOptionNameIsEmpty\x10\xba\x03\x12\x13\n\ + \x0eFieldNotExists\x10\xbb\x03\x12\x1a\n\x15FieldInvalidOperation\x10\ + \xbc\x03\x12\x1a\n\x15TypeOptionDataIsEmpty\x10\xc2\x03\x12\x10\n\x0bInv\ + alidData\x10\xf4\x03b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-error-code/src/protobuf/proto/code.proto b/shared-lib/flowy-error-code/src/protobuf/proto/code.proto index ed12d58848..aca3309526 100644 --- a/shared-lib/flowy-error-code/src/protobuf/proto/code.proto +++ b/shared-lib/flowy-error-code/src/protobuf/proto/code.proto @@ -4,6 +4,7 @@ enum ErrorCode { Internal = 0; UserUnauthorized = 2; RecordNotFound = 3; + UserIdIsEmpty = 4; WorkspaceNameInvalid = 100; WorkspaceIdInvalid = 101; AppColorStyleInvalid = 102; @@ -31,4 +32,16 @@ enum ErrorCode { UserNameIsEmpty = 310; UserIdInvalid = 311; UserNotExist = 312; + TextTooLong = 400; + GridIdIsEmpty = 410; + BlockIdIsEmpty = 420; + RowIdIsEmpty = 430; + OptionIdIsEmpty = 431; + FieldIdIsEmpty = 440; + FieldDoesNotExist = 441; + SelectOptionNameIsEmpty = 442; + FieldNotExists = 443; + FieldInvalidOperation = 444; + TypeOptionDataIsEmpty = 450; + InvalidData = 500; } diff --git a/shared-lib/flowy-folder-data-model/Cargo.toml b/shared-lib/flowy-folder-data-model/Cargo.toml index 90422eaa53..bacd1c9509 100644 --- a/shared-lib/flowy-folder-data-model/Cargo.toml +++ b/shared-lib/flowy-folder-data-model/Cargo.toml @@ -14,7 +14,7 @@ strum = "0.21" strum_macros = "0.21" derive_more = {version = "0.99", features = ["display"]} log = "0.4.14" -uuid = { version = "0.8", features = ["serde", "v4"] } +nanoid = "0.4.0" chrono = { version = "0.4" } flowy-error-code = { path = "../flowy-error-code"} serde = { version = "1.0", features = ["derive"] } diff --git a/shared-lib/flowy-folder-data-model/src/entities/app.rs b/shared-lib/flowy-folder-data-model/src/entities/app.rs index 7d70cf6829..2c87c882ab 100644 --- a/shared-lib/flowy-folder-data-model/src/entities/app.rs +++ b/shared-lib/flowy-folder-data-model/src/entities/app.rs @@ -8,9 +8,13 @@ use crate::{ }, }; use flowy_derive::ProtoBuf; +use nanoid::nanoid; use serde::{Deserialize, Serialize}; use std::convert::TryInto; +pub fn gen_app_id() -> String { + nanoid!(10) +} #[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone, Serialize, Deserialize)] pub struct App { #[pb(index = 1)] diff --git a/shared-lib/flowy-folder-data-model/src/entities/mod.rs b/shared-lib/flowy-folder-data-model/src/entities/mod.rs index a8388db4a3..3ee0f4b591 100644 --- a/shared-lib/flowy-folder-data-model/src/entities/mod.rs +++ b/shared-lib/flowy-folder-data-model/src/entities/mod.rs @@ -1,5 +1,4 @@ pub mod app; -pub mod share; pub mod trash; pub mod view; pub mod workspace; diff --git a/shared-lib/flowy-folder-data-model/src/entities/view.rs b/shared-lib/flowy-folder-data-model/src/entities/view.rs index a16a384be1..1d522a1500 100644 --- a/shared-lib/flowy-folder-data-model/src/entities/view.rs +++ b/shared-lib/flowy-folder-data-model/src/entities/view.rs @@ -4,14 +4,19 @@ use crate::{ impl_def_and_def_mut, parser::{ app::AppIdentify, - view::{ViewDesc, ViewExtensionData, ViewIdentify, ViewName, ViewThumbnail}, + view::{ViewDesc, ViewIdentify, ViewName, ViewThumbnail}, }, }; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use nanoid::nanoid; use serde::{Deserialize, Serialize}; use serde_repr::*; use std::convert::TryInto; +pub fn gen_view_id() -> String { + nanoid!(10) +} + #[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone, Serialize, Deserialize)] pub struct View { #[pb(index = 1)] @@ -80,27 +85,27 @@ impl std::convert::From for Trash { } } -#[derive(Eq, PartialEq, Debug, ProtoBuf_Enum, Clone, Serialize_repr, Deserialize_repr)] +#[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum ViewDataType { - RichText = 0, - PlainText = 1, + TextBlock = 0, + Grid = 1, } impl std::default::Default for ViewDataType { fn default() -> Self { - ViewDataType::RichText + ViewDataType::TextBlock } } impl std::convert::From for ViewDataType { fn from(val: i32) -> Self { match val { - 0 => ViewDataType::RichText, - 1 => ViewDataType::PlainText, + 0 => ViewDataType::TextBlock, + 1 => ViewDataType::Grid, _ => { log::error!("Invalid view type: {}", val); - ViewDataType::PlainText + ViewDataType::TextBlock } } } @@ -124,10 +129,10 @@ pub struct CreateViewPayload { pub data_type: ViewDataType, #[pb(index = 6)] - pub ext_data: String, + pub plugin_type: i32, #[pb(index = 7)] - pub plugin_type: i32, + pub data: Vec, } #[derive(Default, ProtoBuf, Debug, Clone)] @@ -148,15 +153,12 @@ pub struct CreateViewParams { pub data_type: ViewDataType, #[pb(index = 6)] - pub ext_data: String, - - #[pb(index = 7)] pub view_id: String, - #[pb(index = 8)] - pub data: String, + #[pb(index = 7)] + pub data: Vec, - #[pb(index = 9)] + #[pb(index = 8)] pub plugin_type: i32, } @@ -166,13 +168,11 @@ impl TryInto for CreateViewPayload { fn try_into(self) -> Result { let name = ViewName::parse(self.name)?.0; let belong_to_id = AppIdentify::parse(self.belong_to_id)?.0; - let view_id = uuid::Uuid::new_v4().to_string(); - let ext_data = ViewExtensionData::parse(self.ext_data)?.0; + let view_id = gen_view_id(); let thumbnail = match self.thumbnail { None => "".to_string(), Some(thumbnail) => ViewThumbnail::parse(thumbnail)?.0, }; - let data = "".to_string(); Ok(CreateViewParams { belong_to_id, @@ -180,9 +180,8 @@ impl TryInto for CreateViewPayload { desc: self.desc, data_type: self.data_type, thumbnail, - ext_data, view_id, - data, + data: self.data, plugin_type: self.plugin_type, }) } diff --git a/shared-lib/flowy-folder-data-model/src/entities/workspace.rs b/shared-lib/flowy-folder-data-model/src/entities/workspace.rs index fec0b12739..0b479f4477 100644 --- a/shared-lib/flowy-folder-data-model/src/entities/workspace.rs +++ b/shared-lib/flowy-folder-data-model/src/entities/workspace.rs @@ -5,9 +5,13 @@ use crate::{ parser::workspace::{WorkspaceDesc, WorkspaceIdentify, WorkspaceName}, }; use flowy_derive::ProtoBuf; +use nanoid::nanoid; use serde::{Deserialize, Serialize}; use std::convert::TryInto; +pub fn gen_workspace_id() -> String { + nanoid!(10) +} #[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone, Serialize, Deserialize)] pub struct Workspace { #[pb(index = 1)] diff --git a/shared-lib/flowy-folder-data-model/src/protobuf/model/mod.rs b/shared-lib/flowy-folder-data-model/src/protobuf/model/mod.rs index fae1a91d08..d12cb83589 100644 --- a/shared-lib/flowy-folder-data-model/src/protobuf/model/mod.rs +++ b/shared-lib/flowy-folder-data-model/src/protobuf/model/mod.rs @@ -1,9 +1,6 @@ #![cfg_attr(rustfmt, rustfmt::skip)] // Auto-generated, do not edit -mod share; -pub use share::*; - mod app; pub use app::*; diff --git a/shared-lib/flowy-folder-data-model/src/protobuf/model/view.rs b/shared-lib/flowy-folder-data-model/src/protobuf/model/view.rs index 0e1e3a7279..9f19e18f0c 100644 --- a/shared-lib/flowy-folder-data-model/src/protobuf/model/view.rs +++ b/shared-lib/flowy-folder-data-model/src/protobuf/model/view.rs @@ -165,7 +165,7 @@ impl View { self.data_type } pub fn clear_data_type(&mut self) { - self.data_type = ViewDataType::RichText; + self.data_type = ViewDataType::TextBlock; } // Param is passed by value, moved @@ -409,7 +409,7 @@ impl ::protobuf::Message for View { if !self.desc.is_empty() { my_size += ::protobuf::rt::string_size(4, &self.desc); } - if self.data_type != ViewDataType::RichText { + if self.data_type != ViewDataType::TextBlock { my_size += ::protobuf::rt::enum_size(5, self.data_type); } if self.version != 0 { @@ -452,7 +452,7 @@ impl ::protobuf::Message for View { if !self.desc.is_empty() { os.write_string(4, &self.desc)?; } - if self.data_type != ViewDataType::RichText { + if self.data_type != ViewDataType::TextBlock { os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.data_type))?; } if self.version != 0 { @@ -596,7 +596,7 @@ impl ::protobuf::Clear for View { self.belong_to_id.clear(); self.name.clear(); self.desc.clear(); - self.data_type = ViewDataType::RichText; + self.data_type = ViewDataType::TextBlock; self.version = 0; self.belongings.clear(); self.modified_time = 0; @@ -793,8 +793,8 @@ pub struct CreateViewPayload { pub name: ::std::string::String, pub desc: ::std::string::String, pub data_type: ViewDataType, - pub ext_data: ::std::string::String, pub plugin_type: i32, + pub data: ::std::vec::Vec, // message oneof groups pub one_of_thumbnail: ::std::option::Option, // special fields @@ -952,7 +952,7 @@ impl CreateViewPayload { self.data_type } pub fn clear_data_type(&mut self) { - self.data_type = ViewDataType::RichText; + self.data_type = ViewDataType::TextBlock; } // Param is passed by value, moved @@ -960,33 +960,7 @@ impl CreateViewPayload { self.data_type = v; } - // string ext_data = 6; - - - pub fn get_ext_data(&self) -> &str { - &self.ext_data - } - pub fn clear_ext_data(&mut self) { - self.ext_data.clear(); - } - - // Param is passed by value, moved - pub fn set_ext_data(&mut self, v: ::std::string::String) { - self.ext_data = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_ext_data(&mut self) -> &mut ::std::string::String { - &mut self.ext_data - } - - // Take field - pub fn take_ext_data(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.ext_data, ::std::string::String::new()) - } - - // int32 plugin_type = 7; + // int32 plugin_type = 6; pub fn get_plugin_type(&self) -> i32 { @@ -1000,6 +974,32 @@ impl CreateViewPayload { pub fn set_plugin_type(&mut self, v: i32) { self.plugin_type = v; } + + // bytes data = 7; + + + pub fn get_data(&self) -> &[u8] { + &self.data + } + pub fn clear_data(&mut self) { + self.data.clear(); + } + + // Param is passed by value, moved + pub fn set_data(&mut self, v: ::std::vec::Vec) { + self.data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.data + } + + // Take field + pub fn take_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) + } } impl ::protobuf::Message for CreateViewPayload { @@ -1030,15 +1030,15 @@ impl ::protobuf::Message for CreateViewPayload { ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.data_type, 5, &mut self.unknown_fields)? }, 6 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.ext_data)?; - }, - 7 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } let tmp = is.read_int32()?; self.plugin_type = tmp; }, + 7 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; + }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, @@ -1060,14 +1060,14 @@ impl ::protobuf::Message for CreateViewPayload { if !self.desc.is_empty() { my_size += ::protobuf::rt::string_size(3, &self.desc); } - if self.data_type != ViewDataType::RichText { + if self.data_type != ViewDataType::TextBlock { my_size += ::protobuf::rt::enum_size(5, self.data_type); } - if !self.ext_data.is_empty() { - my_size += ::protobuf::rt::string_size(6, &self.ext_data); - } if self.plugin_type != 0 { - my_size += ::protobuf::rt::value_size(7, self.plugin_type, ::protobuf::wire_format::WireTypeVarint); + my_size += ::protobuf::rt::value_size(6, self.plugin_type, ::protobuf::wire_format::WireTypeVarint); + } + if !self.data.is_empty() { + my_size += ::protobuf::rt::bytes_size(7, &self.data); } if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail { match v { @@ -1091,14 +1091,14 @@ impl ::protobuf::Message for CreateViewPayload { if !self.desc.is_empty() { os.write_string(3, &self.desc)?; } - if self.data_type != ViewDataType::RichText { + if self.data_type != ViewDataType::TextBlock { os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.data_type))?; } - if !self.ext_data.is_empty() { - os.write_string(6, &self.ext_data)?; - } if self.plugin_type != 0 { - os.write_int32(7, self.plugin_type)?; + os.write_int32(6, self.plugin_type)?; + } + if !self.data.is_empty() { + os.write_bytes(7, &self.data)?; } if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail { match v { @@ -1170,16 +1170,16 @@ impl ::protobuf::Message for CreateViewPayload { |m: &CreateViewPayload| { &m.data_type }, |m: &mut CreateViewPayload| { &mut m.data_type }, )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "ext_data", - |m: &CreateViewPayload| { &m.ext_data }, - |m: &mut CreateViewPayload| { &mut m.ext_data }, - )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( "plugin_type", |m: &CreateViewPayload| { &m.plugin_type }, |m: &mut CreateViewPayload| { &mut m.plugin_type }, )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "data", + |m: &CreateViewPayload| { &m.data }, + |m: &mut CreateViewPayload| { &mut m.data }, + )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "CreateViewPayload", fields, @@ -1200,9 +1200,9 @@ impl ::protobuf::Clear for CreateViewPayload { self.name.clear(); self.desc.clear(); self.one_of_thumbnail = ::std::option::Option::None; - self.data_type = ViewDataType::RichText; - self.ext_data.clear(); + self.data_type = ViewDataType::TextBlock; self.plugin_type = 0; + self.data.clear(); self.unknown_fields.clear(); } } @@ -1227,9 +1227,8 @@ pub struct CreateViewParams { pub desc: ::std::string::String, pub thumbnail: ::std::string::String, pub data_type: ViewDataType, - pub ext_data: ::std::string::String, pub view_id: ::std::string::String, - pub data: ::std::string::String, + pub data: ::std::vec::Vec, pub plugin_type: i32, // special fields pub unknown_fields: ::protobuf::UnknownFields, @@ -1358,7 +1357,7 @@ impl CreateViewParams { self.data_type } pub fn clear_data_type(&mut self) { - self.data_type = ViewDataType::RichText; + self.data_type = ViewDataType::TextBlock; } // Param is passed by value, moved @@ -1366,33 +1365,7 @@ impl CreateViewParams { self.data_type = v; } - // string ext_data = 6; - - - pub fn get_ext_data(&self) -> &str { - &self.ext_data - } - pub fn clear_ext_data(&mut self) { - self.ext_data.clear(); - } - - // Param is passed by value, moved - pub fn set_ext_data(&mut self, v: ::std::string::String) { - self.ext_data = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_ext_data(&mut self) -> &mut ::std::string::String { - &mut self.ext_data - } - - // Take field - pub fn take_ext_data(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.ext_data, ::std::string::String::new()) - } - - // string view_id = 7; + // string view_id = 6; pub fn get_view_id(&self) -> &str { @@ -1418,10 +1391,10 @@ impl CreateViewParams { ::std::mem::replace(&mut self.view_id, ::std::string::String::new()) } - // string data = 8; + // bytes data = 7; - pub fn get_data(&self) -> &str { + pub fn get_data(&self) -> &[u8] { &self.data } pub fn clear_data(&mut self) { @@ -1429,22 +1402,22 @@ impl CreateViewParams { } // Param is passed by value, moved - pub fn set_data(&mut self, v: ::std::string::String) { + pub fn set_data(&mut self, v: ::std::vec::Vec) { self.data = v; } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. - pub fn mut_data(&mut self) -> &mut ::std::string::String { + pub fn mut_data(&mut self) -> &mut ::std::vec::Vec { &mut self.data } // Take field - pub fn take_data(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.data, ::std::string::String::new()) + pub fn take_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) } - // int32 plugin_type = 9; + // int32 plugin_type = 8; pub fn get_plugin_type(&self) -> i32 { @@ -1485,15 +1458,12 @@ impl ::protobuf::Message for CreateViewParams { ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.data_type, 5, &mut self.unknown_fields)? }, 6 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.ext_data)?; - }, - 7 => { ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?; }, - 8 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?; + 7 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; }, - 9 => { + 8 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } @@ -1524,20 +1494,17 @@ impl ::protobuf::Message for CreateViewParams { if !self.thumbnail.is_empty() { my_size += ::protobuf::rt::string_size(4, &self.thumbnail); } - if self.data_type != ViewDataType::RichText { + if self.data_type != ViewDataType::TextBlock { my_size += ::protobuf::rt::enum_size(5, self.data_type); } - if !self.ext_data.is_empty() { - my_size += ::protobuf::rt::string_size(6, &self.ext_data); - } if !self.view_id.is_empty() { - my_size += ::protobuf::rt::string_size(7, &self.view_id); + my_size += ::protobuf::rt::string_size(6, &self.view_id); } if !self.data.is_empty() { - my_size += ::protobuf::rt::string_size(8, &self.data); + my_size += ::protobuf::rt::bytes_size(7, &self.data); } if self.plugin_type != 0 { - my_size += ::protobuf::rt::value_size(9, self.plugin_type, ::protobuf::wire_format::WireTypeVarint); + my_size += ::protobuf::rt::value_size(8, self.plugin_type, ::protobuf::wire_format::WireTypeVarint); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); @@ -1557,20 +1524,17 @@ impl ::protobuf::Message for CreateViewParams { if !self.thumbnail.is_empty() { os.write_string(4, &self.thumbnail)?; } - if self.data_type != ViewDataType::RichText { + if self.data_type != ViewDataType::TextBlock { os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.data_type))?; } - if !self.ext_data.is_empty() { - os.write_string(6, &self.ext_data)?; - } if !self.view_id.is_empty() { - os.write_string(7, &self.view_id)?; + os.write_string(6, &self.view_id)?; } if !self.data.is_empty() { - os.write_string(8, &self.data)?; + os.write_bytes(7, &self.data)?; } if self.plugin_type != 0 { - os.write_int32(9, self.plugin_type)?; + os.write_int32(8, self.plugin_type)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) @@ -1635,17 +1599,12 @@ impl ::protobuf::Message for CreateViewParams { |m: &CreateViewParams| { &m.data_type }, |m: &mut CreateViewParams| { &mut m.data_type }, )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "ext_data", - |m: &CreateViewParams| { &m.ext_data }, - |m: &mut CreateViewParams| { &mut m.ext_data }, - )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "view_id", |m: &CreateViewParams| { &m.view_id }, |m: &mut CreateViewParams| { &mut m.view_id }, )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( "data", |m: &CreateViewParams| { &m.data }, |m: &mut CreateViewParams| { &mut m.data }, @@ -1675,8 +1634,7 @@ impl ::protobuf::Clear for CreateViewParams { self.name.clear(); self.desc.clear(); self.thumbnail.clear(); - self.data_type = ViewDataType::RichText; - self.ext_data.clear(); + self.data_type = ViewDataType::TextBlock; self.view_id.clear(); self.data.clear(); self.plugin_type = 0; @@ -2821,8 +2779,8 @@ impl ::protobuf::reflect::ProtobufValue for UpdateViewParams { #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum ViewDataType { - RichText = 0, - PlainText = 1, + TextBlock = 0, + Grid = 1, } impl ::protobuf::ProtobufEnum for ViewDataType { @@ -2832,16 +2790,16 @@ impl ::protobuf::ProtobufEnum for ViewDataType { fn from_i32(value: i32) -> ::std::option::Option { match value { - 0 => ::std::option::Option::Some(ViewDataType::RichText), - 1 => ::std::option::Option::Some(ViewDataType::PlainText), + 0 => ::std::option::Option::Some(ViewDataType::TextBlock), + 1 => ::std::option::Option::Some(ViewDataType::Grid), _ => ::std::option::Option::None } } fn values() -> &'static [Self] { static values: &'static [ViewDataType] = &[ - ViewDataType::RichText, - ViewDataType::PlainText, + ViewDataType::TextBlock, + ViewDataType::Grid, ]; values } @@ -2859,7 +2817,7 @@ impl ::std::marker::Copy for ViewDataType { impl ::std::default::Default for ViewDataType { fn default() -> Self { - ViewDataType::RichText + ViewDataType::TextBlock } } @@ -2880,33 +2838,32 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x18\t\x20\x01(\x03R\ncreateTime\x12\x19\n\x08ext_data\x18\n\x20\x01(\tR\ \x07extData\x12\x1c\n\tthumbnail\x18\x0b\x20\x01(\tR\tthumbnail\x12\x1f\ \n\x0bplugin_type\x18\x0c\x20\x01(\x05R\npluginType\"+\n\x0cRepeatedView\ - \x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.ViewR\x05items\"\xf9\x01\n\ + \x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.ViewR\x05items\"\xf2\x01\n\ \x11CreateViewPayload\x12\x20\n\x0cbelong_to_id\x18\x01\x20\x01(\tR\nbel\ ongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\ \x18\x03\x20\x01(\tR\x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\0R\ \tthumbnail\x12*\n\tdata_type\x18\x05\x20\x01(\x0e2\r.ViewDataTypeR\x08d\ - ataType\x12\x19\n\x08ext_data\x18\x06\x20\x01(\tR\x07extData\x12\x1f\n\ - \x0bplugin_type\x18\x07\x20\x01(\x05R\npluginTypeB\x12\n\x10one_of_thumb\ - nail\"\x8f\x02\n\x10CreateViewParams\x12\x20\n\x0cbelong_to_id\x18\x01\ - \x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\ - \x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x1c\n\tthumbnail\x18\ - \x04\x20\x01(\tR\tthumbnail\x12*\n\tdata_type\x18\x05\x20\x01(\x0e2\r.Vi\ - ewDataTypeR\x08dataType\x12\x19\n\x08ext_data\x18\x06\x20\x01(\tR\x07ext\ - Data\x12\x17\n\x07view_id\x18\x07\x20\x01(\tR\x06viewId\x12\x12\n\x04dat\ - a\x18\x08\x20\x01(\tR\x04data\x12\x1f\n\x0bplugin_type\x18\t\x20\x01(\ - \x05R\npluginType\"\x1e\n\x06ViewId\x12\x14\n\x05value\x18\x01\x20\x01(\ - \tR\x05value\"&\n\x0eRepeatedViewId\x12\x14\n\x05items\x18\x01\x20\x03(\ - \tR\x05items\"\xaa\x01\n\x11UpdateViewPayload\x12\x17\n\x07view_id\x18\ - \x01\x20\x01(\tR\x06viewId\x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\x04n\ - ame\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\x04desc\x12\x1e\n\tthumbn\ - ail\x18\x04\x20\x01(\tH\x02R\tthumbnailB\r\n\x0bone_of_nameB\r\n\x0bone_\ - of_descB\x12\n\x10one_of_thumbnail\"\xa9\x01\n\x10UpdateViewParams\x12\ - \x17\n\x07view_id\x18\x01\x20\x01(\tR\x06viewId\x12\x14\n\x04name\x18\ - \x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\ - \x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\x02R\tthumbnailB\r\n\ - \x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnail*+\n\x0cVi\ - ewDataType\x12\x0c\n\x08RichText\x10\0\x12\r\n\tPlainText\x10\x01b\x06pr\ - oto3\ + ataType\x12\x1f\n\x0bplugin_type\x18\x06\x20\x01(\x05R\npluginType\x12\ + \x12\n\x04data\x18\x07\x20\x01(\x0cR\x04dataB\x12\n\x10one_of_thumbnail\ + \"\xf4\x01\n\x10CreateViewParams\x12\x20\n\x0cbelong_to_id\x18\x01\x20\ + \x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\ + \x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x1c\n\tthumbnail\x18\x04\ + \x20\x01(\tR\tthumbnail\x12*\n\tdata_type\x18\x05\x20\x01(\x0e2\r.ViewDa\ + taTypeR\x08dataType\x12\x17\n\x07view_id\x18\x06\x20\x01(\tR\x06viewId\ + \x12\x12\n\x04data\x18\x07\x20\x01(\x0cR\x04data\x12\x1f\n\x0bplugin_typ\ + e\x18\x08\x20\x01(\x05R\npluginType\"\x1e\n\x06ViewId\x12\x14\n\x05value\ + \x18\x01\x20\x01(\tR\x05value\"&\n\x0eRepeatedViewId\x12\x14\n\x05items\ + \x18\x01\x20\x03(\tR\x05items\"\xaa\x01\n\x11UpdateViewPayload\x12\x17\n\ + \x07view_id\x18\x01\x20\x01(\tR\x06viewId\x12\x14\n\x04name\x18\x02\x20\ + \x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\x04desc\ + \x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\x02R\tthumbnailB\r\n\x0bone_of\ + _nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnail\"\xa9\x01\n\x10Upda\ + teViewParams\x12\x17\n\x07view_id\x18\x01\x20\x01(\tR\x06viewId\x12\x14\ + \n\x04name\x18\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\ + \x01(\tH\x01R\x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\x02R\tthu\ + mbnailB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnai\ + l*'\n\x0cViewDataType\x12\r\n\tTextBlock\x10\0\x12\x08\n\x04Grid\x10\x01\ + b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-folder-data-model/src/protobuf/proto/view.proto b/shared-lib/flowy-folder-data-model/src/protobuf/proto/view.proto index b938e004f4..56e09c54e4 100644 --- a/shared-lib/flowy-folder-data-model/src/protobuf/proto/view.proto +++ b/shared-lib/flowy-folder-data-model/src/protobuf/proto/view.proto @@ -23,8 +23,8 @@ message CreateViewPayload { string desc = 3; oneof one_of_thumbnail { string thumbnail = 4; }; ViewDataType data_type = 5; - string ext_data = 6; - int32 plugin_type = 7; + int32 plugin_type = 6; + bytes data = 7; } message CreateViewParams { string belong_to_id = 1; @@ -32,10 +32,9 @@ message CreateViewParams { string desc = 3; string thumbnail = 4; ViewDataType data_type = 5; - string ext_data = 6; - string view_id = 7; - string data = 8; - int32 plugin_type = 9; + string view_id = 6; + bytes data = 7; + int32 plugin_type = 8; } message ViewId { string value = 1; @@ -56,6 +55,6 @@ message UpdateViewParams { oneof one_of_thumbnail { string thumbnail = 4; }; } enum ViewDataType { - RichText = 0; - PlainText = 1; + TextBlock = 0; + Grid = 1; } diff --git a/shared-lib/flowy-folder-data-model/src/user_default.rs b/shared-lib/flowy-folder-data-model/src/user_default.rs index b664557f2b..ed56d2d80a 100644 --- a/shared-lib/flowy-folder-data-model/src/user_default.rs +++ b/shared-lib/flowy-folder-data-model/src/user_default.rs @@ -1,3 +1,6 @@ +use crate::entities::app::gen_app_id; +use crate::entities::view::gen_view_id; +use crate::entities::workspace::gen_workspace_id; use crate::entities::{ app::{App, RepeatedApp}, view::{RepeatedView, View, ViewDataType}, @@ -5,8 +8,9 @@ use crate::entities::{ }; use chrono::Utc; -pub fn create_default_workspace(time: chrono::DateTime) -> Workspace { - let workspace_id = uuid::Uuid::new_v4(); +pub fn create_default_workspace() -> Workspace { + let time = Utc::now(); + let workspace_id = gen_workspace_id(); let name = "Workspace".to_string(); let desc = "".to_string(); @@ -15,7 +19,7 @@ pub fn create_default_workspace(time: chrono::DateTime) -> Workspace { }; Workspace { - id: workspace_id.to_string(), + id: workspace_id, name, desc, apps, @@ -25,7 +29,7 @@ pub fn create_default_workspace(time: chrono::DateTime) -> Workspace { } fn create_default_app(workspace_id: String, time: chrono::DateTime) -> App { - let app_id = uuid::Uuid::new_v4(); + let app_id = gen_app_id(); let name = "⭐️ Getting started".to_string(); let desc = "".to_string(); @@ -34,7 +38,7 @@ fn create_default_app(workspace_id: String, time: chrono::DateTime) -> App }; App { - id: app_id.to_string(), + id: app_id, workspace_id, name, desc, @@ -46,13 +50,13 @@ fn create_default_app(workspace_id: String, time: chrono::DateTime) -> App } fn create_default_view(app_id: String, time: chrono::DateTime) -> View { - let view_id = uuid::Uuid::new_v4(); + let view_id = gen_view_id(); let name = "Read me".to_string(); let desc = "".to_string(); - let data_type = ViewDataType::RichText; + let data_type = ViewDataType::TextBlock; View { - id: view_id.to_string(), + id: view_id, belong_to_id: app_id, name, desc, diff --git a/shared-lib/flowy-grid-data-model/Cargo.toml b/shared-lib/flowy-grid-data-model/Cargo.toml new file mode 100644 index 0000000000..7998b6123d --- /dev/null +++ b/shared-lib/flowy-grid-data-model/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "flowy-grid-data-model" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +flowy-derive = { path = "../flowy-derive" } +protobuf = {version = "2.18.0"} +bytes = "1.0" +strum = "0.21" +strum_macros = "0.21" +serde = { version = "1.0", features = ["derive"] } +serde_json = {version = "1.0"} +serde_repr = "0.1" +nanoid = "0.4.0" +flowy-error-code = { path = "../flowy-error-code"} +indexmap = {version = "1.8.1", features = ["serde"]} +[build-dependencies] +lib-infra = { path = "../lib-infra", features = ["protobuf_file_gen"] } + +[features] +default = [] +backend = [] +frontend = [] +dart = ["lib-infra/dart"] \ No newline at end of file diff --git a/shared-lib/flowy-grid-data-model/Flowy.toml b/shared-lib/flowy-grid-data-model/Flowy.toml new file mode 100644 index 0000000000..dcac35f40a --- /dev/null +++ b/shared-lib/flowy-grid-data-model/Flowy.toml @@ -0,0 +1,3 @@ + +proto_crates = ["src/entities/grid.rs",] +event_files = [] \ No newline at end of file diff --git a/shared-lib/flowy-collaboration/build.rs b/shared-lib/flowy-grid-data-model/build.rs similarity index 100% rename from shared-lib/flowy-collaboration/build.rs rename to shared-lib/flowy-grid-data-model/build.rs diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs new file mode 100644 index 0000000000..d246fd490b --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -0,0 +1,866 @@ +use crate::entities::{CellMeta, FieldMeta, RowMeta, RowMetaChangeset}; +use crate::parser::NotEmptyStr; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error_code::ErrorCode; + +use serde_repr::*; +use std::collections::HashMap; +use std::sync::Arc; +use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct Grid { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub field_orders: Vec, + + #[pb(index = 3)] + pub block_orders: Vec, +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct Field { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub name: String, + + #[pb(index = 3)] + pub desc: String, + + #[pb(index = 4)] + pub field_type: FieldType, + + #[pb(index = 5)] + pub frozen: bool, + + #[pb(index = 6)] + pub visibility: bool, + + #[pb(index = 7)] + pub width: i32, + + #[pb(index = 8)] + pub is_primary: bool, +} + +impl std::convert::From for Field { + fn from(field_meta: FieldMeta) -> Self { + Self { + id: field_meta.id, + name: field_meta.name, + desc: field_meta.desc, + field_type: field_meta.field_type, + frozen: field_meta.frozen, + visibility: field_meta.visibility, + width: field_meta.width, + is_primary: field_meta.is_primary, + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldOrder { + #[pb(index = 1)] + pub field_id: String, +} + +impl std::convert::From<&FieldMeta> for FieldOrder { + fn from(field_meta: &FieldMeta) -> Self { + Self { + field_id: field_meta.id.clone(), + } + } +} + +impl std::convert::From<&str> for FieldOrder { + fn from(s: &str) -> Self { + FieldOrder { field_id: s.to_owned() } + } +} + +impl std::convert::From for FieldOrder { + fn from(s: String) -> Self { + FieldOrder { field_id: s } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct GridFieldChangeset { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub inserted_fields: Vec, + + #[pb(index = 3)] + pub deleted_fields: Vec, + + #[pb(index = 4)] + pub updated_fields: Vec, +} + +impl GridFieldChangeset { + pub fn insert(grid_id: &str, inserted_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_owned(), + inserted_fields, + deleted_fields: vec![], + updated_fields: vec![], + } + } + + pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_string(), + inserted_fields: vec![], + deleted_fields, + updated_fields: vec![], + } + } + + pub fn update(grid_id: &str, updated_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_string(), + inserted_fields: vec![], + deleted_fields: vec![], + updated_fields, + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct IndexField { + #[pb(index = 1)] + pub field: Field, + + #[pb(index = 2)] + pub index: i32, +} + +impl IndexField { + pub fn from_field_meta(field_meta: &FieldMeta, index: usize) -> Self { + Self { + field: Field::from(field_meta.clone()), + index: index as i32, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct GetEditFieldContextPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2, one_of)] + pub field_id: Option, + + #[pb(index = 3)] + pub field_type: FieldType, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct EditFieldPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub field_type: FieldType, +} + +pub struct EditFieldParams { + pub grid_id: String, + pub field_id: String, + pub field_type: FieldType, +} + +impl TryInto for EditFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(EditFieldParams { + grid_id: grid_id.0, + field_id: field_id.0, + field_type: self.field_type, + }) + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct EditFieldContext { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub grid_field: Field, + + #[pb(index = 3)] + pub type_option_data: Vec, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedField { + #[pb(index = 1)] + pub items: Vec, +} +impl std::ops::Deref for RepeatedField { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::ops::DerefMut for RepeatedField { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +impl std::convert::From> for RepeatedField { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct RepeatedFieldOrder { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::ops::Deref for RepeatedFieldOrder { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::convert::From> for RepeatedFieldOrder { + fn from(field_orders: Vec) -> Self { + RepeatedFieldOrder { items: field_orders } + } +} + +impl std::convert::From for RepeatedFieldOrder { + fn from(s: String) -> Self { + RepeatedFieldOrder { + items: vec![FieldOrder::from(s)], + } + } +} + +#[derive(Debug, Default, Clone, ProtoBuf)] +pub struct RowOrder { + #[pb(index = 1)] + pub row_id: String, + + #[pb(index = 2)] + pub block_id: String, + + #[pb(index = 3)] + pub height: i32, +} + +impl std::convert::From<&RowMeta> for RowOrder { + fn from(row: &RowMeta) -> Self { + Self { + row_id: row.id.clone(), + block_id: row.block_id.clone(), + height: row.height, + } + } +} + +impl std::convert::From<&Arc> for RowOrder { + fn from(row: &Arc) -> Self { + Self { + row_id: row.id.clone(), + block_id: row.block_id.clone(), + height: row.height, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct Row { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub cell_by_field_id: HashMap, + + #[pb(index = 3)] + pub height: i32, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedRow { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::convert::From> for RepeatedRow { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedGridBlock { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::convert::From> for RepeatedGridBlock { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct GridBlockOrder { + #[pb(index = 1)] + pub block_id: String, + + #[pb(index = 2)] + pub row_orders: Vec, +} + +impl GridBlockOrder { + pub fn new(block_id: &str) -> Self { + GridBlockOrder { + block_id: block_id.to_owned(), + row_orders: vec![], + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct IndexRowOrder { + #[pb(index = 1)] + pub row_order: RowOrder, + + #[pb(index = 2, one_of)] + pub index: Option, +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct GridRowsChangeset { + #[pb(index = 1)] + pub block_id: String, + + #[pb(index = 2)] + pub inserted_rows: Vec, + + #[pb(index = 3)] + pub deleted_rows: Vec, + + #[pb(index = 4)] + pub updated_rows: Vec, +} + +impl std::convert::From for IndexRowOrder { + fn from(row_order: RowOrder) -> Self { + Self { row_order, index: None } + } +} + +impl std::convert::From<&RowMeta> for IndexRowOrder { + fn from(row: &RowMeta) -> Self { + let row_order = RowOrder::from(row); + Self::from(row_order) + } +} + +impl GridRowsChangeset { + pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { + Self { + block_id: block_id.to_owned(), + inserted_rows, + deleted_rows: vec![], + updated_rows: vec![], + } + } + + pub fn delete(block_id: &str, deleted_rows: Vec) -> Self { + Self { + block_id: block_id.to_owned(), + inserted_rows: vec![], + deleted_rows, + updated_rows: vec![], + } + } + + pub fn update(block_id: &str, updated_rows: Vec) -> Self { + Self { + block_id: block_id.to_owned(), + inserted_rows: vec![], + deleted_rows: vec![], + updated_rows, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct GridBlock { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub row_orders: Vec, +} + +impl GridBlock { + pub fn new(block_id: &str, row_orders: Vec) -> Self { + Self { + id: block_id.to_owned(), + row_orders, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct Cell { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub content: String, +} + +impl Cell { + pub fn new(field_id: &str, content: String) -> Self { + Self { + field_id: field_id.to_owned(), + content, + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct CellNotificationData { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub row_id: String, + + #[pb(index = 4, one_of)] + pub content: Option, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedCell { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::ops::Deref for RepeatedCell { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::ops::DerefMut for RepeatedCell { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +impl std::convert::From> for RepeatedCell { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(ProtoBuf, Default)] +pub struct CreateGridPayload { + #[pb(index = 1)] + pub name: String, +} + +#[derive(Clone, ProtoBuf, Default, Debug)] +pub struct GridId { + #[pb(index = 1)] + pub value: String, +} + +impl AsRef for GridId { + fn as_ref(&self) -> &str { + &self.value + } +} + +#[derive(Clone, ProtoBuf, Default, Debug)] +pub struct GridBlockId { + #[pb(index = 1)] + pub value: String, +} + +impl AsRef for GridBlockId { + fn as_ref(&self) -> &str { + &self.value + } +} + +impl std::convert::From<&str> for GridBlockId { + fn from(s: &str) -> Self { + GridBlockId { value: s.to_owned() } + } +} + +#[derive(ProtoBuf, Default)] +pub struct CreateRowPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2, one_of)] + pub start_row_id: Option, +} + +#[derive(Default)] +pub struct CreateRowParams { + pub grid_id: String, + pub start_row_id: Option, +} + +impl TryInto for CreateRowPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + Ok(CreateRowParams { + grid_id: grid_id.0, + start_row_id: self.start_row_id, + }) + } +} + +#[derive(ProtoBuf, Default)] +pub struct InsertFieldPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field: Field, + + #[pb(index = 3)] + pub type_option_data: Vec, + + #[pb(index = 4, one_of)] + pub start_field_id: Option, +} + +#[derive(Clone)] +pub struct InsertFieldParams { + pub grid_id: String, + pub field: Field, + pub type_option_data: Vec, + pub start_field_id: Option, +} + +impl TryInto for InsertFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + + let start_field_id = match self.start_field_id { + None => None, + Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0), + }; + + Ok(InsertFieldParams { + grid_id: grid_id.0, + field: self.field, + type_option_data: self.type_option_data, + start_field_id, + }) + } +} + +#[derive(ProtoBuf, Default)] +pub struct QueryFieldPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_orders: RepeatedFieldOrder, +} + +pub struct QueryFieldParams { + pub grid_id: String, + pub field_orders: RepeatedFieldOrder, +} + +impl TryInto for QueryFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + Ok(QueryFieldParams { + grid_id: grid_id.0, + field_orders: self.field_orders, + }) + } +} + +#[derive(ProtoBuf, Default)] +pub struct QueryGridBlocksPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub block_orders: Vec, +} + +pub struct QueryGridBlocksParams { + pub grid_id: String, + pub block_orders: Vec, +} + +impl TryInto for QueryGridBlocksPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + Ok(QueryGridBlocksParams { + grid_id: grid_id.0, + block_orders: self.block_orders, + }) + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldChangesetPayload { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, + + #[pb(index = 3, one_of)] + pub name: Option, + + #[pb(index = 4, one_of)] + pub desc: Option, + + #[pb(index = 5, one_of)] + pub field_type: Option, + + #[pb(index = 6, one_of)] + pub frozen: Option, + + #[pb(index = 7, one_of)] + pub visibility: Option, + + #[pb(index = 8, one_of)] + pub width: Option, + + #[pb(index = 9, one_of)] + pub type_option_data: Option>, +} + +#[derive(Debug, Clone, Default)] +pub struct FieldChangesetParams { + pub field_id: String, + + pub grid_id: String, + + pub name: Option, + + pub desc: Option, + + pub field_type: Option, + + pub frozen: Option, + + pub visibility: Option, + + pub width: Option, + + pub type_option_data: Option>, +} + +impl TryInto for FieldChangesetPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + + if let Some(type_option_data) = self.type_option_data.as_ref() { + if type_option_data.is_empty() { + return Err(ErrorCode::TypeOptionDataIsEmpty); + } + } + + Ok(FieldChangesetParams { + field_id: field_id.0, + grid_id: grid_id.0, + name: self.name, + desc: self.desc, + field_type: self.field_type, + frozen: self.frozen, + visibility: self.visibility, + width: self.width, + type_option_data: self.type_option_data, + }) + } +} + +#[derive(Debug, Clone, ProtoBuf_Enum)] +pub enum MoveItemType { + MoveField = 0, + MoveRow = 1, +} + +impl std::default::Default for MoveItemType { + fn default() -> Self { + MoveItemType::MoveField + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct MoveItemPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub item_id: String, + + #[pb(index = 3)] + pub from_index: i32, + + #[pb(index = 4)] + pub to_index: i32, + + #[pb(index = 5)] + pub ty: MoveItemType, +} + +#[derive(Clone)] +pub struct MoveItemParams { + pub grid_id: String, + pub item_id: String, + pub from_index: i32, + pub to_index: i32, + pub ty: MoveItemType, +} + +impl TryInto for MoveItemPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let item_id = NotEmptyStr::parse(self.item_id).map_err(|_| ErrorCode::InvalidData)?; + Ok(MoveItemParams { + grid_id: grid_id.0, + item_id: item_id.0, + from_index: self.from_index, + to_index: self.to_index, + ty: self.ty, + }) + } +} + +#[derive( + Debug, + Clone, + PartialEq, + Eq, + ProtoBuf_Enum, + EnumCountMacro, + EnumString, + EnumIter, + Display, + Serialize_repr, + Deserialize_repr, +)] +#[repr(u8)] +pub enum FieldType { + RichText = 0, + Number = 1, + DateTime = 2, + SingleSelect = 3, + MultiSelect = 4, + Checkbox = 5, +} + +impl std::default::Default for FieldType { + fn default() -> Self { + FieldType::RichText + } +} + +impl AsRef for FieldType { + fn as_ref(&self) -> &FieldType { + self + } +} + +impl From<&FieldType> for FieldType { + fn from(field_type: &FieldType) -> Self { + field_type.clone() + } +} + +impl FieldType { + pub fn type_id(&self) -> String { + let ty = self.clone(); + format!("{}", ty as u8) + } + + pub fn default_cell_width(&self) -> i32 { + match self { + FieldType::DateTime => 180, + _ => 150, + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct CellChangeset { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub row_id: String, + + #[pb(index = 3)] + pub field_id: String, + + #[pb(index = 4, one_of)] + pub data: Option, +} + +impl std::convert::From for RowMetaChangeset { + fn from(changeset: CellChangeset) -> Self { + let mut cell_by_field_id = HashMap::with_capacity(1); + let field_id = changeset.field_id; + let cell_meta = CellMeta { + data: changeset.data.unwrap_or_else(|| "".to_owned()), + }; + cell_by_field_id.insert(field_id, cell_meta); + + RowMetaChangeset { + row_id: changeset.row_id, + height: None, + visibility: None, + cell_by_field_id, + } + } +} diff --git a/shared-lib/flowy-grid-data-model/src/entities/meta.rs b/shared-lib/flowy-grid-data-model/src/entities/meta.rs new file mode 100644 index 0000000000..d5570a58e5 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/entities/meta.rs @@ -0,0 +1,245 @@ +use crate::entities::FieldType; +use bytes::Bytes; +use indexmap::IndexMap; +use nanoid::nanoid; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +pub const DEFAULT_ROW_HEIGHT: i32 = 42; + +pub fn gen_grid_id() -> String { + // nanoid calculator https://zelark.github.io/nano-id-cc/ + nanoid!(10) +} + +pub fn gen_block_id() -> String { + nanoid!(10) +} + +pub fn gen_row_id() -> String { + nanoid!(6) +} + +pub fn gen_field_id() -> String { + nanoid!(6) +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct GridMeta { + pub grid_id: String, + pub fields: Vec, + pub blocks: Vec, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct GridBlockMeta { + pub block_id: String, + pub start_row_index: i32, + pub row_count: i32, +} + +impl GridBlockMeta { + pub fn len(&self) -> i32 { + self.row_count + } + + pub fn is_empty(&self) -> bool { + self.row_count == 0 + } +} + +impl GridBlockMeta { + pub fn new() -> Self { + GridBlockMeta { + block_id: gen_block_id(), + ..Default::default() + } + } +} + +pub struct GridBlockMetaChangeset { + pub block_id: String, + pub start_row_index: Option, + pub row_count: Option, +} + +impl GridBlockMetaChangeset { + pub fn from_row_count(block_id: &str, row_count: i32) -> Self { + Self { + block_id: block_id.to_string(), + start_row_index: None, + row_count: Some(row_count), + } + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct GridBlockMetaData { + pub block_id: String, + pub rows: Vec, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, Eq, PartialEq)] +pub struct FieldMeta { + pub id: String, + + pub name: String, + + pub desc: String, + + pub field_type: FieldType, + + pub frozen: bool, + + pub visibility: bool, + + pub width: i32, + + // #[pb(index = 8)] + /// type_options contains key/value pairs + /// key: id of the FieldType + /// value: type option data that can be parsed into specified TypeOptionStruct. + /// For example, CheckboxTypeOption, MultiSelectTypeOption etc. + #[serde(with = "indexmap::serde_seq")] + pub type_options: IndexMap, + + #[serde(default = "default_is_primary")] + pub is_primary: bool, +} + +fn default_is_primary() -> bool { + false +} + +impl FieldMeta { + pub fn new(name: &str, desc: &str, field_type: FieldType, is_primary: bool) -> Self { + let width = field_type.default_cell_width(); + Self { + id: gen_field_id(), + name: name.to_string(), + desc: desc.to_string(), + field_type, + frozen: false, + visibility: true, + width, + type_options: Default::default(), + is_primary, + } + } + + pub fn insert_type_option_entry(&mut self, entry: &T) + where + T: TypeOptionDataEntry + ?Sized, + { + self.type_options.insert(entry.field_type().type_id(), entry.json_str()); + } + + pub fn get_type_option_entry(&self, field_type: &FieldType) -> Option { + self.type_options + .get(&field_type.type_id()) + .map(|s| T::from_json_str(s)) + } + + pub fn insert_type_option_str(&mut self, field_type: &FieldType, json_str: String) { + self.type_options.insert(field_type.type_id(), json_str); + } + + pub fn get_type_option_str(&self, field_type: Option) -> Option { + let field_type = field_type.as_ref().unwrap_or(&self.field_type); + self.type_options.get(&field_type.type_id()).map(|s| s.to_owned()) + } +} + +pub trait TypeOptionDataEntry { + fn field_type(&self) -> FieldType; + fn json_str(&self) -> String; + fn protobuf_bytes(&self) -> Bytes; +} + +pub trait TypeOptionDataDeserializer { + fn from_json_str(s: &str) -> Self; + fn from_protobuf_bytes(bytes: Bytes) -> Self; +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct RowMeta { + pub id: String, + pub block_id: String, + /// cells contains key/value pairs. + /// key: field id, + /// value: CellMeta + #[serde(with = "indexmap::serde_seq")] + pub cells: IndexMap, + pub height: i32, + pub visibility: bool, +} + +impl RowMeta { + pub fn new(block_id: &str) -> Self { + Self { + id: gen_row_id(), + block_id: block_id.to_owned(), + cells: Default::default(), + height: DEFAULT_ROW_HEIGHT, + visibility: true, + } + } +} + +#[derive(Debug, Clone, Default)] +pub struct RowMetaChangeset { + pub row_id: String, + pub height: Option, + pub visibility: Option, + pub cell_by_field_id: HashMap, +} + +#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] +pub struct CellMeta { + pub data: String, +} + +impl CellMeta { + pub fn new(data: String) -> Self { + Self { data } + } +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct BuildGridContext { + pub field_metas: Vec, + pub block_meta: GridBlockMeta, + pub block_meta_data: GridBlockMetaData, +} + +impl std::convert::From for Bytes { + fn from(ctx: BuildGridContext) -> Self { + let bytes = serde_json::to_vec(&ctx).unwrap_or_else(|_| vec![]); + Bytes::from(bytes) + } +} + +impl std::convert::TryFrom for BuildGridContext { + type Error = serde_json::Error; + + fn try_from(bytes: Bytes) -> Result { + let ctx: BuildGridContext = serde_json::from_slice(&bytes)?; + Ok(ctx) + } +} + +impl std::default::Default for BuildGridContext { + fn default() -> Self { + let block_meta = GridBlockMeta::new(); + let block_meta_data = GridBlockMetaData { + block_id: block_meta.block_id.clone(), + rows: vec![], + }; + + Self { + field_metas: vec![], + block_meta, + block_meta_data, + } + } +} diff --git a/shared-lib/flowy-grid-data-model/src/entities/mod.rs b/shared-lib/flowy-grid-data-model/src/entities/mod.rs new file mode 100644 index 0000000000..350f8092d5 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/entities/mod.rs @@ -0,0 +1,5 @@ +mod grid; +mod meta; + +pub use grid::*; +pub use meta::*; diff --git a/shared-lib/flowy-grid-data-model/src/lib.rs b/shared-lib/flowy-grid-data-model/src/lib.rs new file mode 100644 index 0000000000..bd9ed4465e --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/lib.rs @@ -0,0 +1,3 @@ +pub mod entities; +pub mod parser; +pub mod protobuf; diff --git a/shared-lib/flowy-grid-data-model/src/parser/mod.rs b/shared-lib/flowy-grid-data-model/src/parser/mod.rs new file mode 100644 index 0000000000..3c43c76f39 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/parser/mod.rs @@ -0,0 +1,3 @@ +mod str_parser; + +pub use str_parser::*; diff --git a/shared-lib/flowy-grid-data-model/src/parser/str_parser.rs b/shared-lib/flowy-grid-data-model/src/parser/str_parser.rs new file mode 100644 index 0000000000..175ff3fd49 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/parser/str_parser.rs @@ -0,0 +1,17 @@ +#[derive(Debug)] +pub struct NotEmptyStr(pub String); + +impl NotEmptyStr { + pub fn parse(s: String) -> Result { + if s.trim().is_empty() { + return Err("Input string is empty".to_owned()); + } + Ok(Self(s)) + } +} + +impl AsRef for NotEmptyStr { + fn as_ref(&self) -> &str { + &self.0 + } +} diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/mod.rs b/shared-lib/flowy-grid-data-model/src/protobuf/mod.rs new file mode 100644 index 0000000000..da97aad28a --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/protobuf/mod.rs @@ -0,0 +1,4 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +// Auto-generated, do not edit +mod model; +pub use model::*; \ No newline at end of file diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs new file mode 100644 index 0000000000..754fc11386 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -0,0 +1,7908 @@ +// This file is generated by rust-protobuf 2.25.2. Do not edit +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_imports)] +#![allow(unused_results)] +//! Generated file from `grid.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; + +#[derive(PartialEq,Clone,Default)] +pub struct Grid { + // message fields + pub id: ::std::string::String, + pub field_orders: ::protobuf::RepeatedField, + pub block_orders: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Grid { + fn default() -> &'a Grid { + ::default_instance() + } +} + +impl Grid { + pub fn new() -> Grid { + ::std::default::Default::default() + } + + // string id = 1; + + + pub fn get_id(&self) -> &str { + &self.id + } + pub fn clear_id(&mut self) { + self.id.clear(); + } + + // Param is passed by value, moved + pub fn set_id(&mut self, v: ::std::string::String) { + self.id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_id(&mut self) -> &mut ::std::string::String { + &mut self.id + } + + // Take field + pub fn take_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.id, ::std::string::String::new()) + } + + // repeated .FieldOrder field_orders = 2; + + + pub fn get_field_orders(&self) -> &[FieldOrder] { + &self.field_orders + } + pub fn clear_field_orders(&mut self) { + self.field_orders.clear(); + } + + // Param is passed by value, moved + pub fn set_field_orders(&mut self, v: ::protobuf::RepeatedField) { + self.field_orders = v; + } + + // Mutable pointer to the field. + pub fn mut_field_orders(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.field_orders + } + + // Take field + pub fn take_field_orders(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.field_orders, ::protobuf::RepeatedField::new()) + } + + // repeated .GridBlockOrder block_orders = 3; + + + pub fn get_block_orders(&self) -> &[GridBlockOrder] { + &self.block_orders + } + pub fn clear_block_orders(&mut self) { + self.block_orders.clear(); + } + + // Param is passed by value, moved + pub fn set_block_orders(&mut self, v: ::protobuf::RepeatedField) { + self.block_orders = v; + } + + // Mutable pointer to the field. + pub fn mut_block_orders(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.block_orders + } + + // Take field + pub fn take_block_orders(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.block_orders, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for Grid { + fn is_initialized(&self) -> bool { + for v in &self.field_orders { + if !v.is_initialized() { + return false; + } + }; + for v in &self.block_orders { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.field_orders)?; + }, + 3 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.block_orders)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.id); + } + for value in &self.field_orders { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.block_orders { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.id.is_empty() { + os.write_string(1, &self.id)?; + } + for v in &self.field_orders { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.block_orders { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Grid { + Grid::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "id", + |m: &Grid| { &m.id }, + |m: &mut Grid| { &mut m.id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "field_orders", + |m: &Grid| { &m.field_orders }, + |m: &mut Grid| { &mut m.field_orders }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "block_orders", + |m: &Grid| { &m.block_orders }, + |m: &mut Grid| { &mut m.block_orders }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Grid", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Grid { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Grid::new) + } +} + +impl ::protobuf::Clear for Grid { + fn clear(&mut self) { + self.id.clear(); + self.field_orders.clear(); + self.block_orders.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Grid { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Grid { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Field { + // message fields + pub id: ::std::string::String, + pub name: ::std::string::String, + pub desc: ::std::string::String, + pub field_type: FieldType, + pub frozen: bool, + pub visibility: bool, + pub width: i32, + pub is_primary: bool, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Field { + fn default() -> &'a Field { + ::default_instance() + } +} + +impl Field { + pub fn new() -> Field { + ::std::default::Default::default() + } + + // string id = 1; + + + pub fn get_id(&self) -> &str { + &self.id + } + pub fn clear_id(&mut self) { + self.id.clear(); + } + + // Param is passed by value, moved + pub fn set_id(&mut self, v: ::std::string::String) { + self.id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_id(&mut self) -> &mut ::std::string::String { + &mut self.id + } + + // Take field + pub fn take_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.id, ::std::string::String::new()) + } + + // string name = 2; + + + pub fn get_name(&self) -> &str { + &self.name + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + &mut self.name + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.name, ::std::string::String::new()) + } + + // string desc = 3; + + + pub fn get_desc(&self) -> &str { + &self.desc + } + pub fn clear_desc(&mut self) { + self.desc.clear(); + } + + // Param is passed by value, moved + pub fn set_desc(&mut self, v: ::std::string::String) { + self.desc = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_desc(&mut self) -> &mut ::std::string::String { + &mut self.desc + } + + // Take field + pub fn take_desc(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.desc, ::std::string::String::new()) + } + + // .FieldType field_type = 4; + + + pub fn get_field_type(&self) -> FieldType { + self.field_type + } + pub fn clear_field_type(&mut self) { + self.field_type = FieldType::RichText; + } + + // Param is passed by value, moved + pub fn set_field_type(&mut self, v: FieldType) { + self.field_type = v; + } + + // bool frozen = 5; + + + pub fn get_frozen(&self) -> bool { + self.frozen + } + pub fn clear_frozen(&mut self) { + self.frozen = false; + } + + // Param is passed by value, moved + pub fn set_frozen(&mut self, v: bool) { + self.frozen = v; + } + + // bool visibility = 6; + + + pub fn get_visibility(&self) -> bool { + self.visibility + } + pub fn clear_visibility(&mut self) { + self.visibility = false; + } + + // Param is passed by value, moved + pub fn set_visibility(&mut self, v: bool) { + self.visibility = v; + } + + // int32 width = 7; + + + pub fn get_width(&self) -> i32 { + self.width + } + pub fn clear_width(&mut self) { + self.width = 0; + } + + // Param is passed by value, moved + pub fn set_width(&mut self, v: i32) { + self.width = v; + } + + // bool is_primary = 8; + + + pub fn get_is_primary(&self) -> bool { + self.is_primary + } + pub fn clear_is_primary(&mut self) { + self.is_primary = false; + } + + // Param is passed by value, moved + pub fn set_is_primary(&mut self, v: bool) { + self.is_primary = v; + } +} + +impl ::protobuf::Message for Field { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.desc)?; + }, + 4 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 4, &mut self.unknown_fields)? + }, + 5 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.frozen = tmp; + }, + 6 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.visibility = tmp; + }, + 7 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.width = tmp; + }, + 8 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.is_primary = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.id); + } + if !self.name.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.name); + } + if !self.desc.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.desc); + } + if self.field_type != FieldType::RichText { + my_size += ::protobuf::rt::enum_size(4, self.field_type); + } + if self.frozen != false { + my_size += 2; + } + if self.visibility != false { + my_size += 2; + } + if self.width != 0 { + my_size += ::protobuf::rt::value_size(7, self.width, ::protobuf::wire_format::WireTypeVarint); + } + if self.is_primary != false { + my_size += 2; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.id.is_empty() { + os.write_string(1, &self.id)?; + } + if !self.name.is_empty() { + os.write_string(2, &self.name)?; + } + if !self.desc.is_empty() { + os.write_string(3, &self.desc)?; + } + if self.field_type != FieldType::RichText { + os.write_enum(4, ::protobuf::ProtobufEnum::value(&self.field_type))?; + } + if self.frozen != false { + os.write_bool(5, self.frozen)?; + } + if self.visibility != false { + os.write_bool(6, self.visibility)?; + } + if self.width != 0 { + os.write_int32(7, self.width)?; + } + if self.is_primary != false { + os.write_bool(8, self.is_primary)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Field { + Field::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "id", + |m: &Field| { &m.id }, + |m: &mut Field| { &mut m.id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &Field| { &m.name }, + |m: &mut Field| { &mut m.name }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "desc", + |m: &Field| { &m.desc }, + |m: &mut Field| { &mut m.desc }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "field_type", + |m: &Field| { &m.field_type }, + |m: &mut Field| { &mut m.field_type }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "frozen", + |m: &Field| { &m.frozen }, + |m: &mut Field| { &mut m.frozen }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "visibility", + |m: &Field| { &m.visibility }, + |m: &mut Field| { &mut m.visibility }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "width", + |m: &Field| { &m.width }, + |m: &mut Field| { &mut m.width }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "is_primary", + |m: &Field| { &m.is_primary }, + |m: &mut Field| { &mut m.is_primary }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Field", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Field { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Field::new) + } +} + +impl ::protobuf::Clear for Field { + fn clear(&mut self) { + self.id.clear(); + self.name.clear(); + self.desc.clear(); + self.field_type = FieldType::RichText; + self.frozen = false; + self.visibility = false; + self.width = 0; + self.is_primary = false; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Field { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Field { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct FieldOrder { + // message fields + pub field_id: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a FieldOrder { + fn default() -> &'a FieldOrder { + ::default_instance() + } +} + +impl FieldOrder { + pub fn new() -> FieldOrder { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for FieldOrder { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> FieldOrder { + FieldOrder::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &FieldOrder| { &m.field_id }, + |m: &mut FieldOrder| { &mut m.field_id }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "FieldOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static FieldOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(FieldOrder::new) + } +} + +impl ::protobuf::Clear for FieldOrder { + fn clear(&mut self) { + self.field_id.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for FieldOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GridFieldChangeset { + // message fields + pub grid_id: ::std::string::String, + pub inserted_fields: ::protobuf::RepeatedField, + pub deleted_fields: ::protobuf::RepeatedField, + pub updated_fields: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridFieldChangeset { + fn default() -> &'a GridFieldChangeset { + ::default_instance() + } +} + +impl GridFieldChangeset { + pub fn new() -> GridFieldChangeset { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // repeated .IndexField inserted_fields = 2; + + + pub fn get_inserted_fields(&self) -> &[IndexField] { + &self.inserted_fields + } + pub fn clear_inserted_fields(&mut self) { + self.inserted_fields.clear(); + } + + // Param is passed by value, moved + pub fn set_inserted_fields(&mut self, v: ::protobuf::RepeatedField) { + self.inserted_fields = v; + } + + // Mutable pointer to the field. + pub fn mut_inserted_fields(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.inserted_fields + } + + // Take field + pub fn take_inserted_fields(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.inserted_fields, ::protobuf::RepeatedField::new()) + } + + // repeated .FieldOrder deleted_fields = 3; + + + pub fn get_deleted_fields(&self) -> &[FieldOrder] { + &self.deleted_fields + } + pub fn clear_deleted_fields(&mut self) { + self.deleted_fields.clear(); + } + + // Param is passed by value, moved + pub fn set_deleted_fields(&mut self, v: ::protobuf::RepeatedField) { + self.deleted_fields = v; + } + + // Mutable pointer to the field. + pub fn mut_deleted_fields(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.deleted_fields + } + + // Take field + pub fn take_deleted_fields(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.deleted_fields, ::protobuf::RepeatedField::new()) + } + + // repeated .Field updated_fields = 4; + + + pub fn get_updated_fields(&self) -> &[Field] { + &self.updated_fields + } + pub fn clear_updated_fields(&mut self) { + self.updated_fields.clear(); + } + + // Param is passed by value, moved + pub fn set_updated_fields(&mut self, v: ::protobuf::RepeatedField) { + self.updated_fields = v; + } + + // Mutable pointer to the field. + pub fn mut_updated_fields(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.updated_fields + } + + // Take field + pub fn take_updated_fields(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.updated_fields, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for GridFieldChangeset { + fn is_initialized(&self) -> bool { + for v in &self.inserted_fields { + if !v.is_initialized() { + return false; + } + }; + for v in &self.deleted_fields { + if !v.is_initialized() { + return false; + } + }; + for v in &self.updated_fields { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.inserted_fields)?; + }, + 3 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.deleted_fields)?; + }, + 4 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.updated_fields)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + for value in &self.inserted_fields { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.deleted_fields { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.updated_fields { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + for v in &self.inserted_fields { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.deleted_fields { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.updated_fields { + os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GridFieldChangeset { + GridFieldChangeset::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &GridFieldChangeset| { &m.grid_id }, + |m: &mut GridFieldChangeset| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "inserted_fields", + |m: &GridFieldChangeset| { &m.inserted_fields }, + |m: &mut GridFieldChangeset| { &mut m.inserted_fields }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "deleted_fields", + |m: &GridFieldChangeset| { &m.deleted_fields }, + |m: &mut GridFieldChangeset| { &mut m.deleted_fields }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "updated_fields", + |m: &GridFieldChangeset| { &m.updated_fields }, + |m: &mut GridFieldChangeset| { &mut m.updated_fields }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridFieldChangeset", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridFieldChangeset { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridFieldChangeset::new) + } +} + +impl ::protobuf::Clear for GridFieldChangeset { + fn clear(&mut self) { + self.grid_id.clear(); + self.inserted_fields.clear(); + self.deleted_fields.clear(); + self.updated_fields.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridFieldChangeset { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridFieldChangeset { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct IndexField { + // message fields + pub field: ::protobuf::SingularPtrField, + pub index: i32, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a IndexField { + fn default() -> &'a IndexField { + ::default_instance() + } +} + +impl IndexField { + pub fn new() -> IndexField { + ::std::default::Default::default() + } + + // .Field field = 1; + + + pub fn get_field(&self) -> &Field { + self.field.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_field(&mut self) { + self.field.clear(); + } + + pub fn has_field(&self) -> bool { + self.field.is_some() + } + + // Param is passed by value, moved + pub fn set_field(&mut self, v: Field) { + self.field = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field(&mut self) -> &mut Field { + if self.field.is_none() { + self.field.set_default(); + } + self.field.as_mut().unwrap() + } + + // Take field + pub fn take_field(&mut self) -> Field { + self.field.take().unwrap_or_else(|| Field::new()) + } + + // int32 index = 2; + + + pub fn get_index(&self) -> i32 { + self.index + } + pub fn clear_index(&mut self) { + self.index = 0; + } + + // Param is passed by value, moved + pub fn set_index(&mut self, v: i32) { + self.index = v; + } +} + +impl ::protobuf::Message for IndexField { + fn is_initialized(&self) -> bool { + for v in &self.field { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.field)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.index = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.field.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if self.index != 0 { + my_size += ::protobuf::rt::value_size(2, self.index, ::protobuf::wire_format::WireTypeVarint); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.field.as_ref() { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if self.index != 0 { + os.write_int32(2, self.index)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> IndexField { + IndexField::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "field", + |m: &IndexField| { &m.field }, + |m: &mut IndexField| { &mut m.field }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "index", + |m: &IndexField| { &m.index }, + |m: &mut IndexField| { &mut m.index }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "IndexField", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static IndexField { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(IndexField::new) + } +} + +impl ::protobuf::Clear for IndexField { + fn clear(&mut self) { + self.field.clear(); + self.index = 0; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for IndexField { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for IndexField { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GetEditFieldContextPayload { + // message fields + pub grid_id: ::std::string::String, + pub field_type: FieldType, + // message oneof groups + pub one_of_field_id: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GetEditFieldContextPayload { + fn default() -> &'a GetEditFieldContextPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum GetEditFieldContextPayload_oneof_one_of_field_id { + field_id(::std::string::String), +} + +impl GetEditFieldContextPayload { + pub fn new() -> GetEditFieldContextPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string field_id = 2; + + + pub fn get_field_id(&self) -> &str { + match self.one_of_field_id { + ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(ref v)) => v, + _ => "", + } + } + pub fn clear_field_id(&mut self) { + self.one_of_field_id = ::std::option::Option::None; + } + + pub fn has_field_id(&self) -> bool { + match self.one_of_field_id { + ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.one_of_field_id = ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(v)) + } + + // Mutable pointer to the field. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(_)) = self.one_of_field_id { + } else { + self.one_of_field_id = ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(::std::string::String::new())); + } + match self.one_of_field_id { + ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + if self.has_field_id() { + match self.one_of_field_id.take() { + ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } + + // .FieldType field_type = 3; + + + pub fn get_field_type(&self) -> FieldType { + self.field_type + } + pub fn clear_field_type(&mut self) { + self.field_type = FieldType::RichText; + } + + // Param is passed by value, moved + pub fn set_field_type(&mut self, v: FieldType) { + self.field_type = v; + } +} + +impl ::protobuf::Message for GetEditFieldContextPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_field_id = ::std::option::Option::Some(GetEditFieldContextPayload_oneof_one_of_field_id::field_id(is.read_string()?)); + }, + 3 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 3, &mut self.unknown_fields)? + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if self.field_type != FieldType::RichText { + my_size += ::protobuf::rt::enum_size(3, self.field_type); + } + if let ::std::option::Option::Some(ref v) = self.one_of_field_id { + match v { + &GetEditFieldContextPayload_oneof_one_of_field_id::field_id(ref v) => { + my_size += ::protobuf::rt::string_size(2, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if self.field_type != FieldType::RichText { + os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.field_type))?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_field_id { + match v { + &GetEditFieldContextPayload_oneof_one_of_field_id::field_id(ref v) => { + os.write_string(2, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GetEditFieldContextPayload { + GetEditFieldContextPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &GetEditFieldContextPayload| { &m.grid_id }, + |m: &mut GetEditFieldContextPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "field_id", + GetEditFieldContextPayload::has_field_id, + GetEditFieldContextPayload::get_field_id, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "field_type", + |m: &GetEditFieldContextPayload| { &m.field_type }, + |m: &mut GetEditFieldContextPayload| { &mut m.field_type }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GetEditFieldContextPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GetEditFieldContextPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GetEditFieldContextPayload::new) + } +} + +impl ::protobuf::Clear for GetEditFieldContextPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.one_of_field_id = ::std::option::Option::None; + self.field_type = FieldType::RichText; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GetEditFieldContextPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GetEditFieldContextPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct EditFieldPayload { + // message fields + pub grid_id: ::std::string::String, + pub field_id: ::std::string::String, + pub field_type: FieldType, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a EditFieldPayload { + fn default() -> &'a EditFieldPayload { + ::default_instance() + } +} + +impl EditFieldPayload { + pub fn new() -> EditFieldPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string field_id = 2; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // .FieldType field_type = 3; + + + pub fn get_field_type(&self) -> FieldType { + self.field_type + } + pub fn clear_field_type(&mut self) { + self.field_type = FieldType::RichText; + } + + // Param is passed by value, moved + pub fn set_field_type(&mut self, v: FieldType) { + self.field_type = v; + } +} + +impl ::protobuf::Message for EditFieldPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 3 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 3, &mut self.unknown_fields)? + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.field_id); + } + if self.field_type != FieldType::RichText { + my_size += ::protobuf::rt::enum_size(3, self.field_type); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.field_id.is_empty() { + os.write_string(2, &self.field_id)?; + } + if self.field_type != FieldType::RichText { + os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.field_type))?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> EditFieldPayload { + EditFieldPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &EditFieldPayload| { &m.grid_id }, + |m: &mut EditFieldPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &EditFieldPayload| { &m.field_id }, + |m: &mut EditFieldPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "field_type", + |m: &EditFieldPayload| { &m.field_type }, + |m: &mut EditFieldPayload| { &mut m.field_type }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "EditFieldPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static EditFieldPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(EditFieldPayload::new) + } +} + +impl ::protobuf::Clear for EditFieldPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.field_id.clear(); + self.field_type = FieldType::RichText; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for EditFieldPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for EditFieldPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct EditFieldContext { + // message fields + pub grid_id: ::std::string::String, + pub grid_field: ::protobuf::SingularPtrField, + pub type_option_data: ::std::vec::Vec, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a EditFieldContext { + fn default() -> &'a EditFieldContext { + ::default_instance() + } +} + +impl EditFieldContext { + pub fn new() -> EditFieldContext { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // .Field grid_field = 2; + + + pub fn get_grid_field(&self) -> &Field { + self.grid_field.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_grid_field(&mut self) { + self.grid_field.clear(); + } + + pub fn has_grid_field(&self) -> bool { + self.grid_field.is_some() + } + + // Param is passed by value, moved + pub fn set_grid_field(&mut self, v: Field) { + self.grid_field = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_field(&mut self) -> &mut Field { + if self.grid_field.is_none() { + self.grid_field.set_default(); + } + self.grid_field.as_mut().unwrap() + } + + // Take field + pub fn take_grid_field(&mut self) -> Field { + self.grid_field.take().unwrap_or_else(|| Field::new()) + } + + // bytes type_option_data = 3; + + + pub fn get_type_option_data(&self) -> &[u8] { + &self.type_option_data + } + pub fn clear_type_option_data(&mut self) { + self.type_option_data.clear(); + } + + // Param is passed by value, moved + pub fn set_type_option_data(&mut self, v: ::std::vec::Vec) { + self.type_option_data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_type_option_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.type_option_data + } + + // Take field + pub fn take_type_option_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.type_option_data, ::std::vec::Vec::new()) + } +} + +impl ::protobuf::Message for EditFieldContext { + fn is_initialized(&self) -> bool { + for v in &self.grid_field { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.grid_field)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if let Some(ref v) = self.grid_field.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if !self.type_option_data.is_empty() { + my_size += ::protobuf::rt::bytes_size(3, &self.type_option_data); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if let Some(ref v) = self.grid_field.as_ref() { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if !self.type_option_data.is_empty() { + os.write_bytes(3, &self.type_option_data)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> EditFieldContext { + EditFieldContext::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &EditFieldContext| { &m.grid_id }, + |m: &mut EditFieldContext| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "grid_field", + |m: &EditFieldContext| { &m.grid_field }, + |m: &mut EditFieldContext| { &mut m.grid_field }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "type_option_data", + |m: &EditFieldContext| { &m.type_option_data }, + |m: &mut EditFieldContext| { &mut m.type_option_data }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "EditFieldContext", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static EditFieldContext { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(EditFieldContext::new) + } +} + +impl ::protobuf::Clear for EditFieldContext { + fn clear(&mut self) { + self.grid_id.clear(); + self.grid_field.clear(); + self.type_option_data.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for EditFieldContext { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for EditFieldContext { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct RepeatedField { + // message fields + pub items: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RepeatedField { + fn default() -> &'a RepeatedField { + ::default_instance() + } +} + +impl RepeatedField { + pub fn new() -> RepeatedField { + ::std::default::Default::default() + } + + // repeated .Field items = 1; + + + pub fn get_items(&self) -> &[Field] { + &self.items + } + pub fn clear_items(&mut self) { + self.items.clear(); + } + + // Param is passed by value, moved + pub fn set_items(&mut self, v: ::protobuf::RepeatedField) { + self.items = v; + } + + // Mutable pointer to the field. + pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.items + } + + // Take field + pub fn take_items(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for RepeatedField { + fn is_initialized(&self) -> bool { + for v in &self.items { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.items { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.items { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RepeatedField { + RepeatedField::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "items", + |m: &RepeatedField| { &m.items }, + |m: &mut RepeatedField| { &mut m.items }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RepeatedField", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RepeatedField { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RepeatedField::new) + } +} + +impl ::protobuf::Clear for RepeatedField { + fn clear(&mut self) { + self.items.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RepeatedField { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RepeatedField { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct RepeatedFieldOrder { + // message fields + pub items: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RepeatedFieldOrder { + fn default() -> &'a RepeatedFieldOrder { + ::default_instance() + } +} + +impl RepeatedFieldOrder { + pub fn new() -> RepeatedFieldOrder { + ::std::default::Default::default() + } + + // repeated .FieldOrder items = 1; + + + pub fn get_items(&self) -> &[FieldOrder] { + &self.items + } + pub fn clear_items(&mut self) { + self.items.clear(); + } + + // Param is passed by value, moved + pub fn set_items(&mut self, v: ::protobuf::RepeatedField) { + self.items = v; + } + + // Mutable pointer to the field. + pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.items + } + + // Take field + pub fn take_items(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for RepeatedFieldOrder { + fn is_initialized(&self) -> bool { + for v in &self.items { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.items { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.items { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RepeatedFieldOrder { + RepeatedFieldOrder::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "items", + |m: &RepeatedFieldOrder| { &m.items }, + |m: &mut RepeatedFieldOrder| { &mut m.items }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RepeatedFieldOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RepeatedFieldOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RepeatedFieldOrder::new) + } +} + +impl ::protobuf::Clear for RepeatedFieldOrder { + fn clear(&mut self) { + self.items.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RepeatedFieldOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RepeatedFieldOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct RowOrder { + // message fields + pub row_id: ::std::string::String, + pub block_id: ::std::string::String, + pub height: i32, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RowOrder { + fn default() -> &'a RowOrder { + ::default_instance() + } +} + +impl RowOrder { + pub fn new() -> RowOrder { + ::std::default::Default::default() + } + + // string row_id = 1; + + + pub fn get_row_id(&self) -> &str { + &self.row_id + } + pub fn clear_row_id(&mut self) { + self.row_id.clear(); + } + + // Param is passed by value, moved + pub fn set_row_id(&mut self, v: ::std::string::String) { + self.row_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_id(&mut self) -> &mut ::std::string::String { + &mut self.row_id + } + + // Take field + pub fn take_row_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) + } + + // string block_id = 2; + + + pub fn get_block_id(&self) -> &str { + &self.block_id + } + pub fn clear_block_id(&mut self) { + self.block_id.clear(); + } + + // Param is passed by value, moved + pub fn set_block_id(&mut self, v: ::std::string::String) { + self.block_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_block_id(&mut self) -> &mut ::std::string::String { + &mut self.block_id + } + + // Take field + pub fn take_block_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) + } + + // int32 height = 3; + + + pub fn get_height(&self) -> i32 { + self.height + } + pub fn clear_height(&mut self) { + self.height = 0; + } + + // Param is passed by value, moved + pub fn set_height(&mut self, v: i32) { + self.height = v; + } +} + +impl ::protobuf::Message for RowOrder { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?; + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.height = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.row_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.row_id); + } + if !self.block_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.block_id); + } + if self.height != 0 { + my_size += ::protobuf::rt::value_size(3, self.height, ::protobuf::wire_format::WireTypeVarint); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.row_id.is_empty() { + os.write_string(1, &self.row_id)?; + } + if !self.block_id.is_empty() { + os.write_string(2, &self.block_id)?; + } + if self.height != 0 { + os.write_int32(3, self.height)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RowOrder { + RowOrder::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "row_id", + |m: &RowOrder| { &m.row_id }, + |m: &mut RowOrder| { &mut m.row_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "block_id", + |m: &RowOrder| { &m.block_id }, + |m: &mut RowOrder| { &mut m.block_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "height", + |m: &RowOrder| { &m.height }, + |m: &mut RowOrder| { &mut m.height }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RowOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RowOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RowOrder::new) + } +} + +impl ::protobuf::Clear for RowOrder { + fn clear(&mut self) { + self.row_id.clear(); + self.block_id.clear(); + self.height = 0; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RowOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RowOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Row { + // message fields + pub id: ::std::string::String, + pub cell_by_field_id: ::std::collections::HashMap<::std::string::String, Cell>, + pub height: i32, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Row { + fn default() -> &'a Row { + ::default_instance() + } +} + +impl Row { + pub fn new() -> Row { + ::std::default::Default::default() + } + + // string id = 1; + + + pub fn get_id(&self) -> &str { + &self.id + } + pub fn clear_id(&mut self) { + self.id.clear(); + } + + // Param is passed by value, moved + pub fn set_id(&mut self, v: ::std::string::String) { + self.id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_id(&mut self) -> &mut ::std::string::String { + &mut self.id + } + + // Take field + pub fn take_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.id, ::std::string::String::new()) + } + + // repeated .Row.CellByFieldIdEntry cell_by_field_id = 2; + + + pub fn get_cell_by_field_id(&self) -> &::std::collections::HashMap<::std::string::String, Cell> { + &self.cell_by_field_id + } + pub fn clear_cell_by_field_id(&mut self) { + self.cell_by_field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_cell_by_field_id(&mut self, v: ::std::collections::HashMap<::std::string::String, Cell>) { + self.cell_by_field_id = v; + } + + // Mutable pointer to the field. + pub fn mut_cell_by_field_id(&mut self) -> &mut ::std::collections::HashMap<::std::string::String, Cell> { + &mut self.cell_by_field_id + } + + // Take field + pub fn take_cell_by_field_id(&mut self) -> ::std::collections::HashMap<::std::string::String, Cell> { + ::std::mem::replace(&mut self.cell_by_field_id, ::std::collections::HashMap::new()) + } + + // int32 height = 3; + + + pub fn get_height(&self) -> i32 { + self.height + } + pub fn clear_height(&mut self) { + self.height = 0; + } + + // Param is passed by value, moved + pub fn set_height(&mut self, v: i32) { + self.height = v; + } +} + +impl ::protobuf::Message for Row { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; + }, + 2 => { + ::protobuf::rt::read_map_into::<::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeMessage>(wire_type, is, &mut self.cell_by_field_id)?; + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.height = tmp; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.id); + } + my_size += ::protobuf::rt::compute_map_size::<::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeMessage>(2, &self.cell_by_field_id); + if self.height != 0 { + my_size += ::protobuf::rt::value_size(3, self.height, ::protobuf::wire_format::WireTypeVarint); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.id.is_empty() { + os.write_string(1, &self.id)?; + } + ::protobuf::rt::write_map_with_cached_sizes::<::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeMessage>(2, &self.cell_by_field_id, os)?; + if self.height != 0 { + os.write_int32(3, self.height)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Row { + Row::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "id", + |m: &Row| { &m.id }, + |m: &mut Row| { &mut m.id }, + )); + fields.push(::protobuf::reflect::accessor::make_map_accessor::<_, ::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeMessage>( + "cell_by_field_id", + |m: &Row| { &m.cell_by_field_id }, + |m: &mut Row| { &mut m.cell_by_field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "height", + |m: &Row| { &m.height }, + |m: &mut Row| { &mut m.height }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Row", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Row { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Row::new) + } +} + +impl ::protobuf::Clear for Row { + fn clear(&mut self) { + self.id.clear(); + self.cell_by_field_id.clear(); + self.height = 0; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Row { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Row { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct RepeatedRow { + // message fields + pub items: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RepeatedRow { + fn default() -> &'a RepeatedRow { + ::default_instance() + } +} + +impl RepeatedRow { + pub fn new() -> RepeatedRow { + ::std::default::Default::default() + } + + // repeated .Row items = 1; + + + pub fn get_items(&self) -> &[Row] { + &self.items + } + pub fn clear_items(&mut self) { + self.items.clear(); + } + + // Param is passed by value, moved + pub fn set_items(&mut self, v: ::protobuf::RepeatedField) { + self.items = v; + } + + // Mutable pointer to the field. + pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.items + } + + // Take field + pub fn take_items(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for RepeatedRow { + fn is_initialized(&self) -> bool { + for v in &self.items { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.items { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.items { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RepeatedRow { + RepeatedRow::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "items", + |m: &RepeatedRow| { &m.items }, + |m: &mut RepeatedRow| { &mut m.items }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RepeatedRow", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RepeatedRow { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RepeatedRow::new) + } +} + +impl ::protobuf::Clear for RepeatedRow { + fn clear(&mut self) { + self.items.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RepeatedRow { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RepeatedRow { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct RepeatedGridBlock { + // message fields + pub items: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RepeatedGridBlock { + fn default() -> &'a RepeatedGridBlock { + ::default_instance() + } +} + +impl RepeatedGridBlock { + pub fn new() -> RepeatedGridBlock { + ::std::default::Default::default() + } + + // repeated .GridBlock items = 1; + + + pub fn get_items(&self) -> &[GridBlock] { + &self.items + } + pub fn clear_items(&mut self) { + self.items.clear(); + } + + // Param is passed by value, moved + pub fn set_items(&mut self, v: ::protobuf::RepeatedField) { + self.items = v; + } + + // Mutable pointer to the field. + pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.items + } + + // Take field + pub fn take_items(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for RepeatedGridBlock { + fn is_initialized(&self) -> bool { + for v in &self.items { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.items { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.items { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RepeatedGridBlock { + RepeatedGridBlock::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "items", + |m: &RepeatedGridBlock| { &m.items }, + |m: &mut RepeatedGridBlock| { &mut m.items }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RepeatedGridBlock", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RepeatedGridBlock { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RepeatedGridBlock::new) + } +} + +impl ::protobuf::Clear for RepeatedGridBlock { + fn clear(&mut self) { + self.items.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RepeatedGridBlock { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RepeatedGridBlock { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GridBlockOrder { + // message fields + pub block_id: ::std::string::String, + pub row_orders: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridBlockOrder { + fn default() -> &'a GridBlockOrder { + ::default_instance() + } +} + +impl GridBlockOrder { + pub fn new() -> GridBlockOrder { + ::std::default::Default::default() + } + + // string block_id = 1; + + + pub fn get_block_id(&self) -> &str { + &self.block_id + } + pub fn clear_block_id(&mut self) { + self.block_id.clear(); + } + + // Param is passed by value, moved + pub fn set_block_id(&mut self, v: ::std::string::String) { + self.block_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_block_id(&mut self) -> &mut ::std::string::String { + &mut self.block_id + } + + // Take field + pub fn take_block_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) + } + + // repeated .RowOrder row_orders = 2; + + + pub fn get_row_orders(&self) -> &[RowOrder] { + &self.row_orders + } + pub fn clear_row_orders(&mut self) { + self.row_orders.clear(); + } + + // Param is passed by value, moved + pub fn set_row_orders(&mut self, v: ::protobuf::RepeatedField) { + self.row_orders = v; + } + + // Mutable pointer to the field. + pub fn mut_row_orders(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.row_orders + } + + // Take field + pub fn take_row_orders(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.row_orders, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for GridBlockOrder { + fn is_initialized(&self) -> bool { + for v in &self.row_orders { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.row_orders)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.block_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.block_id); + } + for value in &self.row_orders { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.block_id.is_empty() { + os.write_string(1, &self.block_id)?; + } + for v in &self.row_orders { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GridBlockOrder { + GridBlockOrder::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "block_id", + |m: &GridBlockOrder| { &m.block_id }, + |m: &mut GridBlockOrder| { &mut m.block_id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "row_orders", + |m: &GridBlockOrder| { &m.row_orders }, + |m: &mut GridBlockOrder| { &mut m.row_orders }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridBlockOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridBlockOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridBlockOrder::new) + } +} + +impl ::protobuf::Clear for GridBlockOrder { + fn clear(&mut self) { + self.block_id.clear(); + self.row_orders.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridBlockOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridBlockOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct IndexRowOrder { + // message fields + pub row_order: ::protobuf::SingularPtrField, + // message oneof groups + pub one_of_index: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a IndexRowOrder { + fn default() -> &'a IndexRowOrder { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum IndexRowOrder_oneof_one_of_index { + index(i32), +} + +impl IndexRowOrder { + pub fn new() -> IndexRowOrder { + ::std::default::Default::default() + } + + // .RowOrder row_order = 1; + + + pub fn get_row_order(&self) -> &RowOrder { + self.row_order.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_row_order(&mut self) { + self.row_order.clear(); + } + + pub fn has_row_order(&self) -> bool { + self.row_order.is_some() + } + + // Param is passed by value, moved + pub fn set_row_order(&mut self, v: RowOrder) { + self.row_order = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_order(&mut self) -> &mut RowOrder { + if self.row_order.is_none() { + self.row_order.set_default(); + } + self.row_order.as_mut().unwrap() + } + + // Take field + pub fn take_row_order(&mut self) -> RowOrder { + self.row_order.take().unwrap_or_else(|| RowOrder::new()) + } + + // int32 index = 2; + + + pub fn get_index(&self) -> i32 { + match self.one_of_index { + ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(v)) => v, + _ => 0, + } + } + pub fn clear_index(&mut self) { + self.one_of_index = ::std::option::Option::None; + } + + pub fn has_index(&self) -> bool { + match self.one_of_index { + ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_index(&mut self, v: i32) { + self.one_of_index = ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(v)) + } +} + +impl ::protobuf::Message for IndexRowOrder { + fn is_initialized(&self) -> bool { + for v in &self.row_order { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.row_order)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_index = ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(is.read_int32()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.row_order.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let ::std::option::Option::Some(ref v) = self.one_of_index { + match v { + &IndexRowOrder_oneof_one_of_index::index(v) => { + my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.row_order.as_ref() { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_index { + match v { + &IndexRowOrder_oneof_one_of_index::index(v) => { + os.write_int32(2, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> IndexRowOrder { + IndexRowOrder::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "row_order", + |m: &IndexRowOrder| { &m.row_order }, + |m: &mut IndexRowOrder| { &mut m.row_order }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>( + "index", + IndexRowOrder::has_index, + IndexRowOrder::get_index, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "IndexRowOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static IndexRowOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(IndexRowOrder::new) + } +} + +impl ::protobuf::Clear for IndexRowOrder { + fn clear(&mut self) { + self.row_order.clear(); + self.one_of_index = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for IndexRowOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for IndexRowOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GridRowsChangeset { + // message fields + pub block_id: ::std::string::String, + pub inserted_rows: ::protobuf::RepeatedField, + pub deleted_rows: ::protobuf::RepeatedField, + pub updated_rows: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridRowsChangeset { + fn default() -> &'a GridRowsChangeset { + ::default_instance() + } +} + +impl GridRowsChangeset { + pub fn new() -> GridRowsChangeset { + ::std::default::Default::default() + } + + // string block_id = 1; + + + pub fn get_block_id(&self) -> &str { + &self.block_id + } + pub fn clear_block_id(&mut self) { + self.block_id.clear(); + } + + // Param is passed by value, moved + pub fn set_block_id(&mut self, v: ::std::string::String) { + self.block_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_block_id(&mut self) -> &mut ::std::string::String { + &mut self.block_id + } + + // Take field + pub fn take_block_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) + } + + // repeated .IndexRowOrder inserted_rows = 2; + + + pub fn get_inserted_rows(&self) -> &[IndexRowOrder] { + &self.inserted_rows + } + pub fn clear_inserted_rows(&mut self) { + self.inserted_rows.clear(); + } + + // Param is passed by value, moved + pub fn set_inserted_rows(&mut self, v: ::protobuf::RepeatedField) { + self.inserted_rows = v; + } + + // Mutable pointer to the field. + pub fn mut_inserted_rows(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.inserted_rows + } + + // Take field + pub fn take_inserted_rows(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.inserted_rows, ::protobuf::RepeatedField::new()) + } + + // repeated .RowOrder deleted_rows = 3; + + + pub fn get_deleted_rows(&self) -> &[RowOrder] { + &self.deleted_rows + } + pub fn clear_deleted_rows(&mut self) { + self.deleted_rows.clear(); + } + + // Param is passed by value, moved + pub fn set_deleted_rows(&mut self, v: ::protobuf::RepeatedField) { + self.deleted_rows = v; + } + + // Mutable pointer to the field. + pub fn mut_deleted_rows(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.deleted_rows + } + + // Take field + pub fn take_deleted_rows(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.deleted_rows, ::protobuf::RepeatedField::new()) + } + + // repeated .RowOrder updated_rows = 4; + + + pub fn get_updated_rows(&self) -> &[RowOrder] { + &self.updated_rows + } + pub fn clear_updated_rows(&mut self) { + self.updated_rows.clear(); + } + + // Param is passed by value, moved + pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField) { + self.updated_rows = v; + } + + // Mutable pointer to the field. + pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.updated_rows + } + + // Take field + pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.updated_rows, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for GridRowsChangeset { + fn is_initialized(&self) -> bool { + for v in &self.inserted_rows { + if !v.is_initialized() { + return false; + } + }; + for v in &self.deleted_rows { + if !v.is_initialized() { + return false; + } + }; + for v in &self.updated_rows { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.inserted_rows)?; + }, + 3 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.deleted_rows)?; + }, + 4 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.updated_rows)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.block_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.block_id); + } + for value in &self.inserted_rows { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.deleted_rows { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.updated_rows { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.block_id.is_empty() { + os.write_string(1, &self.block_id)?; + } + for v in &self.inserted_rows { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.deleted_rows { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.updated_rows { + os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GridRowsChangeset { + GridRowsChangeset::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "block_id", + |m: &GridRowsChangeset| { &m.block_id }, + |m: &mut GridRowsChangeset| { &mut m.block_id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "inserted_rows", + |m: &GridRowsChangeset| { &m.inserted_rows }, + |m: &mut GridRowsChangeset| { &mut m.inserted_rows }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "deleted_rows", + |m: &GridRowsChangeset| { &m.deleted_rows }, + |m: &mut GridRowsChangeset| { &mut m.deleted_rows }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "updated_rows", + |m: &GridRowsChangeset| { &m.updated_rows }, + |m: &mut GridRowsChangeset| { &mut m.updated_rows }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridRowsChangeset", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridRowsChangeset { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridRowsChangeset::new) + } +} + +impl ::protobuf::Clear for GridRowsChangeset { + fn clear(&mut self) { + self.block_id.clear(); + self.inserted_rows.clear(); + self.deleted_rows.clear(); + self.updated_rows.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridRowsChangeset { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridRowsChangeset { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GridBlock { + // message fields + pub id: ::std::string::String, + pub row_orders: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridBlock { + fn default() -> &'a GridBlock { + ::default_instance() + } +} + +impl GridBlock { + pub fn new() -> GridBlock { + ::std::default::Default::default() + } + + // string id = 1; + + + pub fn get_id(&self) -> &str { + &self.id + } + pub fn clear_id(&mut self) { + self.id.clear(); + } + + // Param is passed by value, moved + pub fn set_id(&mut self, v: ::std::string::String) { + self.id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_id(&mut self) -> &mut ::std::string::String { + &mut self.id + } + + // Take field + pub fn take_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.id, ::std::string::String::new()) + } + + // repeated .RowOrder row_orders = 2; + + + pub fn get_row_orders(&self) -> &[RowOrder] { + &self.row_orders + } + pub fn clear_row_orders(&mut self) { + self.row_orders.clear(); + } + + // Param is passed by value, moved + pub fn set_row_orders(&mut self, v: ::protobuf::RepeatedField) { + self.row_orders = v; + } + + // Mutable pointer to the field. + pub fn mut_row_orders(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.row_orders + } + + // Take field + pub fn take_row_orders(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.row_orders, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for GridBlock { + fn is_initialized(&self) -> bool { + for v in &self.row_orders { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.row_orders)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.id); + } + for value in &self.row_orders { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.id.is_empty() { + os.write_string(1, &self.id)?; + } + for v in &self.row_orders { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GridBlock { + GridBlock::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "id", + |m: &GridBlock| { &m.id }, + |m: &mut GridBlock| { &mut m.id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "row_orders", + |m: &GridBlock| { &m.row_orders }, + |m: &mut GridBlock| { &mut m.row_orders }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridBlock", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridBlock { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridBlock::new) + } +} + +impl ::protobuf::Clear for GridBlock { + fn clear(&mut self) { + self.id.clear(); + self.row_orders.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridBlock { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridBlock { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Cell { + // message fields + pub field_id: ::std::string::String, + pub content: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Cell { + fn default() -> &'a Cell { + ::default_instance() + } +} + +impl Cell { + pub fn new() -> Cell { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string content = 2; + + + pub fn get_content(&self) -> &str { + &self.content + } + pub fn clear_content(&mut self) { + self.content.clear(); + } + + // Param is passed by value, moved + pub fn set_content(&mut self, v: ::std::string::String) { + self.content = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_content(&mut self) -> &mut ::std::string::String { + &mut self.content + } + + // Take field + pub fn take_content(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.content, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for Cell { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.content)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + if !self.content.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.content); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + if !self.content.is_empty() { + os.write_string(2, &self.content)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Cell { + Cell::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &Cell| { &m.field_id }, + |m: &mut Cell| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "content", + |m: &Cell| { &m.content }, + |m: &mut Cell| { &mut m.content }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Cell", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Cell { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Cell::new) + } +} + +impl ::protobuf::Clear for Cell { + fn clear(&mut self) { + self.field_id.clear(); + self.content.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Cell { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Cell { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct CellNotificationData { + // message fields + pub grid_id: ::std::string::String, + pub field_id: ::std::string::String, + pub row_id: ::std::string::String, + // message oneof groups + pub one_of_content: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CellNotificationData { + fn default() -> &'a CellNotificationData { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum CellNotificationData_oneof_one_of_content { + content(::std::string::String), +} + +impl CellNotificationData { + pub fn new() -> CellNotificationData { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string field_id = 2; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string row_id = 3; + + + pub fn get_row_id(&self) -> &str { + &self.row_id + } + pub fn clear_row_id(&mut self) { + self.row_id.clear(); + } + + // Param is passed by value, moved + pub fn set_row_id(&mut self, v: ::std::string::String) { + self.row_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_id(&mut self) -> &mut ::std::string::String { + &mut self.row_id + } + + // Take field + pub fn take_row_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) + } + + // string content = 4; + + + pub fn get_content(&self) -> &str { + match self.one_of_content { + ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(ref v)) => v, + _ => "", + } + } + pub fn clear_content(&mut self) { + self.one_of_content = ::std::option::Option::None; + } + + pub fn has_content(&self) -> bool { + match self.one_of_content { + ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_content(&mut self, v: ::std::string::String) { + self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(v)) + } + + // Mutable pointer to the field. + pub fn mut_content(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(_)) = self.one_of_content { + } else { + self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(::std::string::String::new())); + } + match self.one_of_content { + ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_content(&mut self) -> ::std::string::String { + if self.has_content() { + match self.one_of_content.take() { + ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } +} + +impl ::protobuf::Message for CellNotificationData { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(is.read_string()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.field_id); + } + if !self.row_id.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.row_id); + } + if let ::std::option::Option::Some(ref v) = self.one_of_content { + match v { + &CellNotificationData_oneof_one_of_content::content(ref v) => { + my_size += ::protobuf::rt::string_size(4, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.field_id.is_empty() { + os.write_string(2, &self.field_id)?; + } + if !self.row_id.is_empty() { + os.write_string(3, &self.row_id)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_content { + match v { + &CellNotificationData_oneof_one_of_content::content(ref v) => { + os.write_string(4, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CellNotificationData { + CellNotificationData::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &CellNotificationData| { &m.grid_id }, + |m: &mut CellNotificationData| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &CellNotificationData| { &m.field_id }, + |m: &mut CellNotificationData| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "row_id", + |m: &CellNotificationData| { &m.row_id }, + |m: &mut CellNotificationData| { &mut m.row_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "content", + CellNotificationData::has_content, + CellNotificationData::get_content, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CellNotificationData", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CellNotificationData { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CellNotificationData::new) + } +} + +impl ::protobuf::Clear for CellNotificationData { + fn clear(&mut self) { + self.grid_id.clear(); + self.field_id.clear(); + self.row_id.clear(); + self.one_of_content = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CellNotificationData { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CellNotificationData { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct RepeatedCell { + // message fields + pub items: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a RepeatedCell { + fn default() -> &'a RepeatedCell { + ::default_instance() + } +} + +impl RepeatedCell { + pub fn new() -> RepeatedCell { + ::std::default::Default::default() + } + + // repeated .Cell items = 1; + + + pub fn get_items(&self) -> &[Cell] { + &self.items + } + pub fn clear_items(&mut self) { + self.items.clear(); + } + + // Param is passed by value, moved + pub fn set_items(&mut self, v: ::protobuf::RepeatedField) { + self.items = v; + } + + // Mutable pointer to the field. + pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.items + } + + // Take field + pub fn take_items(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for RepeatedCell { + fn is_initialized(&self) -> bool { + for v in &self.items { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.items { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + for v in &self.items { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> RepeatedCell { + RepeatedCell::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "items", + |m: &RepeatedCell| { &m.items }, + |m: &mut RepeatedCell| { &mut m.items }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "RepeatedCell", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static RepeatedCell { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(RepeatedCell::new) + } +} + +impl ::protobuf::Clear for RepeatedCell { + fn clear(&mut self) { + self.items.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for RepeatedCell { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for RepeatedCell { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct CreateGridPayload { + // message fields + pub name: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CreateGridPayload { + fn default() -> &'a CreateGridPayload { + ::default_instance() + } +} + +impl CreateGridPayload { + pub fn new() -> CreateGridPayload { + ::std::default::Default::default() + } + + // string name = 1; + + + pub fn get_name(&self) -> &str { + &self.name + } + pub fn clear_name(&mut self) { + self.name.clear(); + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.name = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + &mut self.name + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.name, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for CreateGridPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.name.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.name); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.name.is_empty() { + os.write_string(1, &self.name)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CreateGridPayload { + CreateGridPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "name", + |m: &CreateGridPayload| { &m.name }, + |m: &mut CreateGridPayload| { &mut m.name }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CreateGridPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CreateGridPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CreateGridPayload::new) + } +} + +impl ::protobuf::Clear for CreateGridPayload { + fn clear(&mut self) { + self.name.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CreateGridPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CreateGridPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GridId { + // message fields + pub value: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridId { + fn default() -> &'a GridId { + ::default_instance() + } +} + +impl GridId { + pub fn new() -> GridId { + ::std::default::Default::default() + } + + // string value = 1; + + + pub fn get_value(&self) -> &str { + &self.value + } + pub fn clear_value(&mut self) { + self.value.clear(); + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: ::std::string::String) { + self.value = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_value(&mut self) -> &mut ::std::string::String { + &mut self.value + } + + // Take field + pub fn take_value(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.value, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for GridId { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.value)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.value.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.value); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.value.is_empty() { + os.write_string(1, &self.value)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GridId { + GridId::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "value", + |m: &GridId| { &m.value }, + |m: &mut GridId| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridId", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridId { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridId::new) + } +} + +impl ::protobuf::Clear for GridId { + fn clear(&mut self) { + self.value.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridId { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct GridBlockId { + // message fields + pub value: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridBlockId { + fn default() -> &'a GridBlockId { + ::default_instance() + } +} + +impl GridBlockId { + pub fn new() -> GridBlockId { + ::std::default::Default::default() + } + + // string value = 1; + + + pub fn get_value(&self) -> &str { + &self.value + } + pub fn clear_value(&mut self) { + self.value.clear(); + } + + // Param is passed by value, moved + pub fn set_value(&mut self, v: ::std::string::String) { + self.value = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_value(&mut self) -> &mut ::std::string::String { + &mut self.value + } + + // Take field + pub fn take_value(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.value, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for GridBlockId { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.value)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.value.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.value); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.value.is_empty() { + os.write_string(1, &self.value)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> GridBlockId { + GridBlockId::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "value", + |m: &GridBlockId| { &m.value }, + |m: &mut GridBlockId| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridBlockId", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridBlockId { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridBlockId::new) + } +} + +impl ::protobuf::Clear for GridBlockId { + fn clear(&mut self) { + self.value.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridBlockId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridBlockId { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct CreateRowPayload { + // message fields + pub grid_id: ::std::string::String, + // message oneof groups + pub one_of_start_row_id: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CreateRowPayload { + fn default() -> &'a CreateRowPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum CreateRowPayload_oneof_one_of_start_row_id { + start_row_id(::std::string::String), +} + +impl CreateRowPayload { + pub fn new() -> CreateRowPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string start_row_id = 2; + + + pub fn get_start_row_id(&self) -> &str { + match self.one_of_start_row_id { + ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(ref v)) => v, + _ => "", + } + } + pub fn clear_start_row_id(&mut self) { + self.one_of_start_row_id = ::std::option::Option::None; + } + + pub fn has_start_row_id(&self) -> bool { + match self.one_of_start_row_id { + ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_start_row_id(&mut self, v: ::std::string::String) { + self.one_of_start_row_id = ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(v)) + } + + // Mutable pointer to the field. + pub fn mut_start_row_id(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(_)) = self.one_of_start_row_id { + } else { + self.one_of_start_row_id = ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(::std::string::String::new())); + } + match self.one_of_start_row_id { + ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_start_row_id(&mut self) -> ::std::string::String { + if self.has_start_row_id() { + match self.one_of_start_row_id.take() { + ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } +} + +impl ::protobuf::Message for CreateRowPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_start_row_id = ::std::option::Option::Some(CreateRowPayload_oneof_one_of_start_row_id::start_row_id(is.read_string()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if let ::std::option::Option::Some(ref v) = self.one_of_start_row_id { + match v { + &CreateRowPayload_oneof_one_of_start_row_id::start_row_id(ref v) => { + my_size += ::protobuf::rt::string_size(2, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_start_row_id { + match v { + &CreateRowPayload_oneof_one_of_start_row_id::start_row_id(ref v) => { + os.write_string(2, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CreateRowPayload { + CreateRowPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &CreateRowPayload| { &m.grid_id }, + |m: &mut CreateRowPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "start_row_id", + CreateRowPayload::has_start_row_id, + CreateRowPayload::get_start_row_id, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CreateRowPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CreateRowPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CreateRowPayload::new) + } +} + +impl ::protobuf::Clear for CreateRowPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.one_of_start_row_id = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CreateRowPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CreateRowPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct InsertFieldPayload { + // message fields + pub grid_id: ::std::string::String, + pub field: ::protobuf::SingularPtrField, + pub type_option_data: ::std::vec::Vec, + // message oneof groups + pub one_of_start_field_id: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a InsertFieldPayload { + fn default() -> &'a InsertFieldPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum InsertFieldPayload_oneof_one_of_start_field_id { + start_field_id(::std::string::String), +} + +impl InsertFieldPayload { + pub fn new() -> InsertFieldPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // .Field field = 2; + + + pub fn get_field(&self) -> &Field { + self.field.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_field(&mut self) { + self.field.clear(); + } + + pub fn has_field(&self) -> bool { + self.field.is_some() + } + + // Param is passed by value, moved + pub fn set_field(&mut self, v: Field) { + self.field = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field(&mut self) -> &mut Field { + if self.field.is_none() { + self.field.set_default(); + } + self.field.as_mut().unwrap() + } + + // Take field + pub fn take_field(&mut self) -> Field { + self.field.take().unwrap_or_else(|| Field::new()) + } + + // bytes type_option_data = 3; + + + pub fn get_type_option_data(&self) -> &[u8] { + &self.type_option_data + } + pub fn clear_type_option_data(&mut self) { + self.type_option_data.clear(); + } + + // Param is passed by value, moved + pub fn set_type_option_data(&mut self, v: ::std::vec::Vec) { + self.type_option_data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_type_option_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.type_option_data + } + + // Take field + pub fn take_type_option_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.type_option_data, ::std::vec::Vec::new()) + } + + // string start_field_id = 4; + + + pub fn get_start_field_id(&self) -> &str { + match self.one_of_start_field_id { + ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(ref v)) => v, + _ => "", + } + } + pub fn clear_start_field_id(&mut self) { + self.one_of_start_field_id = ::std::option::Option::None; + } + + pub fn has_start_field_id(&self) -> bool { + match self.one_of_start_field_id { + ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_start_field_id(&mut self, v: ::std::string::String) { + self.one_of_start_field_id = ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(v)) + } + + // Mutable pointer to the field. + pub fn mut_start_field_id(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(_)) = self.one_of_start_field_id { + } else { + self.one_of_start_field_id = ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(::std::string::String::new())); + } + match self.one_of_start_field_id { + ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_start_field_id(&mut self) -> ::std::string::String { + if self.has_start_field_id() { + match self.one_of_start_field_id.take() { + ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } +} + +impl ::protobuf::Message for InsertFieldPayload { + fn is_initialized(&self) -> bool { + for v in &self.field { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.field)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_start_field_id = ::std::option::Option::Some(InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(is.read_string()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if let Some(ref v) = self.field.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if !self.type_option_data.is_empty() { + my_size += ::protobuf::rt::bytes_size(3, &self.type_option_data); + } + if let ::std::option::Option::Some(ref v) = self.one_of_start_field_id { + match v { + &InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(ref v) => { + my_size += ::protobuf::rt::string_size(4, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if let Some(ref v) = self.field.as_ref() { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if !self.type_option_data.is_empty() { + os.write_bytes(3, &self.type_option_data)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_start_field_id { + match v { + &InsertFieldPayload_oneof_one_of_start_field_id::start_field_id(ref v) => { + os.write_string(4, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> InsertFieldPayload { + InsertFieldPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &InsertFieldPayload| { &m.grid_id }, + |m: &mut InsertFieldPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "field", + |m: &InsertFieldPayload| { &m.field }, + |m: &mut InsertFieldPayload| { &mut m.field }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "type_option_data", + |m: &InsertFieldPayload| { &m.type_option_data }, + |m: &mut InsertFieldPayload| { &mut m.type_option_data }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "start_field_id", + InsertFieldPayload::has_start_field_id, + InsertFieldPayload::get_start_field_id, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "InsertFieldPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static InsertFieldPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(InsertFieldPayload::new) + } +} + +impl ::protobuf::Clear for InsertFieldPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.field.clear(); + self.type_option_data.clear(); + self.one_of_start_field_id = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for InsertFieldPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for InsertFieldPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct QueryFieldPayload { + // message fields + pub grid_id: ::std::string::String, + pub field_orders: ::protobuf::SingularPtrField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a QueryFieldPayload { + fn default() -> &'a QueryFieldPayload { + ::default_instance() + } +} + +impl QueryFieldPayload { + pub fn new() -> QueryFieldPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // .RepeatedFieldOrder field_orders = 2; + + + pub fn get_field_orders(&self) -> &RepeatedFieldOrder { + self.field_orders.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_field_orders(&mut self) { + self.field_orders.clear(); + } + + pub fn has_field_orders(&self) -> bool { + self.field_orders.is_some() + } + + // Param is passed by value, moved + pub fn set_field_orders(&mut self, v: RepeatedFieldOrder) { + self.field_orders = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_orders(&mut self) -> &mut RepeatedFieldOrder { + if self.field_orders.is_none() { + self.field_orders.set_default(); + } + self.field_orders.as_mut().unwrap() + } + + // Take field + pub fn take_field_orders(&mut self) -> RepeatedFieldOrder { + self.field_orders.take().unwrap_or_else(|| RepeatedFieldOrder::new()) + } +} + +impl ::protobuf::Message for QueryFieldPayload { + fn is_initialized(&self) -> bool { + for v in &self.field_orders { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.field_orders)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if let Some(ref v) = self.field_orders.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if let Some(ref v) = self.field_orders.as_ref() { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> QueryFieldPayload { + QueryFieldPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &QueryFieldPayload| { &m.grid_id }, + |m: &mut QueryFieldPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "field_orders", + |m: &QueryFieldPayload| { &m.field_orders }, + |m: &mut QueryFieldPayload| { &mut m.field_orders }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "QueryFieldPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static QueryFieldPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(QueryFieldPayload::new) + } +} + +impl ::protobuf::Clear for QueryFieldPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.field_orders.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for QueryFieldPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryFieldPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct QueryGridBlocksPayload { + // message fields + pub grid_id: ::std::string::String, + pub block_orders: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a QueryGridBlocksPayload { + fn default() -> &'a QueryGridBlocksPayload { + ::default_instance() + } +} + +impl QueryGridBlocksPayload { + pub fn new() -> QueryGridBlocksPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // repeated .GridBlockOrder block_orders = 2; + + + pub fn get_block_orders(&self) -> &[GridBlockOrder] { + &self.block_orders + } + pub fn clear_block_orders(&mut self) { + self.block_orders.clear(); + } + + // Param is passed by value, moved + pub fn set_block_orders(&mut self, v: ::protobuf::RepeatedField) { + self.block_orders = v; + } + + // Mutable pointer to the field. + pub fn mut_block_orders(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.block_orders + } + + // Take field + pub fn take_block_orders(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.block_orders, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for QueryGridBlocksPayload { + fn is_initialized(&self) -> bool { + for v in &self.block_orders { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.block_orders)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + for value in &self.block_orders { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + for v in &self.block_orders { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> QueryGridBlocksPayload { + QueryGridBlocksPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &QueryGridBlocksPayload| { &m.grid_id }, + |m: &mut QueryGridBlocksPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "block_orders", + |m: &QueryGridBlocksPayload| { &m.block_orders }, + |m: &mut QueryGridBlocksPayload| { &mut m.block_orders }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "QueryGridBlocksPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static QueryGridBlocksPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(QueryGridBlocksPayload::new) + } +} + +impl ::protobuf::Clear for QueryGridBlocksPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.block_orders.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for QueryGridBlocksPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for QueryGridBlocksPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct FieldChangesetPayload { + // message fields + pub field_id: ::std::string::String, + pub grid_id: ::std::string::String, + // message oneof groups + pub one_of_name: ::std::option::Option, + pub one_of_desc: ::std::option::Option, + pub one_of_field_type: ::std::option::Option, + pub one_of_frozen: ::std::option::Option, + pub one_of_visibility: ::std::option::Option, + pub one_of_width: ::std::option::Option, + pub one_of_type_option_data: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a FieldChangesetPayload { + fn default() -> &'a FieldChangesetPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_name { + name(::std::string::String), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_desc { + desc(::std::string::String), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_field_type { + field_type(FieldType), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_frozen { + frozen(bool), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_visibility { + visibility(bool), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_width { + width(i32), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum FieldChangesetPayload_oneof_one_of_type_option_data { + type_option_data(::std::vec::Vec), +} + +impl FieldChangesetPayload { + pub fn new() -> FieldChangesetPayload { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string grid_id = 2; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string name = 3; + + + pub fn get_name(&self) -> &str { + match self.one_of_name { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(ref v)) => v, + _ => "", + } + } + pub fn clear_name(&mut self) { + self.one_of_name = ::std::option::Option::None; + } + + pub fn has_name(&self) -> bool { + match self.one_of_name { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_name(&mut self, v: ::std::string::String) { + self.one_of_name = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(v)) + } + + // Mutable pointer to the field. + pub fn mut_name(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(_)) = self.one_of_name { + } else { + self.one_of_name = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(::std::string::String::new())); + } + match self.one_of_name { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_name(&mut self) -> ::std::string::String { + if self.has_name() { + match self.one_of_name.take() { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } + + // string desc = 4; + + + pub fn get_desc(&self) -> &str { + match self.one_of_desc { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(ref v)) => v, + _ => "", + } + } + pub fn clear_desc(&mut self) { + self.one_of_desc = ::std::option::Option::None; + } + + pub fn has_desc(&self) -> bool { + match self.one_of_desc { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_desc(&mut self, v: ::std::string::String) { + self.one_of_desc = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(v)) + } + + // Mutable pointer to the field. + pub fn mut_desc(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(_)) = self.one_of_desc { + } else { + self.one_of_desc = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(::std::string::String::new())); + } + match self.one_of_desc { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_desc(&mut self) -> ::std::string::String { + if self.has_desc() { + match self.one_of_desc.take() { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } + + // .FieldType field_type = 5; + + + pub fn get_field_type(&self) -> FieldType { + match self.one_of_field_type { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_field_type::field_type(v)) => v, + _ => FieldType::RichText, + } + } + pub fn clear_field_type(&mut self) { + self.one_of_field_type = ::std::option::Option::None; + } + + pub fn has_field_type(&self) -> bool { + match self.one_of_field_type { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_field_type::field_type(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_field_type(&mut self, v: FieldType) { + self.one_of_field_type = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_field_type::field_type(v)) + } + + // bool frozen = 6; + + + pub fn get_frozen(&self) -> bool { + match self.one_of_frozen { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_frozen::frozen(v)) => v, + _ => false, + } + } + pub fn clear_frozen(&mut self) { + self.one_of_frozen = ::std::option::Option::None; + } + + pub fn has_frozen(&self) -> bool { + match self.one_of_frozen { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_frozen::frozen(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_frozen(&mut self, v: bool) { + self.one_of_frozen = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_frozen::frozen(v)) + } + + // bool visibility = 7; + + + pub fn get_visibility(&self) -> bool { + match self.one_of_visibility { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_visibility::visibility(v)) => v, + _ => false, + } + } + pub fn clear_visibility(&mut self) { + self.one_of_visibility = ::std::option::Option::None; + } + + pub fn has_visibility(&self) -> bool { + match self.one_of_visibility { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_visibility::visibility(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_visibility(&mut self, v: bool) { + self.one_of_visibility = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_visibility::visibility(v)) + } + + // int32 width = 8; + + + pub fn get_width(&self) -> i32 { + match self.one_of_width { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_width::width(v)) => v, + _ => 0, + } + } + pub fn clear_width(&mut self) { + self.one_of_width = ::std::option::Option::None; + } + + pub fn has_width(&self) -> bool { + match self.one_of_width { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_width::width(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_width(&mut self, v: i32) { + self.one_of_width = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_width::width(v)) + } + + // bytes type_option_data = 9; + + + pub fn get_type_option_data(&self) -> &[u8] { + match self.one_of_type_option_data { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(ref v)) => v, + _ => &[], + } + } + pub fn clear_type_option_data(&mut self) { + self.one_of_type_option_data = ::std::option::Option::None; + } + + pub fn has_type_option_data(&self) -> bool { + match self.one_of_type_option_data { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_type_option_data(&mut self, v: ::std::vec::Vec) { + self.one_of_type_option_data = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(v)) + } + + // Mutable pointer to the field. + pub fn mut_type_option_data(&mut self) -> &mut ::std::vec::Vec { + if let ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(_)) = self.one_of_type_option_data { + } else { + self.one_of_type_option_data = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(::std::vec::Vec::new())); + } + match self.one_of_type_option_data { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_type_option_data(&mut self) -> ::std::vec::Vec { + if self.has_type_option_data() { + match self.one_of_type_option_data.take() { + ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(v)) => v, + _ => panic!(), + } + } else { + ::std::vec::Vec::new() + } + } +} + +impl ::protobuf::Message for FieldChangesetPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_name = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_name::name(is.read_string()?)); + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_desc = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_desc::desc(is.read_string()?)); + }, + 5 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_field_type = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_field_type::field_type(is.read_enum()?)); + }, + 6 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_frozen = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_frozen::frozen(is.read_bool()?)); + }, + 7 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_visibility = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_visibility::visibility(is.read_bool()?)); + }, + 8 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_width = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_width::width(is.read_int32()?)); + }, + 9 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_type_option_data = ::std::option::Option::Some(FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(is.read_bytes()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.grid_id); + } + if let ::std::option::Option::Some(ref v) = self.one_of_name { + match v { + &FieldChangesetPayload_oneof_one_of_name::name(ref v) => { + my_size += ::protobuf::rt::string_size(3, &v); + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_desc { + match v { + &FieldChangesetPayload_oneof_one_of_desc::desc(ref v) => { + my_size += ::protobuf::rt::string_size(4, &v); + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_field_type { + match v { + &FieldChangesetPayload_oneof_one_of_field_type::field_type(v) => { + my_size += ::protobuf::rt::enum_size(5, v); + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_frozen { + match v { + &FieldChangesetPayload_oneof_one_of_frozen::frozen(v) => { + my_size += 2; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_visibility { + match v { + &FieldChangesetPayload_oneof_one_of_visibility::visibility(v) => { + my_size += 2; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_width { + match v { + &FieldChangesetPayload_oneof_one_of_width::width(v) => { + my_size += ::protobuf::rt::value_size(8, v, ::protobuf::wire_format::WireTypeVarint); + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_type_option_data { + match v { + &FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(ref v) => { + my_size += ::protobuf::rt::bytes_size(9, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + if !self.grid_id.is_empty() { + os.write_string(2, &self.grid_id)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_name { + match v { + &FieldChangesetPayload_oneof_one_of_name::name(ref v) => { + os.write_string(3, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_desc { + match v { + &FieldChangesetPayload_oneof_one_of_desc::desc(ref v) => { + os.write_string(4, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_field_type { + match v { + &FieldChangesetPayload_oneof_one_of_field_type::field_type(v) => { + os.write_enum(5, ::protobuf::ProtobufEnum::value(&v))?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_frozen { + match v { + &FieldChangesetPayload_oneof_one_of_frozen::frozen(v) => { + os.write_bool(6, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_visibility { + match v { + &FieldChangesetPayload_oneof_one_of_visibility::visibility(v) => { + os.write_bool(7, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_width { + match v { + &FieldChangesetPayload_oneof_one_of_width::width(v) => { + os.write_int32(8, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_type_option_data { + match v { + &FieldChangesetPayload_oneof_one_of_type_option_data::type_option_data(ref v) => { + os.write_bytes(9, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> FieldChangesetPayload { + FieldChangesetPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &FieldChangesetPayload| { &m.field_id }, + |m: &mut FieldChangesetPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &FieldChangesetPayload| { &m.grid_id }, + |m: &mut FieldChangesetPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "name", + FieldChangesetPayload::has_name, + FieldChangesetPayload::get_name, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "desc", + FieldChangesetPayload::has_desc, + FieldChangesetPayload::get_desc, + )); + fields.push(::protobuf::reflect::accessor::make_singular_enum_accessor::<_, FieldType>( + "field_type", + FieldChangesetPayload::has_field_type, + FieldChangesetPayload::get_field_type, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bool_accessor::<_>( + "frozen", + FieldChangesetPayload::has_frozen, + FieldChangesetPayload::get_frozen, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bool_accessor::<_>( + "visibility", + FieldChangesetPayload::has_visibility, + FieldChangesetPayload::get_visibility, + )); + fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>( + "width", + FieldChangesetPayload::has_width, + FieldChangesetPayload::get_width, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor::<_>( + "type_option_data", + FieldChangesetPayload::has_type_option_data, + FieldChangesetPayload::get_type_option_data, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "FieldChangesetPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static FieldChangesetPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(FieldChangesetPayload::new) + } +} + +impl ::protobuf::Clear for FieldChangesetPayload { + fn clear(&mut self) { + self.field_id.clear(); + self.grid_id.clear(); + self.one_of_name = ::std::option::Option::None; + self.one_of_desc = ::std::option::Option::None; + self.one_of_field_type = ::std::option::Option::None; + self.one_of_frozen = ::std::option::Option::None; + self.one_of_visibility = ::std::option::Option::None; + self.one_of_width = ::std::option::Option::None; + self.one_of_type_option_data = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for FieldChangesetPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldChangesetPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct MoveItemPayload { + // message fields + pub grid_id: ::std::string::String, + pub item_id: ::std::string::String, + pub from_index: i32, + pub to_index: i32, + pub ty: MoveItemType, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a MoveItemPayload { + fn default() -> &'a MoveItemPayload { + ::default_instance() + } +} + +impl MoveItemPayload { + pub fn new() -> MoveItemPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string item_id = 2; + + + pub fn get_item_id(&self) -> &str { + &self.item_id + } + pub fn clear_item_id(&mut self) { + self.item_id.clear(); + } + + // Param is passed by value, moved + pub fn set_item_id(&mut self, v: ::std::string::String) { + self.item_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_item_id(&mut self) -> &mut ::std::string::String { + &mut self.item_id + } + + // Take field + pub fn take_item_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.item_id, ::std::string::String::new()) + } + + // int32 from_index = 3; + + + pub fn get_from_index(&self) -> i32 { + self.from_index + } + pub fn clear_from_index(&mut self) { + self.from_index = 0; + } + + // Param is passed by value, moved + pub fn set_from_index(&mut self, v: i32) { + self.from_index = v; + } + + // int32 to_index = 4; + + + pub fn get_to_index(&self) -> i32 { + self.to_index + } + pub fn clear_to_index(&mut self) { + self.to_index = 0; + } + + // Param is passed by value, moved + pub fn set_to_index(&mut self, v: i32) { + self.to_index = v; + } + + // .MoveItemType ty = 5; + + + pub fn get_ty(&self) -> MoveItemType { + self.ty + } + pub fn clear_ty(&mut self) { + self.ty = MoveItemType::MoveField; + } + + // Param is passed by value, moved + pub fn set_ty(&mut self, v: MoveItemType) { + self.ty = v; + } +} + +impl ::protobuf::Message for MoveItemPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.item_id)?; + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.from_index = tmp; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.to_index = tmp; + }, + 5 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 5, &mut self.unknown_fields)? + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.item_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.item_id); + } + if self.from_index != 0 { + my_size += ::protobuf::rt::value_size(3, self.from_index, ::protobuf::wire_format::WireTypeVarint); + } + if self.to_index != 0 { + my_size += ::protobuf::rt::value_size(4, self.to_index, ::protobuf::wire_format::WireTypeVarint); + } + if self.ty != MoveItemType::MoveField { + my_size += ::protobuf::rt::enum_size(5, self.ty); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.item_id.is_empty() { + os.write_string(2, &self.item_id)?; + } + if self.from_index != 0 { + os.write_int32(3, self.from_index)?; + } + if self.to_index != 0 { + os.write_int32(4, self.to_index)?; + } + if self.ty != MoveItemType::MoveField { + os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.ty))?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> MoveItemPayload { + MoveItemPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &MoveItemPayload| { &m.grid_id }, + |m: &mut MoveItemPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "item_id", + |m: &MoveItemPayload| { &m.item_id }, + |m: &mut MoveItemPayload| { &mut m.item_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "from_index", + |m: &MoveItemPayload| { &m.from_index }, + |m: &mut MoveItemPayload| { &mut m.from_index }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "to_index", + |m: &MoveItemPayload| { &m.to_index }, + |m: &mut MoveItemPayload| { &mut m.to_index }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "ty", + |m: &MoveItemPayload| { &m.ty }, + |m: &mut MoveItemPayload| { &mut m.ty }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "MoveItemPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static MoveItemPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(MoveItemPayload::new) + } +} + +impl ::protobuf::Clear for MoveItemPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.item_id.clear(); + self.from_index = 0; + self.to_index = 0; + self.ty = MoveItemType::MoveField; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for MoveItemPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for MoveItemPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct CellChangeset { + // message fields + pub grid_id: ::std::string::String, + pub row_id: ::std::string::String, + pub field_id: ::std::string::String, + // message oneof groups + pub one_of_data: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CellChangeset { + fn default() -> &'a CellChangeset { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum CellChangeset_oneof_one_of_data { + data(::std::string::String), +} + +impl CellChangeset { + pub fn new() -> CellChangeset { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string row_id = 2; + + + pub fn get_row_id(&self) -> &str { + &self.row_id + } + pub fn clear_row_id(&mut self) { + self.row_id.clear(); + } + + // Param is passed by value, moved + pub fn set_row_id(&mut self, v: ::std::string::String) { + self.row_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_id(&mut self) -> &mut ::std::string::String { + &mut self.row_id + } + + // Take field + pub fn take_row_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) + } + + // string field_id = 3; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string data = 4; + + + pub fn get_data(&self) -> &str { + match self.one_of_data { + ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(ref v)) => v, + _ => "", + } + } + pub fn clear_data(&mut self) { + self.one_of_data = ::std::option::Option::None; + } + + pub fn has_data(&self) -> bool { + match self.one_of_data { + ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_data(&mut self, v: ::std::string::String) { + self.one_of_data = ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(v)) + } + + // Mutable pointer to the field. + pub fn mut_data(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(_)) = self.one_of_data { + } else { + self.one_of_data = ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(::std::string::String::new())); + } + match self.one_of_data { + ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_data(&mut self) -> ::std::string::String { + if self.has_data() { + match self.one_of_data.take() { + ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } +} + +impl ::protobuf::Message for CellChangeset { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_data = ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(is.read_string()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.row_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.row_id); + } + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.field_id); + } + if let ::std::option::Option::Some(ref v) = self.one_of_data { + match v { + &CellChangeset_oneof_one_of_data::data(ref v) => { + my_size += ::protobuf::rt::string_size(4, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.row_id.is_empty() { + os.write_string(2, &self.row_id)?; + } + if !self.field_id.is_empty() { + os.write_string(3, &self.field_id)?; + } + if let ::std::option::Option::Some(ref v) = self.one_of_data { + match v { + &CellChangeset_oneof_one_of_data::data(ref v) => { + os.write_string(4, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> CellChangeset { + CellChangeset::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &CellChangeset| { &m.grid_id }, + |m: &mut CellChangeset| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "row_id", + |m: &CellChangeset| { &m.row_id }, + |m: &mut CellChangeset| { &mut m.row_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &CellChangeset| { &m.field_id }, + |m: &mut CellChangeset| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "data", + CellChangeset::has_data, + CellChangeset::get_data, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CellChangeset", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CellChangeset { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CellChangeset::new) + } +} + +impl ::protobuf::Clear for CellChangeset { + fn clear(&mut self) { + self.grid_id.clear(); + self.row_id.clear(); + self.field_id.clear(); + self.one_of_data = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CellChangeset { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CellChangeset { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum MoveItemType { + MoveField = 0, + MoveRow = 1, +} + +impl ::protobuf::ProtobufEnum for MoveItemType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(MoveItemType::MoveField), + 1 => ::std::option::Option::Some(MoveItemType::MoveRow), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [MoveItemType] = &[ + MoveItemType::MoveField, + MoveItemType::MoveRow, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("MoveItemType", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for MoveItemType { +} + +impl ::std::default::Default for MoveItemType { + fn default() -> Self { + MoveItemType::MoveField + } +} + +impl ::protobuf::reflect::ProtobufValue for MoveItemType { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum FieldType { + RichText = 0, + Number = 1, + DateTime = 2, + SingleSelect = 3, + MultiSelect = 4, + Checkbox = 5, +} + +impl ::protobuf::ProtobufEnum for FieldType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(FieldType::RichText), + 1 => ::std::option::Option::Some(FieldType::Number), + 2 => ::std::option::Option::Some(FieldType::DateTime), + 3 => ::std::option::Option::Some(FieldType::SingleSelect), + 4 => ::std::option::Option::Some(FieldType::MultiSelect), + 5 => ::std::option::Option::Some(FieldType::Checkbox), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [FieldType] = &[ + FieldType::RichText, + FieldType::Number, + FieldType::DateTime, + FieldType::SingleSelect, + FieldType::MultiSelect, + FieldType::Checkbox, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("FieldType", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for FieldType { +} + +impl ::std::default::Default for FieldType { + fn default() -> Self { + FieldType::RichText + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldType { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\ngrid.proto\"z\n\x04Grid\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\ + \x12.\n\x0cfield_orders\x18\x02\x20\x03(\x0b2\x0b.FieldOrderR\x0bfieldOr\ + ders\x122\n\x0cblock_orders\x18\x03\x20\x03(\x0b2\x0f.GridBlockOrderR\ + \x0bblockOrders\"\xd7\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\ + \x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\ + \x18\x03\x20\x01(\tR\x04desc\x12)\n\nfield_type\x18\x04\x20\x01(\x0e2\n.\ + FieldTypeR\tfieldType\x12\x16\n\x06frozen\x18\x05\x20\x01(\x08R\x06froze\ + n\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\nvisibility\x12\x14\n\x05w\ + idth\x18\x07\x20\x01(\x05R\x05width\x12\x1d\n\nis_primary\x18\x08\x20\ + \x01(\x08R\tisPrimary\"'\n\nFieldOrder\x12\x19\n\x08field_id\x18\x01\x20\ + \x01(\tR\x07fieldId\"\xc6\x01\n\x12GridFieldChangeset\x12\x17\n\x07grid_\ + id\x18\x01\x20\x01(\tR\x06gridId\x124\n\x0finserted_fields\x18\x02\x20\ + \x03(\x0b2\x0b.IndexFieldR\x0einsertedFields\x122\n\x0edeleted_fields\ + \x18\x03\x20\x03(\x0b2\x0b.FieldOrderR\rdeletedFields\x12-\n\x0eupdated_\ + fields\x18\x04\x20\x03(\x0b2\x06.FieldR\rupdatedFields\"@\n\nIndexField\ + \x12\x1c\n\x05field\x18\x01\x20\x01(\x0b2\x06.FieldR\x05field\x12\x14\n\ + \x05index\x18\x02\x20\x01(\x05R\x05index\"\x90\x01\n\x1aGetEditFieldCont\ + extPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1b\n\ + \x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_type\x18\ + \x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"q\ + \n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridI\ + d\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\nfield_typ\ + e\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFieldContext\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\ + \x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_option_data\ + \x18\x03\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\x1c\n\ + \x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFiel\ + dOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\ + \n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\ + \n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06height\x18\ + \x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\ + \x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.\ + Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\x20\ + \x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\ + \x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.Cel\ + lR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\ + \x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05item\ + s\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\x12\ + \x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\ + \x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\tro\ + w_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05index\ + \x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"\xbf\x01\n\ + \x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07block\ + Id\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cins\ + ertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bde\ + letedRows\x12,\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bup\ + datedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\ + \n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\ + \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07conte\ + nt\x18\x02\x20\x01(\tR\x07content\"\x8f\x01\n\x14CellNotificationData\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_i\ + d\x18\x02\x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\ + \x05rowId\x12\x1a\n\x07content\x18\x04\x20\x01(\tH\0R\x07contentB\x10\n\ + \x0eone_of_content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\ + \x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04nam\ + e\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\ + \x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\ + \x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0\ + R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12InsertFieldPa\ + yload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05fi\ + eld\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\ + \x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\ + \x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\ + \x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ + \x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\ + \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\ + \x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\ + \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ + id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\ + R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\ + ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\ + frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\ + \x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\ + \x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\ + \x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\ + _of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\ + \x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\ + emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\ + \x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\ + \x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\ + \x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\ + \"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\ + Id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_i\ + d\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0\ + R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\ + \0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\ + \0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0c\ + SingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Check\ + box\x10\x05b\x06proto3\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) +} diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/mod.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/mod.rs new file mode 100644 index 0000000000..7b56c6cee8 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/mod.rs @@ -0,0 +1,5 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +// Auto-generated, do not edit + +mod grid; +pub use grid::*; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto new file mode 100644 index 0000000000..2d6dbecfe4 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -0,0 +1,161 @@ +syntax = "proto3"; + +message Grid { + string id = 1; + repeated FieldOrder field_orders = 2; + repeated GridBlockOrder block_orders = 3; +} +message Field { + string id = 1; + string name = 2; + string desc = 3; + FieldType field_type = 4; + bool frozen = 5; + bool visibility = 6; + int32 width = 7; + bool is_primary = 8; +} +message FieldOrder { + string field_id = 1; +} +message GridFieldChangeset { + string grid_id = 1; + repeated IndexField inserted_fields = 2; + repeated FieldOrder deleted_fields = 3; + repeated Field updated_fields = 4; +} +message IndexField { + Field field = 1; + int32 index = 2; +} +message GetEditFieldContextPayload { + string grid_id = 1; + oneof one_of_field_id { string field_id = 2; }; + FieldType field_type = 3; +} +message EditFieldPayload { + string grid_id = 1; + string field_id = 2; + FieldType field_type = 3; +} +message EditFieldContext { + string grid_id = 1; + Field grid_field = 2; + bytes type_option_data = 3; +} +message RepeatedField { + repeated Field items = 1; +} +message RepeatedFieldOrder { + repeated FieldOrder items = 1; +} +message RowOrder { + string row_id = 1; + string block_id = 2; + int32 height = 3; +} +message Row { + string id = 1; + map cell_by_field_id = 2; + int32 height = 3; +} +message RepeatedRow { + repeated Row items = 1; +} +message RepeatedGridBlock { + repeated GridBlock items = 1; +} +message GridBlockOrder { + string block_id = 1; + repeated RowOrder row_orders = 2; +} +message IndexRowOrder { + RowOrder row_order = 1; + oneof one_of_index { int32 index = 2; }; +} +message GridRowsChangeset { + string block_id = 1; + repeated IndexRowOrder inserted_rows = 2; + repeated RowOrder deleted_rows = 3; + repeated RowOrder updated_rows = 4; +} +message GridBlock { + string id = 1; + repeated RowOrder row_orders = 2; +} +message Cell { + string field_id = 1; + string content = 2; +} +message CellNotificationData { + string grid_id = 1; + string field_id = 2; + string row_id = 3; + oneof one_of_content { string content = 4; }; +} +message RepeatedCell { + repeated Cell items = 1; +} +message CreateGridPayload { + string name = 1; +} +message GridId { + string value = 1; +} +message GridBlockId { + string value = 1; +} +message CreateRowPayload { + string grid_id = 1; + oneof one_of_start_row_id { string start_row_id = 2; }; +} +message InsertFieldPayload { + string grid_id = 1; + Field field = 2; + bytes type_option_data = 3; + oneof one_of_start_field_id { string start_field_id = 4; }; +} +message QueryFieldPayload { + string grid_id = 1; + RepeatedFieldOrder field_orders = 2; +} +message QueryGridBlocksPayload { + string grid_id = 1; + repeated GridBlockOrder block_orders = 2; +} +message FieldChangesetPayload { + string field_id = 1; + string grid_id = 2; + oneof one_of_name { string name = 3; }; + oneof one_of_desc { string desc = 4; }; + oneof one_of_field_type { FieldType field_type = 5; }; + oneof one_of_frozen { bool frozen = 6; }; + oneof one_of_visibility { bool visibility = 7; }; + oneof one_of_width { int32 width = 8; }; + oneof one_of_type_option_data { bytes type_option_data = 9; }; +} +message MoveItemPayload { + string grid_id = 1; + string item_id = 2; + int32 from_index = 3; + int32 to_index = 4; + MoveItemType ty = 5; +} +message CellChangeset { + string grid_id = 1; + string row_id = 2; + string field_id = 3; + oneof one_of_data { string data = 4; }; +} +enum MoveItemType { + MoveField = 0; + MoveRow = 1; +} +enum FieldType { + RichText = 0; + Number = 1; + DateTime = 2; + SingleSelect = 3; + MultiSelect = 4; + Checkbox = 5; +} diff --git a/shared-lib/flowy-grid-data-model/tests/serde_test.rs b/shared-lib/flowy-grid-data-model/tests/serde_test.rs new file mode 100644 index 0000000000..22d4b92a6d --- /dev/null +++ b/shared-lib/flowy-grid-data-model/tests/serde_test.rs @@ -0,0 +1,14 @@ +use flowy_grid_data_model::entities::*; + +#[test] +fn grid_default_serde_test() { + let grid_id = "1".to_owned(); + let grid = GridMeta { + grid_id, + fields: vec![], + blocks: vec![], + }; + + let json = serde_json::to_string(&grid).unwrap(); + assert_eq!(json, r#"{"grid_id":"1","fields":[],"blocks":[]}"#) +} diff --git a/shared-lib/flowy-collaboration/Cargo.toml b/shared-lib/flowy-sync/Cargo.toml similarity index 91% rename from shared-lib/flowy-collaboration/Cargo.toml rename to shared-lib/flowy-sync/Cargo.toml index 3afb107b70..6c66a21999 100644 --- a/shared-lib/flowy-collaboration/Cargo.toml +++ b/shared-lib/flowy-sync/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "flowy-collaboration" +name = "flowy-sync" version = "0.1.0" edition = "2018" @@ -10,6 +10,7 @@ lib-ot = { path = "../lib-ot" } lib-infra = { path = "../lib-infra" } flowy-derive = { path = "../flowy-derive" } flowy-folder-data-model = { path = "../flowy-folder-data-model" } +flowy-grid-data-model = { path = "../flowy-grid-data-model" } protobuf = {version = "2.18.0"} bytes = "1.0" log = "0.4.14" diff --git a/shared-lib/flowy-collaboration/Flowy.toml b/shared-lib/flowy-sync/Flowy.toml similarity index 100% rename from shared-lib/flowy-collaboration/Flowy.toml rename to shared-lib/flowy-sync/Flowy.toml diff --git a/shared-lib/flowy-sync/build.rs b/shared-lib/flowy-sync/build.rs new file mode 100644 index 0000000000..7f06ab48c8 --- /dev/null +++ b/shared-lib/flowy-sync/build.rs @@ -0,0 +1,5 @@ +use lib_infra::code_gen; + +fn main() { + code_gen::protobuf_file::gen(env!("CARGO_PKG_NAME"), "./src/protobuf/proto"); +} diff --git a/shared-lib/flowy-collaboration/src/READ_ME.json b/shared-lib/flowy-sync/src/READ_ME.json similarity index 55% rename from shared-lib/flowy-collaboration/src/READ_ME.json rename to shared-lib/flowy-sync/src/READ_ME.json index bb53eff10e..624802720c 100644 --- a/shared-lib/flowy-collaboration/src/READ_ME.json +++ b/shared-lib/flowy-sync/src/READ_ME.json @@ -1 +1 @@ -[{"insert":"\n👋 Welcome to AppFlowy!"},{"insert":"\n","attributes":{"header":1}},{"insert":"\nHere are the basics"},{"insert":"\n","attributes":{"header":2}},{"insert":"Click anywhere and just start typing"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Highlight","attributes":{"background":"#fff2cd"}},{"insert":" any text, and use the menu at the bottom to "},{"insert":"style","attributes":{"italic":true}},{"insert":" "},{"insert":"your","attributes":{"bold":true}},{"insert":" "},{"insert":"writing","attributes":{"underline":true}},{"insert":" "},{"insert":"however","attributes":{"code":true}},{"insert":" "},{"insert":"you","attributes":{"strike":true}},{"insert":" "},{"insert":"like","attributes":{"background":"#e8e0ff"}},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click "},{"insert":"+ New Page","attributes":{"background":"#defff1","bold":true}},{"insert":" button at the bottom of your sidebar to add a new page"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click the "},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":"+'","attributes":{"background":"#defff1","bold":true}},{"insert":" next to any page title in the sidebar to quickly add a new subpage"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\nHave a question? "},{"insert":"\n","attributes":{"header":2}},{"insert":"Click the "},{"insert":"'?'","attributes":{"background":"#defff1","bold":true}},{"insert":" at the bottom right for help and support.\n\nLike AppFlowy? Follow us:"},{"insert":"\n","attributes":{"header":2}},{"insert":"GitHub: https://github.com/AppFlowy-IO/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Twitter: https://twitter.com/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Newsletter: https://www.appflowy.io/blog"},{"insert":"\n","attributes":{"blockquote":true}}] \ No newline at end of file +[{"insert":"\n👋 Welcome to AppFlowy!"},{"insert":"\n","attributes":{"header":1}},{"insert":"\nHere are the basics"},{"insert":"\n","attributes":{"header":2}},{"insert":"Click anywhere and just start typing"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Highlight","attributes":{"background":"#fff2cd"}},{"insert":" any text, and use the menu at the bottom to "},{"insert":"style","attributes":{"italic":true}},{"insert":" "},{"insert":"your","attributes":{"bold":true}},{"insert":" "},{"insert":"writing","attributes":{"underline":true}},{"insert":" "},{"insert":"however","attributes":{"code":true}},{"insert":" "},{"insert":"you","attributes":{"strike":true}},{"insert":" "},{"insert":"like","attributes":{"background":"#e8e0ff"}},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click "},{"insert":"+ New Page","attributes":{"background":"#defff1","bold":true}},{"insert":" button at the bottom of your sidebar to add a new page"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click the "},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":"+","attributes":{"background":"#defff1","bold":true}},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":" next to any page title in the sidebar to quickly add a new subpage"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\nHave a question? "},{"insert":"\n","attributes":{"header":2}},{"insert":"Click the "},{"insert":"'?'","attributes":{"background":"#defff1","bold":true}},{"insert":" at the bottom right for help and support.\n\nLike AppFlowy? Follow us:"},{"insert":"\n","attributes":{"header":2}},{"insert":"GitHub: https://github.com/AppFlowy-IO/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Twitter: https://twitter.com/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Newsletter: https://www.appflowy.io/blog"},{"insert":"\n","attributes":{"blockquote":true}}] \ No newline at end of file diff --git a/shared-lib/flowy-collaboration/src/client_document/data.rs b/shared-lib/flowy-sync/src/client_document/data.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/data.rs rename to shared-lib/flowy-sync/src/client_document/data.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/default/READ_ME.json b/shared-lib/flowy-sync/src/client_document/default/READ_ME.json similarity index 55% rename from shared-lib/flowy-collaboration/src/client_document/default/READ_ME.json rename to shared-lib/flowy-sync/src/client_document/default/READ_ME.json index bb53eff10e..624802720c 100644 --- a/shared-lib/flowy-collaboration/src/client_document/default/READ_ME.json +++ b/shared-lib/flowy-sync/src/client_document/default/READ_ME.json @@ -1 +1 @@ -[{"insert":"\n👋 Welcome to AppFlowy!"},{"insert":"\n","attributes":{"header":1}},{"insert":"\nHere are the basics"},{"insert":"\n","attributes":{"header":2}},{"insert":"Click anywhere and just start typing"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Highlight","attributes":{"background":"#fff2cd"}},{"insert":" any text, and use the menu at the bottom to "},{"insert":"style","attributes":{"italic":true}},{"insert":" "},{"insert":"your","attributes":{"bold":true}},{"insert":" "},{"insert":"writing","attributes":{"underline":true}},{"insert":" "},{"insert":"however","attributes":{"code":true}},{"insert":" "},{"insert":"you","attributes":{"strike":true}},{"insert":" "},{"insert":"like","attributes":{"background":"#e8e0ff"}},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click "},{"insert":"+ New Page","attributes":{"background":"#defff1","bold":true}},{"insert":" button at the bottom of your sidebar to add a new page"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click the "},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":"+'","attributes":{"background":"#defff1","bold":true}},{"insert":" next to any page title in the sidebar to quickly add a new subpage"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\nHave a question? "},{"insert":"\n","attributes":{"header":2}},{"insert":"Click the "},{"insert":"'?'","attributes":{"background":"#defff1","bold":true}},{"insert":" at the bottom right for help and support.\n\nLike AppFlowy? Follow us:"},{"insert":"\n","attributes":{"header":2}},{"insert":"GitHub: https://github.com/AppFlowy-IO/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Twitter: https://twitter.com/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Newsletter: https://www.appflowy.io/blog"},{"insert":"\n","attributes":{"blockquote":true}}] \ No newline at end of file +[{"insert":"\n👋 Welcome to AppFlowy!"},{"insert":"\n","attributes":{"header":1}},{"insert":"\nHere are the basics"},{"insert":"\n","attributes":{"header":2}},{"insert":"Click anywhere and just start typing"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Highlight","attributes":{"background":"#fff2cd"}},{"insert":" any text, and use the menu at the bottom to "},{"insert":"style","attributes":{"italic":true}},{"insert":" "},{"insert":"your","attributes":{"bold":true}},{"insert":" "},{"insert":"writing","attributes":{"underline":true}},{"insert":" "},{"insert":"however","attributes":{"code":true}},{"insert":" "},{"insert":"you","attributes":{"strike":true}},{"insert":" "},{"insert":"like","attributes":{"background":"#e8e0ff"}},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click "},{"insert":"+ New Page","attributes":{"background":"#defff1","bold":true}},{"insert":" button at the bottom of your sidebar to add a new page"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"Click the "},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":"+","attributes":{"background":"#defff1","bold":true}},{"insert":"'","attributes":{"background":"#defff1"}},{"insert":" next to any page title in the sidebar to quickly add a new subpage"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\nHave a question? "},{"insert":"\n","attributes":{"header":2}},{"insert":"Click the "},{"insert":"'?'","attributes":{"background":"#defff1","bold":true}},{"insert":" at the bottom right for help and support.\n\nLike AppFlowy? Follow us:"},{"insert":"\n","attributes":{"header":2}},{"insert":"GitHub: https://github.com/AppFlowy-IO/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Twitter: https://twitter.com/appflowy"},{"insert":"\n","attributes":{"blockquote":true}},{"insert":"Newsletter: https://www.appflowy.io/blog"},{"insert":"\n","attributes":{"blockquote":true}}] \ No newline at end of file diff --git a/shared-lib/flowy-collaboration/src/client_document/default/mod.rs b/shared-lib/flowy-sync/src/client_document/default/mod.rs similarity index 59% rename from shared-lib/flowy-collaboration/src/client_document/default/mod.rs rename to shared-lib/flowy-sync/src/client_document/default/mod.rs index 35f674e41d..f5fb180571 100644 --- a/shared-lib/flowy-collaboration/src/client_document/default/mod.rs +++ b/shared-lib/flowy-sync/src/client_document/default/mod.rs @@ -1,19 +1,19 @@ use lib_ot::{core::DeltaBuilder, rich_text::RichTextDelta}; #[inline] -pub fn initial_delta() -> RichTextDelta { +pub fn initial_quill_delta() -> RichTextDelta { DeltaBuilder::new().insert("\n").build() } #[inline] -pub fn initial_delta_string() -> String { - initial_delta().to_delta_json() +pub fn initial_quill_delta_string() -> String { + initial_quill_delta().to_delta_str() } #[inline] pub fn initial_read_me() -> RichTextDelta { let json = include_str!("READ_ME.json"); - RichTextDelta::from_json(json).unwrap() + RichTextDelta::from_delta_str(json).unwrap() } #[cfg(test)] @@ -22,6 +22,6 @@ mod tests { #[test] fn load_read_me() { - println!("{}", initial_read_me().to_delta_json()); + println!("{}", initial_read_me().to_delta_str()); } } diff --git a/shared-lib/flowy-collaboration/src/client_document/document_pad.rs b/shared-lib/flowy-sync/src/client_document/document_pad.rs similarity index 93% rename from shared-lib/flowy-collaboration/src/client_document/document_pad.rs rename to shared-lib/flowy-sync/src/client_document/document_pad.rs index 99a86769ce..72b52f6415 100644 --- a/shared-lib/flowy-collaboration/src/client_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/client_document/document_pad.rs @@ -1,11 +1,12 @@ use crate::{ client_document::{ - default::initial_delta, + default::initial_quill_delta, history::{History, UndoResult}, view::{ViewExtensions, RECORD_THRESHOLD}, }, errors::CollaborateError, }; +use bytes::Bytes; use lib_ot::{ core::*, rich_text::{RichTextAttribute, RichTextDelta}, @@ -26,7 +27,7 @@ impl InitialDocumentText for PlainDoc { pub struct NewlineDoc(); impl InitialDocumentText for NewlineDoc { fn initial_delta() -> RichTextDelta { - initial_delta() + initial_quill_delta() } } @@ -54,16 +55,16 @@ impl ClientDocument { } pub fn from_json(json: &str) -> Result { - let delta = RichTextDelta::from_json(json)?; + let delta = RichTextDelta::from_delta_str(json)?; Ok(Self::from_delta(delta)) } - pub fn to_json(&self) -> String { - self.delta.to_delta_json() + pub fn delta_str(&self) -> String { + self.delta.to_delta_str() } - pub fn to_bytes(&self) -> Vec { - self.delta.clone().to_bytes().to_vec() + pub fn to_bytes(&self) -> Bytes { + self.delta.to_delta_bytes() } pub fn to_plain_string(&self) -> String { @@ -84,7 +85,7 @@ impl ClientDocument { } pub fn set_delta(&mut self, data: RichTextDelta) { - tracing::trace!("document: {}", data.to_delta_json()); + tracing::trace!("document: {}", data.to_delta_str()); self.delta = data; match &self.notify { @@ -96,7 +97,7 @@ impl ClientDocument { } pub fn compose_delta(&mut self, delta: RichTextDelta) -> Result<(), CollaborateError> { - tracing::trace!("{} compose {}", &self.delta.to_delta_json(), delta.to_delta_json()); + tracing::trace!("{} compose {}", &self.delta.to_delta_str(), delta.to_delta_str()); let composed_delta = self.delta.compose(&delta)?; let mut undo_delta = delta.invert(&self.delta); diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/delete/default_delete.rs b/shared-lib/flowy-sync/src/client_document/extensions/delete/default_delete.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/delete/default_delete.rs rename to shared-lib/flowy-sync/src/client_document/extensions/delete/default_delete.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/delete/mod.rs b/shared-lib/flowy-sync/src/client_document/extensions/delete/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/delete/mod.rs rename to shared-lib/flowy-sync/src/client_document/extensions/delete/mod.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/delete/preserve_line_format_merge.rs b/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/delete/preserve_line_format_merge.rs rename to shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/format/format_at_position.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/format_at_position.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/format/format_at_position.rs rename to shared-lib/flowy-sync/src/client_document/extensions/format/format_at_position.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/format/mod.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/format/mod.rs rename to shared-lib/flowy-sync/src/client_document/extensions/format/mod.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/format/resolve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/format/resolve_block_format.rs rename to shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/format/resolve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/format/resolve_inline_format.rs rename to shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/helper.rs b/shared-lib/flowy-sync/src/client_document/extensions/helper.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/helper.rs rename to shared-lib/flowy-sync/src/client_document/extensions/helper.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/auto_exit_block.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/auto_exit_block.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/auto_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/auto_format.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/default_insert.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/default_insert.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/mod.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/mod.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/mod.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/preserve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/preserve_block_format.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/preserve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/preserve_inline_format.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/insert/reset_format_on_new_line.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/insert/reset_format_on_new_line.rs rename to shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/extensions/mod.rs b/shared-lib/flowy-sync/src/client_document/extensions/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/extensions/mod.rs rename to shared-lib/flowy-sync/src/client_document/extensions/mod.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/history.rs b/shared-lib/flowy-sync/src/client_document/history.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/history.rs rename to shared-lib/flowy-sync/src/client_document/history.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/mod.rs b/shared-lib/flowy-sync/src/client_document/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/mod.rs rename to shared-lib/flowy-sync/src/client_document/mod.rs diff --git a/shared-lib/flowy-collaboration/src/client_document/view.rs b/shared-lib/flowy-sync/src/client_document/view.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_document/view.rs rename to shared-lib/flowy-sync/src/client_document/view.rs diff --git a/shared-lib/flowy-collaboration/src/client_folder/builder.rs b/shared-lib/flowy-sync/src/client_folder/builder.rs similarity index 87% rename from shared-lib/flowy-collaboration/src/client_folder/builder.rs rename to shared-lib/flowy-sync/src/client_folder/builder.rs index c77c6ecf04..22174de348 100644 --- a/shared-lib/flowy-collaboration/src/client_folder/builder.rs +++ b/shared-lib/flowy-sync/src/client_folder/builder.rs @@ -41,10 +41,9 @@ impl FolderPadBuilder { // TODO: Reconvert from history if delta.to_str() failed. let folder_json = delta.to_str()?; - let mut folder: FolderPad = serde_json::from_str(&folder_json).map_err(|e| { - CollaborateError::internal().context(format!("Deserialize json to root folder failed: {}", e)) - })?; - folder.root = delta; + let mut folder: FolderPad = serde_json::from_str(&folder_json) + .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e)))?; + folder.delta = delta; Ok(folder) } @@ -55,11 +54,11 @@ impl FolderPadBuilder { pub(crate) fn build(self) -> CollaborateResult { let json = serde_json::to_string(&self) - .map_err(|e| CollaborateError::internal().context(format!("serial trash to json failed: {}", e)))?; + .map_err(|e| CollaborateError::internal().context(format!("Serialize to folder json str failed: {}", e)))?; Ok(FolderPad { workspaces: self.workspaces, trash: self.trash, - root: PlainTextDeltaBuilder::new().insert(&json).build(), + delta: PlainTextDeltaBuilder::new().insert(&json).build(), }) } } diff --git a/shared-lib/flowy-collaboration/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs similarity index 94% rename from shared-lib/flowy-collaboration/src/client_folder/folder_pad.rs rename to shared-lib/flowy-sync/src/client_folder/folder_pad.rs index 4ce5a11c68..fd79fb8af0 100644 --- a/shared-lib/flowy-collaboration/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -1,3 +1,4 @@ +use crate::util::cal_diff; use crate::{ client_folder::builder::FolderPadBuilder, entities::{ @@ -6,9 +7,9 @@ use crate::{ }, errors::{CollaborateError, CollaborateResult}, }; -use dissimilar::*; use flowy_folder_data_model::entities::{app::App, trash::Trash, view::View, workspace::Workspace}; -use lib_ot::core::{FlowyStr, OperationTransformable, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::*; + use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -17,35 +18,7 @@ pub struct FolderPad { pub(crate) workspaces: Vec>, pub(crate) trash: Vec>, #[serde(skip)] - pub(crate) root: FolderDelta, -} - -pub fn default_folder_delta() -> FolderDelta { - PlainTextDeltaBuilder::new() - .insert(r#"{"workspaces":[],"trash":[]}"#) - .build() -} - -pub fn initial_folder_delta(folder_pad: &FolderPad) -> CollaborateResult { - let json = folder_pad.to_json()?; - let delta = PlainTextDeltaBuilder::new().insert(&json).build(); - Ok(delta) -} - -impl std::default::Default for FolderPad { - fn default() -> Self { - FolderPad { - workspaces: vec![], - trash: vec![], - root: default_folder_delta(), - } - } -} - -pub struct FolderChange { - pub delta: FolderDelta, - /// md5: the md5 of the FolderPad's delta after applying the change. - pub md5: String, + pub(crate) delta: FolderDelta, } impl FolderPad { @@ -65,20 +38,20 @@ impl FolderPad { } pub fn delta(&self) -> &FolderDelta { - &self.root + &self.delta } pub fn reset_folder(&mut self, delta: FolderDelta) -> CollaborateResult { let folder = FolderPad::from_delta(delta)?; self.workspaces = folder.workspaces; self.trash = folder.trash; - self.root = folder.root; + self.delta = folder.delta; Ok(self.md5()) } pub fn compose_remote_delta(&mut self, delta: FolderDelta) -> CollaborateResult { - let composed_delta = self.root.compose(&delta)?; + let composed_delta = self.delta.compose(&delta)?; self.reset_folder(composed_delta) } @@ -295,7 +268,7 @@ impl FolderPad { } pub fn md5(&self) -> String { - md5(&self.root.to_bytes()) + md5(&self.delta.to_delta_bytes()) } pub fn to_json(&self) -> CollaborateResult { @@ -315,9 +288,13 @@ impl FolderPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - let delta = cal_diff(old, new); - self.root = self.root.compose(&delta)?; - Ok(Some(FolderChange { delta, md5: self.md5() })) + match cal_diff::(old, new) { + None => Ok(None), + Some(delta) => { + self.delta = self.delta.compose(&delta)?; + Ok(Some(FolderChange { delta, md5: self.md5() })) + } + } } } } @@ -330,7 +307,7 @@ impl FolderPad { if let Some(workspace) = workspaces.iter_mut().find(|workspace| workspace_id == workspace.id) { f(Arc::make_mut(workspace)) } else { - tracing::warn!("[RootFolder]: Can't find any workspace with id: {}", workspace_id); + tracing::warn!("[FolderPad]: Can't find any workspace with id: {}", workspace_id); Ok(None) } }) @@ -346,9 +323,13 @@ impl FolderPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - let delta = cal_diff(old, new); - self.root = self.root.compose(&delta)?; - Ok(Some(FolderChange { delta, md5: self.md5() })) + match cal_diff::(old, new) { + None => Ok(None), + Some(delta) => { + self.delta = self.delta.compose(&delta)?; + Ok(Some(FolderChange { delta, md5: self.md5() })) + } + } } } } @@ -363,7 +344,7 @@ impl FolderPad { .find(|workspace| workspace.apps.iter().any(|app| app.id == app_id)) { None => { - tracing::warn!("[RootFolder]: Can't find any app with id: {}", app_id); + tracing::warn!("[FolderPad]: Can't find any app with id: {}", app_id); return Ok(None); } Some(workspace) => workspace.id.clone(), @@ -382,7 +363,7 @@ impl FolderPad { self.with_app(belong_to_id, |app| { match app.belongings.iter_mut().find(|view| view_id == view.id) { None => { - tracing::warn!("[RootFolder]: Can't find any view with id: {}", view_id); + tracing::warn!("[FolderPad]: Can't find any view with id: {}", view_id); Ok(None) } Some(view) => f(view), @@ -391,23 +372,32 @@ impl FolderPad { } } -fn cal_diff(old: String, new: String) -> PlainTextDelta { - let chunks = dissimilar::diff(&old, &new); - let mut delta_builder = PlainTextDeltaBuilder::new(); - for chunk in &chunks { - match chunk { - Chunk::Equal(s) => { - delta_builder = delta_builder.retain(FlowyStr::from(*s).utf16_size()); - } - Chunk::Delete(s) => { - delta_builder = delta_builder.delete(FlowyStr::from(*s).utf16_size()); - } - Chunk::Insert(s) => { - delta_builder = delta_builder.insert(*s); - } +pub fn default_folder_delta() -> FolderDelta { + PlainTextDeltaBuilder::new() + .insert(r#"{"workspaces":[],"trash":[]}"#) + .build() +} + +pub fn initial_folder_delta(folder_pad: &FolderPad) -> CollaborateResult { + let json = folder_pad.to_json()?; + let delta = PlainTextDeltaBuilder::new().insert(&json).build(); + Ok(delta) +} + +impl std::default::Default for FolderPad { + fn default() -> Self { + FolderPad { + workspaces: vec![], + trash: vec![], + delta: default_folder_delta(), } } - delta_builder.build() +} + +pub struct FolderChange { + pub delta: FolderDelta, + /// md5: the md5 of the FolderPad's delta after applying the change. + pub md5: String, } #[cfg(test)] diff --git a/shared-lib/flowy-collaboration/src/client_folder/mod.rs b/shared-lib/flowy-sync/src/client_folder/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/client_folder/mod.rs rename to shared-lib/flowy-sync/src/client_folder/mod.rs diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs new file mode 100644 index 0000000000..3f727faf59 --- /dev/null +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs @@ -0,0 +1,408 @@ +use crate::entities::revision::{md5, RepeatedRevision, Revision}; +use crate::errors::{CollaborateError, CollaborateResult}; +use crate::util::{cal_diff, make_delta_from_revisions}; +use flowy_grid_data_model::entities::{gen_block_id, CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset}; +use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; + +use std::collections::HashMap; +use std::sync::Arc; + +pub type GridBlockMetaDelta = PlainTextDelta; +pub type GridBlockMetaDeltaBuilder = PlainTextDeltaBuilder; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GridBlockMetaPad { + block_id: String, + rows: Vec>, + + #[serde(skip)] + pub(crate) delta: GridBlockMetaDelta, +} + +impl GridBlockMetaPad { + pub fn from_delta(delta: GridBlockMetaDelta) -> CollaborateResult { + let s = delta.to_str()?; + let meta_data: GridBlockMetaData = serde_json::from_str(&s).map_err(|e| { + let msg = format!("Deserialize delta to block meta failed: {}", e); + tracing::error!("{}", s); + CollaborateError::internal().context(msg) + })?; + let block_id = meta_data.block_id; + let rows = meta_data.rows.into_iter().map(Arc::new).collect::>>(); + Ok(Self { block_id, rows, delta }) + } + + pub fn from_revisions(_grid_id: &str, revisions: Vec) -> CollaborateResult { + let block_delta: GridBlockMetaDelta = make_delta_from_revisions::(revisions)?; + Self::from_delta(block_delta) + } + + #[tracing::instrument(level = "trace", skip(self, row), err)] + pub fn add_row_meta( + &mut self, + row: RowMeta, + start_row_id: Option, + ) -> CollaborateResult> { + self.modify(|rows| { + if let Some(start_row_id) = start_row_id { + if !start_row_id.is_empty() { + if let Some(index) = rows.iter().position(|row| row.id == start_row_id) { + rows.insert(index + 1, Arc::new(row)); + return Ok(Some(())); + } + } + } + + rows.push(Arc::new(row)); + Ok(Some(())) + }) + } + + pub fn delete_rows(&mut self, row_ids: Vec>) -> CollaborateResult> { + self.modify(|rows| { + rows.retain(|row| !row_ids.contains(&Cow::Borrowed(&row.id))); + Ok(Some(())) + }) + } + + pub fn get_row_metas(&self, row_ids: Option>>) -> CollaborateResult>> + where + T: AsRef + ToOwned + ?Sized, + { + match row_ids { + None => Ok(self.rows.to_vec()), + Some(row_ids) => { + let row_map = self + .rows + .iter() + .map(|row| (row.id.as_str(), row.clone())) + .collect::>>(); + + Ok(row_ids + .iter() + .flat_map(|row_id| { + let row_id = row_id.as_ref().as_ref(); + match row_map.get(row_id) { + None => { + tracing::error!("Can't find the row with id: {}", row_id); + None + } + Some(row) => Some(row.clone()), + } + }) + .collect::>()) + } + } + } + + pub fn get_cell_metas( + &self, + field_id: &str, + row_ids: Option>>, + ) -> CollaborateResult> { + let rows = self.get_row_metas(row_ids)?; + let cell_metas = rows + .iter() + .flat_map(|row| { + let cell_meta = row.cells.get(field_id)?; + Some(cell_meta.clone()) + }) + .collect::>(); + Ok(cell_metas) + } + + pub fn number_of_rows(&self) -> i32 { + self.rows.len() as i32 + } + + pub fn index_of_row(&self, row_id: &str) -> Option { + self.rows + .iter() + .position(|row| row.id == row_id) + .map(|index| index as i32) + } + + pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult> { + let row_id = changeset.row_id.clone(); + self.modify_row(&row_id, |row| { + let mut is_changed = None; + if let Some(height) = changeset.height { + row.height = height; + is_changed = Some(()); + } + + if let Some(visibility) = changeset.visibility { + row.visibility = visibility; + is_changed = Some(()); + } + + if !changeset.cell_by_field_id.is_empty() { + is_changed = Some(()); + changeset.cell_by_field_id.into_iter().for_each(|(field_id, cell)| { + row.cells.insert(field_id, cell); + }) + } + + Ok(is_changed) + }) + } + + pub fn move_row(&mut self, row_id: &str, from: usize, to: usize) -> CollaborateResult> { + self.modify(|row_metas| { + if let Some(position) = row_metas.iter().position(|row_meta| row_meta.id == row_id) { + debug_assert_eq!(from, position); + let row_meta = row_metas.remove(position); + row_metas.insert(to, row_meta); + Ok(Some(())) + } else { + Ok(None) + } + }) + } + + pub fn modify(&mut self, f: F) -> CollaborateResult> + where + F: for<'a> FnOnce(&'a mut Vec>) -> CollaborateResult>, + { + let cloned_self = self.clone(); + match f(&mut self.rows)? { + None => Ok(None), + Some(_) => { + let old = cloned_self.to_json()?; + let new = self.to_json()?; + match cal_diff::(old, new) { + None => Ok(None), + Some(delta) => { + tracing::debug!("[GridBlockMeta] Composing delta {}", delta.to_delta_str()); + // tracing::debug!( + // "[GridBlockMeta] current delta: {}", + // self.delta.to_str().unwrap_or_else(|_| "".to_string()) + // ); + self.delta = self.delta.compose(&delta)?; + Ok(Some(GridBlockMetaChange { delta, md5: self.md5() })) + } + } + } + } + } + + fn modify_row(&mut self, row_id: &str, f: F) -> CollaborateResult> + where + F: FnOnce(&mut RowMeta) -> CollaborateResult>, + { + self.modify(|rows| { + if let Some(row_meta) = rows.iter_mut().find(|row_meta| row_id == row_meta.id) { + f(Arc::make_mut(row_meta)) + } else { + tracing::warn!("[BlockMetaPad]: Can't find any row with id: {}", row_id); + Ok(None) + } + }) + } + + pub fn to_json(&self) -> CollaborateResult { + serde_json::to_string(self) + .map_err(|e| CollaborateError::internal().context(format!("serial trash to json failed: {}", e))) + } + + pub fn md5(&self) -> String { + md5(&self.delta.to_delta_bytes()) + } + + pub fn delta_str(&self) -> String { + self.delta.to_delta_str() + } +} + +pub struct GridBlockMetaChange { + pub delta: GridBlockMetaDelta, + /// md5: the md5 of the grid after applying the change. + pub md5: String, +} + +pub fn make_block_meta_delta(grid_block_meta_data: &GridBlockMetaData) -> GridBlockMetaDelta { + let json = serde_json::to_string(&grid_block_meta_data).unwrap(); + PlainTextDeltaBuilder::new().insert(&json).build() +} + +pub fn make_block_meta_revisions(user_id: &str, grid_block_meta_data: &GridBlockMetaData) -> RepeatedRevision { + let delta = make_block_meta_delta(grid_block_meta_data); + let bytes = delta.to_delta_bytes(); + let revision = Revision::initial_revision(user_id, &grid_block_meta_data.block_id, bytes); + revision.into() +} + +impl std::default::Default for GridBlockMetaPad { + fn default() -> Self { + let block_meta_data = GridBlockMetaData { + block_id: gen_block_id(), + rows: vec![], + }; + + let delta = make_block_meta_delta(&block_meta_data); + GridBlockMetaPad { + block_id: block_meta_data.block_id, + rows: block_meta_data.rows.into_iter().map(Arc::new).collect::>(), + delta, + } + } +} + +#[cfg(test)] +mod tests { + use crate::client_grid::{GridBlockMetaDelta, GridBlockMetaPad}; + use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset}; + use std::borrow::Cow; + + #[test] + fn block_meta_add_row() { + let mut pad = test_pad(); + let row = RowMeta { + id: "1".to_string(), + block_id: pad.block_id.clone(), + cells: Default::default(), + height: 0, + visibility: false, + }; + + let change = pad.add_row_meta(row.clone(), None).unwrap().unwrap(); + assert_eq!(pad.rows.first().unwrap().as_ref(), &row); + assert_eq!( + change.delta.to_delta_str(), + r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# + ); + } + + #[test] + fn block_meta_insert_row() { + let mut pad = test_pad(); + let row_1 = test_row_meta("1", &pad); + let row_2 = test_row_meta("2", &pad); + let row_3 = test_row_meta("3", &pad); + + let change = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap(); + assert_eq!( + change.delta.to_delta_str(), + r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# + ); + + let change = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap(); + assert_eq!( + change.delta.to_delta_str(), + r#"[{"retain":90},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# + ); + + let change = pad.add_row_meta(row_3.clone(), Some("2".to_string())).unwrap().unwrap(); + assert_eq!( + change.delta.to_delta_str(), + r#"[{"retain":157},{"insert":",{\"id\":\"3\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# + ); + + assert_eq!(*pad.rows[0], row_1); + assert_eq!(*pad.rows[1], row_2); + assert_eq!(*pad.rows[2], row_3); + } + + fn test_row_meta(id: &str, pad: &GridBlockMetaPad) -> RowMeta { + RowMeta { + id: id.to_string(), + block_id: pad.block_id.clone(), + cells: Default::default(), + height: 0, + visibility: false, + } + } + + #[test] + fn block_meta_insert_row2() { + let mut pad = test_pad(); + let row_1 = test_row_meta("1", &pad); + let row_2 = test_row_meta("2", &pad); + let row_3 = test_row_meta("3", &pad); + + let _ = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_3.clone(), Some("1".to_string())).unwrap().unwrap(); + + assert_eq!(*pad.rows[0], row_1); + assert_eq!(*pad.rows[1], row_3); + assert_eq!(*pad.rows[2], row_2); + } + + #[test] + fn block_meta_insert_row3() { + let mut pad = test_pad(); + let row_1 = test_row_meta("1", &pad); + let row_2 = test_row_meta("2", &pad); + let row_3 = test_row_meta("3", &pad); + + let _ = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_3.clone(), Some("".to_string())).unwrap().unwrap(); + + assert_eq!(*pad.rows[0], row_1); + assert_eq!(*pad.rows[1], row_2); + assert_eq!(*pad.rows[2], row_3); + } + + #[test] + fn block_meta_delete_row() { + let mut pad = test_pad(); + let pre_delta_str = pad.delta_str(); + let row = RowMeta { + id: "1".to_string(), + block_id: pad.block_id.clone(), + cells: Default::default(), + height: 0, + visibility: false, + }; + + let _ = pad.add_row_meta(row.clone(), None).unwrap().unwrap(); + let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap(); + assert_eq!( + change.delta.to_delta_str(), + r#"[{"retain":24},{"delete":66},{"retain":2}]"# + ); + + assert_eq!(pad.delta_str(), pre_delta_str); + } + + #[test] + fn block_meta_update_row() { + let mut pad = test_pad(); + let row = RowMeta { + id: "1".to_string(), + block_id: pad.block_id.clone(), + cells: Default::default(), + height: 0, + visibility: false, + }; + + let changeset = RowMetaChangeset { + row_id: row.id.clone(), + height: Some(100), + visibility: Some(true), + cell_by_field_id: Default::default(), + }; + + let _ = pad.add_row_meta(row, None).unwrap().unwrap(); + let change = pad.update_row(changeset).unwrap().unwrap(); + + assert_eq!( + change.delta.to_delta_str(), + r#"[{"retain":69},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"# + ); + + assert_eq!( + pad.to_json().unwrap(), + r#"{"block_id":"1","rows":[{"id":"1","block_id":"1","cells":[],"height":100,"visibility":true}]}"# + ); + } + + fn test_pad() -> GridBlockMetaPad { + let delta = GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); + GridBlockMetaPad::from_delta(delta).unwrap() + } +} diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs new file mode 100644 index 0000000000..fb800a9626 --- /dev/null +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -0,0 +1,69 @@ +use crate::errors::{CollaborateError, CollaborateResult}; +use flowy_grid_data_model::entities::{BuildGridContext, FieldMeta, RowMeta}; + +#[derive(Default)] +pub struct GridBuilder { + build_context: BuildGridContext, +} + +impl GridBuilder { + pub fn add_field(mut self, field: FieldMeta) -> Self { + self.build_context.field_metas.push(field); + self + } + + pub fn add_empty_row(mut self) -> Self { + let row = RowMeta::new(&self.build_context.block_meta.block_id); + self.build_context.block_meta_data.rows.push(row); + self.build_context.block_meta.row_count += 1; + self + } + + pub fn build(self) -> BuildGridContext { + self.build_context + } +} + +#[allow(dead_code)] +fn check_rows(fields: &[FieldMeta], rows: &[RowMeta]) -> CollaborateResult<()> { + let field_ids = fields.iter().map(|field| &field.id).collect::>(); + for row in rows { + let cell_field_ids = row.cells.keys().into_iter().collect::>(); + if cell_field_ids != field_ids { + let msg = format!("{:?} contains invalid cells", row); + return Err(CollaborateError::internal().context(msg)); + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + + use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBuilder}; + use flowy_grid_data_model::entities::{FieldMeta, FieldType, GridBlockMetaData, GridMeta}; + + #[test] + fn create_default_grid_test() { + let grid_id = "1".to_owned(); + let build_context = GridBuilder::default() + .add_field(FieldMeta::new("Name", "", FieldType::RichText, true)) + .add_field(FieldMeta::new("Tags", "", FieldType::SingleSelect, false)) + .add_empty_row() + .add_empty_row() + .add_empty_row() + .build(); + + let grid_meta = GridMeta { + grid_id, + fields: build_context.field_metas, + blocks: vec![build_context.block_meta], + }; + + let grid_meta_delta = make_grid_delta(&grid_meta); + let _: GridMeta = serde_json::from_str(&grid_meta_delta.to_str().unwrap()).unwrap(); + + let grid_block_meta_delta = make_block_meta_delta(&build_context.block_meta_data); + let _: GridBlockMetaData = serde_json::from_str(&grid_block_meta_delta.to_str().unwrap()).unwrap(); + } +} diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs new file mode 100644 index 0000000000..d91265e896 --- /dev/null +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -0,0 +1,412 @@ +use crate::entities::revision::{md5, RepeatedRevision, Revision}; +use crate::errors::{internal_error, CollaborateError, CollaborateResult}; +use crate::util::{cal_diff, make_delta_from_revisions}; +use bytes::Bytes; +use flowy_grid_data_model::entities::{ + gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, GridBlockMetaChangeset, + GridMeta, +}; +use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use std::collections::HashMap; +use std::sync::Arc; + +pub type GridMetaDelta = PlainTextDelta; +pub type GridDeltaBuilder = PlainTextDeltaBuilder; + +pub struct GridMetaPad { + pub(crate) grid_meta: Arc, + pub(crate) delta: GridMetaDelta, +} + +pub trait JsonDeserializer { + fn deserialize(&self, type_option_data: Vec) -> CollaborateResult; +} + +impl GridMetaPad { + pub fn from_delta(delta: GridMetaDelta) -> CollaborateResult { + let s = delta.to_str()?; + let grid: GridMeta = serde_json::from_str(&s) + .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?; + + Ok(Self { + grid_meta: Arc::new(grid), + delta, + }) + } + + pub fn from_revisions(_grid_id: &str, revisions: Vec) -> CollaborateResult { + let grid_delta: GridMetaDelta = make_delta_from_revisions::(revisions)?; + Self::from_delta(grid_delta) + } + + #[tracing::instrument(level = "debug", skip_all, err)] + pub fn create_field_meta( + &mut self, + new_field_meta: FieldMeta, + start_field_id: Option, + ) -> CollaborateResult> { + self.modify_grid(|grid_meta| { + // Check if the field exists or not + if grid_meta + .fields + .iter() + .any(|field_meta| field_meta.id == new_field_meta.id) + { + tracing::error!("Duplicate grid field"); + return Ok(None); + } + + let insert_index = match start_field_id { + None => None, + Some(start_field_id) => grid_meta.fields.iter().position(|field| field.id == start_field_id), + }; + + match insert_index { + None => grid_meta.fields.push(new_field_meta), + Some(index) => grid_meta.fields.insert(index, new_field_meta), + } + Ok(Some(())) + }) + } + + pub fn delete_field_meta(&mut self, field_id: &str) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + grid_meta.fields.remove(index); + Ok(Some(())) + } + }, + ) + } + + pub fn duplicate_field_meta( + &mut self, + field_id: &str, + duplicated_field_id: &str, + ) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + let mut duplicate_field_meta = grid_meta.fields[index].clone(); + duplicate_field_meta.id = duplicated_field_id.to_string(); + duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name); + grid_meta.fields.insert(index + 1, duplicate_field_meta); + Ok(Some(())) + } + }, + ) + } + + pub fn switch_to_field( + &mut self, + field_id: &str, + field_type: FieldType, + type_option_json_builder: B, + ) -> CollaborateResult> + where + B: FnOnce(&FieldType) -> String, + { + self.modify_grid(|grid_meta| { + // + match grid_meta.fields.iter_mut().find(|field_meta| field_meta.id == field_id) { + None => { + tracing::warn!("Can not find the field with id: {}", field_id); + Ok(None) + } + Some(field_meta) => { + if field_meta.get_type_option_str(Some(field_type.clone())).is_none() { + let type_option_json = type_option_json_builder(&field_type); + field_meta.insert_type_option_str(&field_type, type_option_json); + } + + field_meta.field_type = field_type; + Ok(Some(())) + } + } + }) + } + + pub fn update_field_meta( + &mut self, + changeset: FieldChangesetParams, + deserializer: T, + ) -> CollaborateResult> { + let field_id = changeset.field_id.clone(); + self.modify_field(&field_id, |field| { + let mut is_changed = None; + if let Some(name) = changeset.name { + field.name = name; + is_changed = Some(()) + } + + if let Some(desc) = changeset.desc { + field.desc = desc; + is_changed = Some(()) + } + + if let Some(field_type) = changeset.field_type { + field.field_type = field_type; + is_changed = Some(()) + } + + if let Some(frozen) = changeset.frozen { + field.frozen = frozen; + is_changed = Some(()) + } + + if let Some(visibility) = changeset.visibility { + field.visibility = visibility; + is_changed = Some(()) + } + + if let Some(width) = changeset.width { + field.width = width; + is_changed = Some(()) + } + + if let Some(type_option_data) = changeset.type_option_data { + match deserializer.deserialize(type_option_data) { + Ok(json_str) => { + let field_type = field.field_type.clone(); + field.insert_type_option_str(&field_type, json_str); + is_changed = Some(()) + } + Err(err) => { + tracing::error!("Deserialize data to type option json failed: {}", err); + } + } + } + + Ok(is_changed) + }) + } + + pub fn get_field_meta(&self, field_id: &str) -> Option<(usize, &FieldMeta)> { + self.grid_meta + .fields + .iter() + .enumerate() + .find(|(_, field)| field.id == field_id) + } + + pub fn replace_field_meta(&mut self, field_meta: FieldMeta) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_meta.id) { + None => Ok(None), + Some(index) => { + grid_meta.fields.remove(index); + grid_meta.fields.insert(index, field_meta); + Ok(Some(())) + } + }, + ) + } + + pub fn move_field( + &mut self, + field_id: &str, + _from_index: usize, + to_index: usize, + ) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + // debug_assert_eq!(index, from_index); + let field_meta = grid_meta.fields.remove(index); + grid_meta.fields.insert(to_index, field_meta); + Ok(Some(())) + } + }, + ) + } + + pub fn contain_field(&self, field_id: &str) -> bool { + self.grid_meta.fields.iter().any(|field| field.id == field_id) + } + + pub fn get_field_orders(&self) -> Vec { + self.grid_meta.fields.iter().map(FieldOrder::from).collect() + } + + pub fn get_field_metas(&self, field_orders: Option>) -> CollaborateResult> { + match field_orders { + None => Ok(self.grid_meta.fields.clone()), + Some(field_orders) => { + let field_by_field_id = self + .grid_meta + .fields + .iter() + .map(|field| (&field.id, field)) + .collect::>(); + + let fields = field_orders + .iter() + .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) { + None => { + tracing::error!("Can't find the field with id: {}", field_order.field_id); + None + } + Some(field) => Some((*field).clone()), + }) + .collect::>(); + Ok(fields) + } + } + } + + pub fn create_block_meta(&mut self, block: GridBlockMeta) -> CollaborateResult> { + self.modify_grid(|grid_meta| { + if grid_meta.blocks.iter().any(|b| b.block_id == block.block_id) { + tracing::warn!("Duplicate grid block"); + Ok(None) + } else { + match grid_meta.blocks.last() { + None => grid_meta.blocks.push(block), + Some(last_block) => { + if last_block.start_row_index > block.start_row_index + && last_block.len() > block.start_row_index + { + let msg = "GridBlock's start_row_index should be greater than the last_block's start_row_index and its len".to_string(); + return Err(CollaborateError::internal().context(msg)) + } + grid_meta.blocks.push(block); + } + } + Ok(Some(())) + } + }) + } + + pub fn get_block_metas(&self) -> Vec { + self.grid_meta.blocks.clone() + } + + pub fn update_block_meta(&mut self, changeset: GridBlockMetaChangeset) -> CollaborateResult> { + let block_id = changeset.block_id.clone(); + self.modify_block(&block_id, |block| { + let mut is_changed = None; + + if let Some(row_count) = changeset.row_count { + block.row_count = row_count; + is_changed = Some(()); + } + + if let Some(start_row_index) = changeset.start_row_index { + block.start_row_index = start_row_index; + is_changed = Some(()); + } + + Ok(is_changed) + }) + } + + pub fn md5(&self) -> String { + md5(&self.delta.to_delta_bytes()) + } + + pub fn delta_str(&self) -> String { + self.delta.to_delta_str() + } + + pub fn delta_bytes(&self) -> Bytes { + self.delta.to_delta_bytes() + } + + pub fn fields(&self) -> &[FieldMeta] { + &self.grid_meta.fields + } + + fn modify_grid(&mut self, f: F) -> CollaborateResult> + where + F: FnOnce(&mut GridMeta) -> CollaborateResult>, + { + let cloned_grid = self.grid_meta.clone(); + match f(Arc::make_mut(&mut self.grid_meta))? { + None => Ok(None), + Some(_) => { + let old = json_from_grid(&cloned_grid)?; + let new = json_from_grid(&self.grid_meta)?; + match cal_diff::(old, new) { + None => Ok(None), + Some(delta) => { + self.delta = self.delta.compose(&delta)?; + Ok(Some(GridChangeset { delta, md5: self.md5() })) + } + } + } + } + } + + pub fn modify_block(&mut self, block_id: &str, f: F) -> CollaborateResult> + where + F: FnOnce(&mut GridBlockMeta) -> CollaborateResult>, + { + self.modify_grid( + |grid_meta| match grid_meta.blocks.iter().position(|block| block.block_id == block_id) { + None => { + tracing::warn!("[GridMetaPad]: Can't find any block with id: {}", block_id); + Ok(None) + } + Some(index) => f(&mut grid_meta.blocks[index]), + }, + ) + } + + pub fn modify_field(&mut self, field_id: &str, f: F) -> CollaborateResult> + where + F: FnOnce(&mut FieldMeta) -> CollaborateResult>, + { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => { + tracing::warn!("[GridMetaPad]: Can't find any field with id: {}", field_id); + Ok(None) + } + Some(index) => f(&mut grid_meta.fields[index]), + }, + ) + } +} + +fn json_from_grid(grid: &Arc) -> CollaborateResult { + let json = serde_json::to_string(grid) + .map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?; + Ok(json) +} + +pub struct GridChangeset { + pub delta: GridMetaDelta, + /// md5: the md5 of the grid after applying the change. + pub md5: String, +} + +pub fn make_grid_delta(grid_meta: &GridMeta) -> GridMetaDelta { + let json = serde_json::to_string(&grid_meta).unwrap(); + PlainTextDeltaBuilder::new().insert(&json).build() +} + +pub fn make_grid_revisions(user_id: &str, grid_meta: &GridMeta) -> RepeatedRevision { + let delta = make_grid_delta(grid_meta); + let bytes = delta.to_delta_bytes(); + let revision = Revision::initial_revision(user_id, &grid_meta.grid_id, bytes); + revision.into() +} + +impl std::default::Default for GridMetaPad { + fn default() -> Self { + let grid = GridMeta { + grid_id: gen_grid_id(), + fields: vec![], + blocks: vec![], + }; + let delta = make_grid_delta(&grid); + GridMetaPad { + grid_meta: Arc::new(grid), + delta, + } + } +} diff --git a/shared-lib/flowy-sync/src/client_grid/mod.rs b/shared-lib/flowy-sync/src/client_grid/mod.rs new file mode 100644 index 0000000000..5df06e7858 --- /dev/null +++ b/shared-lib/flowy-sync/src/client_grid/mod.rs @@ -0,0 +1,7 @@ +mod grid_block_meta_pad; +mod grid_builder; +mod grid_meta_pad; + +pub use grid_block_meta_pad::*; +pub use grid_builder::*; +pub use grid_meta_pad::*; diff --git a/shared-lib/flowy-collaboration/src/entities/folder_info.rs b/shared-lib/flowy-sync/src/entities/folder_info.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/entities/folder_info.rs rename to shared-lib/flowy-sync/src/entities/folder_info.rs diff --git a/shared-lib/flowy-collaboration/src/entities/mod.rs b/shared-lib/flowy-sync/src/entities/mod.rs similarity index 74% rename from shared-lib/flowy-collaboration/src/entities/mod.rs rename to shared-lib/flowy-sync/src/entities/mod.rs index f31f9e34fd..8989125677 100644 --- a/shared-lib/flowy-collaboration/src/entities/mod.rs +++ b/shared-lib/flowy-sync/src/entities/mod.rs @@ -1,5 +1,5 @@ -pub mod document_info; pub mod folder_info; pub mod parser; pub mod revision; +pub mod text_block_info; pub mod ws_data; diff --git a/shared-lib/flowy-collaboration/src/entities/parser/doc_id.rs b/shared-lib/flowy-sync/src/entities/parser/doc_id.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/entities/parser/doc_id.rs rename to shared-lib/flowy-sync/src/entities/parser/doc_id.rs diff --git a/shared-lib/flowy-collaboration/src/entities/parser/mod.rs b/shared-lib/flowy-sync/src/entities/parser/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/entities/parser/mod.rs rename to shared-lib/flowy-sync/src/entities/parser/mod.rs diff --git a/shared-lib/flowy-collaboration/src/entities/revision.rs b/shared-lib/flowy-sync/src/entities/revision.rs similarity index 91% rename from shared-lib/flowy-collaboration/src/entities/revision.rs rename to shared-lib/flowy-sync/src/entities/revision.rs index c85ba937fb..57276bba1b 100644 --- a/shared-lib/flowy-collaboration/src/entities/revision.rs +++ b/shared-lib/flowy-sync/src/entities/revision.rs @@ -82,12 +82,6 @@ impl Revision { } } -impl std::convert::From for RepeatedRevision { - fn from(revision: Revision) -> Self { - RepeatedRevision { items: vec![revision] } - } -} - impl std::fmt::Debug for Revision { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { let _ = f.write_fmt(format_args!("object_id {}, ", self.object_id))?; @@ -95,7 +89,7 @@ impl std::fmt::Debug for Revision { let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?; match RichTextDelta::from_bytes(&self.delta_data) { Ok(delta) => { - let _ = f.write_fmt(format_args!("delta {:?}", delta.to_delta_json()))?; + let _ = f.write_fmt(format_args!("delta {:?}", delta.to_delta_str()))?; } Err(e) => { let _ = f.write_fmt(format_args!("delta {:?}", e))?; @@ -125,6 +119,12 @@ impl std::ops::DerefMut for RepeatedRevision { } } +impl std::convert::From for RepeatedRevision { + fn from(revision: Revision) -> Self { + Self { items: vec![revision] } + } +} + impl RepeatedRevision { pub fn new(mut items: Vec) -> Self { items.sort_by(|a, b| a.rev_id.cmp(&b.rev_id)); @@ -215,27 +215,6 @@ pub fn md5>(data: T) -> String { md5 } -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum RevisionState { - Sync = 0, - Ack = 1, -} - -impl RevisionState { - pub fn is_need_sync(&self) -> bool { - match self { - RevisionState::Sync => true, - RevisionState::Ack => false, - } - } -} - -impl AsRef for RevisionState { - fn as_ref(&self) -> &RevisionState { - self - } -} - #[derive(Debug, ProtoBuf_Enum, Clone, Eq, PartialEq)] pub enum RevType { DeprecatedLocal = 0, diff --git a/shared-lib/flowy-collaboration/src/entities/document_info.rs b/shared-lib/flowy-sync/src/entities/text_block_info.rs similarity index 67% rename from shared-lib/flowy-collaboration/src/entities/document_info.rs rename to shared-lib/flowy-sync/src/entities/text_block_info.rs index a1cb853aab..c325fdad07 100644 --- a/shared-lib/flowy-collaboration/src/entities/document_info.rs +++ b/shared-lib/flowy-sync/src/entities/text_block_info.rs @@ -6,7 +6,7 @@ use flowy_derive::ProtoBuf; use lib_ot::{errors::OTError, rich_text::RichTextDelta}; #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct CreateBlockParams { +pub struct CreateTextBlockParams { #[pb(index = 1)] pub id: String, @@ -15,9 +15,9 @@ pub struct CreateBlockParams { } #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)] -pub struct BlockInfo { +pub struct TextBlockInfo { #[pb(index = 1)] - pub doc_id: String, + pub block_id: String, #[pb(index = 2)] pub text: String, @@ -29,14 +29,14 @@ pub struct BlockInfo { pub base_rev_id: i64, } -impl BlockInfo { +impl TextBlockInfo { pub fn delta(&self) -> Result { let delta = RichTextDelta::from_bytes(&self.text)?; Ok(delta) } } -impl std::convert::TryFrom for BlockInfo { +impl std::convert::TryFrom for TextBlockInfo { type Error = CollaborateError; fn try_from(revision: Revision) -> Result { @@ -46,10 +46,10 @@ impl std::convert::TryFrom for BlockInfo { } let delta = RichTextDelta::from_bytes(&revision.delta_data)?; - let doc_json = delta.to_delta_json(); + let doc_json = delta.to_delta_str(); - Ok(BlockInfo { - doc_id: revision.object_id, + Ok(TextBlockInfo { + block_id: revision.object_id, text: doc_json, rev_id: revision.rev_id, base_rev_id: revision.base_rev_id, @@ -58,21 +58,21 @@ impl std::convert::TryFrom for BlockInfo { } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct ResetDocumentParams { +pub struct ResetTextBlockParams { #[pb(index = 1)] - pub doc_id: String, + pub block_id: String, #[pb(index = 2)] pub revisions: RepeatedRevision, } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct BlockDelta { +pub struct TextBlockDelta { #[pb(index = 1)] pub block_id: String, #[pb(index = 2)] - pub delta_json: String, + pub delta_str: String, } #[derive(ProtoBuf, Default, Debug, Clone)] @@ -88,21 +88,30 @@ pub struct NewDocUser { } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct BlockId { +pub struct TextBlockId { #[pb(index = 1)] pub value: String, } +impl AsRef for TextBlockId { + fn as_ref(&self) -> &str { + &self.value + } +} -impl std::convert::From for BlockId { +impl std::convert::From for TextBlockId { fn from(value: String) -> Self { - BlockId { value } + TextBlockId { value } } } -impl std::convert::From<&String> for BlockId { - fn from(doc_id: &String) -> Self { - BlockId { - value: doc_id.to_owned(), - } +impl std::convert::From for String { + fn from(block_id: TextBlockId) -> Self { + block_id.value + } +} + +impl std::convert::From<&String> for TextBlockId { + fn from(s: &String) -> Self { + TextBlockId { value: s.to_owned() } } } diff --git a/shared-lib/flowy-collaboration/src/entities/ws_data.rs b/shared-lib/flowy-sync/src/entities/ws_data.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/entities/ws_data.rs rename to shared-lib/flowy-sync/src/entities/ws_data.rs diff --git a/shared-lib/flowy-collaboration/src/errors.rs b/shared-lib/flowy-sync/src/errors.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/errors.rs rename to shared-lib/flowy-sync/src/errors.rs diff --git a/shared-lib/flowy-collaboration/src/lib.rs b/shared-lib/flowy-sync/src/lib.rs similarity index 91% rename from shared-lib/flowy-collaboration/src/lib.rs rename to shared-lib/flowy-sync/src/lib.rs index 801c954605..f690edc4b0 100644 --- a/shared-lib/flowy-collaboration/src/lib.rs +++ b/shared-lib/flowy-sync/src/lib.rs @@ -1,5 +1,6 @@ pub mod client_document; pub mod client_folder; +pub mod client_grid; pub mod entities; pub mod errors; pub mod protobuf; diff --git a/shared-lib/flowy-sync/src/protobuf/mod.rs b/shared-lib/flowy-sync/src/protobuf/mod.rs new file mode 100644 index 0000000000..da97aad28a --- /dev/null +++ b/shared-lib/flowy-sync/src/protobuf/mod.rs @@ -0,0 +1,4 @@ +#![cfg_attr(rustfmt, rustfmt::skip)] +// Auto-generated, do not edit +mod model; +pub use model::*; \ No newline at end of file diff --git a/shared-lib/flowy-collaboration/src/protobuf/model/folder_info.rs b/shared-lib/flowy-sync/src/protobuf/model/folder_info.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/protobuf/model/folder_info.rs rename to shared-lib/flowy-sync/src/protobuf/model/folder_info.rs diff --git a/shared-lib/flowy-collaboration/src/protobuf/model/mod.rs b/shared-lib/flowy-sync/src/protobuf/model/mod.rs similarity index 78% rename from shared-lib/flowy-collaboration/src/protobuf/model/mod.rs rename to shared-lib/flowy-sync/src/protobuf/model/mod.rs index 137466e63f..d0627984e3 100644 --- a/shared-lib/flowy-collaboration/src/protobuf/model/mod.rs +++ b/shared-lib/flowy-sync/src/protobuf/model/mod.rs @@ -7,8 +7,8 @@ pub use folder_info::*; mod ws_data; pub use ws_data::*; +mod text_block_info; +pub use text_block_info::*; + mod revision; pub use revision::*; - -mod document_info; -pub use document_info::*; diff --git a/shared-lib/flowy-collaboration/src/protobuf/model/revision.rs b/shared-lib/flowy-sync/src/protobuf/model/revision.rs similarity index 95% rename from shared-lib/flowy-collaboration/src/protobuf/model/revision.rs rename to shared-lib/flowy-sync/src/protobuf/model/revision.rs index 079687ca44..02d1f522cf 100644 --- a/shared-lib/flowy-collaboration/src/protobuf/model/revision.rs +++ b/shared-lib/flowy-sync/src/protobuf/model/revision.rs @@ -914,56 +914,6 @@ impl ::protobuf::reflect::ProtobufValue for RevisionRange { } } -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum RevisionState { - Sync = 0, - Ack = 1, -} - -impl ::protobuf::ProtobufEnum for RevisionState { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(RevisionState::Sync), - 1 => ::std::option::Option::Some(RevisionState::Ack), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [RevisionState] = &[ - RevisionState::Sync, - RevisionState::Ack, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new_pb_name::("RevisionState", file_descriptor_proto()) - }) - } -} - -impl ::std::marker::Copy for RevisionState { -} - -impl ::std::default::Default for RevisionState { - fn default() -> Self { - RevisionState::Sync - } -} - -impl ::protobuf::reflect::ProtobufValue for RevisionState { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) - } -} - #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum RevType { DeprecatedLocal = 0, @@ -1024,8 +974,7 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x10RepeatedRevision\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.Revision\ R\x05items\"\x1d\n\x05RevId\x12\x14\n\x05value\x18\x01\x20\x01(\x03R\x05\ value\"7\n\rRevisionRange\x12\x14\n\x05start\x18\x01\x20\x01(\x03R\x05st\ - art\x12\x10\n\x03end\x18\x02\x20\x01(\x03R\x03end*\"\n\rRevisionState\ - \x12\x08\n\x04Sync\x10\0\x12\x07\n\x03Ack\x10\x01*4\n\x07RevType\x12\x13\ + art\x12\x10\n\x03end\x18\x02\x20\x01(\x03R\x03end*4\n\x07RevType\x12\x13\ \n\x0fDeprecatedLocal\x10\0\x12\x14\n\x10DeprecatedRemote\x10\x01b\x06pr\ oto3\ "; diff --git a/shared-lib/flowy-collaboration/src/protobuf/model/document_info.rs b/shared-lib/flowy-sync/src/protobuf/model/text_block_info.rs similarity index 80% rename from shared-lib/flowy-collaboration/src/protobuf/model/document_info.rs rename to shared-lib/flowy-sync/src/protobuf/model/text_block_info.rs index 52b64df159..1e44767a92 100644 --- a/shared-lib/flowy-collaboration/src/protobuf/model/document_info.rs +++ b/shared-lib/flowy-sync/src/protobuf/model/text_block_info.rs @@ -17,14 +17,14 @@ #![allow(trivial_casts)] #![allow(unused_imports)] #![allow(unused_results)] -//! Generated file from `document_info.proto` +//! Generated file from `text_block_info.proto` /// Generated files are compatible only with the same version /// of protobuf runtime. // const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2; #[derive(PartialEq,Clone,Default)] -pub struct CreateBlockParams { +pub struct CreateTextBlockParams { // message fields pub id: ::std::string::String, pub revisions: ::protobuf::SingularPtrField, @@ -33,14 +33,14 @@ pub struct CreateBlockParams { pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a CreateBlockParams { - fn default() -> &'a CreateBlockParams { - ::default_instance() +impl<'a> ::std::default::Default for &'a CreateTextBlockParams { + fn default() -> &'a CreateTextBlockParams { + ::default_instance() } } -impl CreateBlockParams { - pub fn new() -> CreateBlockParams { +impl CreateTextBlockParams { + pub fn new() -> CreateTextBlockParams { ::std::default::Default::default() } @@ -104,7 +104,7 @@ impl CreateBlockParams { } } -impl ::protobuf::Message for CreateBlockParams { +impl ::protobuf::Message for CreateTextBlockParams { fn is_initialized(&self) -> bool { for v in &self.revisions { if !v.is_initialized() { @@ -187,8 +187,8 @@ impl ::protobuf::Message for CreateBlockParams { Self::descriptor_static() } - fn new() -> CreateBlockParams { - CreateBlockParams::new() + fn new() -> CreateTextBlockParams { + CreateTextBlockParams::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -197,29 +197,29 @@ impl ::protobuf::Message for CreateBlockParams { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "id", - |m: &CreateBlockParams| { &m.id }, - |m: &mut CreateBlockParams| { &mut m.id }, + |m: &CreateTextBlockParams| { &m.id }, + |m: &mut CreateTextBlockParams| { &mut m.id }, )); fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "revisions", - |m: &CreateBlockParams| { &m.revisions }, - |m: &mut CreateBlockParams| { &mut m.revisions }, + |m: &CreateTextBlockParams| { &m.revisions }, + |m: &mut CreateTextBlockParams| { &mut m.revisions }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "CreateBlockParams", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CreateTextBlockParams", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static CreateBlockParams { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(CreateBlockParams::new) + fn default_instance() -> &'static CreateTextBlockParams { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CreateTextBlockParams::new) } } -impl ::protobuf::Clear for CreateBlockParams { +impl ::protobuf::Clear for CreateTextBlockParams { fn clear(&mut self) { self.id.clear(); self.revisions.clear(); @@ -227,22 +227,22 @@ impl ::protobuf::Clear for CreateBlockParams { } } -impl ::std::fmt::Debug for CreateBlockParams { +impl ::std::fmt::Debug for CreateTextBlockParams { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for CreateBlockParams { +impl ::protobuf::reflect::ProtobufValue for CreateTextBlockParams { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default)] -pub struct BlockInfo { +pub struct TextBlockInfo { // message fields - pub doc_id: ::std::string::String, + pub block_id: ::std::string::String, pub text: ::std::string::String, pub rev_id: i64, pub base_rev_id: i64, @@ -251,41 +251,41 @@ pub struct BlockInfo { pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a BlockInfo { - fn default() -> &'a BlockInfo { - ::default_instance() +impl<'a> ::std::default::Default for &'a TextBlockInfo { + fn default() -> &'a TextBlockInfo { + ::default_instance() } } -impl BlockInfo { - pub fn new() -> BlockInfo { +impl TextBlockInfo { + pub fn new() -> TextBlockInfo { ::std::default::Default::default() } - // string doc_id = 1; + // string block_id = 1; - pub fn get_doc_id(&self) -> &str { - &self.doc_id + pub fn get_block_id(&self) -> &str { + &self.block_id } - pub fn clear_doc_id(&mut self) { - self.doc_id.clear(); + pub fn clear_block_id(&mut self) { + self.block_id.clear(); } // Param is passed by value, moved - pub fn set_doc_id(&mut self, v: ::std::string::String) { - self.doc_id = v; + pub fn set_block_id(&mut self, v: ::std::string::String) { + self.block_id = v; } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. - pub fn mut_doc_id(&mut self) -> &mut ::std::string::String { - &mut self.doc_id + pub fn mut_block_id(&mut self) -> &mut ::std::string::String { + &mut self.block_id } // Take field - pub fn take_doc_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.doc_id, ::std::string::String::new()) + pub fn take_block_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) } // string text = 2; @@ -345,7 +345,7 @@ impl BlockInfo { } } -impl ::protobuf::Message for BlockInfo { +impl ::protobuf::Message for TextBlockInfo { fn is_initialized(&self) -> bool { true } @@ -355,7 +355,7 @@ impl ::protobuf::Message for BlockInfo { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?; + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?; }, 2 => { ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.text)?; @@ -386,8 +386,8 @@ impl ::protobuf::Message for BlockInfo { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; - if !self.doc_id.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.doc_id); + if !self.block_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.block_id); } if !self.text.is_empty() { my_size += ::protobuf::rt::string_size(2, &self.text); @@ -404,8 +404,8 @@ impl ::protobuf::Message for BlockInfo { } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.doc_id.is_empty() { - os.write_string(1, &self.doc_id)?; + if !self.block_id.is_empty() { + os.write_string(1, &self.block_id)?; } if !self.text.is_empty() { os.write_string(2, &self.text)?; @@ -446,8 +446,8 @@ impl ::protobuf::Message for BlockInfo { Self::descriptor_static() } - fn new() -> BlockInfo { - BlockInfo::new() + fn new() -> TextBlockInfo { + TextBlockInfo::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -455,42 +455,42 @@ impl ::protobuf::Message for BlockInfo { descriptor.get(|| { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "doc_id", - |m: &BlockInfo| { &m.doc_id }, - |m: &mut BlockInfo| { &mut m.doc_id }, + "block_id", + |m: &TextBlockInfo| { &m.block_id }, + |m: &mut TextBlockInfo| { &mut m.block_id }, )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "text", - |m: &BlockInfo| { &m.text }, - |m: &mut BlockInfo| { &mut m.text }, + |m: &TextBlockInfo| { &m.text }, + |m: &mut TextBlockInfo| { &mut m.text }, )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>( "rev_id", - |m: &BlockInfo| { &m.rev_id }, - |m: &mut BlockInfo| { &mut m.rev_id }, + |m: &TextBlockInfo| { &m.rev_id }, + |m: &mut TextBlockInfo| { &mut m.rev_id }, )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>( "base_rev_id", - |m: &BlockInfo| { &m.base_rev_id }, - |m: &mut BlockInfo| { &mut m.base_rev_id }, + |m: &TextBlockInfo| { &m.base_rev_id }, + |m: &mut TextBlockInfo| { &mut m.base_rev_id }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "BlockInfo", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "TextBlockInfo", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static BlockInfo { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(BlockInfo::new) + fn default_instance() -> &'static TextBlockInfo { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(TextBlockInfo::new) } } -impl ::protobuf::Clear for BlockInfo { +impl ::protobuf::Clear for TextBlockInfo { fn clear(&mut self) { - self.doc_id.clear(); + self.block_id.clear(); self.text.clear(); self.rev_id = 0; self.base_rev_id = 0; @@ -498,63 +498,63 @@ impl ::protobuf::Clear for BlockInfo { } } -impl ::std::fmt::Debug for BlockInfo { +impl ::std::fmt::Debug for TextBlockInfo { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for BlockInfo { +impl ::protobuf::reflect::ProtobufValue for TextBlockInfo { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default)] -pub struct ResetDocumentParams { +pub struct ResetTextBlockParams { // message fields - pub doc_id: ::std::string::String, + pub block_id: ::std::string::String, pub revisions: ::protobuf::SingularPtrField, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a ResetDocumentParams { - fn default() -> &'a ResetDocumentParams { - ::default_instance() +impl<'a> ::std::default::Default for &'a ResetTextBlockParams { + fn default() -> &'a ResetTextBlockParams { + ::default_instance() } } -impl ResetDocumentParams { - pub fn new() -> ResetDocumentParams { +impl ResetTextBlockParams { + pub fn new() -> ResetTextBlockParams { ::std::default::Default::default() } - // string doc_id = 1; + // string block_id = 1; - pub fn get_doc_id(&self) -> &str { - &self.doc_id + pub fn get_block_id(&self) -> &str { + &self.block_id } - pub fn clear_doc_id(&mut self) { - self.doc_id.clear(); + pub fn clear_block_id(&mut self) { + self.block_id.clear(); } // Param is passed by value, moved - pub fn set_doc_id(&mut self, v: ::std::string::String) { - self.doc_id = v; + pub fn set_block_id(&mut self, v: ::std::string::String) { + self.block_id = v; } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. - pub fn mut_doc_id(&mut self) -> &mut ::std::string::String { - &mut self.doc_id + pub fn mut_block_id(&mut self) -> &mut ::std::string::String { + &mut self.block_id } // Take field - pub fn take_doc_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.doc_id, ::std::string::String::new()) + pub fn take_block_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) } // .RepeatedRevision revisions = 2; @@ -591,7 +591,7 @@ impl ResetDocumentParams { } } -impl ::protobuf::Message for ResetDocumentParams { +impl ::protobuf::Message for ResetTextBlockParams { fn is_initialized(&self) -> bool { for v in &self.revisions { if !v.is_initialized() { @@ -606,7 +606,7 @@ impl ::protobuf::Message for ResetDocumentParams { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?; + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?; }, 2 => { ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.revisions)?; @@ -623,8 +623,8 @@ impl ::protobuf::Message for ResetDocumentParams { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; - if !self.doc_id.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.doc_id); + if !self.block_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.block_id); } if let Some(ref v) = self.revisions.as_ref() { let len = v.compute_size(); @@ -636,8 +636,8 @@ impl ::protobuf::Message for ResetDocumentParams { } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.doc_id.is_empty() { - os.write_string(1, &self.doc_id)?; + if !self.block_id.is_empty() { + os.write_string(1, &self.block_id)?; } if let Some(ref v) = self.revisions.as_ref() { os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; @@ -674,8 +674,8 @@ impl ::protobuf::Message for ResetDocumentParams { Self::descriptor_static() } - fn new() -> ResetDocumentParams { - ResetDocumentParams::new() + fn new() -> ResetTextBlockParams { + ResetTextBlockParams::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -683,67 +683,67 @@ impl ::protobuf::Message for ResetDocumentParams { descriptor.get(|| { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "doc_id", - |m: &ResetDocumentParams| { &m.doc_id }, - |m: &mut ResetDocumentParams| { &mut m.doc_id }, + "block_id", + |m: &ResetTextBlockParams| { &m.block_id }, + |m: &mut ResetTextBlockParams| { &mut m.block_id }, )); fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "revisions", - |m: &ResetDocumentParams| { &m.revisions }, - |m: &mut ResetDocumentParams| { &mut m.revisions }, + |m: &ResetTextBlockParams| { &m.revisions }, + |m: &mut ResetTextBlockParams| { &mut m.revisions }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "ResetDocumentParams", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "ResetTextBlockParams", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static ResetDocumentParams { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(ResetDocumentParams::new) + fn default_instance() -> &'static ResetTextBlockParams { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(ResetTextBlockParams::new) } } -impl ::protobuf::Clear for ResetDocumentParams { +impl ::protobuf::Clear for ResetTextBlockParams { fn clear(&mut self) { - self.doc_id.clear(); + self.block_id.clear(); self.revisions.clear(); self.unknown_fields.clear(); } } -impl ::std::fmt::Debug for ResetDocumentParams { +impl ::std::fmt::Debug for ResetTextBlockParams { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for ResetDocumentParams { +impl ::protobuf::reflect::ProtobufValue for ResetTextBlockParams { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default)] -pub struct BlockDelta { +pub struct TextBlockDelta { // message fields pub block_id: ::std::string::String, - pub delta_json: ::std::string::String, + pub delta_str: ::std::string::String, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a BlockDelta { - fn default() -> &'a BlockDelta { - ::default_instance() +impl<'a> ::std::default::Default for &'a TextBlockDelta { + fn default() -> &'a TextBlockDelta { + ::default_instance() } } -impl BlockDelta { - pub fn new() -> BlockDelta { +impl TextBlockDelta { + pub fn new() -> TextBlockDelta { ::std::default::Default::default() } @@ -773,34 +773,34 @@ impl BlockDelta { ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) } - // string delta_json = 2; + // string delta_str = 2; - pub fn get_delta_json(&self) -> &str { - &self.delta_json + pub fn get_delta_str(&self) -> &str { + &self.delta_str } - pub fn clear_delta_json(&mut self) { - self.delta_json.clear(); + pub fn clear_delta_str(&mut self) { + self.delta_str.clear(); } // Param is passed by value, moved - pub fn set_delta_json(&mut self, v: ::std::string::String) { - self.delta_json = v; + pub fn set_delta_str(&mut self, v: ::std::string::String) { + self.delta_str = v; } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. - pub fn mut_delta_json(&mut self) -> &mut ::std::string::String { - &mut self.delta_json + pub fn mut_delta_str(&mut self) -> &mut ::std::string::String { + &mut self.delta_str } // Take field - pub fn take_delta_json(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.delta_json, ::std::string::String::new()) + pub fn take_delta_str(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.delta_str, ::std::string::String::new()) } } -impl ::protobuf::Message for BlockDelta { +impl ::protobuf::Message for TextBlockDelta { fn is_initialized(&self) -> bool { true } @@ -813,7 +813,7 @@ impl ::protobuf::Message for BlockDelta { ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?; }, 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.delta_json)?; + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.delta_str)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; @@ -830,8 +830,8 @@ impl ::protobuf::Message for BlockDelta { if !self.block_id.is_empty() { my_size += ::protobuf::rt::string_size(1, &self.block_id); } - if !self.delta_json.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.delta_json); + if !self.delta_str.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.delta_str); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); @@ -842,8 +842,8 @@ impl ::protobuf::Message for BlockDelta { if !self.block_id.is_empty() { os.write_string(1, &self.block_id)?; } - if !self.delta_json.is_empty() { - os.write_string(2, &self.delta_json)?; + if !self.delta_str.is_empty() { + os.write_string(2, &self.delta_str)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) @@ -875,8 +875,8 @@ impl ::protobuf::Message for BlockDelta { Self::descriptor_static() } - fn new() -> BlockDelta { - BlockDelta::new() + fn new() -> TextBlockDelta { + TextBlockDelta::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -885,43 +885,43 @@ impl ::protobuf::Message for BlockDelta { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "block_id", - |m: &BlockDelta| { &m.block_id }, - |m: &mut BlockDelta| { &mut m.block_id }, + |m: &TextBlockDelta| { &m.block_id }, + |m: &mut TextBlockDelta| { &mut m.block_id }, )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "delta_json", - |m: &BlockDelta| { &m.delta_json }, - |m: &mut BlockDelta| { &mut m.delta_json }, + "delta_str", + |m: &TextBlockDelta| { &m.delta_str }, + |m: &mut TextBlockDelta| { &mut m.delta_str }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "BlockDelta", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "TextBlockDelta", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static BlockDelta { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(BlockDelta::new) + fn default_instance() -> &'static TextBlockDelta { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(TextBlockDelta::new) } } -impl ::protobuf::Clear for BlockDelta { +impl ::protobuf::Clear for TextBlockDelta { fn clear(&mut self) { self.block_id.clear(); - self.delta_json.clear(); + self.delta_str.clear(); self.unknown_fields.clear(); } } -impl ::std::fmt::Debug for BlockDelta { +impl ::std::fmt::Debug for TextBlockDelta { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for BlockDelta { +impl ::protobuf::reflect::ProtobufValue for TextBlockDelta { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } @@ -1164,7 +1164,7 @@ impl ::protobuf::reflect::ProtobufValue for NewDocUser { } #[derive(PartialEq,Clone,Default)] -pub struct BlockId { +pub struct TextBlockId { // message fields pub value: ::std::string::String, // special fields @@ -1172,14 +1172,14 @@ pub struct BlockId { pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a BlockId { - fn default() -> &'a BlockId { - ::default_instance() +impl<'a> ::std::default::Default for &'a TextBlockId { + fn default() -> &'a TextBlockId { + ::default_instance() } } -impl BlockId { - pub fn new() -> BlockId { +impl TextBlockId { + pub fn new() -> TextBlockId { ::std::default::Default::default() } @@ -1210,7 +1210,7 @@ impl BlockId { } } -impl ::protobuf::Message for BlockId { +impl ::protobuf::Message for TextBlockId { fn is_initialized(&self) -> bool { true } @@ -1276,8 +1276,8 @@ impl ::protobuf::Message for BlockId { Self::descriptor_static() } - fn new() -> BlockId { - BlockId::new() + fn new() -> TextBlockId { + TextBlockId::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -1286,56 +1286,57 @@ impl ::protobuf::Message for BlockId { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "value", - |m: &BlockId| { &m.value }, - |m: &mut BlockId| { &mut m.value }, + |m: &TextBlockId| { &m.value }, + |m: &mut TextBlockId| { &mut m.value }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "BlockId", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "TextBlockId", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static BlockId { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(BlockId::new) + fn default_instance() -> &'static TextBlockId { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(TextBlockId::new) } } -impl ::protobuf::Clear for BlockId { +impl ::protobuf::Clear for TextBlockId { fn clear(&mut self) { self.value.clear(); self.unknown_fields.clear(); } } -impl ::std::fmt::Debug for BlockId { +impl ::std::fmt::Debug for TextBlockId { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for BlockId { +impl ::protobuf::reflect::ProtobufValue for TextBlockId { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x13document_info.proto\x1a\x0erevision.proto\"T\n\x11CreateBlockParam\ - s\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12/\n\trevisions\x18\x02\ - \x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\"m\n\tBlockInfo\x12\x15\ - \n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x12\n\x04text\x18\x02\x20\ - \x01(\tR\x04text\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\x05revId\x12\ - \x1e\n\x0bbase_rev_id\x18\x04\x20\x01(\x03R\tbaseRevId\"]\n\x13ResetDocu\ - mentParams\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12/\n\trevi\ - sions\x18\x02\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\"F\n\nBlock\ - Delta\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12\x1d\n\nde\ - lta_json\x18\x02\x20\x01(\tR\tdeltaJson\"S\n\nNewDocUser\x12\x17\n\x07us\ - er_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\ - \x03R\x05revId\x12\x15\n\x06doc_id\x18\x03\x20\x01(\tR\x05docId\"\x1f\n\ - \x07BlockId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05valueb\x06proto3\ + \n\x15text_block_info.proto\x1a\x0erevision.proto\"X\n\x15CreateTextBloc\ + kParams\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12/\n\trevisions\x18\ + \x02\x20\x01(\x0b2\x11.RepeatedRevisionR\trevisions\"u\n\rTextBlockInfo\ + \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12\x12\n\x04text\ + \x18\x02\x20\x01(\tR\x04text\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\ + \x05revId\x12\x1e\n\x0bbase_rev_id\x18\x04\x20\x01(\x03R\tbaseRevId\"b\n\ + \x14ResetTextBlockParams\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07bl\ + ockId\x12/\n\trevisions\x18\x02\x20\x01(\x0b2\x11.RepeatedRevisionR\trev\ + isions\"H\n\x0eTextBlockDelta\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\ + \x07blockId\x12\x1b\n\tdelta_str\x18\x02\x20\x01(\tR\x08deltaStr\"S\n\nN\ + ewDocUser\x12\x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\ + \x06rev_id\x18\x02\x20\x01(\x03R\x05revId\x12\x15\n\x06doc_id\x18\x03\ + \x20\x01(\tR\x05docId\"#\n\x0bTextBlockId\x12\x14\n\x05value\x18\x01\x20\ + \x01(\tR\x05valueb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-collaboration/src/protobuf/model/ws_data.rs b/shared-lib/flowy-sync/src/protobuf/model/ws_data.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/protobuf/model/ws_data.rs rename to shared-lib/flowy-sync/src/protobuf/model/ws_data.rs diff --git a/shared-lib/flowy-collaboration/src/protobuf/proto/folder_info.proto b/shared-lib/flowy-sync/src/protobuf/proto/folder_info.proto similarity index 100% rename from shared-lib/flowy-collaboration/src/protobuf/proto/folder_info.proto rename to shared-lib/flowy-sync/src/protobuf/proto/folder_info.proto diff --git a/shared-lib/flowy-collaboration/src/protobuf/proto/revision.proto b/shared-lib/flowy-sync/src/protobuf/proto/revision.proto similarity index 89% rename from shared-lib/flowy-collaboration/src/protobuf/proto/revision.proto rename to shared-lib/flowy-sync/src/protobuf/proto/revision.proto index 34c37409ab..5e899e9688 100644 --- a/shared-lib/flowy-collaboration/src/protobuf/proto/revision.proto +++ b/shared-lib/flowy-sync/src/protobuf/proto/revision.proto @@ -19,10 +19,6 @@ message RevisionRange { int64 start = 1; int64 end = 2; } -enum RevisionState { - Sync = 0; - Ack = 1; -} enum RevType { DeprecatedLocal = 0; DeprecatedRemote = 1; diff --git a/shared-lib/flowy-collaboration/src/protobuf/proto/document_info.proto b/shared-lib/flowy-sync/src/protobuf/proto/text_block_info.proto similarity index 62% rename from shared-lib/flowy-collaboration/src/protobuf/proto/document_info.proto rename to shared-lib/flowy-sync/src/protobuf/proto/text_block_info.proto index 4e234478f2..70717c4d2b 100644 --- a/shared-lib/flowy-collaboration/src/protobuf/proto/document_info.proto +++ b/shared-lib/flowy-sync/src/protobuf/proto/text_block_info.proto @@ -1,29 +1,29 @@ syntax = "proto3"; import "revision.proto"; -message CreateBlockParams { +message CreateTextBlockParams { string id = 1; RepeatedRevision revisions = 2; } -message BlockInfo { - string doc_id = 1; +message TextBlockInfo { + string block_id = 1; string text = 2; int64 rev_id = 3; int64 base_rev_id = 4; } -message ResetDocumentParams { - string doc_id = 1; +message ResetTextBlockParams { + string block_id = 1; RepeatedRevision revisions = 2; } -message BlockDelta { +message TextBlockDelta { string block_id = 1; - string delta_json = 2; + string delta_str = 2; } message NewDocUser { string user_id = 1; int64 rev_id = 2; string doc_id = 3; } -message BlockId { +message TextBlockId { string value = 1; } diff --git a/shared-lib/flowy-collaboration/src/protobuf/proto/ws_data.proto b/shared-lib/flowy-sync/src/protobuf/proto/ws_data.proto similarity index 100% rename from shared-lib/flowy-collaboration/src/protobuf/proto/ws_data.proto rename to shared-lib/flowy-sync/src/protobuf/proto/ws_data.proto diff --git a/shared-lib/flowy-collaboration/src/server_document/document_manager.rs b/shared-lib/flowy-sync/src/server_document/document_manager.rs similarity index 88% rename from shared-lib/flowy-collaboration/src/server_document/document_manager.rs rename to shared-lib/flowy-sync/src/server_document/document_manager.rs index 864840e9b5..8ce136480e 100644 --- a/shared-lib/flowy-collaboration/src/server_document/document_manager.rs +++ b/shared-lib/flowy-sync/src/server_document/document_manager.rs @@ -1,5 +1,5 @@ use crate::{ - entities::{document_info::BlockInfo, ws_data::ServerRevisionWSDataBuilder}, + entities::{text_block_info::TextBlockInfo, ws_data::ServerRevisionWSDataBuilder}, errors::{internal_error, CollaborateError, CollaborateResult}, protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::document_pad::ServerDocument, @@ -17,41 +17,42 @@ use tokio::{ task::spawn_blocking, }; -pub trait DocumentCloudPersistence: Send + Sync + Debug { - fn read_document(&self, doc_id: &str) -> BoxResultFuture; +pub trait TextBlockCloudPersistence: Send + Sync + Debug { + fn read_text_block(&self, doc_id: &str) -> BoxResultFuture; - fn create_document( + fn create_text_block( &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture, CollaborateError>; + ) -> BoxResultFuture, CollaborateError>; - fn read_document_revisions( + fn read_text_block_revisions( &self, doc_id: &str, rev_ids: Option>, ) -> BoxResultFuture, CollaborateError>; - fn save_document_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError>; + fn save_text_block_revisions(&self, repeated_revision: RepeatedRevisionPB) + -> BoxResultFuture<(), CollaborateError>; - fn reset_document( + fn reset_text_block( &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, ) -> BoxResultFuture<(), CollaborateError>; } -impl RevisionSyncPersistence for Arc { +impl RevisionSyncPersistence for Arc { fn read_revisions( &self, object_id: &str, rev_ids: Option>, ) -> BoxResultFuture, CollaborateError> { - (**self).read_document_revisions(object_id, rev_ids) + (**self).read_text_block_revisions(object_id, rev_ids) } fn save_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { - (**self).save_document_revisions(repeated_revision) + (**self).save_text_block_revisions(repeated_revision) } fn reset_object( @@ -59,17 +60,17 @@ impl RevisionSyncPersistence for Arc { object_id: &str, repeated_revision: RepeatedRevisionPB, ) -> BoxResultFuture<(), CollaborateError> { - (**self).reset_document(object_id, repeated_revision) + (**self).reset_text_block(object_id, repeated_revision) } } pub struct ServerDocumentManager { document_handlers: Arc>>>, - persistence: Arc, + persistence: Arc, } impl ServerDocumentManager { - pub fn new(persistence: Arc) -> Self { + pub fn new(persistence: Arc) -> Self { Self { document_handlers: Arc::new(RwLock::new(HashMap::new())), persistence, @@ -151,7 +152,7 @@ impl ServerDocumentManager { } let mut write_guard = self.document_handlers.write().await; - match self.persistence.read_document(doc_id).await { + match self.persistence.read_text_block(doc_id).await { Ok(doc) => { let handler = self.create_document_handler(doc).await.map_err(internal_error).unwrap(); write_guard.insert(doc_id.to_owned(), handler.clone()); @@ -162,13 +163,12 @@ impl ServerDocumentManager { } } - #[tracing::instrument(level = "debug", skip(self, repeated_revision), err)] async fn create_document( &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, ) -> Result, CollaborateError> { - match self.persistence.create_document(doc_id, repeated_revision).await? { + match self.persistence.create_text_block(doc_id, repeated_revision).await? { None => Err(CollaborateError::internal().context("Create document info from revisions failed")), Some(doc) => { let handler = self.create_document_handler(doc).await?; @@ -181,7 +181,8 @@ impl ServerDocumentManager { } } - async fn create_document_handler(&self, doc: BlockInfo) -> Result, CollaborateError> { + #[tracing::instrument(level = "debug", skip(self, doc), err)] + async fn create_document_handler(&self, doc: TextBlockInfo) -> Result, CollaborateError> { let persistence = self.persistence.clone(); let handle = spawn_blocking(|| OpenDocumentHandler::new(doc, persistence)) .await @@ -205,8 +206,8 @@ struct OpenDocumentHandler { } impl OpenDocumentHandler { - fn new(doc: BlockInfo, persistence: Arc) -> Result { - let doc_id = doc.doc_id.clone(); + fn new(doc: TextBlockInfo, persistence: Arc) -> Result { + let doc_id = doc.block_id.clone(); let (sender, receiver) = mpsc::channel(1000); let users = DashMap::new(); @@ -214,7 +215,7 @@ impl OpenDocumentHandler { let sync_object = ServerDocument::from_delta(&doc_id, delta); let synchronizer = Arc::new(DocumentRevisionSynchronizer::new(doc.rev_id, sync_object, persistence)); - let queue = DocumentCommandRunner::new(&doc.doc_id, receiver, synchronizer); + let queue = DocumentCommandRunner::new(&doc.block_id, receiver, synchronizer); tokio::task::spawn(queue.run()); Ok(Self { doc_id, sender, users }) } diff --git a/shared-lib/flowy-collaboration/src/server_document/document_pad.rs b/shared-lib/flowy-sync/src/server_document/document_pad.rs similarity index 97% rename from shared-lib/flowy-collaboration/src/server_document/document_pad.rs rename to shared-lib/flowy-sync/src/server_document/document_pad.rs index 766fc5cb2a..1f4fa7bda1 100644 --- a/shared-lib/flowy-collaboration/src/server_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/server_document/document_pad.rs @@ -39,7 +39,7 @@ impl RevisionSyncObject for ServerDocument { } fn to_json(&self) -> String { - self.delta.to_delta_json() + self.delta.to_delta_str() } fn set_delta(&mut self, new_delta: Delta) { diff --git a/shared-lib/flowy-collaboration/src/server_document/mod.rs b/shared-lib/flowy-sync/src/server_document/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/server_document/mod.rs rename to shared-lib/flowy-sync/src/server_document/mod.rs diff --git a/shared-lib/flowy-collaboration/src/server_folder/folder_manager.rs b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/server_folder/folder_manager.rs rename to shared-lib/flowy-sync/src/server_folder/folder_manager.rs diff --git a/shared-lib/flowy-collaboration/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs similarity index 96% rename from shared-lib/flowy-collaboration/src/server_folder/folder_pad.rs rename to shared-lib/flowy-sync/src/server_folder/folder_pad.rs index eb1d6aa9dc..3b51e52ed7 100644 --- a/shared-lib/flowy-collaboration/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -32,7 +32,7 @@ impl RevisionSyncObject for ServerFolder { } fn to_json(&self) -> String { - self.delta.to_delta_json() + self.delta.to_delta_str() } fn set_delta(&mut self, new_delta: PlainTextDelta) { diff --git a/shared-lib/flowy-collaboration/src/server_folder/mod.rs b/shared-lib/flowy-sync/src/server_folder/mod.rs similarity index 100% rename from shared-lib/flowy-collaboration/src/server_folder/mod.rs rename to shared-lib/flowy-sync/src/server_folder/mod.rs diff --git a/shared-lib/flowy-collaboration/src/synchronizer.rs b/shared-lib/flowy-sync/src/synchronizer.rs similarity index 99% rename from shared-lib/flowy-collaboration/src/synchronizer.rs rename to shared-lib/flowy-sync/src/synchronizer.rs index 2141b84952..1305c471b2 100644 --- a/shared-lib/flowy-collaboration/src/synchronizer.rs +++ b/shared-lib/flowy-sync/src/synchronizer.rs @@ -83,7 +83,7 @@ where } } - #[tracing::instrument(level = "debug", skip(self, user, repeated_revision), err)] + #[tracing::instrument(level = "trace", skip(self, user, repeated_revision), err)] pub async fn sync_revisions( &self, user: Arc, diff --git a/shared-lib/flowy-collaboration/src/util.rs b/shared-lib/flowy-sync/src/util.rs similarity index 83% rename from shared-lib/flowy-collaboration/src/util.rs rename to shared-lib/flowy-sync/src/util.rs index 07db9cdbce..a3ea7b136e 100644 --- a/shared-lib/flowy-collaboration/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -1,15 +1,17 @@ use crate::{ entities::{ - document_info::BlockInfo, folder_info::{FolderDelta, FolderInfo}, revision::{RepeatedRevision, Revision}, + text_block_info::TextBlockInfo, }, errors::{CollaborateError, CollaborateResult}, protobuf::{ - BlockInfo as BlockInfoPB, FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB, - Revision as RevisionPB, + FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB, + TextBlockInfo as TextBlockInfoPB, }, }; +use dissimilar::Chunk; +use lib_ot::core::{DeltaBuilder, FlowyStr}; use lib_ot::{ core::{Attributes, Delta, OperationTransformable, NEW_LINE, WHITESPACE}, rich_text::RichTextDelta, @@ -187,7 +189,7 @@ pub fn make_folder_pb_from_revisions_pb( folder_delta = folder_delta.compose(&delta)?; } - let text = folder_delta.to_delta_json(); + let text = folder_delta.to_delta_str(); let mut folder_info = FolderInfoPB::new(); folder_info.set_folder_id(folder_id.to_owned()); folder_info.set_text(text); @@ -200,11 +202,11 @@ pub fn make_folder_pb_from_revisions_pb( pub fn make_document_info_from_revisions_pb( doc_id: &str, revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { +) -> Result, CollaborateError> { match make_document_info_pb_from_revisions_pb(doc_id, revisions)? { None => Ok(None), Some(pb) => { - let document_info: BlockInfo = pb.try_into().map_err(|e| { + let document_info: TextBlockInfo = pb.try_into().map_err(|e| { CollaborateError::internal().context(format!("Deserialize document info from pb failed: {}", e)) })?; Ok(Some(document_info)) @@ -216,7 +218,7 @@ pub fn make_document_info_from_revisions_pb( pub fn make_document_info_pb_from_revisions_pb( doc_id: &str, mut revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { +) -> Result, CollaborateError> { let revisions = revisions.take_items(); if revisions.is_empty() { return Ok(None); @@ -237,9 +239,9 @@ pub fn make_document_info_pb_from_revisions_pb( document_delta = document_delta.compose(&delta)?; } - let text = document_delta.to_delta_json(); - let mut block_info = BlockInfoPB::new(); - block_info.set_doc_id(doc_id.to_owned()); + let text = document_delta.to_delta_str(); + let mut block_info = TextBlockInfoPB::new(); + block_info.set_block_id(doc_id.to_owned()); block_info.set_text(text); block_info.set_base_rev_id(base_rev_id); block_info.set_rev_id(rev_id); @@ -254,3 +256,28 @@ pub fn rev_id_from_str(s: &str) -> Result { .map_err(|e| CollaborateError::internal().context(format!("Parse rev_id from {} failed. {}", s, e)))?; Ok(rev_id) } + +pub fn cal_diff(old: String, new: String) -> Option> { + let chunks = dissimilar::diff(&old, &new); + let mut delta_builder = DeltaBuilder::::new(); + for chunk in &chunks { + match chunk { + Chunk::Equal(s) => { + delta_builder = delta_builder.retain(FlowyStr::from(*s).utf16_size()); + } + Chunk::Delete(s) => { + delta_builder = delta_builder.delete(FlowyStr::from(*s).utf16_size()); + } + Chunk::Insert(s) => { + delta_builder = delta_builder.insert(*s); + } + } + } + + let delta = delta_builder.build(); + if delta.is_empty() { + None + } else { + Some(delta) + } +} diff --git a/shared-lib/lib-infra/Cargo.toml b/shared-lib/lib-infra/Cargo.toml index 7644241ec3..cbde79b6d6 100644 --- a/shared-lib/lib-infra/Cargo.toml +++ b/shared-lib/lib-infra/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -uuid = { version = "0.8", features = ["serde", "v4"] } log = "0.4.14" chrono = "0.4.19" bytes = { version = "1.0" } diff --git a/shared-lib/lib-infra/src/future.rs b/shared-lib/lib-infra/src/future.rs index 9a0b6550dd..9077dd18b7 100644 --- a/shared-lib/lib-infra/src/future.rs +++ b/shared-lib/lib-infra/src/future.rs @@ -65,34 +65,3 @@ where } pub type BoxResultFuture<'a, T, E> = BoxFuture<'a, Result>; - -#[pin_project] -pub struct FutureResultSend { - #[pin] - pub fut: Pin> + Send>>, -} - -impl FutureResultSend { - pub fn new(f: F) -> Self - where - F: Future> + Send + 'static, - { - Self { - fut: Box::pin(async { f.await }), - } - } -} - -impl Future for FutureResultSend -where - T: Send, - E: Debug, -{ - type Output = Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.as_mut().project(); - let result = ready!(this.fut.poll(cx)); - Poll::Ready(result) - } -} diff --git a/shared-lib/lib-infra/src/lib.rs b/shared-lib/lib-infra/src/lib.rs index ba8b17c7b5..cb6aee91b0 100644 --- a/shared-lib/lib-infra/src/lib.rs +++ b/shared-lib/lib-infra/src/lib.rs @@ -2,11 +2,6 @@ pub mod code_gen; pub mod future; pub mod retry; -#[allow(dead_code)] -pub fn uuid_string() -> String { - uuid::Uuid::new_v4().to_string() -} - #[allow(dead_code)] pub fn timestamp() -> i64 { chrono::Utc::now().timestamp() diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 94dd904217..29fd424dcb 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -501,7 +501,7 @@ impl Delta where T: Attributes + DeserializeOwned, { - pub fn from_json(json: &str) -> Result { + pub fn from_delta_str(json: &str) -> Result { let delta = serde_json::from_str(json).map_err(|e| { tracing::trace!("Deserialize failed: {:?}", e); tracing::trace!("{:?}", json); @@ -512,7 +512,7 @@ where pub fn from_bytes>(bytes: B) -> Result { let json = str::from_utf8(bytes.as_ref())?.to_owned(); - let val = Self::from_json(&json)?; + let val = Self::from_delta_str(&json)?; Ok(val) } } @@ -521,7 +521,7 @@ impl Delta where T: Attributes + serde::Serialize, { - pub fn to_delta_json(&self) -> String { + pub fn to_delta_str(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) } @@ -529,8 +529,8 @@ where self.apply("") } - pub fn to_bytes(&self) -> Bytes { - let json = self.to_delta_json(); + pub fn to_delta_bytes(&self) -> Bytes { + let json = self.to_delta_str(); Bytes::from(json.into_bytes()) } } diff --git a/shared-lib/lib-ws/src/msg.rs b/shared-lib/lib-ws/src/msg.rs index 522491a8a6..51f0a76607 100644 --- a/shared-lib/lib-ws/src/msg.rs +++ b/shared-lib/lib-ws/src/msg.rs @@ -12,10 +12,12 @@ pub struct WebSocketRawMessage { pub data: Vec, } +// The lib-ws crate should not contain business logic.So WSChannel should be removed into another place. #[derive(ProtoBuf_Enum, Debug, Clone, Eq, PartialEq, Hash)] pub enum WSChannel { Document = 0, Folder = 1, + Grid = 2, } impl std::default::Default for WSChannel { @@ -29,6 +31,7 @@ impl ToString for WSChannel { match self { WSChannel::Document => "0".to_string(), WSChannel::Folder => "1".to_string(), + WSChannel::Grid => "2".to_string(), } } } diff --git a/shared-lib/lib-ws/src/protobuf/model/msg.rs b/shared-lib/lib-ws/src/protobuf/model/msg.rs index 0911d4e9b9..35537df3f0 100644 --- a/shared-lib/lib-ws/src/protobuf/model/msg.rs +++ b/shared-lib/lib-ws/src/protobuf/model/msg.rs @@ -217,6 +217,7 @@ impl ::protobuf::reflect::ProtobufValue for WebSocketRawMessage { pub enum WSChannel { Document = 0, Folder = 1, + Grid = 2, } impl ::protobuf::ProtobufEnum for WSChannel { @@ -228,6 +229,7 @@ impl ::protobuf::ProtobufEnum for WSChannel { match value { 0 => ::std::option::Option::Some(WSChannel::Document), 1 => ::std::option::Option::Some(WSChannel::Folder), + 2 => ::std::option::Option::Some(WSChannel::Grid), _ => ::std::option::Option::None } } @@ -236,6 +238,7 @@ impl ::protobuf::ProtobufEnum for WSChannel { static values: &'static [WSChannel] = &[ WSChannel::Document, WSChannel::Folder, + WSChannel::Grid, ]; values } @@ -266,8 +269,8 @@ impl ::protobuf::reflect::ProtobufValue for WSChannel { static file_descriptor_proto_data: &'static [u8] = b"\ \n\tmsg.proto\"O\n\x13WebSocketRawMessage\x12$\n\x07channel\x18\x01\x20\ \x01(\x0e2\n.WSChannelR\x07channel\x12\x12\n\x04data\x18\x02\x20\x01(\ - \x0cR\x04data*%\n\tWSChannel\x12\x0c\n\x08Document\x10\0\x12\n\n\x06Fold\ - er\x10\x01b\x06proto3\ + \x0cR\x04data*/\n\tWSChannel\x12\x0c\n\x08Document\x10\0\x12\n\n\x06Fold\ + er\x10\x01\x12\x08\n\x04Grid\x10\x02b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/lib-ws/src/protobuf/proto/msg.proto b/shared-lib/lib-ws/src/protobuf/proto/msg.proto index e5237ddef0..9306bd499b 100644 --- a/shared-lib/lib-ws/src/protobuf/proto/msg.proto +++ b/shared-lib/lib-ws/src/protobuf/proto/msg.proto @@ -7,4 +7,5 @@ message WebSocketRawMessage { enum WSChannel { Document = 0; Folder = 1; + Grid = 2; }