Compare commits

...
696 Commits
Author SHA1 Message Date
nathan bc70b04110 chore: update changelog 2022-11-28 19:52:26 +08:00
Lucas.Xu 11a0ef319f Merge pull request #1461 from ramanverma2k/feat_1305
ci: add .exe installer support for Windows releases #1305
2022-11-28 19:51:05 +08:00
Nathan.foooandnathan bd32ce5543 Feat: support single select option filter (#1494)
* feat: support select option filter

* chore: select option filter ui

* chore: support edit single select filter

* chore: add flutter tests

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-28 19:41:57 +08:00
Nathan.foooandnathan c47f755155 feat: support checkbox filter (#1492)
* feat: support checkbox filter

* fix: unit test

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-27 23:44:23 +08:00
Richard Shiue d6cbbf3c2f chore: date cell & header editor UI + move to theme.of(context).texttheme (#1473)
* chore: textstyles

* chore: sizing
2022-11-27 17:24:04 +08:00
Nathan.fooo 8c7e2d341d Merge pull request #1490 from AppFlowy-IO/filter_bloc_test
chore: add filter test
2022-11-27 17:20:24 +08:00
Nathan.foooandnathan 039d62cbbb chore: update version number (#1491)
Co-authored-by: nathan <nathan@appflowy.io>
2022-11-27 17:20:08 +08:00
nathan b6773a732b chore: add filter tests 2022-11-27 16:53:42 +08:00
nathan 60267e674e chore: refactor grid test directory 2022-11-27 15:38:02 +08:00
Nathan.foooandnathan 182bfae5ad fix: filter UI bugs (#1489)
* chore: remove the add filter button if there is no filters can not be added

* fix: update field info after filter was changed

* chore: update filter choicechip ui

* chore: insert and delete one by one to keep the delete/insert index is right

* chore: show filter after creating the default filter

* chore: update textfield_tags version to calm the warnings

* chore: try to fix potential fails on backend test

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-27 14:47:11 +08:00
Nathan.foooandnathan 149c2a2725 Ci/build scripts (#1487)
* chore: rename flowy_dev name

* chore: rename tasks

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-26 22:18:39 +08:00
Nathan.foooandnathan 69a7ae5201 Implement Grid's filter UI (#1474)
* fix: border of field cell

* chore: add filter button

* chore: refactor setting button event

* chore: notify row did changed with filter configuration

* chore: add filter bloc test

* chore: config add filter button

* chore: create filter

* chore: load filters and update corresponding field property

* chore: add filter choice chip

* chore: config choice chip ui

* chore: send notification when filter updated

* chore: update filter after update field type option data

* fix: remove/add filter when update field's type option

* chore: create home setting bloc to save the setting of the home screen

* chore: add filter test

* chore: edit text filter ui

* fix: filter cell bugs

* fix: insert row out of bound

* chore: update setting icon in grid

* chore: shrink wrap the filter list

* refactor: extract row container from row cache

* chore: disable split-debuginfo

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-26 21:28:08 +08:00
Lucas.Xu 462daee934 fix: #1467 Editor's left and right margins is too rigid (#1471) 2022-11-22 20:06:54 +08:00
Richard Shiue 63059ea39d chore: tints depend on light and dark theme (#1470) 2022-11-22 20:06:32 +08:00
Richard Shiue 5a8f1db5a6 fix: divider colors for top and bottom border widgets (#1468) 2022-11-22 20:01:16 +08:00
Richard Shiue a8dc55b4f3 chore: use theme.of(context) text theme in settings and around app (#1466)
* chore: use theme.of(context) text theme in settings and around app

* chore: add textDecoration to FlowyText
2022-11-22 20:00:21 +08:00
Richard Shiue 67a253c9c7 fix: fix colors for buttons and allow more customization (#1465) 2022-11-21 08:23:37 +08:00
Richard Shiue dcf6628aa3 feat: add divider between sidebar and the page (#1450) 2022-11-19 19:05:09 +08:00
Richard Shiue dc462b3847 chore: use theme.of(context) text theme in shared widgets (#1460) 2022-11-19 18:00:08 +08:00
Richard Shiue 81bc31d1b1 chore: use theme.of(context) text theme in FlowyText (#1463) 2022-11-19 17:53:30 +08:00
Annie 500d5efc33 Merge pull request #1442 from ramanverma2k/fix_1416
fix: Application name in Windows taskbar.
2022-11-18 10:57:22 +08:00
Lucas.Xu 39254b7f17 Merge pull request #1319 from LucasXu0/image_selection_area
update image node selection style and fix the context menu display problem
2022-11-18 09:35:06 +08:00
Lucas.Xu 9c40a501fe Merge remote-tracking branch 'origin/main' into image_selection_area 2022-11-18 09:19:49 +08:00
ramanverma2k c1e6f27020 chore: update FileDescription to app name. 2022-11-17 19:45:25 +05:30
Richard Shiue d7f14db6ab chore: use theme.of(context) text theme in board (#1453) 2022-11-17 16:48:48 +08:00
Nathan.foooandnathan fc10ee2d6b Fix filter test (#1459)
* chore: move grid_view_editor.rs to view_editor folder

* chore: hide invisible rows

* fix: lock issue

* fix: flutter test potential failed

* chore: separate group tests

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-17 16:44:17 +08:00
ramanverma2k af9b4b3922 ci: build & upload installer package for windows 2022-11-17 13:33:19 +05:30
Richard Shiue f00a78746e chore: add textTheme to AppTheme (#1448)
* chore: add textTheme to AppTheme

* chore: extend scaled font size options

* chore: add text styles to extension and rename extension to AFThemeExtension

* chore: use 2021 material design text style tokens
2022-11-17 15:28:57 +08:00
Richard Shiue eb35fb25af feat: initial steps to allow changing the app font (#1433)
* feat: initial steps to allow customizing app font

* chore: remove unnecessary factory constructor
2022-11-16 14:40:30 +08:00
Nathan.fooo 276df8202a Merge pull request #1456 from AppFlowy-IO/filter_bloc
Add Filter bloc
2022-11-16 08:50:03 +08:00
nathan 0ee27097ce chore: add fitler bloc test 2022-11-15 23:17:01 +08:00
nathan f1ac38dd59 chore: add filter service 2022-11-15 13:04:30 +08:00
Richard Shiueandnathan 66ed712952 feat: Add new page icon and refactor (#1449)
* refactor: port to popover action list for add new page

* feat: add icons to menu items for add new page

* chore: change translation for Doc to Document

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-15 11:45:23 +08:00
nathan 3dddd907b0 chore: create filter bloc 2022-11-15 11:12:30 +08:00
Nathan.fooo 92de27eae8 Merge pull request #1455 from AppFlowy-IO/rename_doc_folder
chore: rename doc folder to document
2022-11-15 11:10:57 +08:00
nathan 1ee1f9c775 chore: fix ref 2022-11-15 10:46:26 +08:00
Nathan.fooo 5d20e16dc5 Merge pull request #1454 from AppFlowy-IO/feat/select_option_filter_test
Feat/select option filter test
2022-11-15 10:44:06 +08:00
nathan 400220a312 chore: rename doc folder to document 2022-11-15 10:22:35 +08:00
nathan 6846bbf103 chore: fix test 2022-11-15 10:19:13 +08:00
appflowy ef3837f246 chore: add selection option fitler test 2022-11-14 19:40:45 +08:00
Nathan.fooo c3a41ba9ad Merge pull request #1452 from AppFlowy-IO/feat/filter_date
Feat/filter date
2022-11-14 17:38:43 +08:00
appflowy 18c209848b chore: add select option tests 2022-11-14 17:21:32 +08:00
Lucas.Xu e076c2be90 Merge pull request #1451 from richardshiue/flowy-editor-background
fix: use surface color of colorscheme as editor's background color
2022-11-14 16:51:24 +08:00
appflowy c80fa5da78 chore: add date filter tests 2022-11-14 16:33:24 +08:00
Richard Shiue aaadab434c fix: use surface color of colorscheme as editor's background color 2022-11-14 15:31:39 +08:00
appflowy 0e137f12f5 chore: date with utc 2022-11-14 12:03:22 +08:00
appflowy 6aba344583 chore: rename some pb structs 2022-11-14 09:59:23 +08:00
Nathan.foooandnathan a0a16cc493 feat: config grid filter in backend & add tests
* chore: add search crate

* chore: add task order test

* chore: enable timeout

* add task crate

* chore: run filter task

* chore: run filter task

* chore: filter rows

* chore: cache filter result

* chore: filter rows when open a grid

* chore: add tests

* test: add number filter test

* test: add checkbox fitler test

* chore: fix test

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-13 22:23:57 +08:00
Onyedika Israel UkwuezeandLucas.Xu a1e0282df0 fix: NetworkType null safety issues (#1435)
* fix: Networktype null safety issues

Networktype returns nulls when the connectivity result is vpn resulting to null safety issues.
Implemented a case for when the connectivity result is vpn to resolve this issue.

* chore: update connectivity_plus_platform_interface ^1.2.2

* chore: update network state on Rust side

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2022-11-13 11:57:47 +08:00
ramanverma2k bb370b28b7 fix: Application name in Windows taskbar. 2022-11-12 12:14:08 +05:30
Nathan.fooo dd1dcba599 chore: return user setting (#1438) 2022-11-11 17:24:10 +08:00
Richard Shiue 5b4a93ee34 test: split test into widget and unit test (#1432) 2022-11-11 12:42:20 +08:00
Nathan.fooo f426745094 fix: await the cell dispose (#1437) 2022-11-11 12:41:53 +08:00
Nathan.fooo 840095d73c fix: create grid for each test (#1431) 2022-11-10 20:22:37 +08:00
Richard Shiueandappflowy bbd64fae81 refactor: appflowy theme system pt. 1 (#1407)
* refactor: port theme provider to bloc

* refactor: port from custom theme type enum to material design's brightness

* chore: add custom color extension to ThemeData

* refactor: use Theme.of(context) when trying to get theme colors

* refactor: toggle widget code refactor

* refactor: flowy hover style refactor

* refactor: flowy icon refactor

* fix: regression on sidebar tooltip text from #1210

* chore: read color from theme.of

* chore: quick access to custom color

* fix: dart test

* fix: scrollbar regression

* chore: fix flutter lint

* chore: fix grid bloc test

Co-authored-by: appflowy <annie@appflowy.io>
2022-11-10 14:22:18 +08:00
Annie eff1da2812 chore: include latest product screenshots 2022-11-09 17:08:58 +08:00
Lucas.Xu 65f677b277 Merge pull request #1429 from LucasXu0/refactor_appflowy_editor_example
Refactor appflowy editor example
2022-11-09 16:48:57 +08:00
Lucas.Xu b6ad0ba597 chore: update changelog 2022-11-09 16:06:55 +08:00
Lucas.Xu 9b56cbb648 fix: export error on Web platform 2022-11-09 16:00:07 +08:00
Lucas.Xu e20ce9052a feat: implement theme customizer showcase 2022-11-09 15:36:30 +08:00
Lucas.Xu 853be71bf5 feat: implement initalize editor from json and markdown 2022-11-09 15:06:36 +08:00
Lucas.Xu 9a908abfdd feat: implement save document to markdown 2022-11-09 14:36:55 +08:00
Nathan.fooo e482ac75f9 test: edit a field in kanban board (#1428) 2022-11-09 12:25:07 +08:00
Lucas.Xu 205b5f2c21 feat: implement save document to json 2022-11-09 11:50:08 +08:00
Lucas.Xu 064ed16a7a feat: implement drawer and simple editor 2022-11-09 11:37:26 +08:00
Lucas.Xu 8a53abef3f chore: update version and documentation 2022-11-09 11:37:06 +08:00
Nathan.fooo 42c2c4738a chore: remove flutter quill (#1426) 2022-11-09 11:07:29 +08:00
Lucas.Xu cdf6f1b38a Merge pull request #1424 from LucasXu0/markdown
Implement appflowy editor document to markdown
2022-11-09 09:50:15 +08:00
Lucas.Xu 17536fdecb feat: implement paste markdown text 2022-11-09 09:50:00 +08:00
Lucas.Xu eb7356474c feat: integate appflowy_editor markdown codec into appflowy 2022-11-08 21:43:51 +08:00
Lucas.Xu 76d1267aa5 feat: remove the codec code from main project 2022-11-08 21:36:51 +08:00
Lucas.Xu 888c1b86f0 test: markdown decoder test 2022-11-08 21:34:27 +08:00
Nathan.fooo 882d5535e6 Extract protobuf structs from flowy-sync crate (#1425)
* refactor: extract data model from flowy-sync crate

* chore: rename lib-infra features
2022-11-08 21:13:28 +08:00
Lucas.Xu 4622a412b7 feat: markdown to document 2022-11-08 20:10:09 +08:00
Lucas.Xu fc35f74751 feat: markdown to delta 2022-11-08 17:19:14 +08:00
Lucas.Xu f6e1f2185e chore: remove unused code 2022-11-08 15:55:02 +08:00
Lucas.Xu 2e7f803e02 test: markdown encoder test 2022-11-08 15:44:40 +08:00
Lucas.Xu 9eaa79b558 feat: document to markdown 2022-11-08 15:44:10 +08:00
Lucas.Xu c85ab276e9 feat: delta to markdown 2022-11-08 14:47:10 +08:00
Nathan.fooo 7f6ad504fd Merge pull request #1423 from AppFlowy-IO/refactor/revision_model
Refactor/revision model
2022-11-08 14:36:21 +08:00
appflowy 130c5f8e6e refactor: reanme flowy-grid-data-model to grid-rev-model 2022-11-08 14:12:13 +08:00
appflowy d39b31f357 refactor: rename folder-data-model to folder-rev-model 2022-11-08 13:47:48 +08:00
Nathan.fooo f36cc9a5d0 Merge pull request #1420 from AppFlowy-IO/refactor/flowy_revision_crate
Refactor: merge multiple revision into one
2022-11-08 13:41:04 +08:00
appflowy 6425997508 chore: merge lagging revisions when close the document 2022-11-08 12:00:04 +08:00
Lucas.Xu bf06211bff Merge pull request #1422 from LucasXu0/editor_background
chore: set theme.surface as editor's background color
2022-11-08 11:00:49 +08:00
Lucas.Xu 506f789318 chore: set theme.surface as editor's background color 2022-11-08 10:00:28 +08:00
nathan ebdd28cf1c chore: add ref count map 2022-11-08 09:30:10 +08:00
appflowy de4c1b24ef chore: fix warnings 2022-11-07 20:40:10 +08:00
Lucas.Xu ab664ebb2f Merge pull request #1419 from LucasXu0/fix_1413
fix: #1413 [Bug] Azrty keyboard not opening menu when typing /
2022-11-07 20:20:58 +08:00
Nathan.fooo 20f527f4eb Merge pull request #1384 from Cyrine-benabid/fix-option_button_doesnt-close_popover
Close popover on text field tap
2022-11-07 17:36:44 +08:00
appflowy b3b24d0cc0 chore: calculate the compact length after receiving ack 2022-11-07 17:30:24 +08:00
Lucas.Xu b15ed56008 fix: #1413 [Bug] Azrty keyboard not opening menu when typing / 2022-11-07 16:46:25 +08:00
Nathan.fooo 992be378bb Merge pull request #1418 from AppFlowy-IO/ci/fix_build
ci: fix typo
2022-11-07 15:54:33 +08:00
appflowy 5156248918 ci: fix typo 2022-11-07 15:27:31 +08:00
Lucas.Xu adaad9367d Merge pull request #1417 from LucasXu0/ci
fix: Windows CI error, need to install vcpkg
2022-11-07 15:08:54 +08:00
Lucas.Xu 8dc28e9286 fix: Windows CI error, need to install vcpkg 2022-11-07 14:49:32 +08:00
Lucas.Xu 49b2bcd20d Merge pull request #1386 from ramanverma2k/dep-pkg_1303
feat: create deb package for linux (#1303)
2022-11-07 10:29:38 +08:00
nathan e729c0a81f chore: add documentation 2022-11-07 10:09:05 +08:00
nathan ff7aab73cc chore: merge with config setting 2022-11-06 10:31:07 +08:00
Richard Shiue fcd214b1c0 fix: lint unhappy with unused import (#1412) 2022-11-04 22:15:03 +08:00
Xavier Chrétien a50f2a6eb9 ci: Add dmg support for MacOS and add the .dmg to the release (#1401) 2022-11-04 22:14:28 +08:00
nathan 2c71e4f885 chore: add tests 2022-11-02 17:15:27 +08:00
nathan f5dc9ed975 test: add revision tests 2022-11-02 11:49:36 +08:00
nathan 608a08eb76 refactor: md5 of revision 2022-11-02 10:21:10 +08:00
Eakam cd8e4ddf00 fix: disappearing hover effect on popover trigger (#1403) 2022-11-01 21:01:35 +08:00
cyrine-benabid 9c8d00bb61 fix: request focus when InputTextField is added (#1394)
* fix request focus when InputTextField is added

* style: fix indentation
2022-11-01 20:56:42 +08:00
ce19 9015e6f160 chore: Improved CHangelog.md (#1387) 2022-11-01 20:55:40 +08:00
wanderer163andarpitpandey0209 1262653144 fix: typos and grammar (#1408)
Co-authored-by: arpitpandey0209 <arpit100.700@rediffmail.com>
2022-11-01 20:51:03 +08:00
Nathan.fooo e9ad705ea3 Refactor/revision compose (#1410) 2022-11-01 18:59:53 +08:00
Nathan.foooandnathan b0d2cdf55a ci: Update release title (#1409)
* chore: update release title

* chore: update changelog

Co-authored-by: nathan <nathan@appflowy.io>
2022-11-01 14:27:33 +08:00
Cyrine-benabid c7d8a0b7c3 refactor: remove useless popoverMutex from _AddOptionButton widget 2022-10-31 06:48:28 +01:00
Cyrine-benabid 286c89bf74 refactor: remove useless onTap and don't pass popovermutex when not needed 2022-10-30 20:30:38 +01:00
Cyrine-benabid 339e3d242f style: rename class and fix constructor 2022-10-30 20:20:13 +01:00
Cyrine-benabid fad02eb09d fix: remove useless onTap 2022-10-30 20:19:20 +01:00
Cyrine-benabid 8f1752a253 fix: add missing super.initState() call 2022-10-30 19:30:56 +01:00
Cyrine-benabid 16a8dbc6ce feat: unfocus CreateOptionTextField when popover state changes 2022-10-30 18:27:12 +01:00
Cyrine-benabid 1a53a0e375 refactor: implementation using focusNode 2022-10-30 18:25:50 +01:00
appflowy 52b713081d chore: update version 2022-10-30 19:44:39 +08:00
Nathan.fooo 3fbcd928db fix: padding for edit field (#1400) 2022-10-30 19:31:53 +08:00
Lucas.Xu fa4e3d0d2a Merge pull request #1397 from LucasXu0/auto_focus
feat: implement auto focus
2022-10-30 17:07:35 +08:00
ramanverma2k 319c358d1b ci: add postinst & postrm scripts to linux deb package 2022-10-30 12:09:20 +05:30
Nathan.fooo bc5548ff75 fix: changeset composing (#1398) 2022-10-30 12:54:07 +08:00
ramanverma2k 46a20123c1 ci: update linux deb package build workflow 2022-10-30 09:45:52 +05:30
ramanverma2k 380d921dae ci: respect debian package naming convention. 2022-10-30 09:33:06 +05:30
Lucas.Xu 6130dfe36a feat: implement auto focus 2022-10-30 10:34:55 +08:00
Lucas.Xu 64b4a99aa1 Merge pull request #1391 from LucasXu0/pick_0_0_6_1_to_main
chore: pick release/0.0.6 to main
2022-10-30 10:17:05 +08:00
Nathan.foooandnathan 9344ea23ca fix: support float value in attributes (#1396)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-30 09:35:15 +08:00
Cyrine-benabid baeedf557d feat: close popover on AddOptionButton tap 2022-10-30 02:24:57 +02:00
Cyrine ben-abid b7f369b3d9 feat: close popover on text field tap 2022-10-29 16:47:32 +02:00
Cyrine ben-abid 3e76fa8e42 fix: close popover on add option button clicked and textfield focused 2022-10-29 16:47:32 +02:00
Nathan.fooo 783fd40f63 Feat/op compose (#1392) 2022-10-29 20:54:11 +08:00
Lucas.Xu 10541502b8 chore: pick release/0.0.6 to main 2022-10-29 17:00:40 +08:00
Lucas.Xu 95fdfd7da2 Merge pull request #1390 from LucasXu0/fix_enter_key_handler
fix: remove the unnecessary operation in enter key handler
2022-10-29 16:56:07 +08:00
Lucas.Xu 4a48a2af5a fix: remove the unnecessary operation in enter keyhandler 2022-10-29 15:16:31 +08:00
Annie d82a6c5924 Merge pull request #1388 from Abubakrce19/chore-improved-changelog.md
chore: improved changelog.md
2022-10-29 15:00:41 +08:00
Sean Riley Hawkins 4d89b7a24e test: scroll service test for editor 2022-10-28 21:25:04 +08:00
ce19 e5bca9e9cc chore: improved changelog.md 2022-10-28 11:07:22 +05:00
ramanverma2k 2cbd74c716 feat: create deb package for linux 2022-10-27 20:05:37 +05:30
Lucas.Xu 43e4b1efad Merge pull request #1382 from LucasXu0/changelog
chore: update CHANGELOG
2022-10-27 20:32:35 +08:00
Lucas.Xu a8f791e98c chore: update CHANGELOG 2022-10-27 15:38:37 +08:00
Lucas.Xu b6dc18ba32 chore: update appflowy_editor CHANGELOG 2022-10-27 15:30:19 +08:00
Lucas.Xu 9c24597bbd Merge pull request #1380 from LucasXu0/appflowy_editor_0_0_7
appflowy editor 0.0.7
2022-10-27 15:23:17 +08:00
Lucas.Xu ea46272b49 Merge pull request #1373 from LucasXu0/fix_checkbox_copy
fix: copy link and code style
2022-10-27 15:22:54 +08:00
Lucas.Xu ac36d76eed chore: update version 0.0.7 2022-10-27 14:53:15 +08:00
Lucas.Xu 90b9456b0b chore: update documentation for customizing a theme 2022-10-27 14:52:17 +08:00
Nathan.fooo 309bbbd8e7 chore: Add group by field tests 2022-10-27 14:11:15 +08:00
Lucas.Xu 862ba3173a chore: update main.dart 2022-10-27 14:08:54 +08:00
Lucas.Xu 76cdb689fb chore: update language for bn_BN 2022-10-27 14:00:24 +08:00
Nathan.fooo 3bbf91ab2b Add board group test (#1376) 2022-10-26 22:36:34 +08:00
Nathan.fooo c8044a92d1 fix: group by field (#1374) 2022-10-26 21:46:47 +08:00
Lucas.Xu 799ceb432f fix: copy link and code style 2022-10-26 20:14:35 +08:00
Lucas.Xu c7c9048fe3 Merge pull request #1364 from LucasXu0/adapt_dart_mode
feat: adapt dark mode
2022-10-26 14:55:37 +08:00
Utsav Paul 7e2a0144a1 feat: added new translation (bn_BN) to appflowy-editor (#1356)
* Create intl_bn_BN.arb

* Update intl_bn_BN.arb
2022-10-26 14:52:53 +08:00
Lucas.Xu 3f97820094 feat: customize the placeholder text style 2022-10-26 14:51:39 +08:00
Lucas.Xu e7adc3bcbf fix: selection menu show in wrong position 2022-10-26 14:36:00 +08:00
Lucas.Xu 381913307c fix: copy selection exception 2022-10-26 11:54:21 +08:00
Lucas.Xu 799ed2fdb9 feat: custom upload image menu style 2022-10-26 11:47:38 +08:00
Lucas.Xu a68903918c feat: custom link menu style 2022-10-26 11:43:10 +08:00
Nathan.fooo 170bbb6db0 test: add home bloc test (#1371) 2022-10-26 11:09:51 +08:00
Lucas.Xu a702c06dc8 feat: custom context menu style 2022-10-26 11:01:25 +08:00
Lucas.Xu fac76ac5b8 feat: custom selection menu style 2022-10-26 10:52:30 +08:00
Nathan.fooo 2eea57aefa test: add app bloc test (#1370) 2022-10-26 10:38:57 +08:00
Lucas.Xu 23a65bfa2a feat: customize appflowy editor selection menu style 2022-10-26 10:16:14 +08:00
Hridaya Agrawal 23ffc3d0a8 chore: Update README.md (#1346) 2022-10-26 08:28:18 +08:00
Utsav PaulandNathan.fooo ff5a8c322d chore: Update README.md (#1357)
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2022-10-26 08:26:00 +08:00
Taduri Saimahesh e320439049 chore: Update README.md (#1360) 2022-10-26 08:23:58 +08:00
Lucas.Xu 8656cfeb1e chore: add extension for themedata 2022-10-25 22:15:31 +08:00
Lucas.Xu 6a853036a5 feat: customize appflowy editor heading style 2022-10-25 22:07:30 +08:00
Lucas.Xu c5cea81be2 feat: integrate appflowy editor dark mode 2022-10-25 21:58:44 +08:00
Lucas.Xu dde50d32d6 feat: refactor theme plugin, use themedata extension 2022-10-25 21:35:44 +08:00
Lucas.Xu cdee706f46 feat: refactor theme plugin, use themedata extension 2022-10-25 20:22:38 +08:00
Nathan.fooo 586c20a14e chore: add board test (#1363) 2022-10-25 19:50:11 +08:00
Richard Shiue 1e6c4a4d88 feat: introduce a default font (#1210)
* style: code auto-format

* feat: introduce default poppins font

* chore: port more const textstyles to shared styles
2022-10-25 19:49:58 +08:00
Nathan.fooo 18185cc90c chore: add app setting test (#1361) 2022-10-25 17:30:57 +08:00
Nathan.foooandnathan 67e4a759c7 chore: add reorder bloc test (#1354)
* chore: add reorder bloc test

* chore: add trash test

Co-authored-by: nathan <nathan@appflowy.io>
2022-10-25 16:51:51 +08:00
Lucas.Xu 68da3955c1 fix: disable toolbar hover color 2022-10-25 14:41:50 +08:00
Lucas.Xu 3fb997af84 feat: support dark mode for number-list and bulleted-list 2022-10-25 14:40:18 +08:00
Lucas.Xu 6fb677d346 Merge pull request #1353 from alemoreau/fix-undo_quote_doesnt_work
fix: remove attribute if it already exists on the node
2022-10-25 14:30:55 +08:00
Lucas.Xu 50814b2bee test: add test for format_rich_text_style.dart 2022-10-25 11:13:14 +08:00
Nathan.foooandnathan 5a6103f5d6 chore: add app bloc test (#1344)
* chore: add app bloc test

* chore: add wait

Co-authored-by: nathan <nathan@appflowy.io>
2022-10-25 09:01:26 +08:00
Richard Shiue da3d575295 chore: no longer need to delete all options before each test (#1348) 2022-10-25 08:36:09 +08:00
Richard Shiue 10229ca8b5 fix: avoid overlapping option colors (#1318) 2022-10-25 08:35:31 +08:00
Richard Shiue 58ad9a260c fix: several grid ui improvements (#1347) 2022-10-25 08:29:21 +08:00
Alexandre Moreau 5d2ff8e07c fix: remove attribute if it already exists on the node 2022-10-25 00:42:31 +02:00
nathan cc6bf3cc1e chore: update version 2022-10-23 22:16:40 +08:00
Nathan.foooandnathan 0d8be87031 chore: add view bloc test (#1343)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-23 17:52:17 +08:00
Nathan.foooandnathan c65d00e95c chore: add field editor bloc test (#1342)
* chore: add field editor bloc test

* chore: update log

Co-authored-by: nathan <nathan@appflowy.io>
2022-10-23 16:56:33 +08:00
Nathan.foooandnathan 96b1c6a540 chore: add grid header bloc test (#1341)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-23 16:44:10 +08:00
Lucas.Xu aa58c79dbb feat: support markdown export and customize save path (#1339) 2022-10-23 15:05:51 +08:00
Nathan.foooandnathan 87247ccd9d fix: hide field & add field tests (#1340)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-23 15:05:06 +08:00
Åke Engelbrektson aa8addf4a3 feat: Add Swedish translation (#1333)
* Create sv.json

* Update app_widget.dart

* Update language.dart
2022-10-23 13:14:08 +08:00
Nathan.fooo 7a92c5b538 Merge pull request #1337 from AppFlowy-IO/fix_create_field
fix: create a new property from grid
2022-10-23 12:06:03 +08:00
nathan 1af6c5eadc fix: bloc test errors 2022-10-23 11:52:15 +08:00
nathan 54826da701 chore: update wait response time 2022-10-23 10:59:53 +08:00
nathan 299e771877 fix: create a new property from grid 2022-10-23 10:32:37 +08:00
Lucas.Xu ad9a4b7d71 Integrate appflowy editor (#1040) 2022-10-22 21:57:44 +08:00
Nathan.fooo 8dff9dc67c chore: disable log in bloc test (#1336) 2022-10-22 20:58:33 +08:00
Richard Shiueandappflowy 80f034beee feat: alter some select option editor bloc events and add tests (#1264)
* chore: separate select and unselect events

* style: improve readability

* chore: don't send empty payloads if we can help it

* test: add select option text field test

* test: complete bloc test for select option

* test: delete all options between each test

* fix: keep insert order

* test: combine select and unselect tests

* chore: remove duplicate wait

Co-authored-by: appflowy <annie@appflowy.io>
2022-10-22 19:55:18 +08:00
Lucas.Xu bf1d4b923a Merge pull request #1322 from ChiragKr04/fix/grid-half-hidden-textfield
fix: half hidden textfield in name field
2022-10-21 09:48:54 +08:00
chiragkr04 9064b9f7ad fix: half hidden textfield in name field 2022-10-20 16:19:23 +05:30
Nathan.fooo 7dbd9fe8cd chore: implement document editor trait (#1321) 2022-10-20 15:33:18 +08:00
Nathan.foooandnathan f1a5726fcb Feat: add appflowy editor in backend (#1320)
* chore: remove update attributes

* chore: format code

* chore: extension for transaction

* refactor: add document editor trait

* chore: add appflowy_document editor

* chore: add document serde

* chore: add new document editor

* chore: add tests

* chore: add more test

* chore: add test

Co-authored-by: nathan <nathan@appflowy.io>
2022-10-20 11:35:11 +08:00
Lucas.Xu 2d66dfabe8 fix: the old context menu didn't dismiss after double-tap the other place 2022-10-19 16:49:41 +08:00
Lucas.Xu 585e71aa9d feat: update image builder to support board selection style 2022-10-19 16:35:52 +08:00
Lucas.Xu 833a6cd95f Merge pull request #1314 from LucasXu0/feature/context_menu
feat: implement context menu
2022-10-19 08:14:00 +07:00
Lucas.Xu 31ed88364a Merge pull request #1317 from alemoreau/grid-incomplete_display_of_the_property_names
fix: add overflow ellipsis in FieldCellButton
2022-10-19 08:13:43 +07:00
Alexandre Moreau 3ee703cd6d style: align code and add comment 2022-10-18 19:03:26 +02:00
Alexandre Moreau 0e278ddf3f fix: add overflow ellipsis in FieldCellButton 2022-10-18 13:44:23 +02:00
Lucas.Xu c793eb67fc test: skip the secondary tap test on Windows 2022-10-18 19:26:50 +08:00
Lucas.Xu d90414a8c1 fix: could not copy and paste the plain text 2022-10-18 19:23:04 +08:00
Lucas.Xu 056441bb39 Merge pull request #1316 from LucasXu0/escape
feat: implement new shortcut: press Escape to exit editing mode
2022-10-18 16:45:08 +07:00
Lucas.Xu 1eaeb2c4c1 feat: implement new shortcut: press Escape to exit editing mode 2022-10-18 17:22:12 +08:00
Lucas.Xu 793d3808ec test: add context menu test 2022-10-18 16:58:09 +08:00
Lucas.Xu 9e40b7f992 Merge remote-tracking branch 'origin/main' into feature/context_menu 2022-10-18 16:17:29 +08:00
Lucas.Xu cb769a7213 Merge pull request #1315 from LucasXu0/fix_codecov
chore: Run appflowy editor test every time
2022-10-18 15:16:55 +07:00
Lucas.Xu 255a4e6849 chore: Run appflowy editor test every time 2022-10-18 16:16:25 +08:00
Lucas.Xu 30700cd513 feat: implement context menu 2022-10-18 15:44:32 +08:00
Lucas.Xu bd88d89814 Merge pull request #1293 from LucasXu0/typo
fix: github issue template typo
2022-10-17 13:58:57 +07:00
Nathan.fooo 825725df7d Refactor/selection option transform (#1294)
* chore: support unnamed struct in AST parser progress

* chore: handle select option type option data transform in one place
2022-10-17 14:14:10 +08:00
Lucas.Xu 78728bb6ff fix: github issue template typo 2022-10-17 13:19:15 +08:00
He LinmingandNathan.fooo aead4dd068 feat: transform checkbox to select value (#1274)
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2022-10-17 13:10:44 +08:00
Nathan.foooandnathan 7edc4fd76e chore: add select option bloc test (#1291)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-17 10:31:56 +08:00
Chirag Bargoojar df91e00985 feat: horizontal scroll on multiselect options (#1282) 2022-10-16 20:49:47 +08:00
Nathan.foooandnathan 6a8c15899c chore: add grid bloc test (#1289)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-16 16:51:21 +08:00
David cbd84dfaad chore: Update es-VE.json (#1287)
Corrected some errors of the spanish translation file.
2022-10-16 11:17:46 +07:00
Nathan.foooandnathan 230eb5fd55 fix: run bloc_test (#1286)
* fix: run bloc_test

* fix: dart_test ci  workflow

Co-authored-by: nathan <nathan@appflowy.io>
2022-10-15 23:34:56 +08:00
Nathan.foooandnathan eb970a6b7a fix: FieldEditor not refresh its type-option data after switching to a new field (#1285)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-15 19:06:34 +08:00
Nathan.foooandnathan 63111927cc chore: remove events files when run clean + rebuild all (#1284)
Co-authored-by: nathan <nathan@appflowy.io>
2022-10-15 17:15:11 +08:00
Lucas.Xu 4d1e1a1c28 Merge pull request #1283 from LucasXu0/fix_macos_package_size
fix: #1279 macOS package size
2022-10-15 16:13:14 +07:00
8a94bbd602 feat: added support for markdown to link an image (#1277)
* feat: added support for markdown to link an image

#1064

* fix: fixed failing FlowyEditor test

#1064

* chore: add documentation

* chore: add documentation

* chore: update locale

* Refactor/rename crate (#1275)

* chore: addressed review comments

#1064

* chore: removed unused import

* fix: compile error and wrong image attributes

Co-authored-by: appflowy <annie@appflowy.io>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2022-10-15 17:04:02 +08:00
Lucas.Xu 9c7e64c502 fix: #1279 macOS package size 2022-10-14 21:10:58 +08:00
Chirag Bargoojar f53c2567fc fix: grid cell abnormal on click behaviour (#1278) 2022-10-14 16:09:40 +08:00
Lucas.Xu c7bdd4bcc2 Merge pull request #1273 from LucasXu0/transform
feat: notify transaction instead of operations
2022-10-14 11:36:28 +08:00
Nathan.fooo cf4a2920f8 Refactor/rename crate (#1275) 2022-10-13 23:29:37 +08:00
Lucas.Xu f3eeb471e7 refactor: abstract the common transaction to commands 2022-10-13 19:46:22 +08:00
Lucas.Xu 48bb80b1d0 Merge pull request #1272 from LucasXu0/locale
chore: update locale
2022-10-13 11:56:25 +08:00
Lucas.Xu 71b1769eee feat: notify transaction instead of operations 2022-10-13 11:55:16 +08:00
Lucas.Xu 8895430d9e chore: update locale 2022-10-13 11:30:02 +08:00
Nathan.fooo f363d3b0f6 Merge pull request #1269 from AppFlowy-IO/refactor/cell_data_parser_documentation
Refactor/cell data parser documentation
2022-10-13 09:29:24 +08:00
appflowy 3a7660108c chore: add documentation 2022-10-12 22:16:14 +08:00
appflowy a0d0a13030 chore: add documentation 2022-10-12 21:52:17 +08:00
Nathan.fooo c170b133e6 Merge pull request #1268 from AppFlowy-IO/fix/edit_no_status_card
Fix/edit no status card
2022-10-12 16:19:10 +08:00
appflowy 3511737bb3 fix: edit no status card 2022-10-12 15:41:34 +08:00
appflowy d2933bdb04 chore: add documentation 2022-10-12 12:11:33 +08:00
Nathan.fooo 00f7256e70 Merge pull request #1267 from AppFlowy-IO/fix/no_status_group_order
fix: no status groups order
2022-10-12 11:45:55 +08:00
appflowy da20d5c221 fix: can not keep the noo status groups order. Refactor the default index of no status group is 0 2022-10-12 11:16:59 +08:00
Nathan.fooo a516ec82bc fix: row disappear when update the row in checkbox board (#1266) 2022-10-12 10:20:26 +08:00
Nathan.foooandnathan 1adf6530fe Refactor/update type options (#1265)
* chore: add documentation

* chore: update type option data after switching to a new field type

* chore: insert yes/no option when switch from checkbox to single/multi select

Co-authored-by: nathan <nathan@appflowy.io>
2022-10-11 21:51:02 +08:00
Swapnil Kumbhar 0bc0a72d8a Code coverage for Rust (#1263)
* feat: Bumped Rust to stable-2022-04-07 (1.60.0)

* feat: Added coverage tests and report generation

* feat: Added workflow for Rust Coverage

* feat: Bumped Rust to 1.60.0 in Workflows

* test: Testing for CI

* ci: Added name and fixed path for Rust Coverage

* revert: "test: Testing for CI"

This reverts commit 049a7b1088.

* fix: Added .pub-cache to PATH, change incremental builds to zero

* test: Testing for CI

* ci: Installing protobuf compiler in CI

* revert: "test: Testing for CI"

This reverts commit 049a7b1088.

* ci: Added environment setup for dart

* test: Testing for CI

* feat: Added task to check if 'grcov' is installed

* ci: Added steps to install grcov

* test: Testing for CI

* ci: Fixed name for grcov installation step

* feat: Added cargo binaries to PATH in tests

* revert: "test: Testing for CI"

This reverts commit 24e425db66.

* revert: "test: Testing for CI"

This reverts commit a5de816bce.

* ci: Fixed a very silly failing case

* test: Created a test rust file for cov test
2022-10-11 19:54:31 +08:00
Richard Shiueandappflowy 295b887cf1 feat: use commas to select a tag in multi-select grid cells (#1158)
* fix: comma to select tags

* chore: support passing multiple option ids

* chore: add more unit tests for single select and multi select

* chore: move to select multiple options using a single payload

* chore: do not unselect the option if insert option ids contain that option

Co-authored-by: appflowy <annie@appflowy.io>
2022-10-11 13:43:29 +08:00
Lucas.Xu d80a67bdda refactor: implement appflowy editor core 2022-10-11 12:02:46 +08:00
Lucas.Xu f469253916 chore: update README.MD 2022-10-11 09:36:04 +08:00
Lucas.Xu 06173195c5 chore: dart fix 2022-10-11 09:33:16 +08:00
Minho Yi 68344ef718 Feat: Translation for Korean ko_KR (#1262)
* feat: add translation ko_KR.json

* feat: add ko Locale
2022-10-11 09:27:20 +08:00
Nathan.fooo 6b528733fa Merge pull request #1261 from sahej-dev/main
fix: Extra spacing in multiselect cell
2022-10-11 08:21:42 +08:00
Nathan.fooo a20e92f08a Merge pull request #1260 from AppFlowy-IO/refactor/switch_to_field 2022-10-11 07:58:59 +08:00
sahej-dev 820d2548b6 fix: Extra spacing in multiselect cell 2022-10-10 23:08:35 +05:30
nathan b8895ce787 chore: remove unuse code 2022-10-11 01:04:13 +08:00
Linchengyi 396d310d22 test: cover all Enum NumberFormat (#1257) 2022-10-11 00:02:44 +08:00
Lucas.Xu b5e9bf6ee3 test: operation.dart 2022-10-10 23:33:58 +08:00
appflowy 1f94d9d496 chore: fix test 2022-10-10 21:21:29 +08:00
Lucas.Xu 19bf8e3b7a refactor: move transaction.dart to core/transform 2022-10-10 20:07:52 +08:00
appflowy a2d27657dc refactor: remove insertField function in dart 2022-10-10 20:02:52 +08:00
Nathan.fooo 4e122a9452 chore: add group documentation (#1258) 2022-10-10 19:44:41 +08:00
Lucas.Xu 319875529f refactor: move operation.dart to core/transform 2022-10-10 16:31:28 +08:00
Lucas.Xu 805bdc9d32 refactor: move document.dart to core/document 2022-10-10 14:58:28 +08:00
Lucas.Xu b10ff5e68e refactor: move built_in_attributes_key to core/legacy 2022-10-10 14:53:36 +08:00
Lucas.Xu 5e7507c8e7 refactor: rename state_tree to document and move document to core/state 2022-10-10 12:08:13 +08:00
Nathan.fooo 4549ed20e7 Refactor/rename delta (#1256)
* chore: rename delta

* chore: renanme delta
2022-10-10 11:56:48 +08:00
Lucas.Xu d02c29426e refactor: move selection to core/location 2022-10-10 10:39:42 +08:00
Lucas.Xu b0257a626d refactor: move position to core/selection 2022-10-10 09:59:12 +08:00
Lucas.Xu e095fd4181 refactor: move text_delta to core/document 2022-10-10 09:41:54 +08:00
Lucas.Xu b9788bce09 refactor: move path to core/document 2022-10-09 23:53:18 +08:00
Lucas.Xu 7f92f8988f refactor: move node_iterator to core/document 2022-10-09 23:25:47 +08:00
Richard Shiueandappflowy 9758fe51f8 fix: regression on hover effect persisting after closing menu (#1253)
* fix: regression on hover effect persisting after closing menu

* chore: reset onhover when FlowyHover get rebuild

Co-authored-by: appflowy <annie@appflowy.io>
2022-10-09 22:50:35 +08:00
Ishan Pandhare 78b7027343 added new translation (hi_IN) to appflowy-editor (#1237)
feat: added new translation (hi_IN) to appflowy-editor
2022-10-09 16:11:46 +08:00
Ishan Pandhare 6c39b5b321 added translation for ru-RU (#1234)
feat: added translation for ru-RU
2022-10-09 16:11:05 +08:00
Lucas.Xu 123e6968af Merge pull request #1252 from Ishanned/windows-platform
feat: support windows platform in ci.yaml
2022-10-09 16:10:23 +08:00
Lucas.Xu a015c28e5a Merge pull request #1232 from Ishanned/branch1
feat: added translation for de_DE
2022-10-09 16:09:15 +08:00
Lucas.Xu cbb6b2d9b0 refactor: move attributes to core/document 2022-10-09 15:54:39 +08:00
Lucas.Xu 3d014ef274 chore: update ci.yaml 2022-10-09 14:33:46 +08:00
Lucas.Xu 11eca2b3d9 refactor: move node to core/document 2022-10-09 14:30:55 +08:00
Ishan Pandhare 47942ffadf feat: updated ci.yaml control statement 2022-10-09 11:22:37 +05:30
Ishan Pandhare 62c9108a68 feat: updated ci.yaml to support windows platform 2022-10-09 11:13:01 +05:30
Ishan Pandhare 3ebe783684 Merge branch 'AppFlowy-IO:main' into windows-platform 2022-10-09 11:06:02 +05:30
Annie 25347a3a90 chore: update README to include contributor icons 2022-10-09 11:51:45 +08:00
Ishan Pandhare 2dd9b9767e feat: support windows platform in ci.yaml 2022-10-08 19:50:30 +05:30
Nathan.fooo 89d036158b chore: update view state when close the popover (#1251) 2022-10-08 20:48:14 +08:00
Nathan.fooo ca8be6ab10 chore: replace overlay with popover (#1250) 2022-10-08 17:10:04 +08:00
Lucas.Xu 8d6e1cdaa1 Merge pull request #1187 from tekdel/main
feat: Support markdown to bold text
2022-10-08 11:46:20 +08:00
Lucas.Xu 1841fb293e chore: temporarily remove the code that automatically formats when inserting text 2022-10-08 11:25:26 +08:00
Lucas.Xu e9c0956c51 Merge remote-tracking branch 'origin/main' into tekdel/main
# Conflicts:
#	frontend/app_flowy/packages/appflowy_editor/test/infra/test_raw_key_event.dart
2022-10-08 11:11:42 +08:00
Lucas.Xu 06f1d52cc0 Merge pull request #1229 from enzoftware/main
test: Improve Code Coverage for extensions files
2022-10-08 10:50:36 +08:00
Enzo Lizama 2e45624973 test: Merge branch 'main' of github-enzo:enzoftware/AppFlowy 2022-10-07 21:25:59 -05:00
Enzo Lizama b784e9b842 chore: Merge branch 'main' of github-enzo:enzoftware/AppFlowy 2022-10-07 21:25:17 -05:00
Lucas.Xu 228a41d7ea Merge remote-tracking branch 'origin/main' into enzoftware/main
# Conflicts:
#	frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/tex_block_node_widget.dart
2022-10-08 10:24:51 +08:00
Enzo Lizama 2b8e4d3e61 test: delete file 2022-10-07 21:24:28 -05:00
Lucas.Xu 74b43511d1 Merge remote-tracking branch 'origin/main' into enzoftware/main
# Conflicts:
#	frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/tex_block_node_widget.dart
2022-10-08 10:15:30 +08:00
Ayush 238af3ed0e Added flatpak files (#208) 2022-10-08 09:29:29 +08:00
vortixhead fa9e32d86a feat: limit max character length on select/multiselect options (#1246)
* Add maxLength of 30 characters and truncation to text fields

* Add dynamic height

* Add maxLength param

* Add maxLength in Rounded Field
2022-10-08 09:24:05 +08:00
Sarang S 2537a04fef feat: Translation for Malayalam (ml_IN) (#1245) 2022-10-07 21:33:09 +08:00
Lucas.Xu b9f6b62053 Merge pull request #1242 from LucasXu0/0.0.6
chore: flutter analyze and flutter format
2022-10-07 16:27:36 +08:00
Nathan.fooo 0d2ceba817 Merge pull request #1243 from AppFlowy-IO/feat/pub_appflowy_board
chore: update appflowy_board version
2022-10-07 15:56:05 +08:00
appflowy dff5e84ca5 chore: update appflowy_board version 2022-10-07 15:33:54 +08:00
Lucas.Xu 2d61581eb3 chore: flutter analyze and flutter format 2022-10-07 15:25:33 +08:00
Lucas.Xu 4abd74ed4b Merge pull request #1240 from LucasXu0/0.0.6
chore: bump version to 0.0.6 (appflowy_editor)
2022-10-07 15:17:20 +08:00
Nathan.fooo 591d8a3872 Merge pull request #1241 from AppFlowy-IO/fix/1193
Fix/1193
2022-10-07 15:15:05 +08:00
appflowy fa3f9c21fc fix: state of AppFlowyBoard is wrong after reordering the group 2022-10-07 14:42:40 +08:00
Lucas.Xu 323b56982b chore: bump version to 0.0.6 (appflowy_editor) 2022-10-07 12:24:10 +08:00
Lucas.Xu c0879e8445 Merge pull request #1239 from LucasXu0/horizontal_rule
feat: implement horizontal rule
2022-10-07 12:01:18 +08:00
Lucas.Xu e27e8e43e1 chore: update the menu item size for code_block, horizaontal_rule and tex_block 2022-10-07 11:39:49 +08:00
Lucas.Xu e6d4f9e3f7 feat: implement horizontal rule 2022-10-07 11:24:39 +08:00
appflowy 73e81da356 fix: select card text 2022-10-06 22:26:18 +08:00
Lucas.Xu 8b87b77c15 Merge pull request #1238 from LucasXu0/fix_compile_error
chore: fix compile error
2022-10-06 22:22:57 +08:00
Lucas.Xu d146bb6481 chore: fix compile error 2022-10-06 22:02:56 +08:00
Richard Shiue 5860d35d1a fix: improve look of calendar (#1226) 2022-10-06 21:36:39 +08:00
Richard Shiue a4a88959fd fix: make sidebar resizing follow cursor more closely (#1202)
* fix: make sidebar resizing follow cursor more closely

* fix: don't animate sidebar size changes when dragging
2022-10-06 21:31:52 +08:00
Richard Shiue 5a5f5eceb5 fix: improve look of share button dropdown menu (#1224) 2022-10-06 19:33:02 +08:00
Enzo Lizama 73a97fdbea fix: conflict merge 2022-10-05 23:55:01 -05:00
Enzo Lizama Paredes d2121ed2b9 Merge branch 'main' into main 2022-10-05 23:53:58 -05:00
Enzo Lizama 90ac7970bd chore: remove dynamic methods 2022-10-05 23:49:41 -05:00
Enzo Lizama bfe61ea09d test: node tests 2022-10-05 23:46:34 -05:00
Ishan Pandhare 454f33e0fb added translation for de_DE 2022-10-06 09:59:09 +05:30
Enzo Lizama eaf396630c chore: url launcher test 2022-10-05 23:06:48 -05:00
Lucas.Xu 8a2c57014c Merge pull request #1184 from LucasXu0/latex
feat: implement TeX plugin
2022-10-06 10:53:35 +08:00
Lucas.Xu c9fc9e7497 Merge branch 'main' into latex 2022-10-06 10:32:38 +08:00
Lucas.Xu e67f91b380 Merge pull request #1209 from alemoreau/double_tilde_to_strikethrough
feat: double tildes to strikethrough text
2022-10-06 10:26:58 +08:00
Lucas.Xu 09bf373e92 Merge branch 'main' into double_tilde_to_strikethrough
# Conflicts:
#	frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart
#	frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart
2022-10-06 10:08:50 +08:00
Lucas.Xu d7d6729241 Merge pull request #1211 from citricacid2/main
feat: added markdown links
2022-10-06 09:59:16 +08:00
Lucas.Xu 562da32586 Merge pull request #1220 from citricacid2/num-list
feat: added numbered list to the slash menu
2022-10-05 22:31:22 +08:00
Ishan Pandhare 8ee5c6ed25 added translation for pt_PT (#1219) 2022-10-05 21:26:55 +08:00
Lucas.Xu 2501c15a8f chore: update l10n and fix selection_menu_widget_test 2022-10-05 21:07:45 +08:00
Enzo Lizama fe524736ec test: add url launcher test 2022-10-04 22:40:15 -05:00
Enzo Lizama b4aceec346 test: add mockito 2022-10-04 22:40:07 -05:00
Enzo Lizama 4acce447f2 test: add node extension test 2022-10-04 22:39:55 -05:00
Enzo Lizama c0aa90b0b3 test: text style tests 2022-10-04 22:19:38 -05:00
Enzo Lizama 50ebaa3ab8 test: object tests 2022-10-04 17:59:30 -05:00
Enzo Lizama 7914949613 test: color tests 2022-10-04 17:59:20 -05:00
Enzo Lizama dd15a49d76 test: add unit tests for attributes extensions 2022-10-04 11:38:34 -05:00
Enzo Lizama bf9f6ac13f chore: small code improvements 2022-10-04 11:37:59 -05:00
Enzo Lizama 6ea3ea189e chore: remove unused imports 2022-10-04 11:37:40 -05:00
Ankur 176668049c feat: Added fr_CA translation (#1212)
Signed-off-by: ankur12-1610 <anknerd.12@gmail.com>

Signed-off-by: ankur12-1610 <anknerd.12@gmail.com>
2022-10-04 20:30:45 +08:00
Ankur 069a23c96b feat: Added hu-HU translation (#1214)
Signed-off-by: ankur12-1610 <anknerd.12@gmail.com>

Signed-off-by: ankur12-1610 <anknerd.12@gmail.com>
2022-10-04 20:30:06 +08:00
Ankur c403e083cc feat: Added id-ID translation (#1217)
Signed-off-by: ankur12-1610 <anknerd.12@gmail.com>

Signed-off-by: ankur12-1610 <anknerd.12@gmail.com>
2022-10-04 20:29:38 +08:00
Alexandre Moreau d6cae56d74 test: add tests for double tilde to strikethrough 2022-10-04 01:01:24 +02:00
Alexandre Moreau b52dfe12c2 feat: add doubleTildeToStrikethrough ShortcutEventHandler to built-in ShortcutEvents 2022-10-04 01:01:17 +02:00
Alexandre Moreau be5123ca21 feat: implement doubleTildeToStrikethrough ShortcutEventHandler 2022-10-04 01:01:10 +02:00
citricacid2 3e620ed335 feat: added numbered list to the slash menu 2022-10-03 17:00:17 -04:00
citricacid2 6f4ab9a55d feat: added markdown links 2022-10-03 00:00:32 -04:00
Richard Shiue 2331b328d8 feat: elide sidebar text (#1026) 2022-10-03 09:58:13 +08:00
Richard Shiue cff24581a4 feat: use appflowy styled toggle widget in date settings (#1192)
* feat: use appflowy styled toggle widgets in date settings

* feat: some date cell UI improvements
2022-10-03 09:56:45 +08:00
Mehdi BertulandNoé Landré 285231a845 fix : added French translations (#1203)
* fix : added French translations

As usually, I worked on translating the new English UI strings to French.

* fix : "fixed the translation"

Co-authored-by: Noé Landré <68849024+DevNono@users.noreply.github.com>

* fix : "fixed the translation"

Co-authored-by: Noé Landré <68849024+DevNono@users.noreply.github.com>

Co-authored-by: Noé Landré <68849024+DevNono@users.noreply.github.com>
2022-10-03 09:46:45 +08:00
PapuleX 1eaf97b669 feat: Add Czech language (#1207) 2022-10-03 09:45:45 +08:00
Alessio Marinelli 35fbf99fb1 feat: Added it_IT translation (#1200) 2022-10-02 20:25:06 +08:00
Alessio Marinelli 7b8aa78e95 feat: Added fr_FR AppFlowy editor translation (#1201) 2022-10-02 20:21:00 +08:00
Luke Greenwood 2d1793c5ff fix: Theme toggle not updating UI (#1205) 2022-10-02 20:19:17 +08:00
Victor Szabo 04a7c8dc6d fix(scripts): add libkeybinder3 to Dockerfile (#1204) 2022-10-02 20:15:53 +08:00
Richard Shiue 3dc64f3d50 fix: improve look of select option list (#1168) 2022-10-01 21:13:56 +08:00
Lucas.Xu b8cbbf7454 Merge branch 'main' into main 2022-10-01 21:11:08 +08:00
Lucas.Xu 5e7a54183a Merge pull request #1133 from flappyBug/fix/click-selection-menu-item-delete-text
fix: remove keyword when click selection menu item
2022-10-01 21:09:54 +08:00
Lucas.Xu c0df0badec Merge pull request #1143 from MrHeer/feat/markdown_syntax_to_code_text
feat: backquote to code text
2022-10-01 21:08:37 +08:00
Lucas.Xu d115a8a79e Merge pull request #1196 from yabamiah/feat_pt-BR_translate
feat: translate AppFlowy Editor to pt_BR
2022-10-01 21:07:35 +08:00
Lucas.Xu 3156568594 Merge branch 'main' into feat/markdown_syntax_to_code_text 2022-10-01 19:35:08 +08:00
Lucas.Xu 570eb40c7a Merge pull request #1199 from MBlokhuijzen/feature/dutch_translations
Feature: Add Dutch Translation
2022-10-01 19:33:38 +08:00
Melvin Blokhuijzen 9206e2cdff feat: Add translation for Embed code 2022-10-01 11:56:36 +02:00
Melvin Blokhuijzen b20aaecc01 feat: Translate into dutch language 2022-10-01 11:53:48 +02:00
Syeerzy c11a00a380 locale fix (#1195) 2022-10-01 17:50:19 +08:00
Nathan.fooo f355ff01e4 Merge pull request #1197 from AppFlowy-IO/feat/support_drag_group
Feat/support drag group
2022-10-01 17:19:07 +08:00
Nathan.fooo cb3bd8efb5 Merge pull request #1198 from AppFlowy-IO/fix/fr_FR_conflict
fix: conflict in fr-FR file
2022-10-01 17:06:27 +08:00
appflowy 4894361076 fix: conflict in fr-FR file 2022-10-01 17:04:49 +08:00
appflowy 62d0a31a76 refactor: save default group order 2022-10-01 16:50:54 +08:00
Yaba adda0218fa feat: translate AppFlowy Editor to pt_BR 2022-10-01 00:06:29 -03:00
appflowy 5763e289ef feat: support moving group 2022-09-30 20:44:41 +08:00
Lucas.Xu 3df31c43f8 Merge pull request #1188 from LucasXu0/commands
feat: add commands and update checkbox logic
2022-09-30 20:09:19 +08:00
Lucas.Xu 8d39dac145 chore: disable IME support for the Web platform 2022-09-29 11:33:27 +08:00
Nathan.fooo 6c3978c3ba Merge pull request #578 from MidouWebDev/main
feature: Translate new words to French
2022-09-29 08:58:50 +08:00
Lucas.Xu 0a49a18280 fix: could not insert space sometimes on the web 2022-09-28 23:36:44 +08:00
Lucas.Xu 6ec93d49c2 feat: set link menu as auto focus 2022-09-28 23:03:02 +08:00
Lucas.Xu 99cb2430f7 fix: could not insert link on the Web 2022-09-28 23:01:22 +08:00
Mehdi Bertul 5a4af5a983 Fix translation of the color "Purple" 2022-09-28 14:17:39 +08:00
MidouWebDev 96ad14e891 Translate new words to French
Closes #462
2022-09-28 14:17:37 +08:00
Nathan.fooo 01230704ea Merge pull request #1189 from AppFlowy-IO/refactor/setting_documentation
refactor: add setting documentation and support save key/value in set…
2022-09-28 13:26:21 +08:00
Lucas.Xu ab0131c19c feat: disable apply operation when setting editable = false 2022-09-28 11:49:31 +08:00
appflowy 908d005737 refactor: add setting documentation and support save key/value in setting 2022-09-28 11:44:44 +08:00
Lucas.Xu 6230d0ad9f feat: add commands and update checkbox logic 2022-09-28 11:21:42 +08:00
Andrei Dolgov a8cb58cb4a fix: address a minor isssue when there is content after last asterisk/underscore 2022-09-27 16:38:18 -04:00
Andrei Dolgov 6a902a2b21 fix: workaround infinity formatting 2022-09-27 11:09:16 -04:00
Nathan.fooo 82182d7872 Merge pull request #1182 from AppFlowy-IO/fix/switch_to_text_property
fix: display cell data after switching to text field
2022-09-27 19:05:10 +08:00
appflowy 155cf3dca5 fix: display cell data after switching to text field 2022-09-27 18:22:11 +08:00
Lucas.Xu 9df11256cc feat: implement TeX plugin 2022-09-27 17:52:32 +08:00
Lucas.Xu b578067092 Merge pull request #1166 from LucasXu0/code_block
Implement code block feature for appflowy editor
2022-09-27 15:58:46 +08:00
Nathan.fooo e44b0a4bb8 Merge pull request #1180 from AppFlowy-IO/refactor/text_type_option_test
refactor: text type option test
2022-09-27 15:49:11 +08:00
Lucas.Xu af877913d7 feat: add auto detect language and remove the unused package 2022-09-27 14:36:40 +08:00
Lucas.Xu 86a6f5827d chore: revert the example.json 2022-09-27 14:24:59 +08:00
appflowy 84aa156885 refactor: text type option test 2022-09-27 14:20:18 +08:00
Nathan.fooo f66b3a447c Merge pull request #1176 from AppFlowy-IO/fix/update_group_if_field_changed
fix: update the group when the corresponding field changed
2022-09-27 13:53:49 +08:00
appflowy d1f80b15a0 fix: update the group when the corresponding field changed 2022-09-27 11:21:06 +08:00
Lucas.Xu 31ba12d289 fix: disable built-in toolbar items for non-built-in widget 2022-09-27 11:14:58 +08:00
Nathan.fooo 9b78f35ffe Merge pull request #1167 from AppFlowy-IO/fix/0053
Fix/0053
2022-09-27 10:57:28 +08:00
appflowy 602f7e7b6c fix: format number in percent format 2022-09-27 09:52:50 +08:00
Nathan.fooo 9a6dda417a Merge pull request #1165 from AppFlowy-IO/fix/open_latest_plugin
fix: open latest view
2022-09-27 09:19:09 +08:00
Andrei Dolgov c0964fad5d feat: double asterisks/underscores to bold text 2022-09-26 15:04:25 -04:00
Lucas.Xu 5421c156c3 fix: tab & enter test 2022-09-26 18:13:45 +08:00
appflowy e3a1384f7f fix: open latest after deleting current view 2022-09-26 17:17:46 +08:00
Lucas.Xu ff9cf905fa feat: implement simple code block 2022-09-26 16:55:49 +08:00
Lucas.Xu 2d32e02dba feat: tab for 4 spaces 2022-09-26 16:55:32 +08:00
Lucas.Xu ec97735e94 fix: prevent to copy the style in some cases when pressing the enter key in the front of the text 2022-09-26 16:55:06 +08:00
Lucas.Xu 49fb0470ab fix: should not notify the parent node when the subtype is not changed 2022-09-26 16:54:13 +08:00
appflowy 81ecbd8ae2 fix: open latest view 2022-09-26 15:25:33 +08:00
appflowy 41084da708 chore: update change log 2022-09-26 15:12:01 +08:00
Nathan.fooo 02fd2bc427 Merge pull request #1161 from Poly-Pixel/trash-resize-fix
fix: only open the last opened view if plugin is blank
2022-09-26 15:01:33 +08:00
Nathan.fooo 7037378947 Merge pull request #1162 from AppFlowy-IO/fix/1156
fix: calculate overlap
2022-09-26 11:40:02 +08:00
nathan ee463037e3 fix: calculate overlap 2022-09-26 11:26:17 +08:00
He Linming 9604bc06bb test: add unit test for backquote to code 2022-09-26 10:40:45 +08:00
He Linming 39bbfe109d feat: backquote to code text 2022-09-26 09:48:00 +08:00
Nathan.fooo 882043ef96 Merge pull request #1160 from AppFlowy-IO/fix/view_action_auto_width
fix: auto width for view action
2022-09-26 08:53:35 +08:00
Poly-Pixel 510fd11680 fix: only open the last opened view if plugin is blank 2022-09-25 11:36:34 -04:00
nathan b2d2e071bd fix: auto width for view action 2022-09-25 22:05:22 +08:00
Nathan.fooo bc5f0c206b Merge pull request #1147 from huyz/main
feat: make Rust installation prompt default to No
2022-09-25 20:00:17 +08:00
Lucas.Xu d1d5b37c14 Merge remote-tracking branch 'origin/main' into fix/click-selection-menu-item-delete-text 2022-09-25 16:28:22 +08:00
Lucas.Xu e8f5b1ade3 Merge pull request #1157 from LucasXu0/remove_selection_menu_widget_test
chore: remove the selection_menu_widget_test.dart
2022-09-25 16:13:22 +08:00
Lucas.Xu 62c2da06d4 chore: remove the selection_menu_widget_test.dart 2022-09-25 15:55:28 +08:00
Nathan.fooo a4b08e4f46 Merge pull request #1155 from AppFlowy-IO/fix/1126
fix: auto resize Action list
2022-09-25 15:28:37 +08:00
nathan 42995b6baf fix: auto resize Action list 2022-09-25 15:01:39 +08:00
Nathan.fooo ae3a68efb6 Merge pull request #1140 from richardshiue/improv-select-options
grid: fix pressing enter on an option that already exists recreates it
2022-09-25 14:04:04 +08:00
Richard Shiue edd9128046 fix: press enter to create or select option in text field 2022-09-25 12:32:40 +08:00
Nathan.fooo cd183b569a Merge pull request #1154 from AppFlowy-IO/fix/1129
fix: duplicate time format str
2022-09-25 11:13:08 +08:00
nathan d6d8b4da5a fix: duplicate time format str 2022-09-25 10:57:40 +08:00
Nathan.fooo a1b54e0646 Merge pull request #1132 from richardshiue/fix-blue-tint
Fix blue tint
2022-09-25 09:32:04 +08:00
Nathan.fooo 8cba015af1 Merge pull request #1152 from AppFlowy-IO/fix/1135_34
fix: switch field type in board
2022-09-24 23:04:36 +08:00
nathan dfb7ed1053 fix: switch field type in board 2022-09-24 22:36:35 +08:00
Nathan.fooo 6fa79b65f6 Merge pull request #1150 from AppFlowy-IO/fix/1135_1
Fix/1135 issue 1
2022-09-24 22:04:20 +08:00
nathan e66b3b07db fix: duplicate board 2022-09-24 21:49:47 +08:00
appflowy fa0a485c85 fix: move checkbox card fail 2022-09-24 17:25:59 +08:00
Lucas.Xu 55be554cc7 Merge pull request #1144 from LucasXu0/web_support
Support web platform for AppFlowy Editor
2022-09-24 15:50:38 +08:00
huyz 69ae3cba04 feat: make Rust installation prompt default to N 2022-09-23 21:59:32 -07:00
Lucas.Xu 6bda1fd2ea fix: delete the nested bulleted list will lost the children nodes 2022-09-24 12:01:23 +08:00
Nathan.fooo 69423b00d4 Merge pull request #1146 from AppFlowy-IO/fix/typo_on_install_macos_script
chore fix typo in install_macos.sh
2022-09-24 11:52:41 +08:00
weidong fu 91469df126 chore: fix typo in install_macos.sh 2022-09-24 10:39:00 +08:00
Lucas.Xu d648f2b5b9 fix: merge current text node's children to previous text node 2022-09-23 23:08:48 +08:00
Lucas.Xu ab353551d1 feat: implement find the forward nearest text node 2022-09-23 22:59:56 +08:00
Lucas.Xu c5af7db2cd fix: could not input space in editor 2022-09-23 19:57:00 +08:00
Nathan.fooo f317bae216 Merge pull request #1142 from AppFlowy-IO/fix/ui_adjust
Fix/UI adjust
2022-09-23 18:21:16 +08:00
appflowy f990e3cabb chore: set icon color of the app ation panel 2022-09-23 18:00:11 +08:00
appflowy 77d1dbedd6 chore: adjust insets of some popup 2022-09-23 17:50:32 +08:00
appflowy 9730069ec1 chore: rounded button hover 2022-09-23 17:40:17 +08:00
appflowy 0218f4e8b9 fix: create view panel icon color 2022-09-23 17:27:30 +08:00
appflowy ee7cb0cb42 chore: delete button ui 2022-09-23 16:24:01 +08:00
Nathan.fooo a352adf0d7 Merge pull request #1138 from AppFlowy-IO/fix/context_not_found
fix: can't find context after popover disappear
2022-09-23 16:22:29 +08:00
Nathan.fooo 7de6a21331 Merge pull request #1137 from AppFlowy-IO/fix/format_date_fail
fix: switch format style of the date after creating
2022-09-23 16:22:17 +08:00
Nathan.fooo ef5c1474cb Merge pull request #1136 from AppFlowy-IO/fix/group_of_grid
fix: create the default group for grid
2022-09-23 16:22:05 +08:00
appflowy 8da2d24d4e fix: unit test 2022-09-23 15:22:22 +08:00
appflowy af98febcb0 fix: can't find context after popover disappear 2022-09-23 15:10:20 +08:00
appflowy 082b0d2f5d fix: switch format style of the date after creating 2022-09-23 13:43:48 +08:00
appflowy 44ad0a2623 fix: create the default group for grid 2022-09-23 11:23:35 +08:00
Nathan.fooo 6a1b84a098 Merge pull request #1130 from AppFlowy-IO/fix/open_card_error
fix: open card error
2022-09-23 09:15:56 +08:00
Nathan.fooo 0b8909a150 Merge pull request #1131 from AppFlowy-IO/fix/date_select_pannel_layout
fix: UI layout issue when date select panel popup
2022-09-23 09:15:25 +08:00
Haoran Lin 5782dec45c fix: remove keyword when click selection menu item 2022-09-23 01:38:33 +08:00
Richard Shiue e5f5169a39 style: code auto-format 2022-09-23 01:21:04 +08:00
Richard Shiue fc1535696b fix: color code for tint 9 2022-09-23 01:20:01 +08:00
appflowy 5464f1851b fix: UI layout issue when date select panel popup 2022-09-22 21:12:41 +08:00
appflowy c790b698f2 fix: open card error 2022-09-22 21:02:10 +08:00
Nathan.fooo 206b06f023 Merge pull request #1114 from andercard0/main
chore: Update 2: Brazilian Portuguese Localization
2022-09-22 14:43:50 +08:00
Nathan.fooo f84e0548a8 Merge pull request #1121 from AppFlowy-IO/fix/black_page_after_delete_doc
chore: open next page when current page get deleted
2022-09-22 14:39:48 +08:00
Nathan.fooo 8206e58800 Merge pull request #1115 from AppFlowy-IO/fix/git_commit_msg
chore: add install gitlint script & ignore body length
2022-09-22 13:45:52 +08:00
appflowy 37f85cebde chore: open next page when current page get deleted 2022-09-22 13:43:37 +08:00
appflowy ca50e61762 chore: add install gitlint script & ignore body length 2022-09-22 10:50:04 +08:00
Anderson Cardoso bb80a34123 chore: Update Brazilian Portuguese Localization
- Added missings strings;
- Clean up my latest changes;
- Fixed some indentations and spaces

Translation 100% completed!
2022-09-21 22:29:33 -03:00
Annie 3cd9ea5366 Merge pull request #1083 from Poly-Pixel/issue-template-update
chore: update issue templates to forms
2022-09-21 20:10:18 +08:00
Annie a5e0e97df5 Merge pull request #1080 from richardshiue/fix-include-time
fix: some improvements for when including time in a date cell
2022-09-21 20:08:35 +08:00
Poly-Pixel 4e0b9c87e2 feat: show menu as overlapping drawer on small screens (#1088)
* feat: show menu as overlapping drawer on small screens

* refactor: simplify home page left offset ternary expression
2022-09-21 20:06:48 +08:00
Nathan.fooo 811dc46bc6 Merge pull request #1111 from AppFlowy-IO/fix/create_grid_row
fix: insert grid row
2022-09-21 20:03:50 +08:00
Annie 22d7ade18b Merge pull request #1101 from LucasXu0/translation
docs: add translation.md
2022-09-21 18:24:19 +08:00
appflowy ccc1d91896 fix: insert grid row 2022-09-21 18:23:05 +08:00
Nathan.fooo 2258e3468d Merge pull request #1109 from AppFlowy-IO/fix/drag_grid_header_cell
fix: tap event conflict when dragging grid header cell
2022-09-21 16:15:32 +08:00
appflowy 437228d4cf ci: fix warnings 2022-09-21 15:54:34 +08:00
Nathan.fooo 03e3c2efe4 Merge pull request #1110 from AppFlowy-IO/feat/highlight_trash_button
Feat/highlight trash button
2022-09-21 15:49:04 +08:00
appflowy 7e972c3ccd chore: display highlight color in delete/restore button 2022-09-21 11:46:32 +08:00
appflowy ece29b95f5 refactor: separate the trash page widget from trash.dart file 2022-09-21 11:37:42 +08:00
appflowy 0ff08ff8d2 fix: tap event conflict when dragging grid header cell 2022-09-21 11:24:37 +08:00
Nathan.fooo 488882c96b Merge pull request #1105 from andercard0/main
chore: Update Brazilian Portuguese Localization
2022-09-21 11:06:27 +08:00
Nathan.fooo 04f8fc0a3a Merge pull request #1077 from dadyarri/main
feature: update russian translations
2022-09-21 11:01:42 +08:00
Nathan.fooo 1967913db6 Merge branch 'main' into main 2022-09-21 10:31:38 +08:00
Nathan.fooo bdf4e60b48 Merge pull request #1104 from AppFlowy-IO/fix/appflowy_popover_detach_bugs
fix: set the leader size when attach get called
2022-09-21 10:06:03 +08:00
Anderson Cardoso 283de97c90 Update pt-BR.json 2022-09-20 21:48:13 -03:00
Anderson Cardoso 459a949e76 Update pt-BR.json 2022-09-20 17:59:35 -03:00
Anderson Cardoso 6d11ab6078 Update pt-BR.json 2022-09-20 17:59:01 -03:00
Anderson Cardoso 4d2ca4f27f Update Brazilian Portuguese
- Updated a missing string in English;
- Removed some anglicism to proper Portuguese;
- Fixed some terms, typo in general for Brazilian Portuguese language.
2022-09-20 17:56:17 -03:00
appflowy e178c7c4f4 fix: set the leader size when attach get called 2022-09-20 21:14:57 +08:00
Nathan.fooo bb61bf0a30 Merge pull request #1102 from AppFlowy-IO/fix/ui_bugs
Fix/UI bugs
2022-09-20 17:50:45 +08:00
appflowy ca89fd93f3 fix: notify state changed after set state 2022-09-20 16:57:51 +08:00
appflowy ba3f2f3c02 fix: focus when SelectOptionCellEditor show 2022-09-20 16:49:19 +08:00
appflowy 5191b6af93 chore: remove field type option widget one by one 2022-09-20 16:37:14 +08:00
Lucas.Xu 595405f2cc docs: add translation.md 2022-09-20 16:24:20 +08:00
appflowy 370db4f71b fix: center left the date cell of the grid 2022-09-20 16:23:35 +08:00
appflowy 2544aeb290 fix: button width in trash page 2022-09-20 16:20:40 +08:00
appflowy 893b6e041d fix: show multi-line in row detail page 2022-09-20 16:15:05 +08:00
appflowy 1f2b30abfb fix: show delete field dialog 2022-09-20 16:08:24 +08:00
Nathan.fooo 56e68d1346 Merge pull request #1097 from AppFlowy-IO/refactor/appflowy_overlay
Refactor/appflowy overlay
2022-09-20 11:57:56 +08:00
appflowy d35727b93c chore: make some overlay as barrier 2022-09-20 11:09:25 +08:00
appflowy 723b34a736 feat: enable remove one layer when click the empty space 2022-09-20 10:53:47 +08:00
Lucas.Xu 4a39c69ea7 Merge pull request #1093 from LucasXu0/fix_gif_link_error
docs: fix link error
2022-09-19 20:19:37 +08:00
Lucas.Xu 6018200946 docs: fix link error 2022-09-19 20:18:43 +08:00
Lucas.Xu 222fba21fb Merge pull request #1092 from LucasXu0/update_gif
docs: update appflowy_editor example gif
2022-09-19 19:49:49 +08:00
Lucas.Xu 12fc952026 docs: update appflowy_editor example gif 2022-09-19 19:48:55 +08:00
Richard Shiue 05975e55f0 test: fix includeTime-related tests 2022-09-19 18:50:31 +08:00
Richard Shiue c3033bd6e8 fix: few UI/usability issues with the time input field 2022-09-19 18:50:31 +08:00
Richard Shiue a413746c05 fix: immediately show or hide time when includeTime changes 2022-09-19 18:50:31 +08:00
Richard Shiue 2e60459878 chore: rewrite UI strings for time format hints 2022-09-19 18:50:21 +08:00
appflowy d1737d35fe chore: add src folder 2022-09-19 18:12:41 +08:00
Lucas.Xu 3e75b1ac92 fix: convert markdown symbol to styled text fails (#1090)
* fix: convert markdown symbol to styled text fails

* docs: update customzing.md

* chore: disable macOS titlebar

* chore: specify the built-in language as en_US

* docs: update documentation

* docs: update documentation
2022-09-19 18:10:48 +08:00
Nathan.fooo 5896855dda Merge pull request #1091 from AppFlowy-IO/fix/appflowy_overlay_bugs
Fix/appflowy overlay bugs
2022-09-19 17:46:21 +08:00
Nathan.fooo 3119759c92 Merge pull request #1089 from sunny7dusk/fix_language_when_reopening_700
fix: Fixed locale bug when oppening -
2022-09-19 15:51:39 +08:00
appflowy d26d620db8 fix: typo 2022-09-19 15:49:27 +08:00
appflowy 53cc0fff9d fix: open GridRowActionSheet with appflowy overlay 2022-09-19 15:46:06 +08:00
appflowy 4d835757d2 fix: select option pannel didn't disappear 2022-09-19 12:04:06 +08:00
sunny7dusk 9274444bde fix: fixed bug - if case before stopped AppearanceSettingModel to load locale 2022-09-18 13:55:47 -04:00
Nathan.fooo 39b0fe69b5 Merge pull request #1085 from AppFlowy-IO/fix/popover_bugs
Fix/popover bugs
2022-09-18 22:20:16 +08:00
nathan bda16b136b chore: replace Popover with Appflowy style popover and fix some bugs 2022-09-18 20:57:28 +08:00
nathan c493ba79e0 chore: unfocus the textField after switching to another popover 2022-09-18 20:56:43 +08:00
Nathan.fooo ed691be7d8 Merge pull request #1086 from AppFlowy-IO/fix/build_on_intel_mac 2022-09-18 17:33:04 +08:00
nathan c2cc08928d fix: fix macOS build on intel chip 2022-09-18 17:08:33 +08:00
nathan 6c27b5455e refactor: replace FlowyOverlay with AppFlowyPopover in select option 2022-09-18 11:46:04 +08:00
nathan 3a1148d11a refactor: add documentation to card.dart 2022-09-18 11:10:32 +08:00
Nathan.fooo f1d818bec7 Merge pull request #1082 from AppFlowy-IO/feat/optional_openssl_build 2022-09-18 10:03:03 +08:00
Poly-Pixel b86931a499 chore: delete feature request issue template 2022-09-17 21:44:04 -04:00
Poly-Pixel 92043c49f3 chore: add feature request issue form 2022-09-17 21:42:55 -04:00
Poly-Pixel 6c58a27247 fix: fix errors in bug report form 2022-09-17 21:42:51 -04:00
Poly-Pixel ac305e8821 chore: delete bug report issue template 2022-09-17 21:42:46 -04:00
nathan 27f4cf2d12 chore: add vendored_openssl feature 2022-09-18 09:30:59 +08:00
Poly-Pixel c1ec45e3a8 chore: create bug report issue form 2022-09-17 18:57:08 -04:00
Daniil 3d8fd6fe8d feature: update russian translations 2022-09-17 10:11:37 +03:00
Nathan.fooo 92a751b32a Merge pull request #1073 from AppFlowy-IO/feat/merge_release_0052
Feat/merge release 0052
2022-09-16 21:47:12 +08:00
Annie 7e8ed1e824 chore: update readme add an image for Kanban Board 2022-09-16 21:30:20 +08:00
appflowy 589acd9e2b fix: can not delete row from no status group 2022-09-16 21:19:04 +08:00
appflowy 2b451fa06d chore: fix delete card issue 2022-09-16 21:09:26 +08:00
appflowy a204af9783 chore: enable create card from no status column 2022-09-16 21:08:52 +08:00
appflowy 4961236012 chore: update version to 0.0.5.2 2022-09-16 21:08:44 +08:00
appflowy 4c07ae26fc chore: fix trailing characters parser error 2022-09-16 21:08:35 +08:00
appflowy f792283e70 chore: fix open application error when upgrade to 0.0.5.1 2022-09-16 21:08:25 +08:00
Lucas.Xu bc404c4ea5 Merge pull request #1054 from LucasXu0/feature/theme
feat: implement theme customizer
2022-09-16 19:04:06 +08:00
Lucas.Xu 5b482248ec fix: analyze problem 2022-09-16 15:03:11 +08:00
Lucas.Xu 5bb5337de8 feat: 0.0.5 release preparation 2022-09-16 14:07:38 +08:00
Lucas.Xu a371cf3a7c test: add single/double/triple tap test 2022-09-16 11:11:13 +08:00
Lucas.Xu 5c13b324ec Merge remote-tracking branch 'origin/main' into feature/theme 2022-09-16 10:37:26 +08:00
Lucas.Xu 8137769edd fix: add simple test for l10n 2022-09-16 10:26:17 +08:00
Nathan.fooo b0ab4eff11 Merge pull request #1052 from AppFlowy-IO/feat/node_transform 2022-09-15 22:34:25 +08:00
Nathan.fooo 4f34068f51 Merge pull request #1045 from AppFlowy-IO/feat/wrap-appflowy-style-popover 2022-09-15 22:34:13 +08:00
appflowy 520d5c2cb0 chore: replace popover with appflowy popover 2022-09-15 21:51:18 +08:00
8856b9abb7 Flowy editor keyboard fix (#1044)
* fix: fix linux build

* Merge pull request #599 from AppFlowy-IO/refactor/grid_decode_cell_data

Refactor/grid decode cell data

* fix: 🔧 fixed keyboard shortcut bugs

* test: 🧪 updated keyboard layout tests

* fix: included macOS for tests

* fix: macOS test

* fix: add linux in test

* fix: redefine move cursor end command error on macOS

Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2022-09-15 21:44:24 +08:00
appflowy 499ee29c3d chore: remove unused ref 2022-09-15 21:44:07 +08:00
appflowy 5294d7700e Merge branch 'main' into feat/wrap-appflowy-style-popover 2022-09-15 21:42:31 +08:00
Lucas.Xu 68997a9c93 feat: implement theme customizer 2022-09-15 21:40:12 +08:00
appflowy f88b8051f7 chore: rename folder 2022-09-15 21:04:57 +08:00
appflowy 01589c6f94 chore: compose operation 2022-09-15 20:59:19 +08:00
Nathan.fooo 733b7e1a45 Merge pull request #1046 from richardshiue/fix-grid-cell-context-menus
fix: add missing padding between number format list and filter bar
2022-09-15 19:14:39 +08:00
Nathan.fooo 90ded00a70 Merge pull request #1049 from AppFlowy-IO/feat/merge_release_0051
Feat/merge release 0051
2022-09-15 19:14:15 +08:00
appflowy 1de3999e3a chore: fix bugs 2022-09-15 16:05:55 +08:00
appflowy 97eab3b648 chore: merge release 0.0.5.1 2022-09-15 11:12:06 +08:00
appflowy cb293e9e51 chore: update version number 2022-09-14 17:04:03 +08:00
appflowy 34275664b2 feat: enable delete field in edit row detail page 2022-09-14 17:03:46 +08:00
Richard Shiue 33b72c8f6a fix: add padding to number format list 2022-09-14 16:40:53 +08:00
Vincent Chan 41b85510bf fix: lint issues 2022-09-14 12:18:44 +08:00
appflowy 4b654de2e6 chore: updata path documentation 2022-09-14 12:03:52 +08:00
Vincent Chan 7bde75ee2f feat: wrap appflowy style popover 2022-09-14 11:59:12 +08:00
Vincent Chan 286781f5cc refactor: PopoverContainerState -> PopoverContainer 2022-09-14 11:11:57 +08:00
Nathan.fooo 988e8db798 Merge pull request #1041 from ChiragKr04/fix/set-icon-theme-for-setting-add-icon
fix: Icon theme on setting and new column icon
2022-09-14 11:03:23 +08:00
Vincent Chan cc0d408775 fix: popover container 2022-09-14 10:54:21 +08:00
Lucas.Xu 84a71674f6 Merge pull request #991 from AppFlowy-IO/feat/number-list
Feat: number list
2022-09-14 09:42:01 +08:00
nathan 2d738fedaa chore: update test 2022-09-14 09:23:33 +08:00
appflowy fa2cfd7c20 chore: node transform path test 2022-09-13 20:23:56 +08:00
Vincent Chan ee0f3d3227 feat: handle number list on delete event 2022-09-13 19:36:22 +08:00
Vincent Chan cfdd891991 fix: redo/undo error 2022-09-13 18:35:29 +08:00
chiragkr04 1e2017cdd0 fix: Icon theme on setting and new column icon 2022-09-13 15:27:57 +05:30
Vincent Chan 9b3701dd88 feat: back delete to previous line 2022-09-13 14:47:29 +08:00
Nathan.fooo 9ff0975f7c Merge pull request #1039 from AppFlowy-IO/refactor/lib_ot_attribute
Refactor/lib ot attribute
2022-09-13 12:14:32 +08:00
Vincent Chan 06bd6064ac fix: cancel number list style after enter in empty line 2022-09-13 11:51:10 +08:00
appflowy c991473259 refactor: refactor delta attributes 2022-09-13 11:38:19 +08:00
1f9686dc66 Tests for toolbar (#1006)
* fix: fix linux build

* Merge pull request #599 from AppFlowy-IO/refactor/grid_decode_cell_data

Refactor/grid decode cell data

* test: 🧪 tests for toolbar widget

* fix: removed multiText & replaced with single line

* refactor: cleaned up code & removed unused imports

* fix: fix some tests about the toolbar service

Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2022-09-12 20:11:23 +08:00
Sean Riley HawkinsandNathan.fooo f4cf5d0808 Feat embed code (#985)
* fix: fix linux build

* Merge pull request #599 from AppFlowy-IO/refactor/grid_decode_cell_data

Refactor/grid decode cell data

* refactor: cleaned up and added bold, italic styles

* refactor: remove bold & italic styles

Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2022-09-12 20:10:48 +08:00
chiragkr04 7b06b4c427 fix: splited shortcut event functions 2022-09-12 20:04:36 +08:00
appflowy c552e958ce chore: create attribute 2022-09-12 11:30:02 +08:00
Nathan.fooo 944b2d97cd Merge pull request #1033 from AppFlowy-IO/feat/lib_ot_directory
Feat/lib ot directory
2022-09-12 11:06:54 +08:00
appflowy 822263529c refactor: rename structs 2022-09-12 10:44:33 +08:00
appflowy 2039cc00b5 refactor: move operation to delta folder 2022-09-12 10:27:34 +08:00
Nathan.fooo d6fa38a4b2 Merge pull request #1032 from richardshiue/fix-identical-selecion-options
fix: prevent select property from having identical options
2022-09-12 10:23:02 +08:00
Richard Shiue a6130a27c2 fix: prevent grid header from creating identical options 2022-09-12 00:33:46 +08:00
Nathan.fooo 1ab0a8351e Merge pull request #1031 from AppFlowy-IO/refactor/node_body_serde
Refactor/node body serde
2022-09-11 22:33:26 +08:00
nathan 04ba711441 chore: add deserial appflowy editor test 2022-09-11 22:06:36 +08:00
nathan b7f65ff11d chore: customize node and operation serde 2022-09-11 19:48:14 +08:00
nathan 1d7d4092a5 chore: add update node body test 2022-09-11 12:59:01 +08:00
Nathan.fooo d368ba78e0 Merge pull request #1023 from AppFlowy-IO/feat/node_documentation
chore: update node documentation
2022-09-11 12:57:56 +08:00
nathan 2a5d9d5530 chore: rename structs 2022-09-11 08:59:12 +08:00
nathan 3c84e8df51 chore: update node documentation 2022-09-11 08:49:45 +08:00
Nathan.fooo 9142f5d870 Merge pull request #1018 from AppFlowy-IO/refactor/node_delta
refactor: replace delta with node body
2022-09-10 21:35:01 +08:00
appflowy 3dff72942b refactor: replace delta with node body 2022-09-10 20:35:18 +08:00
Nathan.fooo 4becc2eb75 Merge pull request #1012 from richardshiue/fix-disabled-icon-color
fix: disabled icon color in grid header menu
2022-09-10 17:34:24 +08:00
Nathan.fooo 61ea7ea3df Merge pull request #1017 from richardshiue/fix-empty-create-select-tag
fix: empty create option in select/multi-select properties
2022-09-10 16:45:26 +08:00
Richard Shiue 0ef3247076 style: if-else block 2022-09-10 12:26:51 +08:00
Richard Shiue a4d1c614ac fix: making selection in grid/kanban sometimes results in a create option 2022-09-10 12:26:51 +08:00
Richard Shiue 3b6c6e92d6 fix: disabled icon color in grid header menu 2022-09-10 12:26:20 +08:00
Nathan.fooo 21d09f7741 Merge pull request #1016 from AppFlowy-IO/refactor/document_node
Refactor/document node
2022-09-10 10:58:52 +08:00
appflowy 1faf959e1e chore: fix rename errors 2022-09-10 10:17:00 +08:00
appflowy 41ccd4f59f chore: move path test to path.rs file 2022-09-10 10:12:59 +08:00
appflowy 387ee911a9 chore: rename files 2022-09-10 10:07:06 +08:00
appflowy 328e0ac73a refactor: rename && fix potential bugs 2022-09-10 10:05:27 +08:00
appflowy 2d44a9a956 refactor: rename docuemnt tree to node tree 2022-09-10 08:58:08 +08:00
appflowy 745018cf22 refactor: node attribute 2022-09-10 08:42:53 +08:00
appflowy 61c2b928c9 chore: fix warnings 2022-09-09 17:08:20 +08:00
Nathan.fooo b24c4413e8 Merge pull request #1014 from AppFlowy-IO/refactor/document_tree
Refactor/document tree
2022-09-09 17:07:35 +08:00
appflowy 8f114e843c chore: replace fold with count 2022-09-09 17:06:18 +08:00
Vincent Chan 4402f4dec9 feat: use const num 2022-09-09 15:43:56 +08:00
Vincent Chan 2775737260 feat: refresh number list when delete multiple lines 2022-09-09 15:20:53 +08:00
Vincent Chan 0310b92723 fix: dynamic width of the number 2022-09-09 14:38:25 +08:00
appflowy a2918d251f refactor: refactor transaction builder in rust style 2022-09-09 14:34:40 +08:00
Vincent Chan 002eac63f7 feat: handle paste number list 2022-09-09 14:24:57 +08:00
appflowy ac23f81e24 chore: private the root node 2022-09-09 14:14:15 +08:00
appflowy 9974539946 chore: private the Arena 2022-09-08 20:39:25 +08:00
appflowy e711bfce1d chore: udpate test 2022-09-08 19:21:06 +08:00
appflowy d386698e97 fix: skip root to get the right path 2022-09-08 18:29:23 +08:00
Vincent Chan c9b6e02167 feat: add return value for copy paste handler 2022-09-08 17:58:17 +08:00
Vincent Chan 880669c0e5 feat: handle paste multi lines 2022-09-08 17:56:51 +08:00
appflowy 89a5ee4a8a fix: potential crash while calling apply_insert if the path is empty 2022-09-08 17:47:53 +08:00
appflowy 8f5134305e refactor: generic insert_nodes method 2022-09-08 17:41:38 +08:00
appflowy 294b1bea13 refactor: remove Box in DocumentOperation 2022-09-08 16:58:37 +08:00
appflowy 800e02d85e refactor: remove Box in DocumentOperation 2022-09-08 16:49:09 +08:00
Vincent Chan e223eecf32 fix: selection after pasting nodes 2022-09-08 16:37:55 +08:00
Vincent Chan 1736fb794d fix: unit test on number list 2022-09-08 15:49:58 +08:00
Vincent Chan 875c109b14 feat: check previous node's number 2022-09-08 15:35:24 +08:00
Vincent Chan 2810097b95 feat: backspace 2022-09-08 15:35:24 +08:00
Vincent Chan 69f04d0958 feat: make following lines incremental 2022-09-08 15:35:24 +08:00
Vincent Chan 565617d1f0 feat: recognize number 2022-09-08 15:35:24 +08:00
Nathan.fooo 5bb52ba77e Merge pull request #1010 from AppFlowy-IO/fix/merge_release_005
Fix/merge release 005
2022-09-08 11:52:53 +08:00
Nathan.fooo 8371efd3e6 Merge pull request #1007 from LucasXu0/windows_relesae_action
feat: integrate github action for windows x86_64 release
2022-09-08 11:31:42 +08:00
appflowy 81a7b7f3eb chore: fallback to en localization if the key is not found in the locale file 2022-09-08 11:30:36 +08:00
appflowy 2202c28534 fix: refactor grid row count UI layout 2022-09-08 11:21:39 +08:00
Lucas.Xu 708afda27d chore: delete the windows_release.yml 2022-09-08 10:33:02 +08:00
Lucas.Xu fc0fb1c3df feat: integrate github action for windows x86_64 release 2022-09-07 22:49:57 +08:00
Nathan.fooo ea271c7342 Merge pull request #1005 from AppFlowy-IO/fix/board_dark_mode
Fix/board dark mode
2022-09-07 22:11:13 +08:00
Nathan.fooo 69da9acd8b Merge pull request #1004 from AppFlowy-IO/fix/board_ui_bugs
Fix/board UI bugs
2022-09-07 22:11:02 +08:00
appflowy 8632b141ad fix: adjust board dark mode UI 2022-09-07 20:57:34 +08:00
appflowy c5963bc765 fix: default name when create a new field 2022-09-07 20:56:23 +08:00
appflowy 9a57593690 feat: auto scroll to bottom after crating a new field 2022-09-07 20:06:49 +08:00
appflowy 56fdc99990 feat: enable select checkbox directly 2022-09-07 19:08:08 +08:00
appflowy c7db59c99b fix: autofocus after creating a new option 2022-09-07 19:08:05 +08:00
appflowy af813806f1 fix: duplicate key 2022-09-07 19:07:52 +08:00
Nathan.fooo 3d2bfcc7c1 Merge pull request #1001 from AppFlowy-IO/merge/release_005
Merge/release 005
2022-09-07 14:42:50 +08:00
appflowy e826d68b16 chore: remove unuse code 2022-09-07 14:25:40 +08:00
appflowy 4f97133183 Merge branch 'release/0.0.5' into merge/release_005 2022-09-07 14:22:23 +08:00
Nathan.fooo 3d10d46e6a Merge pull request #989 from LucasXu0/imporve_keyboard_service
#964 Support the shortcut keys customization
2022-09-07 11:11:30 +08:00
Lucas.Xu 759c10faca chore: fix analysis problems 2022-09-07 11:10:15 +08:00
Nathan.fooo a4e48e53a6 Merge pull request #996 from AppFlowy-IO/feat/upgrade_dart_sdk_version
chore: upgarde dart sdk version to 2.17.0
2022-09-07 10:36:21 +08:00
appflowy 164cde50d3 chore: upgarde dart sdk version to 2.17.0 2022-09-07 10:15:32 +08:00
Nathan.fooo 05b9bc50f6 Merge pull request #903 from AppFlowy-IO/feat/flowy-overlay
Feat: appflowy_popover
2022-09-06 16:25:54 +08:00
Lucas.Xu 930ad26155 docs: update customizing.md 2022-09-06 15:34:19 +08:00
Lucas.Xu 5d2160b0bb chore: rename keyEventHandlers to shortcutEvents 2022-09-06 13:15:50 +08:00
Lucas.Xu 2571c6b1bf test: add shortcut_event / keybinding test 2022-09-06 13:15:50 +08:00
Lucas.Xu 73cfe39e41 feat: refactor copy / paste / redo / undo / select all / format event handler 2022-09-06 13:15:50 +08:00
Lucas.Xu 804b2b27c1 feat: refactor arrow key handler 2022-09-06 13:15:50 +08:00
Lucas.Xu 43a0a02328 feat: keyboard service improvement 2022-09-06 13:15:50 +08:00
Nathan.fooo f54f90b647 Merge branch 'main' into feat/flowy-overlay 2022-09-06 09:46:10 +08:00
Vincent Chan caa6f0446b feat(doc): add doc about how to use popover 2022-09-05 16:14:02 +08:00
Vincent Chan 21e90ffac0 fix: lint of board_setting 2022-09-05 13:49:57 +08:00
Vincent Chan bd40768c6a Merge branch 'main' into feat/flowy-overlay 2022-09-05 12:06:28 +08:00
Vincent Chan 6296367efc refactor: use Popover in URL cell 2022-09-02 14:25:06 +08:00
Vincent Chan a43259bddb fix: lints for popover 2022-09-01 18:21:47 +08:00
Vincent Chan 0cd384802e feat: use popoer for select widget 2022-09-01 16:03:57 +08:00
Vincent Chan 9574f282e7 fix: example of popover 2022-09-01 15:28:16 +08:00
Vincent Chan ac91b25219 feat: use popover on overlay 2022-09-01 15:00:40 +08:00
Vincent Chan 9b5184cd72 Merge branch 'main' into feat/flowy-overlay 2022-09-01 14:37:16 +08:00
Vincent Chan 2bbba547ee fix: key issue of ReorderableRow 2022-09-01 13:15:48 +08:00
Vincent Chan 8229371f63 feat: add mutex to property list 2022-08-31 20:10:56 +08:00
Vincent Chan 4c31c0dcf0 feat: remove legacy alignment 2022-08-31 18:57:46 +08:00
Vincent Chan 14c1959d63 feat: use custom follower 2022-08-31 17:53:28 +08:00
Vincent Chan d79a7cb194 feat: use popover in property field 2022-08-31 11:28:06 +08:00
Vincent Chan 8bab4cce61 feat: use pop over for date selector 2022-08-30 20:13:55 +08:00
Vincent Chan 1718d03884 feat: use stateless widget 2022-08-30 19:19:52 +08:00
Vincent Chan 27557c52a3 feat: add flags to popover 2022-08-30 19:06:40 +08:00
Vincent Chan 33e45a86c4 refactor: select option cell 2022-08-30 18:04:27 +08:00
Vincent Chan 6ef7b6cf68 feat: use popover in date cell 2022-08-30 16:53:30 +08:00
Vincent Chan 01a79c69c3 feat: use popover in detail page 2022-08-30 14:51:25 +08:00
Vincent Chan a7f02ec7df refactor: number field to use popover 2022-08-30 14:13:47 +08:00
Vincent Chan bfb60dcaec feat: refactor multi select 2022-08-30 14:06:03 +08:00
Vincent Chan e9535201a4 refactor: rename popover 2022-08-30 12:53:51 +08:00
Vincent Chan 406f185ab7 feat: field action sheet use popover 2022-08-29 17:45:08 +08:00
Vincent Chan 99a3a386a3 feat: add popover removal 2022-08-29 16:36:01 +08:00
Vincent Chan defef552ed feat: add exclusive 2022-08-29 15:32:59 +08:00
Vincent Chan 072d94ebe6 feat: add secondary button 2022-08-29 15:30:10 +08:00
Vincent Chan fe549e8d67 feat: add example 2022-08-29 15:30:02 +08:00
Vincent Chan 2fb11519d2 feat: add popover package 2022-08-29 13:56:16 +08:00
Vincent Chan 5cdd1d38c4 feat: aciton sheet 2022-08-26 15:39:44 +08:00
Vincent Chan e9b215ebbd feat: poover anchor on the object 2022-08-26 15:15:29 +08:00
Vincent Chan 4fb760e44c feat: add popover overlay 2022-08-26 13:47:49 +08:00
Vincent Chan ddc394fcd7 feat: introduce popover widget 2022-08-25 16:58:03 +08:00
Vincent Chan 84b5762017 feat: unify styles 2022-08-25 11:45:51 +08:00
Vincent Chan 58ad84b7df feat: flowy overlay 2022-08-25 11:30:00 +08:00
1206 changed files with 57819 additions and 69387 deletions

No files matched your search

+2 -3
View File
@@ -36,16 +36,15 @@ test "" = "$(grep '^Signed-off-by: ' "$1" |
.githooks/gitlint \
--msg-file=$1 \
--subject-regex="^(build|chore|ci|docs|feat|feature|fix|perf|refactor|revert|style|test)(.*)?:\s?.*" \
--subject-maxlen=100 \
--subject-maxlen=150 \
--subject-minlen=10 \
--body-regex=".*" \
--body-maxlen=200 \
--max-parents=1
if [ $? -ne 0 ]
then
printError "Please fix your commit message to match AppFlowy coding standards"
printError "https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/style-guides"
printError "https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/code-submission-guidelines#commit-message-guidelines"
exit 1
fi
-33
View File
@@ -1,33 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[Bug] Untitled Bug Issue"
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
- Environment [e.g. flutter doctor -v or rustup show]
Add any other context about the problem here.
+49
View File
@@ -0,0 +1,49 @@
name: Bug Report
description: Create a bug report to help us improve
title: "[Bug] "
body:
- type: textarea
id: desc
attributes:
label: Bug Description
description: A clear and concise description of what the bug is
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: How to Reproduce
description: What steps can we take to reproduce this behavior?
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen
validations:
required: true
- type: input
id: os
attributes:
label: Operating System
description: What OS are you seeing this bug on?
validations:
required: true
- type: input
id: version
attributes:
label: AppFlowy Version(s)
description: What version(s) of AppFlowy do you see this bug on?
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, please add screenshots to help explain your problem
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any additonal context about the problem here
-17
View File
@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FR] Untitled Feature Request"
labels: ''
assignees: ''
---
**1~3 main use cases of the proposed feature**
Ex: As a ... , I want to set a reminder for a checkbox item so that I can be reminded by the system at a specific time.
**what types of users can benefit from using your proposed feature**
Ex: busy students who tend to forget their paper deadlines
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,25 @@
name: Feature Request
description: Suggest an idea for AppFlowy
title: "[FR] "
body:
- type: textarea
id: desc
attributes:
label: Description
description: Describe your suggested feature and the main use cases
validations:
required: true
- type: textarea
id: users
attributes:
label: Impact
description: What types of users can benefit from using the suggested feature?
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any additonal context about the feature here
@@ -1,15 +1,15 @@
name: FlowyEditor test
name: AppFlowyEditor test
on:
push:
branches:
- "main"
paths:
- "frontend/app_flowy/packages/appflowy_editor/**"
- "release/*"
pull_request:
branches:
- "main"
- "release/*"
paths:
- "frontend/app_flowy/packages/appflowy_editor/**"
@@ -37,6 +37,8 @@ jobs:
working-directory: frontend/app_flowy/packages/appflowy_editor
run: |
flutter pub get
flutter format --set-exit-if-changed .
flutter analyze .
flutter test --coverage
- uses: codecov/codecov-action@v3
+12 -4
View File
@@ -4,21 +4,25 @@ on:
push:
branches:
- "main"
- "release/*"
pull_request:
branches:
- "main"
- "release/*"
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
- os: macos-latest
flutter_profile: development-mac-x86_64
- os: windows-latest
flutter_profile: development-windows-x86
runs-on: ${{ matrix.os }}
steps:
@@ -27,7 +31,7 @@ jobs:
- id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: "stable-2022-01-20"
toolchain: "stable-2022-04-07"
- id: flutter
uses: subosito/flutter-action@v2
@@ -60,6 +64,8 @@ jobs:
sudo apt-get update
sudo apt-get install -y dart curl build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
elif [ "$RUNNER_OS" == "Windows" ]; then
vcpkg integrate install
elif [ "$RUNNER_OS" == "macOS" ]; then
echo 'do nothing'
fi
@@ -72,10 +78,10 @@ jobs:
cargo install cargo-make
cargo install duckscript_cli
- name: Cargo make flowy_dev
- name: Cargo make appflowy-deps-tools
working-directory: frontend
run: |
cargo make flowy_dev
cargo make appflowy-deps-tools
- name: Config Flutter
run: |
@@ -83,6 +89,8 @@ jobs:
flutter config --enable-linux-desktop
elif [ "$RUNNER_OS" == "macOS" ]; then
flutter config --enable-macos-desktop
elif [ "$RUNNER_OS" == "Windows" ]; then
flutter config --enable-windows-desktop
fi
shell: bash
+6 -4
View File
@@ -9,12 +9,14 @@ on:
push:
branches:
- "main"
- "release/*"
paths:
- "frontend/app_flowy/**"
pull_request:
branches:
- "main"
- "release/*"
paths:
- "frontend/app_flowy/**"
@@ -34,7 +36,7 @@ jobs:
channel: "stable"
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable-2022-01-20"
toolchain: "stable-2022-04-07"
- name: Cache Cargo
id: cache-cargo
@@ -62,7 +64,7 @@ jobs:
- name: Cargo make flowy dev
working-directory: frontend
run: |
cargo make flowy_dev
cargo make appflowy-deps-tools
- name: Flutter Deps
run: flutter packages pub get
@@ -71,9 +73,9 @@ jobs:
- name: Build FlowySDK
working-directory: frontend
run: |
cargo make --profile development-linux-x86_64 flowy-sdk-dev
cargo make --profile development-linux-x86_64 appflowy-sdk-dev
- name: Code Generation
- name: Flutter Code Generation
working-directory: frontend/app_flowy
run: |
flutter packages pub run easy_localization:generate -f keys -o locale_keys.g.dart -S assets/translations -s en.json
+8 -11
View File
@@ -1,15 +1,17 @@
name: Unit test(Flutter)
name: Frontend test
on:
push:
branches:
- "main"
- "release/*"
paths:
- "frontend/app_flowy/**"
pull_request:
branches:
- "main"
- "release/*"
paths:
- "frontend/app_flowy/**"
@@ -21,10 +23,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: "stable-2022-01-20"
toolchain: "stable-2022-04-07"
- uses: subosito/flutter-action@v2
with:
@@ -53,23 +54,19 @@ jobs:
working-directory: frontend
run: |
cargo install cargo-make
- name: Cargo make flowy dev
working-directory: frontend
run: |
cargo make flowy_dev
cargo make appflowy-deps-tools
- name: Flutter Deps
working-directory: frontend/app_flowy
run: |
flutter config --enable-linux-desktop
- name: Build FlowySDK
- name: Build Test lib
working-directory: frontend
run: |
cargo make --profile development-linux-x86_64 flowy-sdk-dev
cargo make --profile test-linux build-test-lib
- name: Code Generation
- name: Flutter Code Generation
working-directory: frontend/app_flowy
run: |
flutter packages pub get
+156 -6
View File
@@ -28,7 +28,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
release_name: v${{ github.ref }}
body_path: ${{ env.RELEASE_NOTES_PATH }}
build-linux-x86:
@@ -37,6 +37,7 @@ jobs:
env:
LINUX_APP_RELEASE_PATH: frontend/app_flowy/product/${{ github.ref_name }}/linux/Release
LINUX_ZIP_NAME: AppFlowy-linux-x86.tar.gz
LINUX_PACKAGE_NAME: AppFlowy_${{ github.ref_name }}_linux-amd64.deb
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -44,7 +45,7 @@ jobs:
- name: Setup environment - Rust and Cargo
uses: actions-rs/toolchain@v1
with:
toolchain: 'stable-2022-01-20'
toolchain: 'stable-2022-04-07'
- name: Setup environment - Flutter
uses: subosito/flutter-action@v2
@@ -62,7 +63,7 @@ jobs:
source $HOME/.cargo/env
cargo install --force cargo-make
cargo install --force duckscript_cli
cargo make flowy_dev
cargo make appflowy-deps-tools
- name: Build Linux app
working-directory: frontend
@@ -70,6 +71,46 @@ jobs:
flutter config --enable-linux-desktop
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-linux-x86_64 appflowy
- name: Build Linux package
working-directory: ${{ env.LINUX_APP_RELEASE_PATH }}
run: |
mkdir -p package/opt && mv AppFlowy package/opt/
cd package && mkdir DEBIAN
# Create control file
printf 'Package: AppFlowy
Version: %s
Architecture: amd64
Essential: no
Priority: optional
Maintainer: AppFlowy
Description: An Open Source Alternative to Notion\n' "${{ github.ref_name }}" > DEBIAN/control
# postinst script for creating symlink
printf '#!/bin/bash
if [ -e /usr/local/bin/appflowy ]; then
echo "Symlink already exists, skipping."
else
echo "Creating Symlink in /usr/local/bin/appflowy"
ln -s /opt/AppFlowy/app_flowy /usr/local/bin/appflowy
fi' > DEBIAN/postinst
chmod 0755 DEBIAN/postinst
# postrm script for cleaning up residuals
printf '#!/bin/bash
if [ -e /usr/local/bin/appflowy ]; then
rm /usr/local/bin/appflowy
fi' > DEBIAN/postrm
chmod 0755 DEBIAN/postrm
mkdir -p usr/share/applications
# Update Exec & icon path in desktop entry
grep -rl "\[CHANGE_THIS\]" ./opt/AppFlowy/appflowy.desktop.temp | xargs sed -i "s/\[CHANGE_THIS\]/\/opt/"
# Add desktop entry in package
mv ./opt/AppFlowy/appflowy.desktop.temp ./usr/share/applications/appflowy.desktop
# Build
cd ../ && dpkg-deb --build --root-owner-group package ${{ env.LINUX_PACKAGE_NAME }}
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
@@ -81,12 +122,24 @@ jobs:
asset_name: ${{ env.LINUX_ZIP_NAME }}
asset_content_type: application/octet-stream
- name: Upload Release Asset Install Package
id: upload-release-asset-install-package
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_NAME }}
asset_name: ${{ env.LINUX_PACKAGE_NAME }}
asset_content_type: application/octet-stream
build-macos-x86_64:
runs-on: macos-latest
needs: create-release
env:
MACOS_APP_RELEASE_PATH: frontend/app_flowy/product/${{ github.ref_name }}/macos/Release
MACOS_X86_ZIP_NAME: Appflowy-macos-x86_64.zip
MACOS_DMG_NAME: Appflowy-macos-x86_64-installer
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -94,7 +147,7 @@ jobs:
- name: Setup environment - Rust and Cargo
uses: actions-rs/toolchain@v1
with:
toolchain: 'stable-2022-01-20'
toolchain: 'stable-2022-04-07'
- name: Setup environment - Flutter
uses: subosito/flutter-action@v2
@@ -108,7 +161,7 @@ jobs:
source $HOME/.cargo/env
cargo install --force cargo-make
cargo install --force duckscript_cli
cargo make flowy_dev
cargo make appflowy-deps-tools
- name: Build macOS app for x86_64
working-directory: frontend
@@ -116,9 +169,24 @@ jobs:
flutter config --enable-macos-desktop
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-mac-x86_64 appflowy
- name: Create MacOS dmg
working-directory: frontend
run: |
brew install create-dmg
create-dmg \
--volname ${{ env.MACOS_DMG_NAME }} \
--hide-extension "AppFlowy.app" \
--background scripts/dmg_assets/AppFlowyInstallerBackground.jpg \
--window-size 600 450 \
--icon-size 94 \
--icon "AppFlowy.app" 141 249 \
--app-drop-link 458 249 \
"${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \
"${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app"
- name: Archive macOS app
working-directory: ${{ env.MACOS_APP_RELEASE_PATH }}
run: zip -qr ${{ env.MACOS_X86_ZIP_NAME }} AppFlowy.app
run: zip --symlinks -qr ${{ env.MACOS_X86_ZIP_NAME }} AppFlowy.app
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
@@ -129,3 +197,85 @@ jobs:
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_X86_ZIP_NAME }}
asset_name: ${{ env.MACOS_X86_ZIP_NAME }}
asset_content_type: application/octet-stream
- name: Upload DMG Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg
asset_name: ${{ env.MACOS_DMG_NAME }}.dmg
asset_content_type: application/octet-stream
build-windows-x86_64:
runs-on: windows-latest
needs: create-release
env:
WINDOWS_APP_RELEASE_PATH: frontend\app_flowy\product\${{ github.ref_name }}\windows
WINDOWS_ZIP_NAME: AppFlowy-windows-x86_64.zip
WINDOWS_INSTALLER_NAME: AppFlowy-${{ github.ref_name }}-windows-x86_64
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup environment - Rust and Cargo
uses: actions-rs/toolchain@v1
with:
toolchain: 'stable-2022-04-07'
- name: Setup environment - Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
flutter-version: '3.0.5'
- name: Pre build
working-directory: frontend
run: |
vcpkg integrate install
cargo install --force cargo-make
cargo install --force duckscript_cli
cargo make appflowy-deps-tools
- name: Build Windows app
working-directory: frontend
run: |
flutter config --enable-windows-desktop
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-windows-x86 appflowy
- uses: vimtor/action-zip@v1
with:
files: ${{ env.WINDOWS_APP_RELEASE_PATH }}\
dest: ${{ env.WINDOWS_APP_RELEASE_PATH }}\${{ env.WINDOWS_ZIP_NAME }}
- name: Copy installer config & icon file
working-directory: frontend
run: |
cp scripts/windows_installer/* ../${{ env.WINDOWS_APP_RELEASE_PATH }}
- name: Build installer executable
working-directory: ${{ env.WINDOWS_APP_RELEASE_PATH }}
run: |
iscc /F${{ env.WINDOWS_INSTALLER_NAME }} inno_setup_config.iss /DAppVersion=${{ github.ref_name }}
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.WINDOWS_APP_RELEASE_PATH }}\${{ env.WINDOWS_ZIP_NAME }}
asset_name: ${{ env.WINDOWS_ZIP_NAME }}
asset_content_type: application/octet-stream
- name: Upload Installer Asset
id: upload-installer-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.WINDOWS_APP_RELEASE_PATH }}\Output\${{ env.WINDOWS_INSTALLER_NAME }}.exe
asset_name: ${{ env.WINDOWS_INSTALLER_NAME }}.exe
asset_content_type: application/octet-stream
+73
View File
@@ -0,0 +1,73 @@
name: Rust coverage tests
on:
push:
branches:
- "main"
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
pull_request:
branches:
- "main"
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
env:
CARGO_TERM_COLOR: always
jobs:
test-coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 'stable-2022-04-07'
- name: Cache Cargo
uses: actions/cache@v2
with:
path: |
~/.cargo
key: ${{ runner.os }}-cargo-${{ steps.rust_toolchain.outputs.rustc_hash }}-${{ hashFiles('./frontend/rust-lib/Cargo.toml') }}
- name: Cache Rust
uses: actions/cache@v2
with:
path: |
frontend/rust-lib/target
shared-lib/target
key: ${{ runner.os }}-rust-rust-lib-share-lib-${{ steps.rust_toolchain.outputs.rustc_hash }}-${{ hashFiles('./frontend/rust-lib/Cargo.toml') }}
- name: Setup Environment
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
elif [ "$RUNNER_OS" == "macOS" ]; then
echo 'do nothing'
fi
shell: bash
- name: Install cargo-make, grcov and llvm-tools-preview
working-directory: frontend
run: |
cargo install cargo-make
cargo install grcov
rustup component add llvm-tools-preview
- name: Run Coverage tests and generate LCOV report
working-directory: frontend
run: cargo make get_ci_test_coverage
+5 -3
View File
@@ -4,6 +4,7 @@ on:
push:
branches:
- "main"
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -11,6 +12,7 @@ on:
pull_request:
branches:
- "main"
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -26,7 +28,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: 'stable-2022-01-20'
toolchain: 'stable-2022-04-07'
override: true
- uses: subosito/flutter-action@v1
with:
@@ -37,12 +39,12 @@ jobs:
working-directory: frontend
run: |
cargo install cargo-make
cargo make flowy_dev
cargo make appflowy-deps-tools
- name: Build FlowySDK
working-directory: frontend
run: |
cargo make --profile development-linux-x86_64 flowy-sdk-dev
cargo make --profile development-linux-x86_64 appflowy-sdk-dev
- run: rustup component add rustfmt
working-directory: frontend/rust-lib
+5 -3
View File
@@ -1,9 +1,10 @@
name: Unit test(Rust)
name: Backend test
on:
push:
branches:
- "main"
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -11,6 +12,7 @@ on:
pull_request:
branches:
- "main"
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
@@ -28,7 +30,7 @@ jobs:
- id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 'stable-2022-01-20'
toolchain: 'stable-2022-04-07'
- name: Cache Cargo
uses: actions/cache@v2
@@ -55,4 +57,4 @@ jobs:
- name: Run shared-lib tests
working-directory: shared-lib
run: RUST_LOG=info cargo test --no-default-features
run: RUST_LOG=info cargo test --no-default-features
+72 -6
View File
@@ -1,8 +1,74 @@
# Release Notes
## Version 0.0.7 - 11/27/2022
### New features
- Support adding filters by the text/checkbox/single-select property in Grid
## Version 0.0.6.2 - 10/30/2022
- Fix some bugs
## Version 0.0.6.1 - 10/26/2022
### New features
- Optimize appflowy_editor dark mode style
### Bug Fixes
- Unable to copy the text with checkbox or link style
## Version 0.0.6 - 10/23/2022
### New features
- Integrate **appflowy_editor**
## Version 0.0.5.3 - 09/26/2022
### New features
- Open the next page automatically after deleting the current page
- Refresh the Kanban board after altering a property type
### Bug Fixes
- Fix switch board bug
- Fix delete the Kanban board's row error
- Remove duplicate time format
- Fix can't delete field in property edit panel
- Adjust some display UI issues
## Version 0.0.5.2 - 09/16/2022
### New features
- Enable adding a new card to the "No Status" group
- Fix some bugs
### Bug Fixes
- Fix cannot open AppFlowy error
- Fix delete the Kanban board's row error
## Version 0.0.5.1 - 09/14/2022
### New features
- Enable deleting a field in board
- Fix some bugs
## Version 0.0.5 - 09/08/2022
### New features - Kanban Board like Notion and Trello beta
Boards are the best way to manage projects & tasks. Use them to group your databases by select, multiselect, and checkbox.
<p align="left"><img src="https://user-images.githubusercontent.com/12026239/190055984-6efa2d7a-ee38-4551-859e-ee56388e1859.gif" width="1000px" /></p>
- Set up columns that represent a specific phase of the project cycle and use cards to represent each project/task
- Drag and drop a card from one phase/column to another phase/column
- Update database properties in the Board view by clicking on a property and making edits on the card
### Other Features & Improvements
- Settings allow users to change avatars
- Click and drag the right edge to resize your sidebar
- And many user interface improvements (link)
## Version 0.0.5 - beta.2 - beta.1 - 09/01/2022
New features
### New features
- Board-view database
- Support start editing after creating a new card
- Support editing the card directly by clicking the edit button
@@ -14,7 +80,7 @@ New features
## Version 0.0.5 - beta.1 - 08/25/2022
New features
### New features
- Board-view database
- Group by single select
- drag and drop cards
@@ -37,7 +103,7 @@ New features
## Version 0.0.4 - beta.3 - 05/02/2022
- Drag to reorder app/ view/ field
- Row record open as a page
- Row record opens as a page
- Auto resize the height of the row in the grid
- Support more number formats
- Search column options, supporting Single-select, Multi-select, and number format
@@ -61,7 +127,7 @@ New features
## Version 0.0.4 - beta.1 - 04/08/2022
v0.0.4 - beta.1 is pre-release
New features
### New features
- Table-view database
- supported column types: Text, Checkbox, Single-select, Multi-select, Numbers
- hide / delete columns
@@ -70,12 +136,12 @@ New features
## Version 0.0.3 - 02/23/2022
v0.0.3 is production ready, available on Linux, macOS, and Windows
New features
### New features
- Dark Mode
- Support new languages: French, Italian, Russian, Simplified Chinese, Spanish
- Add Settings: Toggle on Dark Mode; Select a language
- Show device info
- Add tooltip on toolbar icons
- Add tooltip on the toolbar icons
Bug fixes and improvements
- Increased height of action
+15 -5
View File
@@ -23,12 +23,15 @@ You are in charge of your data and customizations.
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
</p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/174754661-682980e4-e386-4685-bb6f-2da357390b61.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/200787830-96be260b-d0a0-4152-864e-6730b19095cd.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/174753177-98e4c899-2356-4137-bb42-374bba2b127b.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/190650183-a940f1e0-a2c5-4797-ab3a-56758f6f696c.png" alt="The Open Source Alternative To Notion." width="1000px" /></p>
## User Installation
Please view the [documentation](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods) for OS specific installation instructions.
* [Windows/Mac/Linux](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages)
* [Docker](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker)
* [Source](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source)
## Built With
@@ -48,7 +51,9 @@ Please view the [documentation](https://appflowy.gitbook.io/docs/essential-docum
- [AppFlowy Roadmap ReadMe](https://appflowy.gitbook.io/docs/essential-documentation/roadmap)
- [AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12)
If you'd like to propose a feature, submit an issue [here](https://github.com/AppFlowy-IO/appflowy/issues).
If you'd like to propose a feature, submit a feature request [here](https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&template=feature_request.yaml&title=%5BFR%5D+) <br/>
If you'd like to report a bug, submit bug report [here](https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&template=bug_report.yaml&title=%5BBug%5D+)
## **Releases**
@@ -61,7 +66,11 @@ Contributions are what make the open source community such an amazing place to b
If your Pull Request is accepted as it fixes a bug, adds functionality, or makes AppFlowy's codebase significantly easier to use or understand, congratulations! If your administrative and managerial work behind the scenes that sustains the community as a whole, congratulations! You are now an official contributor to AppFlowy. Get in touch with us ([link](https://tally.so/r/mKP5z3)) to receive the very special Contributor T-shirt!
Proudly wear your T-shirt and show it to us by tagging [@appflowy](https://twitter.com/appflowy) on Twitter.
![DSCF3560](https://user-images.githubusercontent.com/12026239/186106423-a923f6fe-b169-477b-87e4-ffb2e375e0f6.jpg)
## Join the community to build AppFlowy together!
<a href="https://github.com/AppFlowy-IO/AppFlowy/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AppFlowy-IO/AppFlowy" />
</a>
## Why Are We Building This?
@@ -86,7 +95,7 @@ To be honest, we do not claim to outperform Notion in terms of functionality and
## License
Distributed under the AGPLv3 License. See `LICENSE.md` for more information.
Distributed under the AGPLv3 License. See [`LICENSE.md`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/LICENSE) for more information.
## Acknowledgements
@@ -94,3 +103,4 @@ Special thanks to these amazing projects which help power AppFlowy.IO:
- [flutter-quill](https://github.com/singerdmx/flutter-quill)
- [cargo-make](https://github.com/sagiegurari/cargo-make)
- [contrib.rocks](https://contrib.rocks)
+1 -1
View File
@@ -48,7 +48,7 @@
{
"label": "AF: build_flowy_sdk_for_android",
"type": "shell",
"command": "cargo make --profile development-android flowy-sdk-dev-android",
"command": "cargo make --profile development-android appflowy-sdk-dev-android",
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
+71 -19
View File
@@ -14,7 +14,7 @@ extend = [
on_error_task = "catch"
[tasks.catch]
run_task = {name = ["restore-crate-type"]}
run_task = { name = ["restore-crate-type"] }
[env]
RUST_LOG = "info"
@@ -22,7 +22,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
CURRENT_APP_VERSION = "0.0.5"
CURRENT_APP_VERSION = "0.0.7"
FEATURES = "flutter"
PRODUCT_NAME = "AppFlowy"
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
@@ -40,10 +40,16 @@ PRODUCT_NAME = "AppFlowy"
# for cdylib:
# if (Platform.isMacOS) return DynamicLibrary.open('${prefix}/libdart_ffi.dylib');
CRATE_TYPE = "staticlib"
SDK_EXT = "a"
LIB_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"
FLUTTER_FLOWY_SDK_PATH = "app_flowy/packages/flowy_sdk"
PROTOBUF_DERIVE_CACHE = "../shared-lib/flowy-derive/src/derive_cache/derive_cache.rs"
# Test default config
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "dylib"
TEST_RUST_LOG = "info"
TEST_BUILD_FLAG = "debug"
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
[env.development-mac-arm64]
RUST_LOG = "info"
@@ -88,7 +94,7 @@ BUILD_FLAG = "debug"
FLUTTER_OUTPUT_DIR = "Debug"
PRODUCT_EXT = "exe"
CRATE_TYPE = "cdylib"
SDK_EXT = "dll"
LIB_EXT = "dll"
[env.production-windows-x86]
BUILD_FLAG = "release"
@@ -97,7 +103,7 @@ RUST_COMPILE_TARGET = "x86_64-pc-windows-msvc"
FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "exe"
CRATE_TYPE = "cdylib"
SDK_EXT = "dll"
LIB_EXT = "dll"
APP_ENVIRONMENT = "production"
[env.development-linux-x86_64]
@@ -106,7 +112,7 @@ RUST_COMPILE_TARGET = "x86_64-unknown-linux-gnu"
BUILD_FLAG = "debug"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Debug"
SDK_EXT = "so"
LIB_EXT = "so"
LINUX_ARCH = "x64"
[env.production-linux-x86_64]
@@ -115,7 +121,7 @@ TARGET_OS = "linux"
RUST_COMPILE_TARGET = "x86_64-unknown-linux-gnu"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Release"
SDK_EXT = "so"
LIB_EXT = "so"
LINUX_ARCH = "x64"
APP_ENVIRONMENT = "production"
@@ -125,7 +131,7 @@ RUST_COMPILE_TARGET = "aarch64-unknown-linux-gnu"
BUILD_FLAG = "debug"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Debug"
SDK_EXT = "so"
LIB_EXT = "so"
LINUX_ARCH = "arm64"
[env.production-linux-aarch64]
@@ -134,13 +140,12 @@ TARGET_OS = "linux"
RUST_COMPILE_TARGET = "aarch64-unknown-linux-gnu"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Release"
SDK_EXT = "so"
LIB_EXT = "so"
LINUX_ARCH = "arm64"
APP_ENVIRONMENT = "production"
[tasks.echo_env]
script = [
'''
script = ['''
echo "-------- Env Parameters --------"
echo CRATE_TYPE: ${CRATE_TYPE}
echo BUILD_FLAG: ${BUILD_FLAG}
@@ -151,8 +156,7 @@ script = [
echo APP_ENVIRONMENT: ${APP_ENVIRONMENT}
echo ${platforms}
echo ${BUILD_ARCHS}
'''
]
''']
script_runner = "@shell"
[env.production-ios]
@@ -166,6 +170,14 @@ BUILD_FLAG = "debug"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Debug"
FEATURES = "flutter,openssl_vendored"
[env.production-android]
BUILD_FLAG = "release"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Release"
FEATURES = "flutter,openssl_vendored"
[tasks.setup-crate-type]
private = true
@@ -191,12 +203,52 @@ script = [
]
script_runner = "@duckscript"
[tasks.test-build]
condition = { env_set = [ "FLUTTER_FLOWY_SDK_PATH"] }
[env.test-macos]
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "dylib"
# For the moment, the DynamicLibrary only supports open x86_64 architectures binary.
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
[env.test-linux]
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "so"
TEST_COMPILE_TARGET = "x86_64-unknown-linux-gnu"
[env.test-windows]
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "dll"
TEST_COMPILE_TARGET = "x86_64-pc-windows-msvc"
[tasks.setup-test-crate-type]
private = true
script = [
"""
cd ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/flowy-net
cargo build -vv --features=dart
toml = readfile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml
val = replace ${toml} "staticlib" ${TEST_CRATE_TYPE}
result = writefile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml ${val}
assert ${result}
""",
]
script_runner = "@duckscript"
[tasks.restore-test-crate-type]
private = true
script = [
"""
toml = readfile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml
val = replace ${toml} ${TEST_CRATE_TYPE} "staticlib"
result = writefile ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/${CARGO_MAKE_CRATE_NAME}/Cargo.toml ${val}
assert ${result}
""",
]
script_runner = "@duckscript"
[tasks.test-build]
condition = { env_set = ["FLUTTER_FLOWY_SDK_PATH"] }
script = ["""
cd ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/flowy-net
cargo build -vv --features=dart
"""]
script_runner = "@shell"
+5 -5
View File
@@ -12,8 +12,8 @@ When compiling for android we need the following pre-requisites:
- [Download](https://developer.android.com/ndk/downloads/) Android NDK version 24.
- When downloading Android NDK you can get the compressed version as a standalone from the site.
Or you can download it through [Android Studio](https://developer.android.com/studio).
- After downloading the two you need to set the environment variables. For Windows that's a seperate process.
On MacOs and Linux the process is similar.
- After downloading the two you need to set the environment variables. For Windows that's a separate process.
On macOS and Linux the process is similar.
- The variables needed are '$ANDROID_NDK_HOME', this will point to where the NDK is located.
---
@@ -48,9 +48,9 @@ linker = "/home/user/Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux
**Folder path: 'Android/Sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/14.0.1/lib/linux'.**
After that you have to copy this file into three different folders namely aarch64, arm, i386 and x86_64.
We have to do this so we Android NDK can find clang on our system, if we used NDK 22 we wouldnt have to do this process.
Though using NDK v22 will not give us alot of features to work with.
This github [issue](https://github.com/fzyzcjy/flutter_rust_bridge/issues/419) explains the reason why we are doing this.
We have to do this so we Android NDK can find clang on our system, if we used NDK 22 we wouldn't have to do this process.
Though using NDK v22 will not give us a lot of features to work with.
This GitHub [issue](https://github.com/fzyzcjy/flutter_rust_bridge/issues/419) explains the reason why we are doing this.
---
@@ -0,0 +1,93 @@
Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
+52 -9
View File
@@ -161,7 +161,47 @@
"filter": "Filter",
"sortBy": "Sort by",
"Properties": "Properties",
"group": "Group"
"group": "Group",
"addFilter": "Add Filter",
"deleteFilter": "Delete filter",
"filterBy": "Filter by...",
"typeAValue": "Type a value..."
},
"textFilter": {
"contains": "Contains",
"doesNotContain": "Does not contain",
"endsWith": "Ends with",
"startWith": "Starts with",
"is": "Is",
"isNot": "Is not",
"isEmpty": "Is empty",
"isNotEmpty": "Is not empty",
"choicechipPrefix": {
"isNot": "Not",
"startWith": "Starts with",
"endWith": "Ends with",
"isEmpty": "is empty",
"isNotEmpty": "is not empty"
}
},
"checkboxFilter": {
"isChecked": "Checked",
"isUnchecked": "Unchecked",
"choicechipPrefix": {
"is": "is"
}
},
"singleSelectOptionFilter": {
"is": "Is",
"isNot": "Is not",
"isEmpty": "Is empty",
"isNotEmpty": "Is not empty"
},
"multiSelectOptionFilter": {
"contains": "Contains",
"doesNotContain": "Does not contain",
"isEmpty": "Is empty",
"isNotEmpty": "Is not empty"
},
"field": {
"hide": "Hide",
@@ -181,7 +221,7 @@
"includeTime": " Include time",
"dateFormatFriendly": "Month Day,Year",
"dateFormatISO": "Year-Month-Day",
"dateFormatLocal": "Year/Month/Day",
"dateFormatLocal": "Month/Day/Year",
"dateFormatUS": "Year/Month/Day",
"timeFormat": " Time format",
"invalidTimeFormat": "Invalid format",
@@ -191,13 +231,16 @@
"optionTitle": "Options",
"addOption": "Add option",
"editProperty": "Edit property",
"newColumn": "New column"
"newColumn": "New column",
"deleteFieldPromptMessage": "Are you sure? This property will be deleted"
},
"row": {
"duplicate": "Duplicate",
"delete": "Delete",
"textPlaceholder": "Empty",
"copyProperty": "Copied property to clipboard"
"copyProperty": "Copied property to clipboard",
"count": "Count",
"newRow": "New row"
},
"selectOption": {
"create": "Create",
@@ -211,17 +254,17 @@
"aquaColor": "Aqua",
"blueColor": "Blue",
"deleteTag": "Delete tag",
"colorPannelTitle": "Colors",
"pannelTitle": "Select an option or create one",
"colorPanelTitle": "Colors",
"panelTitle": "Select an option or create one",
"searchOption": "Search for an option"
},
"menuName": "Grid"
},
"document": {
"menuName": "Doc",
"menuName": "Document",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
@@ -7,7 +7,7 @@
"letsGoButtonText": "Vamos",
"title": "Título",
"signUp": {
"buttonText": "Registar",
"buttonText": "Registrar",
"title": "Registrar en @:appName",
"getStartedText": "Empezar",
"emptyPasswordError": "La contraseña no puede estar en blanco",
@@ -16,7 +16,7 @@
"alreadyHaveAnAccount": "¿Posee credenciales?",
"emailHint": "Correo",
"passwordHint": "Contraseña",
"repeatPasswordHint": "Repite la contraseña"
"repeatPasswordHint": "Repetir contraseña"
},
"signIn": {
"loginTitle": "Ingresa a @:appName",
@@ -58,7 +58,7 @@
}
},
"deletePagePrompt": {
"text": "Esta paágina esta en la Papelera",
"text": "Esta página está en la Papelera",
"restore": "Recuperar página",
"deletePermanent": "Eliminar permanentemente"
},
@@ -69,7 +69,7 @@
"debug": {
"name": "Información de depuración",
"success": "¡Información copiada!",
"fail": "No fué posible copiar la información"
"fail": "No fue posible copiar la información"
}
},
"menuAppHeader": {
@@ -167,15 +167,15 @@
"singleSelectFieldName": "Seleccionar",
"multiSelectFieldName": "Selección múltiple",
"urlFieldName": "URL",
"numberFormat": " Formato numérico",
"dateFormat": " Formato de fecha",
"includeTime": " Incluir tiempo",
"numberFormat": "Formato numérico",
"dateFormat": "Formato de fecha",
"includeTime": "Incluir tiempo",
"dateFormatFriendly": "Mes Día, Año",
"dateFormatISO": "Año-Mes-Día",
"dateFormatLocal": "Año/Mes/Día",
"dateFormatLocal": "Mes/Día/Año",
"dateFormatUS": "Año/Mes/Día",
"timeFormat": " Time format",
"invalidTimeFormat": "Formato de tiempo",
"timeFormat": "Formato de tiempo",
"invalidTimeFormat": "Formato de tiempo inválido",
"timeFormatTwelveHour": "12 horas",
"timeFormatTwentyFourHour": "24 horas",
"addSelectOption": "Añadir una opción",
@@ -201,21 +201,26 @@
"aquaColor": "Agua",
"blueColor": "Azul",
"deleteTag": "Borrar etiqueta",
"colorPannelTitle": "Colores",
"pannelTitle": "Selecciona una opción o crea una",
"colorPanelTitle": "Colores",
"panelTitle": "Selecciona una opción o crea una",
"searchOption": "Buscar una opción"
},
"menuName": "Grid"
"menuName": "Cuadrícula"
},
"document": {
"menuName": "Doc",
"menuName": "Documento",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
"openSidebar": "Abrir panel lateral",
"closeSidebar": "Cerrar panel lateral"
},
"board": {
"column": {
"create_new_card": "Nuevo"
}
}
}
@@ -94,7 +94,20 @@
},
"tooltip": {
"lightMode": "Passer en mode clair",
"darkMode": "Passer en mode sombre"
"darkMode": "Passer en mode sombre",
"openAsPage": "Ouvrir en tant que page",
"addNewRow": "Ajouter une ligne",
"openMenu": "Cliquer pour ouvrir le menu"
},
"sideBar": {
"closeSidebar": "Fermer le menu latéral",
"openSidebar": "Ouvrir le menu latéral"
},
"notifications": {
"export": {
"markdown": "Note exportée en Markdown",
"path": "Documents/flowy"
}
},
"contactsPage": {
"title": "Contacts",
@@ -123,7 +136,7 @@
"failedMsg": "Assurez-vous d'avoir terminé le processus de connexion dans votre navigateur."
},
"google": {
"title": "CONNEXION GOOGLE",
"title": "CONNEXION VIA GOOGLE",
"instruction1": "Pour importer vos contacts Google, vous devez autoriser cette application à l'aide de votre navigateur web.",
"instruction2": "Copiez ce code dans votre presse-papiers en cliquant sur l'icône ou en sélectionnant le texte:",
"instruction3": "Accédez au lien suivant dans votre navigateur web et saisissez le code ci-dessus:",
@@ -135,6 +148,7 @@
"menu": {
"appearance": "Apparence",
"language": "Langue",
"user": "Utilisateur",
"open": "Ouvrir les paramètres"
},
"appearance": {
@@ -142,15 +156,12 @@
"darkLabel": "Mode sombre"
}
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
},
"grid": {
"settings": {
"filter": "Filtrer",
"sortBy": "Trier par",
"Properties": "Propriétés"
"sortBy": "Filtrer par",
"Properties": "Propriétés",
"group": "Groupe"
},
"field": {
"hide": "Cacher",
@@ -170,7 +181,7 @@
"includeTime": " Inclure l'heure",
"dateFormatFriendly": "Mois Jour, Année",
"dateFormatISO": "Année-Mois-Jour",
"dateFormatLocal": "Année/Mois/Jour",
"dateFormatLocal": "Mois/Jour/Année",
"dateFormatUS": "Année/Mois/Jour",
"timeFormat": " Format du temps",
"invalidTimeFormat": "Format invalide",
@@ -179,13 +190,17 @@
"addSelectOption": "Ajouter une option",
"optionTitle": "Options",
"addOption": "Ajouter une option",
"editProperty": "Modifier la propriété"
"editProperty": "Modifier la propriété",
"newColumn": "Nouvelle colonne",
"deleteFieldPromptMessage": "Vous voulez supprimer cette propriété ?"
},
"row": {
"duplicate": "Dupliquer",
"delete": "Supprimer",
"textPlaceholder": "Vide",
"copyProperty": "Copie de la propriété dans le presse-papiers"
"copyProperty": "Copie de la propriété dans le presse-papiers",
"count": "Nombre",
"newRow": "Nouvelle ligne"
},
"selectOption": {
"create": "Créer",
@@ -199,17 +214,22 @@
"aquaColor": "Aqua",
"blueColor": "Bleu",
"deleteTag": "Supprimer l'étiquette",
"colorPannelTitle": "Couleurs",
"pannelTitle": "Sélectionnez une option ou créez-en une",
"colorPanelTitle": "Couleurs",
"panelTitle": "Sélectionnez une option ou créez-en une",
"searchOption": "Rechercher une option"
},
"menuName": "Grille"
},
"document": {
"menuName": "Doc",
"menuName": "Document",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
"column": {
"create_new_card": "Nouveau"
}
}
}
}
@@ -173,7 +173,7 @@
"includeTime": " Sertakan waktu",
"dateFormatFriendly": "Bulan Hari,Tahun",
"dateFormatISO": "Tahun-Bulan-Hari",
"dateFormatLocal": "Tahun/Bulan/Hari",
"dateFormatLocal": "Bulan/Hari/Tahun",
"dateFormatUS": "Tahun/Bulan/Hari",
"timeFormat": " Format waktu",
"invalidTimeFormat": "Format yang tidak valid",
@@ -202,17 +202,17 @@
"aquaColor": "Air",
"blueColor": "Biru",
"deleteTag": "Hapus tag",
"colorPannelTitle": "Warna",
"pannelTitle": "Pilih opsi atau buat baru",
"colorPanelTitle": "Warna",
"panelTitle": "Pilih opsi atau buat baru",
"searchOption": "Cari opsi"
},
"menuName": "Grid"
},
"document": {
"menuName": "Doc",
"menuName": "Dokter",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"sideBar": {
@@ -165,7 +165,7 @@
"includeTime": " 時刻を含める",
"dateFormatFriendly": "月 日,年",
"dateFormatISO": "年-月-日",
"dateFormatLocal": "年/月/日",
"dateFormatLocal": "月/日/年",
"dateFormatUS": "年/月/日",
"timeFormat": " 時刻書式",
"timeFormatTwelveHour": "12 時間表記",
@@ -191,8 +191,8 @@
"aquaColor": "水色",
"blueColor": "青",
"deleteTag": "選択候補を削除",
"colorPannelTitle": "色",
"pannelTitle": "選択候補を検索 または 作成する",
"colorPanelTitle": "色",
"panelTitle": "選択候補を検索 または 作成する",
"searchOption": "選択候補を検索"
}
},
@@ -0,0 +1,236 @@
{
"appName": "AppFlowy",
"defaultUsername": "Me",
"welcomeText": "@:appName 에 오신것을 환영합니다",
"githubStarText": "Star on GitHub",
"subscribeNewsletterText": "뉴스레터 구독",
"letsGoButtonText": "Let's Go",
"title": "제목",
"signUp": {
"buttonText": "회원가입",
"title": "@:appName 에 회원가입",
"getStartedText": "시작하기",
"emptyPasswordError": "비밀번호는 공백일 수 없습니다",
"repeatPasswordEmptyError": "비밀번호 재입력란은 공백일 수 없습니다",
"unmatchedPasswordError": "재입력 하신 비밀번호가 같지 않습니다",
"alreadyHaveAnAccount": "이미 계정이 있으신가요?",
"emailHint": "이메일",
"passwordHint": "비밀번호",
"repeatPasswordHint": "비밀번호 재입력"
},
"signIn": {
"loginTitle": "@:appName 에 로그인",
"loginButtonText": "로그인",
"buttonText": "로그인",
"forgotPassword": "비밀번호를 잊으셨나요?",
"emailHint": "이메일",
"passwordHint": "비밀번호",
"dontHaveAnAccount": "계정이 없으신가요?",
"repeatPasswordEmptyError": "비밀번호 재입력란은 공백일 수 없습니다",
"unmatchedPasswordError": "재입력 하신 비밀번호가 같지 않습니다"
},
"workspace": {
"create": "워크스페이스 생성",
"hint": "워크스페이스",
"notFoundError": "워크스페이스를 찾을 수 없습니다"
},
"shareAction": {
"buttonText": "공유",
"workInProgress": "Coming soon",
"markdown": "마크다운",
"copyLink": "링크 복사"
},
"disclosureAction": {
"rename": "이름변경",
"delete": "삭제",
"duplicate": "복제"
},
"blankPageTitle": "빈 페이지",
"newPageText": "새로운 페이지",
"trash": {
"text": "휴지통",
"restoreAll": "모두 복구",
"deleteAll": "모두 삭제",
"pageHeader": {
"fileName": "파일 이름",
"lastModified": "수정날짜",
"created": "생성날짜"
}
},
"deletePagePrompt": {
"text": "현재 페이지는 휴지통에 있습니다",
"restore": "페이지 복구",
"deletePermanent": "영구 삭제"
},
"dialogCreatePageNameHint": "페이지 이름",
"questionBubble": {
"whatsNew": "새로운 소식",
"help": "도움 및 지원",
"debug": {
"name": "디버그 정보",
"success": "디버그 정보를 클립보드로 복사했습니다.",
"fail": "디버그 정보를 클립보드로 복사할 수 없습니다."
}
},
"menuAppHeader": {
"addPageTooltip": "하위에 페이지 추가",
"defaultNewPageName": "제목없음",
"renameDialog": "이름변경"
},
"toolbar": {
"undo": "실행취소",
"redo": "재실행",
"bold": "굵게",
"italic": "기울임꼴",
"underline": "밑줄",
"strike": "취소선",
"numList": "번호 매기기 목록",
"bulletList": "글머리 기호 목록",
"checkList": "작업 목록",
"inlineCode": "인라인 코드",
"quote": "인용구 블록",
"header": "헤더",
"highlight": "하이라이트"
},
"tooltip": {
"lightMode": "라이트 모드로 변경",
"darkMode": "다크 모드로 변경",
"openAsPage": "페이지로 열기",
"addNewRow": "열 추가",
"openMenu": "메뉴를 여시려면 클릭하세요"
},
"sideBar": {
"closeSidebar": "사이드바 닫기",
"openSidebar": "사이드바 열기"
},
"notifications": {
"export": {
"markdown": "마크다운으로 노트를 내보냄",
"path": "Documents/flowy"
}
},
"contactsPage": {
"title": "연락처",
"whatsHappening": "이번주에는 무슨 일이 있나요?",
"addContact": "연락처 추가",
"editContact": "연락처 편집"
},
"button": {
"OK": "확인",
"Cancel": "취소",
"signIn": "로그인",
"signOut": "로그아웃",
"complete": "완료",
"save": "저장"
},
"label": {
"welcome": "환영합니다!",
"firstName": "이름",
"middleName": "중간 이름",
"lastName": "성",
"stepX": "{X} 단계"
},
"oAuth": {
"err": {
"failedTitle": "계정에 연결을 할 수 없습니다.",
"failedMsg": "브라우저에서 회원가입이 완료되었는지 확인해주세요."
},
"google": {
"title": "GOOGLE SIGN-IN",
"instruction1": "구글 연락처를 가져오기 위해서 웹브라우저로 앱을 승인 해야 합니다.",
"instruction2": "아이콘을 클릭 또는 텍스트를 선택해서 이 코드를 클립보드로 복사하세요:",
"instruction3": "웹브라우저로 다음 링크로 가셔서 위 코드를 입력해주세요:",
"instruction4": "가입 완료 후 아래 버튼을 눌러주세요:"
}
},
"settings": {
"title": "설정",
"menu": {
"appearance": "화면",
"language": "언어",
"user": "사용자",
"open": "설정 열기"
},
"appearance": {
"lightLabel": "라이트 모드",
"darkLabel": "다크 모드"
}
},
"grid": {
"settings": {
"filter": "필터",
"sortBy": "정렬 기준",
"Properties": "속성",
"group": "그룹"
},
"field": {
"hide": "숨기기",
"insertLeft": "왼쪽 삽입",
"insertRight": "오른쪽 삽입",
"duplicate": "복제",
"delete": "삭제",
"textFieldName": "텍스트",
"checkboxFieldName": "체크박스",
"dateFieldName": "날짜",
"numberFieldName": "숫자",
"singleSelectFieldName": "선택",
"multiSelectFieldName": "다중선택",
"urlFieldName": "링크",
"numberFormat": " 숫자 형식",
"dateFormat": " 날짜 형식",
"includeTime": " 시간 표시",
"dateFormatFriendly": "월 일,년",
"dateFormatISO": "년-월-일",
"dateFormatLocal": "월/일/년",
"dateFormatUS": "년/월/일",
"timeFormat": " 시간 형식",
"invalidTimeFormat": "잘못된 형식",
"timeFormatTwelveHour": "12 시간",
"timeFormatTwentyFourHour": "24 시간",
"addSelectOption": "옵션 추가",
"optionTitle": "옵션",
"addOption": "옵션 추가",
"editProperty": "속성 편집",
"newColumn": "열 추가",
"deleteFieldPromptMessage": "해당 속성을 삭제 하시겠습니까?"
},
"row": {
"duplicate": "복제",
"delete": "삭제",
"textPlaceholder": "비어있음",
"copyProperty": "속성이 클립보드로 복사됨",
"count": "개수",
"newRow": "행 추가"
},
"selectOption": {
"create": "생성",
"purpleColor": "보라색",
"pinkColor": "핑크색",
"lightPinkColor": "연한 핑크색",
"orangeColor": "오렌지색",
"yellowColor": "노랑색",
"limeColor": "라임색",
"greenColor": "초록색",
"aquaColor": "아쿠아색",
"blueColor": "파랑색",
"deleteTag": "태그 삭제",
"colorPanelTitle": "색상",
"panelTitle": "옵션 선택 또는 생성",
"searchOption": "옵션 검색"
},
"menuName": "그리드"
},
"document": {
"menuName": "도큐먼트",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
"column": {
"create_new_card": "추가"
}
}
}
+227 -144
View File
@@ -1,151 +1,234 @@
{
"appName": "AppFlowy",
"defaultUsername": "Me",
"welcomeText": "Bem vindo @:appName",
"githubStarText": "Star on GitHub",
"subscribeNewsletterText": "Se inscreva na Newsletter",
"letsGoButtonText": "Vamos lá",
"title": "Título",
"signUp": {
"buttonText": "Se inscreva",
"title": "Se inscreva no @:appName",
"getStartedText": "Começar",
"emptyPasswordError": "Senha não pode estar em branco.",
"repeatPasswordEmptyError": "Confirmar a senha não pode estar em branco.",
"unmatchedPasswordError": "As senhas não conferem.",
"alreadyHaveAnAccount": "Já possui uma conta?",
"emailHint": "Email",
"passwordHint": "Senha",
"repeatPasswordHint": "Confirme a senha"
"appName": "AppFlowy",
"defaultUsername": "Eu",
"welcomeText": "Bem-vindo @:appName",
"githubStarText": "Dar uma estrela no Github",
"subscribeNewsletterText": "Inscreva-se para receber novidades",
"letsGoButtonText": "Vamos lá",
"title": "Título",
"signUp": {
"buttonText": "Inscreva-se",
"title": "Inscreva-se no @:appName",
"getStartedText": "Começar",
"emptyPasswordError": "Senha não pode estar em branco.",
"repeatPasswordEmptyError": "Senha não estar em branco.",
"unmatchedPasswordError": "As senhas não conferem.",
"alreadyHaveAnAccount": "Já possui uma conta?",
"emailHint": "E-mail",
"passwordHint": "Dica de senha",
"repeatPasswordHint": "Confirme a senha"
},
"signIn": {
"loginTitle": "Conectar-se ao @:appName",
"loginButtonText": "Conectar-se",
"buttonText": "Entre",
"forgotPassword": "Esqueceu sua senha?",
"emailHint": "E-mail",
"passwordHint": "Senha",
"dontHaveAnAccount": "Não possui uma conta?",
"repeatPasswordEmptyError": "Senha não pode estar em branco.",
"unmatchedPasswordError": "As senhas não conferem."
},
"workspace": {
"create": "Crie uma área de trabalho",
"hint": "Espaço de trabalho",
"notFoundError": "Espaço de trabalho não encontrada"
},
"shareAction": {
"buttonText": "Compartilhar",
"workInProgress": "Em breve",
"markdown": "Marcador",
"copyLink": "Copiar o link"
},
"disclosureAction": {
"rename": "Renomear",
"delete": "Apagar",
"duplicate": "Duplicar"
},
"blankPageTitle": "Página em branco",
"newPageText": "Nova página",
"trash": {
"text": "Lixeira",
"restoreAll": "Restaurar tudo",
"deleteAll": "Apagar tudo",
"pageHeader": {
"fileName": "Nome do arquivo",
"lastModified": "Última modificação",
"created": "Criado"
}
},
"deletePagePrompt": {
"text": "Está página está na lixeira",
"restore": "Restaurar a página",
"deletePermanent": "Apagar permanentemente"
},
"dialogCreatePageNameHint": "Nome da página",
"questionBubble": {
"whatsNew": "O que há de novo?",
"help": "Ajuda e Suporte",
"debug": {
"name": "Informação de depuração",
"success": "Informação de depuração copiada para a área de transferência!",
"fail": "Falha ao copiar a informação de depuração para a área de transferência"
}
},
"menuAppHeader": {
"addPageTooltip": "Adicionar uma nova página.",
"defaultNewPageName": "Sem título",
"renameDialog": "Renomear"
},
"toolbar": {
"undo": "Desfazer",
"redo": "Refazer",
"bold": "Negrito",
"italic": "Itálico",
"underline": "Sublinhado",
"strike": "Tachado",
"numList": "Lista numerada",
"bulletList": "Lista com marcadores",
"checkList": "Check list",
"inlineCode": "Embutir código",
"quote": "Citação em bloco",
"header": "Cabeçalho",
"highlight": "Realçar"
},
"tooltip": {
"lightMode": "Mudar para o modo claro",
"darkMode": "Mudar para o modo escuro",
"openAsPage": "Abrir como uma página",
"addNewRow": "Adicionar uma nova linha",
"openMenu": "Clique para abrir o menu"
},
"sideBar": {
"openSidebar": "Abrir barra lateral",
"closeSidebar": "Fechar barra lateral"
},
"notifications": {
"export": {
"markdown": "Nota exportada como um marcador",
"path": "Documentos/flowy"
}
},
"contactsPage": {
"title": "Contatos",
"whatsHappening": "O que está acontecendo essa semana?",
"addContact": "Adicionar um contato",
"editContact": "Editar um contato"
},
"button": {
"OK": "Ok",
"Cancel": "Cancelar",
"signIn": "Conectar",
"signOut": "Desconectar",
"complete": "Completar",
"save": "Salvar"
},
"label": {
"welcome": "Welcome!",
"firstName": "Nome",
"middleName": "Sobrenome",
"lastName": "Último nome",
"stepX": "Passo {X}"
},
"oAuth": {
"err": {
"failedTitle": "Erro ao conectar a sua conta.",
"failedMsg": "Verifique se você concluiu o processo de conexão em seu navegador."
},
"signIn": {
"loginTitle": "Entre no @:appName",
"loginButtonText": "Login",
"buttonText": "Entre",
"forgotPassword": "Esqueceu a senha?",
"emailHint": "Email",
"passwordHint": "Senha",
"dontHaveAnAccount": "Não possui uma conta?",
"repeatPasswordEmptyError": "Confirmar a senha não pode estar em branco.",
"unmatchedPasswordError": "As senhas não conferem."
},
"workspace": {
"create": "Crie uma área de trabalho",
"hint": "área de trabalho",
"notFoundError": "Área de trabalho não encontrada"
},
"shareAction": {
"buttonText": "Compartilhar",
"workInProgress": "Em breve",
"markdown": "Markdown",
"copyLink": "Copiar o link"
},
"disclosureAction": {
"rename": "Renomear",
"delete": "Deletar",
"duplicate": "Duplicar"
},
"blankPageTitle": "Página em branco",
"newPageText": "Nova página",
"trash": {
"text": "Lixeira",
"restoreAll": "Restaurar todos",
"deleteAll": "Deletar todos",
"pageHeader": {
"fileName": "Nome do arquivo",
"lastModified": "Última modificação",
"created": "Criado"
}
},
"deletePagePrompt": {
"text": "Está página está na lixeira",
"restore": "Restaurar a oágina",
"deletePermanent": "Deletar permanentemente"
},
"dialogCreatePageNameHint": "Nome da página",
"questionBubble": {
"whatsNew": "O que há de novo?",
"help": "Ajuda & Suporte",
"debug": {
"name": "Informação de depuração",
"success": "Copiar informação de debug para o clipboard!",
"fail": "Falha em copiar a informação de debug para o clipboard"
}
},
"menuAppHeader": {
"addPageTooltip": "Adicione uma nova página.",
"defaultNewPageName": "Sem título",
"renameDialog": "Renomear"
},
"toolbar": {
"undo": "Desfazer",
"redo": "Refazer",
"bold": "Negrito",
"italic": "Itálico",
"underline": "Sublinhado",
"strike": "Tachado",
"numList": "Lista numerada",
"bulletList": "Lista com marcadores",
"checkList": "Check List",
"inlineCode": "Embutir código",
"quote": "Citação em bloco",
"header": "Cabeçalho",
"highlight": "Realçar"
},
"tooltip": {
"lightMode": "Mudar para o modo Claro.",
"darkMode": "Mudar para o modo Escuro."
},
"contactsPage": {
"title": "Contatos",
"whatsHappening": "O que está acontecendo essa semana?",
"addContact": "Adicionar um contato",
"editContact": "Editar um contato"
},
"button": {
"OK": "OK",
"Cancel": "Cancelar",
"signIn": "Entrar",
"signOut": "Sair",
"complete": "Completar",
"save": "Salvar"
},
"label": {
"welcome": "Bem vindo!",
"firstName": "Primeiro Nome",
"middleName": "Nome do Meio",
"lastName": "Último Nome",
"stepX": "Passo {X}"
},
"oAuth": {
"err": {
"failedTitle": "Erro ao conectar a sua conta.",
"failedMsg": "Verifique se você concluiu o processo de login em seu navegador."
},
"google": {
"title": "GOOGLE SIGN-IN",
"instruction1": "Para importar seus Contatos do Google, você precisará autorizar este aplicativo usando seu navegador web.",
"instruction2": "Copie este código para sua área de transferência clicando no ícone ou selecionando o texto:",
"instruction3": "Navegue até o link a seguir em seu navegador e digite o código acima:",
"instruction4": "Pressione o botão abaixo ao concluir a inscrição:"
}
"google": {
"title": "Conexão com o GOOGLE",
"instruction1": "Para importar seus Contatos do Google, você precisará autorizar este aplicativo usando seu navegador.",
"instruction2": "Copie este código para sua área de transferência clicando no ícone ou selecionando o texto:",
"instruction3": "Navegue até o link a seguir em seu navegador e digite o código acima:",
"instruction4": "Pressione o botão abaixo ao concluir a inscrição:"
}
},
"settings": {
"title": "Configurações",
"menu": {
"appearance": "Aparência",
"language": "Idioma",
"user": "Usuário",
"open": "Abrir as Configurações"
},
"appearance": {
"lightLabel": "Modo Claro",
"darkLabel": "Modo Escuro"
}
},
"grid": {
"settings": {
"title": "Configurações",
"menu": {
"appearance": "Aparência",
"language": "Idioma",
"open": "Abrir as Configurações"
},
"appearance": {
"lightLabel": "Modo Claro",
"darkLabel": "Modo Escuro"
}
"filter": "Filtro",
"sortBy": "Ordenar por",
"Properties": "Propriedades",
"group": "Grupo"
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
"field": {
"hide": "Esconder",
"insertLeft": "Inserir à esquerda",
"insertRight": "Inserir à direita",
"duplicate": "Duplicar",
"delete": "Apagar",
"textFieldName": "Texto",
"checkboxFieldName": "Caixa de seleção",
"dateFieldName": "Data",
"numberFieldName": "Números",
"singleSelectFieldName": "Selecionar",
"multiSelectFieldName": "Seleção múltipla",
"urlFieldName": "URL",
"numberFormat": "Formato numérico",
"dateFormat": "Formato de data",
"includeTime": "Incluir horário",
"dateFormatFriendly": "Mês/Dia/Ano",
"dateFormatISO": "Ano/Mês/Dia",
"dateFormatLocal": "Mês/Dia/Ano",
"dateFormatUS": "Ano/Mês/Dia",
"timeFormat": "Formato de hora",
"invalidTimeFormat": "Formato Inválido",
"timeFormatTwelveHour": "12 horas",
"timeFormatTwentyFourHour": "24 horas",
"addSelectOption": "Adicionar uma opção",
"optionTitle": "Opções",
"addOption": "Adicionar opção",
"editProperty": "Editar propriedade",
"newColumn": "Nova coluna",
"deleteFieldPromptMessage": "Tem certeza? Esta propriedade será excluída"
},
"row": {
"duplicate": "Duplicar",
"delete": "Apagar",
"textPlaceholder": "Vazio",
"copyProperty": "Propriedade copiada para a área de transferência",
"count": "Contagem"
},
"selectOption": {
"create": "Criar",
"purpleColor": "Roxo",
"pinkColor": "Rosa",
"lightPinkColor": "Rosa claro",
"orangeColor": "Laranja",
"yellowColor": "Amarelo",
"limeColor": "Verde limão",
"greenColor": "Verde",
"aquaColor": "Áqua",
"blueColor": "Azul",
"deleteTag": "Apagar etiqueta",
"colorPannelTitle": "Cores",
"pannelTitle": "Escolha uma opção ou crie uma",
"searchOption": "Procure uma opção"
},
"menuName": "Grade"
},
"document": {
"menuName": "Documento",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
"column": {
"create_new_card": "Novo"
}
}
}
+225 -204
View File
@@ -1,212 +1,233 @@
{
"appName": "AppFlowy",
"defaultUsername": "Я",
"welcomeText": "Добро пожаловать в @:appName",
"githubStarText": "Поставить звезду на GitHub",
"subscribeNewsletterText": "Подписаться на рассылку",
"letsGoButtonText": "Начнём",
"title": "Заголовок",
"signUp": {
"buttonText": "Зарегистрироваться",
"title": "Регистрация в @:appName",
"getStartedText": "Начать",
"emptyPasswordError": "Пароль не может быть пустым",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают",
"alreadyHaveAnAccount": "Уже есть аккаунт?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"repeatPasswordHint": "Повторите пароль"
"appName": "AppFlowy",
"defaultUsername": "Я",
"welcomeText": "Добро пожаловать в @:appName",
"githubStarText": "Поставить звезду на GitHub",
"subscribeNewsletterText": "Подписаться на рассылку",
"letsGoButtonText": "Начнём",
"title": "Заголовок",
"signUp": {
"buttonText": "Зарегистрироваться",
"title": "Регистрация в @:appName",
"getStartedText": "Начать",
"emptyPasswordError": "Пароль не может быть пустым",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают",
"alreadyHaveAnAccount": "Уже есть аккаунт?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"repeatPasswordHint": "Повторите пароль"
},
"signIn": {
"loginTitle": "Войти в @:appName",
"loginButtonText": "Войти",
"buttonText": "Авторизация",
"forgotPassword": "Забыли пароль?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"dontHaveAnAccount": "Нет аккаунта?",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают"
},
"workspace": {
"create": "Создать рабочее пространство",
"hint": "рабочее пространство",
"notFoundError": "Нет такого рабочего пространства"
},
"shareAction": {
"buttonText": "Поделиться",
"workInProgress": "В разработке",
"markdown": "Markdown",
"copyLink": "Скопировать ссылку"
},
"disclosureAction": {
"rename": "Переименовать",
"delete": "Удалить",
"duplicate": "Дублировать"
},
"blankPageTitle": "Пустая страница",
"newPageText": "Новая страница",
"trash": {
"text": "Корзина",
"restoreAll": "Восстановить всё",
"deleteAll": "Очистить",
"pageHeader": {
"fileName": "Имя",
"lastModified": "Последнее изменение",
"created": "Создан"
}
},
"deletePagePrompt": {
"text": "Эта страница в Корзине",
"restore": "Восстановить страницу",
"deletePermanent": "Удалить навсегда"
},
"dialogCreatePageNameHint": "Имя",
"questionBubble": {
"whatsNew": "Что нового?",
"help": "Помощь",
"debug": {
"name": "Отладочная информация",
"success": "Скопировано в буфер обмена!",
"fail": "Не получилось скопировать"
}
},
"menuAppHeader": {
"addPageTooltip": "Быстро добавить новую страницу",
"defaultNewPageName": "Без заголовка",
"renameDialog": "Переименовать"
},
"toolbar": {
"undo": "Отменить",
"redo": "Повторить",
"bold": "Жирный",
"italic": "Курсив",
"underline": "Подчёркнутый",
"strike": "Зачёркнутый",
"numList": "Нумерованный список",
"bulletList": "Маркированный список",
"checkList": "Список To-Do",
"inlineCode": "Код",
"quote": "Цитата",
"header": "Заголовок",
"highlight": "Выделение"
},
"tooltip": {
"darkMode": "Переключиться в тёмную тему",
"openAsPage": "Открыть как страницу",
"addNewRow": "Добавить новую строку",
"openMenu": "Открыть меню"
},
"sideBar": {
"closeSidebar": "Закрыть боковое меню",
"openSidebar": "Открыть боковое меню"
},
"notifications": {
"export": {
"markdown": "Заметка экспортирована в Markdown",
"path": "Документы/flowy"
}
},
"contactsPage": {
"title": "Контакты",
"whatsHappening": "Что происходит на этой неделе?",
"addContact": "Новый контакт",
"editContact": "Редактировать"
},
"button": {
"OK": "OK",
"Cancel": "Отмена",
"signIn": "Войти",
"signOut": "Выйти",
"complete": "Завершить",
"save": "Сохранить"
},
"label": {
"welcome": "Добро пожаловать!",
"firstName": "Имя",
"middleName": "Отчество",
"lastName": "Фамилия",
"stepX": "Этап {X}"
},
"oAuth": {
"err": {
"failedTitle": "Ошибка подключения к аккаунту.",
"failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
},
"signIn": {
"loginTitle": "Войти в @:appName",
"loginButtonText": "Войти",
"buttonText": "Авторизация",
"forgotPassword": "Забыли пароль?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"dontHaveAnAccount": "Нет аккаунта?",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают"
},
"workspace": {
"create": "Создать рабочее пространство",
"hint": "рабочее пространство",
"notFoundError": "Нет такого рабочего пространства"
},
"shareAction": {
"buttonText": "Поделиться",
"workInProgress": "В разработке",
"markdown": "Markdown",
"copyLink": "Скопировать ссылку"
},
"disclosureAction": {
"rename": "Переименовать",
"delete": "Удалить",
"duplicate": "Дублировать"
},
"blankPageTitle": "Пустая страница",
"newPageText": "Новая страница",
"trash": {
"text": "Корзина",
"restoreAll": "Восстановить всё",
"deleteAll": "Очистить",
"pageHeader": {
"fileName": "Имя",
"lastModified": "Последнее изменение",
"created": "Создан"
}
},
"deletePagePrompt": {
"text": "Эта страница в Корзине",
"restore": "Восстановить страницу",
"deletePermanent": "Удалить навсегда"
},
"dialogCreatePageNameHint": "Имя",
"questionBubble": {
"whatsNew": "Что нового?",
"help": "Помощь",
"debug": {
"name": "Отладочная информация",
"success": "Скопировано в буфер обмена!",
"fail": "Не получилось скопировать"
}
},
"menuAppHeader": {
"addPageTooltip": "Быстро добавить новую страницу",
"defaultNewPageName": "Без заголовка",
"renameDialog": "Переименовать"
},
"toolbar": {
"undo": "Отменить",
"redo": "Повторить",
"bold": "Жирный",
"italic": "Курсив",
"underline": "Подчёркнутый",
"strike": "Зачёркнутый",
"numList": "Нумерованный список",
"bulletList": "Маркированный список",
"checkList": "Список To-Do",
"inlineCode": "Код",
"quote": "Цитата",
"header": "Заголовок",
"highlight": "Выделение"
},
"tooltip": {
"lightMode": "Переключиться в светлую тему",
"darkMode": "Переключиться в тёмную тему"
},
"contactsPage": {
"title": "Контакты",
"whatsHappening": "Что происходит на этой неделе?",
"addContact": "Новый контакт",
"editContact": "Редактировать"
},
"button": {
"OK": "OK",
"Cancel": "Отмена",
"signIn": "Войти",
"signOut": "Выйти",
"complete": "Завершить",
"save": "Сохранить"
},
"label": {
"welcome": "Добро пожаловать!",
"firstName": "Имя",
"middleName": "Отчество",
"lastName": "Фамилия",
"stepX": "Этап {X}"
},
"oAuth": {
"err": {
"failedTitle": "Ошибка подключения к аккаунту.",
"failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
},
"google": {
"title": "Вход через Google",
"instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
"instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
"instruction3": "Пройдите по ссылке и введите этот код:",
"instruction4": "Нажмите на кнопку, когда завершите вход:"
}
"google": {
"title": "Вход через Google",
"instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
"instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
"instruction3": "Пройдите по ссылке и введите этот код:",
"instruction4": "Нажмите на кнопку ниже, когда завершите вход:"
}
},
"settings": {
"title": "Настройки",
"menu": {
"appearance": "Внешний вид",
"language": "Язык",
"user": "Пользователь",
"open": "Открыть настройки"
},
"appearance": {
"lightLabel": "Светлая",
"darkLabel": "Тёмная"
}
},
"grid": {
"settings": {
"title": "Настройки",
"menu": {
"appearance": "Внешний вид",
"language": "Язык",
"open": "Открыть настройки"
},
"appearance": {
"lightLabel": "Светлая тема",
"darkLabel": "Тёмная тема"
}
"filter": "Фильтр",
"sortBy": "Сортировать",
"Properties": "Свойства",
"group": "Группировать"
},
"grid": {
"settings": {
"filter": "Фильтр",
"sortBy": "Сортировать",
"Properties": "Свойства"
},
"field": {
"hide": "Скрыть",
"insertLeft": "Вставить слева",
"insertRight": "Вставить справа",
"duplicate": "Дублировать",
"delete": "Удалить",
"textFieldName": "Текст",
"checkboxFieldName": "Checkbox",
"dateFieldName": "Дата",
"numberFieldName": "Число",
"singleSelectFieldName": "Выбор",
"multiSelectFieldName": "Выбор многих",
"urlFieldName": "URL",
"numberFormat": " Формат числа",
"dateFormat": " Формат даты",
"includeTime": " Время",
"dateFormatFriendly": "День Месяц, Год",
"dateFormatISO": "Год-Месяц-День",
"dateFormatLocal": "Год/Месяц/День",
"dateFormatUS": "Год/Месяц/День",
"timeFormat": " Форматировать время",
"invalidTimeFormat": "Неверный формат",
"timeFormatTwelveHour": "12 часов",
"timeFormatTwentyFourHour": "24 часа",
"addSelectOption": "Добавить вариант",
"optionTitle": "Варианты",
"addOption": "Добавить",
"editProperty": "Редактировать свойство"
},
"row": {
"duplicate": "Дублировать",
"delete": "Удалить",
"textPlaceholder": "Пусто",
"copyProperty": "Свойство скопировано"
},
"selectOption": {
"create": "Создать",
"purpleColor": "Фиолетовый",
"pinkColor": "Розовый",
"lightPinkColor": "Светло-розовый",
"orangeColor": "Оранжевый",
"yellowColor": "Желтый",
"limeColor": "Ярко-зелёный",
"greenColor": "Зелёный",
"aquaColor": "Морской волны",
"blueColor": "Синий",
"deleteTag": "Удалить вариант",
"colorPannelTitle": "Цвета",
"pannelTitle": "Выберите или создайте вариант",
"searchOption": "Поиск"
},
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
}
"field": {
"hide": "Скрыть",
"insertLeft": "Вставить слева",
"insertRight": "Вставить справа",
"duplicate": "Дублировать",
"delete": "Удалить",
"textFieldName": "Текст",
"checkboxFieldName": "Чекбокс",
"dateFieldName": "Дата",
"numberFieldName": "Число",
"singleSelectFieldName": "Выбор",
"multiSelectFieldName": "Выбор нескольких",
"urlFieldName": "URL",
"numberFormat": " Формат числа",
"dateFormat": " Формат даты",
"includeTime": " Время",
"dateFormatFriendly": "День Месяц, Год",
"dateFormatISO": "Год-Месяц-День",
"dateFormatLocal": "Месяц/День/Год",
"dateFormatUS": "Год/Месяц/День",
"timeFormat": " Форматировать время",
"invalidTimeFormat": "Неверный формат",
"timeFormatTwelveHour": "12 часов",
"timeFormatTwentyFourHour": "24 часа",
"addSelectOption": "Добавить вариант",
"optionTitle": "Варианты",
"addOption": "Добавить",
"editProperty": "Редактировать свойство",
"newColumn": "Добавить колонку",
"deleteFieldPromptMessage": "Вы уверены? Свойство будет удалено"
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
"row": {
"duplicate": "Дублировать",
"delete": "Удалить",
"textPlaceholder": "Пусто",
"copyProperty": "Свойство скопировано",
"count": "Количество"
},
"selectOption": {
"create": "Создать",
"purpleColor": "Фиолетовый",
"pinkColor": "Розовый",
"lightPinkColor": "Светло-розовый",
"orangeColor": "Оранжевый",
"yellowColor": "Желтый",
"limeColor": "Ярко-зелёный",
"greenColor": "Зелёный",
"aquaColor": "Бирюзовый",
"blueColor": "Синий",
"deleteTag": "Удалить вариант",
"colorPanelTitle": "Цвета",
"panelTitle": "Выберите или создайте вариант",
"searchOption": "Поиск"
},
"menuName": "Сетка"
},
"document": {
"menuName": "Документ",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
"column": {
"create_new_card": "Создать"
}
}
}
@@ -0,0 +1,235 @@
{
"appName": "AppFlowy",
"defaultUsername": "Jag",
"welcomeText": "Välkommen till @:appName",
"githubStarText": "Stärnmärk på GitHub",
"subscribeNewsletterText": "Prenumerera på nyhetsbrev",
"letsGoButtonText": "Kör igång",
"title": "Namn",
"signUp": {
"buttonText": "Registrera dig",
"title": "Registrera dig på @:appName",
"getStartedText": "Sätt igång",
"emptyPasswordError": "Lösenordet kan inte vara tomt",
"repeatPasswordEmptyError": "Upprepat lösenord kan inte vara tomt",
"unmatchedPasswordError": "Upprepat lösenord är inte samma som det första",
"alreadyHaveAnAccount": "Har du redan ett konto?",
"emailHint": "E-post",
"passwordHint": "Lösenord",
"repeatPasswordHint": "Uprepa lösenordet"
},
"signIn": {
"loginTitle": "Logga in till @:appName",
"loginButtonText": "Logga in",
"buttonText": "Registrering",
"forgotPassword": "Glömt lösenordet?",
"emailHint": "E-post",
"passwordHint": "Lösenord",
"dontHaveAnAccount": "Har du inget konto?",
"repeatPasswordEmptyError": "Upprepat lösenord kan inte vara tomt",
"unmatchedPasswordError": "Upprepat lösenord är inte samma som det första"
},
"workspace": {
"create": "Skapa arbetsyta",
"hint": "Arbetsyta",
"notFoundError": "Hittade ingen arbetsyta"
},
"shareAction": {
"buttonText": "Dela",
"workInProgress": "Kommer snart",
"markdown": "Markdown",
"copyLink": "Kopiera länk"
},
"disclosureAction": {
"rename": "Byt namn",
"delete": "Ta bort",
"duplicate": "Klona"
},
"blankPageTitle": "Tom sida",
"newPageText": "Ny sida",
"trash": {
"text": "Skräp",
"restoreAll": "Återställ alla",
"deleteAll": "Ta bort alla",
"pageHeader": {
"fileName": "Filnamn",
"lastModified": "Ändrad",
"created": "Skapad"
}
},
"deletePagePrompt": {
"text": "Denna sida är i skräpmappen",
"restore": "Återställ sida",
"deletePermanent": "Radera permanent"
},
"dialogCreatePageNameHint": "Sidnamn",
"questionBubble": {
"whatsNew": "Vad nytt?",
"help": "Hjälp & Support",
"debug": {
"name": "Felsökningsinfo",
"success": "Kopierade felsökningsinfo till urklipp!",
"fail": "Kunde inte kopiera felsökningsinfo till urklipp"
}
},
"menuAppHeader": {
"addPageTooltip": "Lägg snabbt till en sida inuti",
"defaultNewPageName": "Namnlös",
"renameDialog": "Byt namn"
},
"toolbar": {
"undo": "Ångra",
"redo": "Upprepa",
"bold": "Fet",
"italic": "Kursiv",
"underline": "Understruken",
"strike": "Genomstruken",
"numList": "Numrerad lista",
"bulletList": "Punktlista",
"checkList": "Checklista",
"inlineCode": "Infogad kod",
"quote": "Citatblock",
"header": "Rubrik",
"highlight": "Färgmarkera"
},
"tooltip": {
"lightMode": "Växla till ljust läge",
"darkMode": "Växla till mörkt läge",
"openAsPage": "Öppna som sida",
"addNewRow": "Lägg till ny rad",
"openMenu": "Klicka för att öppna meny"
},
"sideBar": {
"closeSidebar": "Stäng sidofältet",
"openSidebar": "Öppna sidofältet"
},
"notifications": {
"export": {
"markdown": "Exporterade anteckning till Markdown",
"path": "Dokument/flowy"
}
},
"contactsPage": {
"title": "Kontakter",
"whatsHappening": "Vad händer denna vecka?",
"addContact": "Lägg till kontakt",
"editContact": "Redigera kontakt"
},
"button": {
"OK": "OK",
"Cancel": "Avbryt",
"signIn": "Logga in",
"signOut": "Logga ut",
"complete": "Slutfört",
"save": "Spara"
},
"label": {
"welcome": "Välkommen!",
"firstName": "Förnamn",
"middleName": "Mellannamn",
"lastName": "Efternamn",
"stepX": "Steg {X}"
},
"oAuth": {
"err": {
"failedTitle": "Kan inte ansluta till ditt konto.",
"failedMsg": "Tillse att du har slutfört registreringsprocessen i din webbläsare."
},
"google": {
"title": "GOOGLE-inloggning",
"instruction1": "För att kunna importera dina Google-kontakter, måste du auktorisera detta program med hjälp av din webbläsare.",
"instruction2": "Kopiera den här koden till urklipp genom att klicka på ikonen eller genom att markera texten:",
"instruction3": "Gå till följande länk i din webbläsare, och ange ovanstående kod:",
"instruction4": "Tryck på nedanstående knapp när du slutfört registreringen:"
}
},
"settings": {
"title": "Inställningar",
"menu": {
"appearance": "Utseende",
"language": "Språk",
"user": "Användare",
"open": "Öppna inställningarna"
},
"appearance": {
"lightLabel": "Ljust läge",
"darkLabel": "Mörkt läge"
}
},
"grid": {
"settings": {
"filter": "Filter",
"sortBy": "Sortera efter",
"Properties": "Egenskaper",
"group": "Grupp"
},
"field": {
"hide": "Dölj",
"insertLeft": "Infoga till vänster",
"insertRight": "Infoga till höger",
"duplicate": "Klona",
"delete": "Ta bort",
"textFieldName": "Text",
"checkboxFieldName": "Checkruta",
"dateFieldName": "Datum",
"numberFieldName": "Siffror",
"singleSelectFieldName": "Välj",
"multiSelectFieldName": "Välj flera",
"urlFieldName": "URL",
"numberFormat": " Sifferformat",
"dateFormat": " Datumformat",
"includeTime": " Inkludera tid",
"dateFormatFriendly": "Månad Dag,År",
"dateFormatISO": "År-Månad-Dag",
"dateFormatLocal": "Månad/Dag/År",
"dateFormatUS": "År/Månad/Dag",
"timeFormat": " Tidsformat",
"invalidTimeFormat": "Ogiltigt format",
"timeFormatTwelveHour": "12-timmars",
"timeFormatTwentyFourHour": "24-timmars",
"addSelectOption": "Lägg till ett alternativ",
"optionTitle": "Alternativ",
"addOption": "Lägg till alternativ",
"editProperty": "Redigera egenskap",
"newColumn": "Ny kolumn",
"deleteFieldPromptMessage": "Är du säker? Denna egenskap kommer att raderas."
},
"row": {
"duplicate": "Klona",
"delete": "Ta bort",
"textPlaceholder": "Tom",
"copyProperty": "Kopierade egenskap till urklipp",
"count": "Antal",
"newRow": "Ny rad"
},
"selectOption": {
"create": "Skapa",
"purpleColor": "Purpur",
"pinkColor": "Rosa",
"lightPinkColor": "Ljusrosa",
"orangeColor": "Orange",
"yellowColor": "Gul",
"limeColor": "Lime",
"greenColor": "Grön",
"aquaColor": "Vatten",
"blueColor": "Blå",
"deleteTag": "Ta bort tagg",
"colorPanelTitle": "Färger",
"panelTitle": "Välj ett alternativ eller skapa ett",
"searchOption": "Sök efter ett alternativ"
},
"menuName": "Tabell"
},
"document": {
"menuName": "Dokument",
"date": {
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
"column": {
"create_new_card": "Nytt"
}
}
}
@@ -94,7 +94,14 @@
},
"tooltip": {
"lightMode": "切换到亮色模式",
"darkMode": "切换到暗色模式"
"darkMode": "切换到暗色模式",
"openAsPage": "作为页面打开",
"addNewRow": "增加一行",
"openMenu": "点击打开菜单"
},
"sideBar": {
"openSidebar": "打开侧边栏",
"closeSidebar": "关闭侧边栏"
},
"notifications": {
"export": {
@@ -149,15 +156,12 @@
"darkLabel": "夜间模式"
}
},
"sideBar": {
"openSidebar": "打开侧边栏",
"closeSidebar": "关闭侧边栏"
},
"grid": {
"settings": {
"filter": "过滤器",
"sortBy": "排序",
"Properties": "属性"
"Properties": "属性",
"group": "组"
},
"field": {
"hide": "隐藏",
@@ -177,7 +181,7 @@
"includeTime": " 包含时间",
"dateFormatFriendly": "月 日,年",
"dateFormatISO": "年-月-日",
"dateFormatLocal": "年/月/日",
"dateFormatLocal": "月/日/年",
"dateFormatUS": "年/月/日",
"timeFormat": " 时间格式",
"invalidTimeFormat": "时间格式错误",
@@ -186,13 +190,17 @@
"addSelectOption": "添加一个标签",
"optionTitle": "标签",
"addOption": "添加标签",
"editProperty": "编辑列属性"
"editProperty": "编辑列属性",
"newColumn": "增加一列",
"deleteFieldPromptMessage": "确定要删除这个属性吗? "
},
"row": {
"duplicate": "复制",
"delete": "删除",
"textPlaceholder": "空",
"copyProperty": "复制列"
"copyProperty": "复制列",
"count": "数量",
"newRow": "添加一行"
},
"selectOption": {
"create": "新建",
@@ -206,8 +214,8 @@
"aquaColor": "水蓝色",
"blueColor": "蓝色",
"deleteTag": "删除标签",
"colorPannelTitle": "颜色",
"pannelTitle": "选择或新建一个标签",
"colorPanelTitle": "颜色",
"panelTitle": "选择或新建一个标签",
"searchOption": "搜索标签"
},
"menuName": "网格"
@@ -215,8 +223,14 @@
"document": {
"menuName": "文档",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"board": {
"column": {
"create_new_card": "新建"
},
"menuName": "看板"
}
}
@@ -173,7 +173,7 @@
"includeTime": " 包含時間",
"dateFormatFriendly": "月 日,年",
"dateFormatISO": "年-月-日",
"dateFormatLocal": "年/月/日",
"dateFormatLocal": "月/日/年",
"dateFormatUS": "年/月/日",
"timeFormat": " 時間格式",
"invalidTimeFormat": "格式無效",
@@ -202,8 +202,8 @@
"aquaColor": "水藍色",
"blueColor": "藍色",
"deleteTag": "刪除標籤",
"colorPannelTitle": "顏色",
"pannelTitle": "搜尋或建立選項",
"colorPanelTitle": "顏色",
"panelTitle": "搜尋或建立選項",
"searchOption": "搜尋選項"
},
"menuName": "網格"
@@ -211,8 +211,8 @@
"document": {
"menuName": "檔案",
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
"timeHintTextInTwelveHour": "01:00 PM",
"timeHintTextInTwentyFourHour": "13:00"
}
},
"sideBar": {
+2
View File
@@ -45,5 +45,7 @@
<array>
<string>en</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
@@ -9,31 +9,38 @@ import 'package:flowy_sdk/rust_stream.dart';
import 'notification_helper.dart';
// GridPB
typedef GridNotificationCallback = void Function(GridNotification, Either<Uint8List, FlowyError>);
typedef GridNotificationCallback = void Function(
GridDartNotification, Either<Uint8List, FlowyError>);
class GridNotificationParser extends NotificationParser<GridNotification, FlowyError> {
GridNotificationParser({String? id, required GridNotificationCallback callback})
class GridNotificationParser
extends NotificationParser<GridDartNotification, FlowyError> {
GridNotificationParser(
{String? id, required GridNotificationCallback callback})
: super(
id: id,
callback: callback,
tyParser: (ty) => GridNotification.valueOf(ty),
tyParser: (ty) => GridDartNotification.valueOf(ty),
errorParser: (bytes) => FlowyError.fromBuffer(bytes),
);
}
typedef GridNotificationHandler = Function(GridNotification ty, Either<Uint8List, FlowyError> result);
typedef GridNotificationHandler = Function(
GridDartNotification ty, Either<Uint8List, FlowyError> result);
class GridNotificationListener {
StreamSubscription<SubscribeObject>? _subscription;
GridNotificationParser? _parser;
GridNotificationListener({required String objectId, required GridNotificationHandler handler})
GridNotificationListener(
{required String objectId, required GridNotificationHandler handler})
: _parser = GridNotificationParser(id: objectId, callback: handler) {
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
_subscription =
RustStreamReceiver.listen((observable) => _parser?.parse(observable));
}
Future<void> stop() async {
_parser = null;
await _subscription?.cancel();
_subscription = null;
}
}
@@ -11,7 +11,8 @@ class NetworkListener {
late StreamSubscription<ConnectivityResult> _connectivitySubscription;
NetworkListener() {
_connectivitySubscription = _connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
_connectivitySubscription =
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
}
Future<void> start() async {
@@ -39,9 +40,11 @@ class NetworkListener {
return NetworkType.Ethernet;
case ConnectivityResult.mobile:
return NetworkType.Cell;
case ConnectivityResult.none:
return NetworkType.UnknownNetworkType;
case ConnectivityResult.bluetooth:
return NetworkType.Bluetooth;
case ConnectivityResult.vpn:
return NetworkType.VPN;
case ConnectivityResult.none:
return NetworkType.UnknownNetworkType;
}
}();
@@ -9,12 +9,15 @@ import 'package:app_flowy/startup/plugin/plugin.dart';
class BlankPluginBuilder extends PluginBuilder {
@override
Plugin build(dynamic data) {
return BlankPagePlugin(pluginType: pluginType);
return BlankPagePlugin();
}
@override
String get menuName => "Blank";
@override
String get menuIcon => "";
@override
PluginType get pluginType => PluginType.blank;
}
@@ -25,11 +28,6 @@ class BlankPluginConfig implements PluginConfig {
}
class BlankPagePlugin extends Plugin {
final PluginType _pluginType;
BlankPagePlugin({
required PluginType pluginType,
}) : _pluginType = pluginType;
@override
PluginDisplay get display => BlankPagePluginDisplay();
@@ -37,16 +35,15 @@ class BlankPagePlugin extends Plugin {
PluginId get id => "BlankStack";
@override
PluginType get ty => _pluginType;
PluginType get ty => PluginType.blank;
}
class BlankPagePluginDisplay extends PluginDisplay with NavigationItem {
@override
Widget get leftBarItem =>
FlowyText.medium(LocaleKeys.blankPageTitle.tr(), fontSize: 12);
Widget get leftBarItem => FlowyText.medium(LocaleKeys.blankPageTitle.tr());
@override
Widget buildWidget() => const BlankPage();
Widget buildWidget(PluginContext context) => const BlankPage();
@override
List<NavigationItem> get navigationItems => [this];
@@ -24,7 +24,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
final BoardDataController _gridDataController;
late final AppFlowyBoardController boardController;
final MoveRowFFIService _rowService;
LinkedHashMap<String, GroupController> groupControllers = LinkedHashMap();
final LinkedHashMap<String, GroupController> groupControllers =
LinkedHashMap();
GridFieldController get fieldController =>
_gridDataController.fieldController;
@@ -36,21 +37,21 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
super(BoardState.initial(view.id)) {
boardController = AppFlowyBoardController(
onMoveGroup: (
fromColumnId,
fromGroupId,
fromIndex,
toColumnId,
toGroupId,
toIndex,
) {
_moveGroup(fromColumnId, toColumnId);
_moveGroup(fromGroupId, toGroupId);
},
onMoveGroupItem: (
columnId,
groupId,
fromIndex,
toIndex,
) {
final fromRow = groupControllers[columnId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[columnId]?.rowAtIndex(toIndex);
_moveRow(fromRow, columnId, toRow);
final fromRow = groupControllers[groupId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[groupId]?.rowAtIndex(toIndex);
_moveRow(fromRow, groupId, toRow);
},
onMoveGroupItemToGroup: (
fromGroupId,
@@ -69,7 +70,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
await event.when(
initial: () async {
_startListening();
await _loadGrid(emit);
await _openGrid(emit);
},
createBottomRow: (groupId) async {
final startRowId = groupControllers[groupId]?.lastRow()?.id;
@@ -89,18 +90,30 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
(err) => Log.error(err),
);
},
didCreateRow: (String groupId, RowPB row, int? index) {
didCreateRow: (group, row, int? index) {
emit(state.copyWith(
editingRow: Some(BoardEditingRow(
columnId: groupId,
group: group,
row: row,
index: index,
)),
));
_groupItemStartEditing(group, row, true);
},
endEditRow: (rowId) {
startEditingRow: (group, row) {
emit(state.copyWith(
editingRow: Some(BoardEditingRow(
group: group,
row: row,
index: null,
)),
));
_groupItemStartEditing(group, row, true);
},
endEditingRow: (rowId) {
state.editingRow.fold(() => null, (editingRow) {
assert(editingRow.row.id == rowId);
_groupItemStartEditing(editingRow.group, editingRow.row, false);
emit(state.copyWith(editingRow: none()));
});
},
@@ -122,6 +135,24 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
);
}
void _groupItemStartEditing(GroupPB group, RowPB row, bool isEdit) {
final fieldInfo = fieldController.getField(group.fieldId);
if (fieldInfo == null) {
Log.warn("fieldInfo should not be null");
return;
}
boardController.enableGroupDragging(!isEdit);
// boardController.updateGroupItem(
// group.groupId,
// GroupItem(
// row: row,
// fieldInfo: fieldInfo,
// isDraggable: !isEdit,
// ),
// );
}
void _moveRow(RowPB? fromRow, String columnId, RowPB? toRow) {
if (fromRow != null) {
_rowService
@@ -136,11 +167,11 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
}
}
void _moveGroup(String fromColumnId, String toColumnId) {
void _moveGroup(String fromGroupId, String toGroupId) {
_rowService
.moveGroup(
fromGroupId: fromColumnId,
toGroupId: toColumnId,
fromGroupId: fromGroupId,
toGroupId: toGroupId,
)
.then((result) {
result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
@@ -156,7 +187,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
return super.close();
}
void initializeGroups(List<GroupPB> groups) {
void initializeGroups(List<GroupPB> groupsData) {
for (var controller in groupControllers.values) {
controller.dispose();
}
@@ -164,27 +195,27 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
boardController.clear();
//
List<AppFlowyGroupData> columns = groups
List<AppFlowyGroupData> groups = groupsData
.where((group) => fieldController.getField(group.fieldId) != null)
.map((group) {
return AppFlowyGroupData(
id: group.groupId,
name: group.desc,
items: _buildRows(group),
customData: BoardCustomData(
items: _buildGroupItems(group),
customData: GroupData(
group: group,
fieldContext: fieldController.getField(group.fieldId)!,
fieldInfo: fieldController.getField(group.fieldId)!,
),
);
}).toList();
boardController.addGroups(columns);
boardController.addGroups(groups);
for (final group in groups) {
for (final group in groupsData) {
final delegate = GroupControllerDelegateImpl(
controller: boardController,
fieldController: fieldController,
onNewColumnItem: (groupId, row, index) {
add(BoardEvent.didCreateRow(groupId, row, index));
add(BoardEvent.didCreateRow(group, row, index));
},
);
final controller = GroupController(
@@ -242,17 +273,20 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
);
}
List<AppFlowyGroupItem> _buildRows(GroupPB group) {
List<AppFlowyGroupItem> _buildGroupItems(GroupPB group) {
final items = group.rows.map((row) {
final fieldContext = fieldController.getField(group.fieldId);
return BoardColumnItem(row: row, fieldContext: fieldContext!);
final fieldInfo = fieldController.getField(group.fieldId);
return GroupItem(
row: row,
fieldInfo: fieldInfo!,
);
}).toList();
return <AppFlowyGroupItem>[...items];
}
Future<void> _loadGrid(Emitter<BoardState> emit) async {
final result = await _gridDataController.loadData();
Future<void> _openGrid(Emitter<BoardState> emit) async {
final result = await _gridDataController.openGrid();
result.fold(
(grid) => emit(
state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
@@ -270,11 +304,15 @@ class BoardEvent with _$BoardEvent {
const factory BoardEvent.createBottomRow(String groupId) = _CreateBottomRow;
const factory BoardEvent.createHeaderRow(String groupId) = _CreateHeaderRow;
const factory BoardEvent.didCreateRow(
String groupId,
GroupPB group,
RowPB row,
int? index,
) = _DidCreateRow;
const factory BoardEvent.endEditRow(String rowId) = _EndEditRow;
const factory BoardEvent.startEditingRow(
GroupPB group,
RowPB row,
) = _StartEditRow;
const factory BoardEvent.endEditingRow(String rowId) = _EndEditRow;
const factory BoardEvent.didReceiveError(FlowyError error) = _DidReceiveError;
const factory BoardEvent.didReceiveGridUpdate(
GridPB grid,
@@ -334,14 +372,17 @@ class GridFieldEquatable extends Equatable {
UnmodifiableListView<FieldPB> get value => UnmodifiableListView(_fields);
}
class BoardColumnItem extends AppFlowyGroupItem {
class GroupItem extends AppFlowyGroupItem {
final RowPB row;
final GridFieldContext fieldContext;
final FieldInfo fieldInfo;
BoardColumnItem({
GroupItem({
required this.row,
required this.fieldContext,
});
required this.fieldInfo,
bool draggable = true,
}) {
super.draggable = draggable;
}
@override
String get id => row.id;
@@ -360,17 +401,23 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
@override
void insertRow(GroupPB group, RowPB row, int? index) {
final fieldContext = fieldController.getField(group.fieldId);
if (fieldContext == null) {
Log.warn("FieldContext should not be null");
final fieldInfo = fieldController.getField(group.fieldId);
if (fieldInfo == null) {
Log.warn("fieldInfo should not be null");
return;
}
if (index != null) {
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
final item = GroupItem(
row: row,
fieldInfo: fieldInfo,
);
controller.insertGroupItem(group.groupId, index, item);
} else {
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
final item = GroupItem(
row: row,
fieldInfo: fieldInfo,
);
controller.addGroupItem(group.groupId, item);
}
}
@@ -382,25 +429,32 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
@override
void updateRow(GroupPB group, RowPB row) {
final fieldContext = fieldController.getField(group.fieldId);
if (fieldContext == null) {
Log.warn("FieldContext should not be null");
final fieldInfo = fieldController.getField(group.fieldId);
if (fieldInfo == null) {
Log.warn("fieldInfo should not be null");
return;
}
controller.updateGroupItem(
group.groupId,
BoardColumnItem(row: row, fieldContext: fieldContext),
GroupItem(
row: row,
fieldInfo: fieldInfo,
),
);
}
@override
void addNewRow(GroupPB group, RowPB row, int? index) {
final fieldContext = fieldController.getField(group.fieldId);
if (fieldContext == null) {
Log.warn("FieldContext should not be null");
final fieldInfo = fieldController.getField(group.fieldId);
if (fieldInfo == null) {
Log.warn("fieldInfo should not be null");
return;
}
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
final item = GroupItem(
row: row,
fieldInfo: fieldInfo,
draggable: false,
);
if (index != null) {
controller.insertGroupItem(group.groupId, index, item);
@@ -412,23 +466,23 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
}
class BoardEditingRow {
String columnId;
GroupPB group;
RowPB row;
int? index;
BoardEditingRow({
required this.columnId,
required this.group,
required this.row,
required this.index,
});
}
class BoardCustomData {
class GroupData {
final GroupPB group;
final GridFieldContext fieldContext;
BoardCustomData({
final FieldInfo fieldInfo;
GroupData({
required this.group,
required this.fieldContext,
required this.fieldInfo,
});
CheckboxGroup? asCheckboxGroup() {
@@ -436,7 +490,7 @@ class BoardCustomData {
return CheckboxGroup(group);
}
FieldType get fieldType => fieldContext.fieldType;
FieldType get fieldType => fieldInfo.fieldType;
}
class CheckboxGroup {
@@ -12,7 +12,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
import 'board_listener.dart';
typedef OnFieldsChanged = void Function(UnmodifiableListView<GridFieldContext>);
typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldInfo>);
typedef OnGridChanged = void Function(GridPB);
typedef DidLoadGroups = void Function(List<GroupPB>);
typedef OnUpdatedGroup = void Function(List<GroupPB>);
@@ -34,7 +34,8 @@ class BoardDataController {
// key: the block id
final LinkedHashMap<String, GridBlockCache> _blocks;
LinkedHashMap<String, GridBlockCache> get blocks => _blocks;
UnmodifiableMapView<String, GridBlockCache> get blocks =>
UnmodifiableMapView(_blocks);
OnFieldsChanged? _onFieldsChanged;
OnGridChanged? _onGridChanged;
@@ -87,13 +88,13 @@ class BoardDataController {
onUpdatedGroup.call(changeset.updateGroups);
}
if (changeset.insertedGroups.isNotEmpty) {
onInsertedGroup.call(changeset.insertedGroups);
}
if (changeset.deletedGroups.isNotEmpty) {
onDeletedGroup.call(changeset.deletedGroups);
}
if (changeset.insertedGroups.isNotEmpty) {
onInsertedGroup.call(changeset.insertedGroups);
}
},
(e) => _onError?.call(e),
);
@@ -107,21 +108,22 @@ class BoardDataController {
);
}
Future<Either<Unit, FlowyError>> loadData() async {
final result = await _gridFFIService.loadGrid();
Future<Either<Unit, FlowyError>> openGrid() async {
final result = await _gridFFIService.openGrid();
return Future(
() => result.fold(
(grid) async {
_onGridChanged?.call(grid);
return await fieldController.loadFields(fieldIds: grid.fields).then(
(result) => result.fold(
(l) {
_loadGroups(grid.blocks);
return left(l);
},
(err) => right(err),
),
);
final result = await fieldController.loadFields(
fieldIds: grid.fields,
);
return result.fold(
(l) {
_loadGroups(grid.blocks);
return left(l);
},
(err) => right(err),
);
},
(err) => right(err),
),
@@ -32,18 +32,18 @@ class BoardListener {
}
void _handler(
GridNotification ty,
GridDartNotification ty,
Either<Uint8List, FlowyError> result,
) {
switch (ty) {
case GridNotification.DidUpdateGroupView:
case GridDartNotification.DidUpdateGroupView:
result.fold(
(payload) => _groupUpdateNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload)),
(error) => _groupUpdateNotifier?.value = right(error),
);
break;
case GridNotification.DidGroupByNewField:
case GridDartNotification.DidGroupByNewField:
result.fold(
(payload) => _groupByNewFieldNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload).newGroups),
@@ -21,6 +21,9 @@ class BoardCheckboxCellBloc
didReceiveCellUpdate: (cellData) {
emit(state.copyWith(isSelected: _isSelected(cellData)));
},
select: () async {
cellController.saveCellData(!state.isSelected ? "Yes" : "No");
},
);
},
);
@@ -32,7 +35,7 @@ class BoardCheckboxCellBloc
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
cellController.dispose();
await cellController.dispose();
return super.close();
}
@@ -50,6 +53,7 @@ class BoardCheckboxCellBloc
@freezed
class BoardCheckboxCellEvent with _$BoardCheckboxCellEvent {
const factory BoardCheckboxCellEvent.initial() = _InitialCell;
const factory BoardCheckboxCellEvent.select() = _Selected;
const factory BoardCheckboxCellEvent.didReceiveCellUpdate(
String cellContent) = _DidReceiveCellUpdate;
}
@@ -31,7 +31,7 @@ class BoardDateCellBloc extends Bloc<BoardDateCellEvent, BoardDateCellState> {
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
cellController.dispose();
await cellController.dispose();
return super.close();
}
@@ -58,14 +58,14 @@ class BoardDateCellState with _$BoardDateCellState {
const factory BoardDateCellState({
required DateCellDataPB? data,
required String dateStr,
required GridFieldContext fieldContext,
required FieldInfo fieldInfo,
}) = _BoardDateCellState;
factory BoardDateCellState.initial(GridDateCellController context) {
final cellData = context.getCellData();
return BoardDateCellState(
fieldContext: context.fieldContext,
fieldInfo: context.fieldInfo,
data: cellData,
dateStr: _dateStrFromCellData(cellData),
);
@@ -32,7 +32,7 @@ class BoardNumberCellBloc
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
cellController.dispose();
await cellController.dispose();
return super.close();
}
@@ -1,5 +1,5 @@
import 'dart:async';
import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
@@ -34,7 +34,7 @@ class BoardSelectOptionCellBloc
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
cellController.dispose();
await cellController.dispose();
return super.close();
}
@@ -41,7 +41,7 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
cellController.dispose();
await cellController.dispose();
return super.close();
}
@@ -38,7 +38,7 @@ class BoardURLCellBloc extends Bloc<BoardURLCellEvent, BoardURLCellState> {
cellController.removeListener(_onCellChangedFn!);
_onCellChangedFn = null;
}
cellController.dispose();
await cellController.dispose();
return super.close();
}
@@ -63,7 +63,7 @@ class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
return RowInfo(
gridId: _rowService.gridId,
fields: UnmodifiableListView(
state.cells.map((cell) => cell.identifier.fieldContext).toList(),
state.cells.map((cell) => cell.identifier.fieldInfo).toList(),
),
rowPB: state.rowPB,
);
@@ -132,10 +132,10 @@ class BoardCellEquatable extends Equatable {
@override
List<Object?> get props {
return [
identifier.fieldContext.id,
identifier.fieldContext.fieldType,
identifier.fieldContext.visibility,
identifier.fieldContext.width,
identifier.fieldInfo.id,
identifier.fieldInfo.fieldType,
identifier.fieldInfo.visibility,
identifier.fieldInfo.width,
];
}
}
@@ -39,7 +39,7 @@ class GroupController {
void startListening() {
_listener.start(onGroupChanged: (result) {
result.fold(
(GroupChangesetPB changeset) {
(GroupRowsNotificationPB changeset) {
for (final deletedRow in changeset.deletedRows) {
group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
delegate.removeRow(group, deletedRow);
@@ -8,7 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart';
typedef UpdateGroupNotifiedValue = Either<GroupChangesetPB, FlowyError>;
typedef UpdateGroupNotifiedValue = Either<GroupRowsNotificationPB, FlowyError>;
class GroupListener {
final GroupPB group;
@@ -27,14 +27,14 @@ class GroupListener {
}
void _handler(
GridNotification ty,
GridDartNotification ty,
Either<Uint8List, FlowyError> result,
) {
switch (ty) {
case GridNotification.DidUpdateGroup:
case GridDartNotification.DidUpdateGroup:
result.fold(
(payload) => _groupNotifier?.value =
left(GroupChangesetPB.fromBuffer(payload)),
left(GroupRowsNotificationPB.fromBuffer(payload)),
(error) => _groupNotifier?.value = right(error),
);
break;
+27 -10
View File
@@ -1,3 +1,4 @@
import 'package:app_flowy/plugins/util.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
@@ -19,14 +20,17 @@ class BoardPluginBuilder implements PluginBuilder {
@override
String get menuName => "Board";
@override
String get menuIcon => "editor/board";
@override
PluginType get pluginType => PluginType.board;
@override
ViewDataTypePB get dataType => ViewDataTypePB.Database;
ViewDataFormatPB get dataFormatType => ViewDataFormatPB.DatabaseFormat;
@override
ViewLayoutTypePB? get subDataType => ViewLayoutTypePB.Board;
ViewLayoutTypePB? get layoutType => ViewLayoutTypePB.Board;
}
class BoardPluginConfig implements PluginConfig {
@@ -35,34 +39,47 @@ class BoardPluginConfig implements PluginConfig {
}
class BoardPlugin extends Plugin {
final ViewPB _view;
@override
final ViewPluginNotifier notifier;
final PluginType _pluginType;
BoardPlugin({
required ViewPB view,
required PluginType pluginType,
}) : _pluginType = pluginType,
_view = view;
notifier = ViewPluginNotifier(view: view);
@override
PluginDisplay get display => GridPluginDisplay(view: _view);
PluginDisplay get display => GridPluginDisplay(notifier: notifier);
@override
PluginId get id => _view.id;
PluginId get id => notifier.view.id;
@override
PluginType get ty => _pluginType;
}
class GridPluginDisplay extends PluginDisplay {
final ViewPB _view;
GridPluginDisplay({required ViewPB view, Key? key}) : _view = view;
final ViewPluginNotifier notifier;
GridPluginDisplay({required this.notifier, Key? key});
ViewPB get view => notifier.view;
@override
Widget get leftBarItem => ViewLeftBarItem(view: _view);
Widget get leftBarItem => ViewLeftBarItem(view: view);
@override
Widget buildWidget() => BoardPage(view: _view);
Widget buildWidget(PluginContext context) {
notifier.isDeleted.addListener(() {
notifier.isDeleted.value.fold(() => null, (deletedView) {
if (deletedView.hasIndex()) {
context.onDeleted(view, deletedView.index);
}
});
});
return BoardPage(key: ValueKey(view.id), view: view);
}
@override
List<NavigationItem> get navigationItems => [this];
@@ -12,8 +12,8 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_detail.dart'
import 'package:appflowy_board/appflowy_board.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/style_widget/text.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
@@ -28,7 +28,10 @@ import 'toolbar/board_toolbar.dart';
class BoardPage extends StatelessWidget {
final ViewPB view;
BoardPage({required this.view, Key? key}) : super(key: ValueKey(view.id));
BoardPage({
required this.view,
Key? key,
}) : super(key: ValueKey(view.id));
@override
Widget build(BuildContext context) {
@@ -63,7 +66,6 @@ class BoardContent extends StatefulWidget {
class _BoardContentState extends State<BoardContent> {
late AppFlowyBoardScrollController scrollManager;
final Map<String, ValueKey> cardKeysCache = {};
final config = AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
@@ -78,7 +80,7 @@ class _BoardContentState extends State<BoardContent> {
@override
Widget build(BuildContext context) {
return BlocListener<BoardBloc, BoardState>(
listener: (context, state) => _handleEditState(state, context),
listener: (context, state) => _handleEditStateChanged(state, context),
child: BlocBuilder<BoardBloc, BoardState>(
buildWhen: (previous, current) => previous.groupIds != current.groupIds,
builder: (context, state) {
@@ -87,19 +89,16 @@ class _BoardContentState extends State<BoardContent> {
children: [const _ToolbarBlocAdaptor(), _buildBoard(context)],
);
return Container(
color: context.read<AppTheme>().surface,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: column,
),
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: column,
);
},
),
);
}
Expanded _buildBoard(BuildContext context) {
Widget _buildBoard(BuildContext context) {
return Expanded(
child: AppFlowyBoard(
boardScrollController: scrollManager,
@@ -114,27 +113,20 @@ class _BoardContentState extends State<BoardContent> {
),
groupConstraints: const BoxConstraints.tightFor(width: 300),
config: AppFlowyBoardConfig(
groupBackgroundColor: HexColor.fromHex('#F7F8FC'),
groupBackgroundColor: Theme.of(context).colorScheme.surfaceVariant,
),
),
);
}
void _handleEditState(BoardState state, BuildContext context) {
void _handleEditStateChanged(BoardState state, BuildContext context) {
state.editingRow.fold(
() => null,
(editingRow) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (editingRow.index != null) {
context
.read<BoardBloc>()
.add(BoardEvent.endEditRow(editingRow.row.id));
} else {
scrollManager.scrollToBottom(editingRow.columnId, () {
context
.read<BoardBloc>()
.add(BoardEvent.endEditRow(editingRow.row.id));
});
scrollManager.scrollToBottom(editingRow.group.groupId);
}
});
},
@@ -148,17 +140,16 @@ class _BoardContentState extends State<BoardContent> {
Widget _buildHeader(
BuildContext context,
AppFlowyGroupData columnData,
AppFlowyGroupData groupData,
) {
final boardCustomData = columnData.customData as BoardCustomData;
final boardCustomData = groupData.customData as GroupData;
return AppFlowyGroupHeader(
title: Flexible(
fit: FlexFit.tight,
child: FlowyText.medium(
columnData.headerData.groupName,
groupData.headerData.groupName,
fontSize: 14,
overflow: TextOverflow.clip,
color: context.read<AppTheme>().textColor,
),
),
icon: _buildHeaderIcon(boardCustomData),
@@ -167,12 +158,12 @@ class _BoardContentState extends State<BoardContent> {
width: 20,
child: svgWidget(
"home/add",
color: context.read<AppTheme>().iconColor,
color: Theme.of(context).colorScheme.onSurface,
),
),
onAddButtonClick: () {
context.read<BoardBloc>().add(
BoardEvent.createHeaderRow(columnData.id),
BoardEvent.createHeaderRow(groupData.id),
);
},
height: 50,
@@ -181,48 +172,44 @@ class _BoardContentState extends State<BoardContent> {
}
Widget _buildFooter(BuildContext context, AppFlowyGroupData columnData) {
final boardCustomData = columnData.customData as BoardCustomData;
final group = boardCustomData.group;
// final boardCustomData = columnData.customData as BoardCustomData;
// final group = boardCustomData.group;
if (group.isDefault) {
return const SizedBox();
} else {
return AppFlowyGroupFooter(
icon: SizedBox(
height: 20,
width: 20,
child: svgWidget(
"home/add",
color: context.read<AppTheme>().iconColor,
),
return AppFlowyGroupFooter(
icon: SizedBox(
height: 20,
width: 20,
child: svgWidget(
"home/add",
color: Theme.of(context).colorScheme.onSurface,
),
title: FlowyText.medium(
LocaleKeys.board_column_create_new_card.tr(),
fontSize: 14,
color: context.read<AppTheme>().textColor,
),
height: 50,
margin: config.footerPadding,
onAddButtonClick: () {
context.read<BoardBloc>().add(
BoardEvent.createBottomRow(columnData.id),
);
},
);
}
),
title: FlowyText.medium(
LocaleKeys.board_column_create_new_card.tr(),
fontSize: 14,
),
height: 50,
margin: config.footerPadding,
onAddButtonClick: () {
context.read<BoardBloc>().add(
BoardEvent.createBottomRow(columnData.id),
);
},
);
}
Widget _buildCard(
BuildContext context,
AppFlowyGroupData column,
AppFlowyGroupItem columnItem,
AppFlowyGroupData afGroupData,
AppFlowyGroupItem afGroupItem,
) {
final boardColumnItem = columnItem as BoardColumnItem;
final rowPB = boardColumnItem.row;
final groupItem = afGroupItem as GroupItem;
final groupData = afGroupData.customData as GroupData;
final rowPB = groupItem.row;
final rowCache = context.read<BoardBloc>().getRowCache(rowPB.blockId);
/// Return placeholder widget if the rowCache is null.
if (rowCache == null) return SizedBox(key: ObjectKey(columnItem));
if (rowCache == null) return SizedBox(key: ObjectKey(groupItem));
final fieldController = context.read<BoardBloc>().fieldController;
final gridId = context.read<BoardBloc>().gridId;
@@ -237,25 +224,19 @@ class _BoardContentState extends State<BoardContent> {
context.read<BoardBloc>().state.editingRow.fold(
() => null,
(editingRow) {
isEditing = editingRow.row.id == columnItem.row.id;
isEditing = editingRow.row.id == groupItem.row.id;
},
);
ValueKey? key = cardKeysCache[columnItem.id];
if (key == null) {
final newKey = ValueKey(columnItem.id);
cardKeysCache[columnItem.id] = newKey;
key = newKey;
}
final groupItemId = groupItem.row.id + groupData.group.groupId;
return AppFlowyGroupCard(
key: key,
key: ValueKey(groupItemId),
margin: config.cardPadding,
decoration: _makeBoxDecoration(context),
child: BoardCard(
gridId: gridId,
groupId: column.id,
fieldId: boardColumnItem.fieldContext.id,
groupId: groupData.group.groupId,
fieldId: groupItem.fieldInfo.id,
isEditing: isEditing,
cellBuilder: cellBuilder,
dataController: cardController,
@@ -266,25 +247,45 @@ class _BoardContentState extends State<BoardContent> {
rowCache,
context,
),
onStartEditing: () {
context.read<BoardBloc>().add(
BoardEvent.startEditingRow(
groupData.group,
groupItem.row,
),
);
},
onEndEditing: () {
context
.read<BoardBloc>()
.add(BoardEvent.endEditingRow(groupItem.row.id));
},
),
);
}
BoxDecoration _makeBoxDecoration(BuildContext context) {
final theme = context.read<AppTheme>();
final borderSide = BorderSide(color: theme.shader6, width: 1.0);
final borderSide = BorderSide(
color: Theme.of(context).dividerColor,
width: 1.0,
);
return BoxDecoration(
color: theme.surface,
color: Theme.of(context).colorScheme.surface,
border: Border.fromBorderSide(borderSide),
borderRadius: const BorderRadius.all(Radius.circular(6)),
);
}
void _openCard(String gridId, GridFieldController fieldController,
RowPB rowPB, GridRowCache rowCache, BuildContext context) {
void _openCard(
String gridId,
GridFieldController fieldController,
RowPB rowPB,
GridRowCache rowCache,
BuildContext context,
) {
final rowInfo = RowInfo(
gridId: gridId,
fields: UnmodifiableListView(fieldController.fieldContexts),
fields: UnmodifiableListView(fieldController.fieldInfos),
rowPB: rowPB,
);
@@ -294,10 +295,15 @@ class _BoardContentState extends State<BoardContent> {
rowCache: rowCache,
);
RowDetailPage(
cellBuilder: GridCellBuilder(delegate: dataController),
dataController: dataController,
).show(context);
FlowyOverlay.show(
context: context,
builder: (BuildContext context) {
return RowDetailPage(
cellBuilder: GridCellBuilder(delegate: dataController),
dataController: dataController,
);
},
);
}
}
@@ -329,7 +335,7 @@ extension HexColor on Color {
}
}
Widget? _buildHeaderIcon(BoardCustomData customData) {
Widget? _buildHeaderIcon(GroupData customData) {
Widget? widget;
switch (customData.fieldType) {
case FieldType.Checkbox:
@@ -23,7 +23,7 @@ class EditableRowNotifier {
EditableRowNotifier({required bool isEditing})
: isEditing = ValueNotifier(isEditing);
void insertCell(
void bindCell(
GridCellIdentifier cellIdentifier,
EditableCellNotifier notifier,
) {
@@ -59,7 +59,7 @@ class EditableRowNotifier {
_cells.values.first.isCellEditing.value = false;
}
void clear() {
void unbind() {
for (final notifier in _cells.values) {
notifier.dispose();
}
@@ -76,6 +76,10 @@ class EditableRowNotifier {
}
abstract class EditableCell {
// Each cell notifier will be bind to the [EditableRowNotifier], which enable
// the row notifier receive its cells event. For example: begin editing the
// cell or end editing the cell.
//
EditableCellNotifier? get editableNotifier;
}
@@ -48,6 +48,9 @@ class _BoardCheckboxCellState extends State<BoardCheckboxCell> {
iconPadding: EdgeInsets.zero,
icon: icon,
width: 20,
onPressed: () => context
.read<BoardCheckboxCellBloc>()
.add(const BoardCheckboxCellEvent.select()),
),
);
},
@@ -1,6 +1,5 @@
import 'package:app_flowy/plugins/board/application/card/board_date_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -53,7 +52,7 @@ class _BoardDateCellState extends State<BoardDateCell> {
child: FlowyText.regular(
state.dateStr,
fontSize: 13,
color: context.read<AppTheme>().shader3,
color: Theme.of(context).hintColor,
),
),
);
@@ -3,7 +3,6 @@ import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_servic
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'define.dart';
class BoardNumberCell extends StatefulWidget {
@@ -2,6 +2,8 @@ import 'package:app_flowy/plugins/board/application/card/board_select_option_cel
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -26,9 +28,11 @@ class BoardSelectOptionCell extends StatefulWidget with EditableCell {
class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
late BoardSelectOptionCellBloc _cellBloc;
late PopoverController _popover;
@override
void initState() {
_popover = PopoverController();
final cellController =
widget.cellControllerBuilder.build() as GridSelectOptionCellController;
_cellBloc = BoardSelectOptionCellBloc(cellController: cellController)
@@ -41,43 +45,60 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardSelectOptionCellBloc, BoardSelectOptionCellState>(
buildWhen: (previous, current) {
return previous.selectedOptions != current.selectedOptions;
},
builder: (context, state) {
if (state.selectedOptions
.where((element) => element.id == widget.groupId)
.isNotEmpty ||
state.selectedOptions.isEmpty) {
return const SizedBox();
} else {
final children = state.selectedOptions
.map(
(option) => SelectOptionTag.fromOption(
context: context,
option: option,
onSelected: () {
SelectOptionCellEditor.show(
context: context,
cellController: widget.cellControllerBuilder.build()
as GridSelectOptionCellController,
);
},
),
)
.toList();
buildWhen: (previous, current) {
return previous.selectedOptions != current.selectedOptions;
}, builder: (context, state) {
// Returns SizedBox if the content of the cell is empty
if (_isEmpty(state)) return const SizedBox();
return IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SizedBox.expand(
child: Wrap(spacing: 4, runSpacing: 2, children: children),
),
),
final children = state.selectedOptions.map(
(option) {
final tag = SelectOptionTag.fromOption(
context: context,
option: option,
onSelected: () => _popover.show(),
);
}
},
),
return _wrapPopover(tag);
},
).toList();
return IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: SizedBox.expand(
child: Wrap(spacing: 4, runSpacing: 2, children: children),
),
),
);
}),
);
}
bool _isEmpty(BoardSelectOptionCellState state) {
// The cell should hide if the option id is equal to the groupId.
final isInGroup = state.selectedOptions
.where((element) => element.id == widget.groupId)
.isNotEmpty;
return isInGroup || state.selectedOptions.isEmpty;
}
Widget _wrapPopover(Widget child) {
final constraints = BoxConstraints.loose(Size(
SelectOptionCellEditor.editorPanelWidth,
300,
));
return AppFlowyPopover(
controller: _popover,
constraints: constraints,
direction: PopoverDirection.bottomWithLeftAligned,
popupBuilder: (BuildContext context) {
return SelectOptionCellEditor(
cellController: widget.cellControllerBuilder.build()
as GridSelectOptionCellController,
);
},
onClose: () {},
child: child,
);
}
@@ -87,24 +108,3 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
super.dispose();
}
}
class _SelectOptionDialog extends StatelessWidget {
final GridSelectOptionCellController _controller;
const _SelectOptionDialog({
Key? key,
required IGridCellController controller,
}) : _controller = controller as GridSelectOptionCellController,
super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
child: InkWell(onTap: () {
SelectOptionCellEditor.show(
context: context,
cellController: _controller,
);
}),
);
}
}
@@ -1,9 +1,11 @@
import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'board_cell.dart';
import 'define.dart';
@@ -42,6 +44,9 @@ class _BoardTextCellState extends State<BoardTextCell> {
focusNode.requestFocus();
}
// If the focusNode lost its focus, the widget's editableNotifier will
// set to false, which will cause the [EditableRowNotifier] to receive
// end edit event.
focusNode.addListener(() {
if (!focusNode.hasFocus) {
focusWhenInit = false;
@@ -131,7 +136,11 @@ class _BoardTextCellState extends State<BoardTextCell> {
padding: EdgeInsets.symmetric(
vertical: BoardSizes.cardCellVPadding,
),
child: FlowyText.medium(state.content, fontSize: 14),
child: FlowyText.medium(
state.content,
fontSize: 14,
maxLines: null, // Enable multiple lines
),
);
}
@@ -143,11 +152,7 @@ class _BoardTextCellState extends State<BoardTextCell> {
onChanged: (value) => focusChanged(),
onEditingComplete: () => focusNode.unfocus(),
maxLines: null,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
fontFamily: 'Mulish',
),
style: Theme.of(context).textTheme.bodyMedium!.size(FontSizes.s14),
decoration: InputDecoration(
// Magic number 4 makes the textField take up the same space as FlowyText
contentPadding: EdgeInsets.symmetric(
@@ -1,8 +1,9 @@
import 'package:app_flowy/plugins/board/application/card/board_url_cell_bloc.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textstyle_extensions/textstyle_extensions.dart';
import 'define.dart';
@@ -34,7 +35,6 @@ class _BoardUrlCellState extends State<BoardUrlCell> {
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return BlocProvider.value(
value: _cellBloc,
child: BlocBuilder<BoardURLCellBloc, BoardURLCellState>(
@@ -53,11 +53,12 @@ class _BoardUrlCellState extends State<BoardUrlCell> {
textAlign: TextAlign.left,
text: TextSpan(
text: state.content,
style: TextStyle(
color: theme.main2,
fontSize: 14,
decoration: TextDecoration.underline,
),
style: Theme.of(context)
.textTheme
.bodyMedium!
.size(FontSizes.s14)
.textColor(Theme.of(context).colorScheme.primary)
.underline,
),
),
),
@@ -1,16 +1,16 @@
import 'package:app_flowy/plugins/board/application/card/card_bloc.dart';
import 'package:app_flowy/plugins/board/application/card/card_data_controller.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_action_sheet.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'board_cell.dart';
import 'card_cell_builder.dart';
import 'card_container.dart';
import 'container/accessory.dart';
import 'container/card_container.dart';
class BoardCard extends StatefulWidget {
final String gridId;
@@ -20,6 +20,8 @@ class BoardCard extends StatefulWidget {
final CardDataController dataController;
final BoardCellBuilder cellBuilder;
final void Function(BuildContext) openCard;
final VoidCallback onStartEditing;
final VoidCallback onEndEditing;
const BoardCard({
required this.gridId,
@@ -29,6 +31,8 @@ class BoardCard extends StatefulWidget {
required this.dataController,
required this.cellBuilder,
required this.openCard,
required this.onStartEditing,
required this.onEndEditing,
Key? key,
}) : super(key: key);
@@ -39,6 +43,8 @@ class BoardCard extends StatefulWidget {
class _BoardCardState extends State<BoardCard> {
late BoardCardBloc _cardBloc;
late EditableRowNotifier rowNotifier;
late PopoverController popoverController;
AccessoryType? accessoryType;
@override
void initState() {
@@ -53,8 +59,15 @@ class _BoardCardState extends State<BoardCard> {
rowNotifier.isEditing.addListener(() {
if (!mounted) return;
_cardBloc.add(BoardCardEvent.setIsEditing(rowNotifier.isEditing.value));
if (rowNotifier.isEditing.value) {
widget.onStartEditing();
} else {
widget.onEndEditing();
}
});
popoverController = PopoverController();
super.initState();
}
@@ -64,31 +77,44 @@ class _BoardCardState extends State<BoardCard> {
value: _cardBloc,
child: BlocBuilder<BoardCardBloc, BoardCardState>(
buildWhen: (previous, current) {
// Rebuild when:
// 1.If the length of the cells is not the same
// 2.isEditing changed
if (previous.cells.length != current.cells.length ||
previous.isEditing != current.isEditing) {
return true;
}
// 3.Compare the content of the cells. The cells consists of
// list of [BoardCellEquatable] that extends the [Equatable].
return !listEquals(previous.cells, current.cells);
},
builder: (context, state) {
return BoardCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) {
return [
_CardEditOption(
startEditing: () => rowNotifier.becomeFirstResponder(),
),
const _CardMoreOption(),
];
},
onTap: (context) {
widget.openCard(context);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: _makeCells(
context,
state.cells.map((cell) => cell.identifier).toList(),
return AppFlowyPopover(
controller: popoverController,
triggerActions: PopoverTriggerFlags.none,
constraints: BoxConstraints.loose(const Size(140, 200)),
margin: const EdgeInsets.all(6),
direction: PopoverDirection.rightWithCenterAligned,
popupBuilder: (popoverContext) => _handlePopoverBuilder(
context,
popoverContext,
),
child: BoardCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) {
return [
_CardEditOption(rowNotifier: rowNotifier),
_CardMoreOption(),
];
},
openAccessory: _handleOpenAccessory,
openCard: (context) => widget.openCard(context),
child: _CellColumn(
groupId: widget.groupId,
rowNotifier: rowNotifier,
cellBuilder: widget.cellBuilder,
cells: state.cells,
),
),
);
@@ -97,42 +123,29 @@ class _BoardCardState extends State<BoardCard> {
);
}
List<Widget> _makeCells(
void _handleOpenAccessory(AccessoryType newAccessoryType) {
accessoryType = newAccessoryType;
switch (newAccessoryType) {
case AccessoryType.edit:
break;
case AccessoryType.more:
popoverController.show();
break;
}
}
Widget _handlePopoverBuilder(
BuildContext context,
List<GridCellIdentifier> cells,
BuildContext popoverContext,
) {
final List<Widget> children = [];
rowNotifier.clear();
cells.asMap().forEach(
(int index, GridCellIdentifier cellId) {
EditableCellNotifier cellNotifier;
if (index == 0) {
// Only use the first cell to receive user's input when click the edit
// button
cellNotifier = EditableCellNotifier(
isEditing: rowNotifier.isEditing.value,
);
rowNotifier.insertCell(cellId, cellNotifier);
} else {
cellNotifier = EditableCellNotifier();
}
Widget child = widget.cellBuilder.buildCell(
widget.groupId,
cellId,
cellNotifier,
switch (accessoryType!) {
case AccessoryType.edit:
throw UnimplementedError();
case AccessoryType.more:
return GridRowActionSheet(
rowData: context.read<BoardCardBloc>().rowInfo(),
);
child = Padding(
key: cellId.key(),
padding: const EdgeInsets.only(left: 4, right: 4),
child: child,
);
children.add(child);
},
);
return children;
}
}
@override
@@ -143,30 +156,85 @@ class _BoardCardState extends State<BoardCard> {
}
}
class _CellColumn extends StatelessWidget {
final String groupId;
final BoardCellBuilder cellBuilder;
final EditableRowNotifier rowNotifier;
final List<BoardCellEquatable> cells;
const _CellColumn({
required this.groupId,
required this.rowNotifier,
required this.cellBuilder,
required this.cells,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: _makeCells(context, cells),
);
}
List<Widget> _makeCells(
BuildContext context,
List<BoardCellEquatable> cells,
) {
final List<Widget> children = [];
// Remove all the cell listeners.
rowNotifier.unbind();
cells.asMap().forEach(
(int index, BoardCellEquatable cell) {
final isEditing = index == 0 ? rowNotifier.isEditing.value : false;
final cellNotifier = EditableCellNotifier(isEditing: isEditing);
if (index == 0) {
// Only use the first cell to receive user's input when click the edit
// button
rowNotifier.bindCell(cell.identifier, cellNotifier);
}
final child = Padding(
key: cell.identifier.key(),
padding: const EdgeInsets.only(left: 4, right: 4),
child: cellBuilder.buildCell(
groupId,
cell.identifier,
cellNotifier,
),
);
children.add(child);
},
);
return children;
}
}
class _CardMoreOption extends StatelessWidget with CardAccessory {
const _CardMoreOption({Key? key}) : super(key: key);
_CardMoreOption({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(3.0),
child:
svgWidget('grid/details', color: context.read<AppTheme>().iconColor),
child: svgWidget(
'grid/details',
color: Theme.of(context).colorScheme.onSurface,
),
);
}
@override
void onTap(BuildContext context) {
GridRowActionSheet(
rowData: context.read<BoardCardBloc>().rowInfo(),
).show(context, direction: AnchorDirection.bottomWithCenterAligned);
}
AccessoryType get type => AccessoryType.more;
}
class _CardEditOption extends StatelessWidget with CardAccessory {
final VoidCallback startEditing;
final EditableRowNotifier rowNotifier;
const _CardEditOption({
required this.startEditing,
required this.rowNotifier,
Key? key,
}) : super(key: key);
@@ -176,13 +244,14 @@ class _CardEditOption extends StatelessWidget with CardAccessory {
padding: const EdgeInsets.all(3.0),
child: svgWidget(
'editor/edit',
color: context.read<AppTheme>().iconColor,
color: Theme.of(context).colorScheme.onSurface,
),
);
}
@override
void onTap(BuildContext context) {
startEditing();
}
void onTap(BuildContext context) => rowNotifier.becomeFirstResponder();
@override
AccessoryType get type => AccessoryType.edit;
}
@@ -0,0 +1,72 @@
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
enum AccessoryType {
edit,
more,
}
abstract class CardAccessory implements Widget {
AccessoryType get type;
void onTap(BuildContext context) {}
}
typedef CardAccessoryBuilder = List<CardAccessory> Function(
BuildContext buildContext,
);
class CardAccessoryContainer extends StatelessWidget {
final void Function(AccessoryType) onTapAccessory;
final List<CardAccessory> accessories;
const CardAccessoryContainer({
required this.accessories,
required this.onTapAccessory,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final children = accessories.map((accessory) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
accessory.onTap(context);
onTapAccessory(accessory.type);
},
child: _wrapHover(context, accessory),
);
}).toList();
return _wrapDecoration(context, Row(children: children));
}
FlowyHover _wrapHover(BuildContext context, CardAccessory accessory) {
return FlowyHover(
style: HoverStyle(
backgroundColor: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.zero,
),
builder: (_, onHover) => SizedBox(
width: 24,
height: 24,
child: accessory,
),
);
}
Widget _wrapDecoration(BuildContext context, Widget child) {
final borderSide = BorderSide(
color: Theme.of(context).dividerColor,
width: 1.0,
);
final decoration = BoxDecoration(
color: Colors.transparent,
border: Border.fromBorderSide(borderSide),
borderRadius: const BorderRadius.all(Radius.circular(4)),
);
return Container(
clipBehavior: Clip.hardEdge,
decoration: decoration,
child: child,
);
}
}
@@ -1,17 +1,19 @@
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'accessory.dart';
class BoardCardContainer extends StatelessWidget {
final Widget child;
final CardAccessoryBuilder? accessoryBuilder;
final bool Function()? buildAccessoryWhen;
final void Function(BuildContext) onTap;
final void Function(BuildContext) openCard;
final void Function(AccessoryType) openAccessory;
const BoardCardContainer({
required this.child,
required this.onTap,
required this.openCard,
required this.openAccessory,
this.accessoryBuilder,
this.buildAccessoryWhen,
Key? key,
@@ -34,13 +36,14 @@ class BoardCardContainer extends StatelessWidget {
if (accessories.isNotEmpty) {
container = _CardEnterRegion(
accessories: accessories,
onTapAccessory: openAccessory,
child: container,
);
}
}
return GestureDetector(
onTap: () => onTap(context),
onTap: () => openCard(context),
child: Padding(
padding: const EdgeInsets.all(8),
child: ConstrainedBox(
@@ -55,75 +58,16 @@ class BoardCardContainer extends StatelessWidget {
}
}
abstract class CardAccessory implements Widget {
void onTap(BuildContext context);
}
typedef CardAccessoryBuilder = List<CardAccessory> Function(
BuildContext buildContext,
);
class CardAccessoryContainer extends StatelessWidget {
final List<CardAccessory> accessories;
const CardAccessoryContainer({required this.accessories, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
final children = accessories.map((accessory) {
final hover = FlowyHover(
style: HoverStyle(
hoverColor: theme.hover,
backgroundColor: theme.surface,
borderRadius: BorderRadius.zero,
),
builder: (_, onHover) => SizedBox(
width: 24,
height: 24,
child: accessory,
),
);
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => accessory.onTap(context),
child: hover,
);
}).toList();
return Container(
clipBehavior: Clip.hardEdge,
decoration: _makeBoxDecoration(context),
child: Row(children: children),
);
}
}
BoxDecoration _makeBoxDecoration(BuildContext context) {
final theme = context.read<AppTheme>();
final borderSide = BorderSide(color: theme.shader6, width: 1.0);
return BoxDecoration(
color: Colors.transparent,
border: Border.fromBorderSide(borderSide),
// boxShadow: const [
// BoxShadow(
// color: Colors.transparent,
// spreadRadius: 0,
// blurRadius: 5,
// offset: Offset.zero,
// )
// ],
borderRadius: const BorderRadius.all(Radius.circular(4)),
);
}
class _CardEnterRegion extends StatelessWidget {
final Widget child;
final List<CardAccessory> accessories;
const _CardEnterRegion(
{required this.child, required this.accessories, Key? key})
: super(key: key);
final void Function(AccessoryType) onTapAccessory;
const _CardEnterRegion({
required this.child,
required this.accessories,
required this.onTapAccessory,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -132,9 +76,12 @@ class _CardEnterRegion extends StatelessWidget {
builder: (context, onEnter, _) {
List<Widget> children = [child];
if (onEnter) {
children.add(CardAccessoryContainer(
accessories: accessories,
).positioned(right: 0));
children.add(
CardAccessoryContainer(
accessories: accessories,
onTapAccessory: onTapAccessory,
).positioned(right: 0),
);
}
return MouseRegion(
@@ -4,10 +4,9 @@ import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_group.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/toolbar/grid_property.dart';
import 'package:appflowy_popover/appflowy_popover.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';
@@ -50,7 +49,6 @@ class BoardSettingList extends StatelessWidget {
previous.selectedAction != current.selectedAction,
listener: (context, state) {
state.selectedAction.foldLeft(null, (_, action) {
FlowyOverlay.of(context).remove(identifier());
onAction(action, settingContext);
});
},
@@ -84,43 +82,6 @@ class BoardSettingList extends StatelessWidget {
),
);
}
static void show(BuildContext context, BoardSettingContext settingContext) {
final list = BoardSettingList(
settingContext: settingContext,
onAction: (action, settingContext) {
switch (action) {
case BoardSettingAction.properties:
GridPropertyList(
gridId: settingContext.viewId,
fieldController: settingContext.fieldController)
.show(context);
break;
case BoardSettingAction.groups:
GridGroupList(
viewId: settingContext.viewId,
fieldController: settingContext.fieldController)
.show(context);
break;
}
},
);
FlowyOverlay.of(context).insertWithAnchor(
widget: OverlayContainer(
constraints: BoxConstraints.loose(const Size(140, 400)),
child: list,
),
identifier: identifier(),
anchorContext: context,
anchorDirection: AnchorDirection.bottomRight,
style: FlowyOverlayStyle(blur: false),
);
}
static String identifier() {
return (BoardSettingList).toString();
}
}
class _SettingItem extends StatelessWidget {
@@ -133,7 +94,6 @@ class _SettingItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
final isSelected = context
.read<BoardSettingBloc>()
.state
@@ -144,15 +104,16 @@ class _SettingItem extends StatelessWidget {
height: 30,
child: FlowyButton(
isSelected: isSelected,
text: FlowyText.medium(action.title(),
fontSize: 12, color: theme.textColor),
hoverColor: theme.hover,
text: FlowyText.medium(action.title()),
onTap: () {
context
.read<BoardSettingBloc>()
.add(BoardSettingEvent.performAction(action));
},
leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
leftIcon: svgWidget(
action.iconName(),
color: Theme.of(context).colorScheme.onSurface,
),
),
);
}
@@ -177,3 +138,49 @@ extension _GridSettingExtension on BoardSettingAction {
}
}
}
class BoardSettingListPopover extends StatefulWidget {
final PopoverController popoverController;
final BoardSettingContext settingContext;
const BoardSettingListPopover({
Key? key,
required this.popoverController,
required this.settingContext,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _BoardSettingListPopoverState();
}
class _BoardSettingListPopoverState extends State<BoardSettingListPopover> {
BoardSettingAction? _action;
@override
Widget build(BuildContext context) {
if (_action != null) {
switch (_action!) {
case BoardSettingAction.groups:
return GridGroupList(
viewId: widget.settingContext.viewId,
fieldController: widget.settingContext.fieldController,
onDismissed: () {
widget.popoverController.close();
},
);
case BoardSettingAction.properties:
return GridPropertyList(
gridId: widget.settingContext.viewId,
fieldController: widget.settingContext.fieldController,
);
}
}
return BoardSettingList(
settingContext: widget.settingContext,
onAction: (action, settingContext) {
setState(() => _action = action);
},
);
}
}
@@ -1,10 +1,12 @@
import 'package:app_flowy/plugins/grid/application/field/field_controller.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/widgets.dart';
import 'package:provider/provider.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/color_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flutter/material.dart';
import '../../../../generated/locale_keys.g.dart';
import 'board_setting.dart';
class BoardToolbarContext {
@@ -30,6 +32,7 @@ class BoardToolbar extends StatelessWidget {
height: 40,
child: Row(
children: [
const Spacer(),
_SettingButton(
settingContext: BoardSettingContext.from(toolbarContext),
),
@@ -39,22 +42,47 @@ class BoardToolbar extends StatelessWidget {
}
}
class _SettingButton extends StatelessWidget {
class _SettingButton extends StatefulWidget {
final BoardSettingContext settingContext;
const _SettingButton({required this.settingContext, Key? key})
: super(key: key);
@override
State<_SettingButton> createState() => _SettingButtonState();
}
class _SettingButtonState extends State<_SettingButton> {
late PopoverController popoverController;
@override
void initState() {
popoverController = PopoverController();
super.initState();
}
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
return FlowyIconButton(
hoverColor: theme.hover,
width: 22,
onPressed: () => BoardSettingList.show(context, settingContext),
icon: Padding(
padding: const EdgeInsets.symmetric(vertical: 3.0, horizontal: 3.0),
child: svgWidget("grid/setting/setting"),
return AppFlowyPopover(
controller: popoverController,
direction: PopoverDirection.leftWithTopAligned,
triggerActions: PopoverTriggerFlags.none,
constraints: BoxConstraints.loose(const Size(260, 400)),
child: FlowyTextButton(
LocaleKeys.settings_title.tr(),
fontSize: 14,
fillColor: Colors.transparent,
hoverColor: AFThemeExtension.of(context).lightGreyHover,
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 6),
onPressed: () {
popoverController.show();
},
),
popupBuilder: (BuildContext popoverContext) {
return BoardSettingListPopover(
settingContext: widget.settingContext,
popoverController: popoverController,
);
},
);
}
}
@@ -0,0 +1,16 @@
// import 'package:flutter_test/flutter_test.dart';
// import 'package:integration_test/integration_test.dart';
// import 'package:app_flowy/main.dart' as app;
// void main() {
// IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// group('end-to-end test', () {
// testWidgets('tap on the floating action button, verify counter',
// (tester) async {
// app.main();
// await tester.pumpAndSettle();
// });
// });
// }
@@ -1,29 +0,0 @@
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-sync/text_block.pb.dart';
class DocumentService {
Future<Either<TextBlockDeltaPB, FlowyError>> openDocument({
required String docId,
}) async {
await FolderEventSetLatestView(ViewIdPB(value: docId)).send();
final payload = TextBlockIdPB(value: docId);
return TextBlockEventGetBlockData(payload).send();
}
Future<Either<TextBlockDeltaPB, FlowyError>> composeDelta({required String docId, required String data}) {
final payload = TextBlockDeltaPB.create()
..blockId = docId
..deltaStr = data;
return TextBlockEventApplyDelta(payload).send();
}
Future<Either<Unit, FlowyError>> closeDocument({required String docId}) {
final request = ViewIdPB(value: docId);
return FolderEventCloseView(request).send();
}
}
@@ -1,27 +0,0 @@
import 'dart:async';
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-text-block/protobuf.dart';
class ShareService {
Future<Either<ExportDataPB, FlowyError>> export(String docId, ExportType type) {
final request = ExportPayloadPB.create()
..viewId = docId
..exportType = type;
return TextBlockEventExportDocument(request).send();
}
Future<Either<ExportDataPB, FlowyError>> exportText(String docId) {
return export(docId, ExportType.Text);
}
Future<Either<ExportDataPB, FlowyError>> exportMarkdown(String docId) {
return export(docId, ExportType.Markdown);
}
Future<Either<ExportDataPB, FlowyError>> exportURL(String docId) {
return export(docId, ExportType.Link);
}
}
@@ -1,263 +0,0 @@
library document_plugin;
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart';
import 'package:app_flowy/plugins/doc/application/share_bloc.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart';
import 'package:app_flowy/workspace/presentation/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:clipboard/clipboard.dart';
import 'package:dartz/dartz.dart' as dartz;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flowy_infra/size.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-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-text-block/entities.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'document_page.dart';
class DocumentPluginBuilder extends PluginBuilder {
@override
Plugin build(dynamic data) {
if (data is ViewPB) {
return DocumentPlugin(pluginType: pluginType, view: data);
} else {
throw FlowyPluginException.invalidData;
}
}
@override
String get menuName => LocaleKeys.document_menuName.tr();
@override
PluginType get pluginType => PluginType.editor;
@override
ViewDataTypePB get dataType => ViewDataTypePB.Text;
}
class DocumentPlugin implements Plugin {
late ViewPB _view;
ViewListener? _listener;
late PluginType _pluginType;
DocumentPlugin(
{required PluginType pluginType, required ViewPB view, Key? key})
: _view = view {
_pluginType = pluginType;
_listener = getIt<ViewListener>(param1: view);
_listener?.start(onViewUpdated: (result) {
result.fold(
(newView) {
_view = newView;
display.notifier!.value = _view.hashCode;
},
(error) {},
);
});
}
@override
void dispose() {
_listener?.stop();
_listener = null;
}
@override
PluginDisplay<int> get display => DocumentPluginDisplay(view: _view);
@override
PluginType get ty => _pluginType;
@override
PluginId get id => _view.id;
}
class DocumentPluginDisplay extends PluginDisplay<int> with NavigationItem {
final PublishNotifier<int> _displayNotifier = PublishNotifier<int>();
final ViewPB _view;
DocumentPluginDisplay({required ViewPB view, Key? key}) : _view = view;
@override
Widget buildWidget() => DocumentPage(view: _view, key: ValueKey(_view.id));
@override
Widget get leftBarItem => ViewLeftBarItem(view: _view);
@override
Widget? get rightBarItem => DocumentShareButton(view: _view);
@override
List<NavigationItem> get navigationItems => [this];
@override
PublishNotifier<int>? get notifier => _displayNotifier;
}
class DocumentShareButton extends StatelessWidget {
final ViewPB view;
DocumentShareButton({Key? key, required this.view})
: super(key: ValueKey(view.hashCode));
@override
Widget build(BuildContext context) {
double buttonWidth = 60;
return BlocProvider(
create: (context) => getIt<DocShareBloc>(param1: view),
child: BlocListener<DocShareBloc, DocShareState>(
listener: (context, state) {
state.map(
initial: (_) {},
loading: (_) {},
finish: (state) {
state.successOrFail.fold(
_handleExportData,
_handleExportError,
);
},
);
},
child: BlocBuilder<DocShareBloc, DocShareState>(
builder: (context, state) {
return ChangeNotifierProvider.value(
value: Provider.of<AppearanceSettingModel>(context, listen: true),
child: Selector<AppearanceSettingModel, Locale>(
selector: (ctx, notifier) => notifier.locale,
builder: (ctx, _, child) => ConstrainedBox(
constraints: const BoxConstraints.expand(
height: 30,
// minWidth: buttonWidth,
width: 100,
),
child: RoundedTextButton(
title: LocaleKeys.shareAction_buttonText.tr(),
fontSize: 12,
borderRadius: Corners.s6Border,
color: Colors.lightBlue,
onPressed: () => _showActionList(
context, Offset(-(buttonWidth / 2), 10)),
),
),
),
);
},
),
),
);
}
void _handleExportData(ExportDataPB exportData) {
switch (exportData.exportType) {
case ExportType.Link:
break;
case ExportType.Markdown:
FlutterClipboard.copy(exportData.data)
.then((value) => Log.info('copied to clipboard'));
break;
case ExportType.Text:
break;
}
}
void _handleExportError(FlowyError error) {}
void _showActionList(BuildContext context, Offset offset) {
final actionList = ShareActions(onSelected: (result) {
result.fold(() {}, (action) {
switch (action) {
case ShareAction.markdown:
context
.read<DocShareBloc>()
.add(const DocShareEvent.shareMarkdown());
showMessageToast(
'Exported to: ${LocaleKeys.notifications_export_path.tr()}');
break;
case ShareAction.copyLink:
FlowyAlertDialog(title: LocaleKeys.shareAction_workInProgress.tr())
.show(context);
break;
}
});
});
actionList.show(
context,
anchorDirection: AnchorDirection.bottomWithCenterAligned,
anchorOffset: offset,
);
}
}
class ShareActions with ActionList<ShareActionWrapper>, FlowyOverlayDelegate {
final Function(dartz.Option<ShareAction>) onSelected;
final _items =
ShareAction.values.map((action) => ShareActionWrapper(action)).toList();
ShareActions({required this.onSelected});
@override
double get maxWidth => 130;
@override
double get itemHeight => 22;
@override
List<ShareActionWrapper> get items => _items;
@override
void Function(dartz.Option<ShareActionWrapper> p1) get selectCallback =>
(result) {
result.fold(
() => onSelected(dartz.none()),
(wrapper) => onSelected(
dartz.some(wrapper.inner),
),
);
};
@override
FlowyOverlayDelegate? get delegate => this;
@override
void didRemove() => onSelected(dartz.none());
}
enum ShareAction {
markdown,
copyLink,
}
class ShareActionWrapper extends ActionItem {
final ShareAction inner;
ShareActionWrapper(this.inner);
@override
Widget? get icon => null;
@override
String get name => inner.name;
}
extension QuestionBubbleExtension on ShareAction {
String get name {
switch (this) {
case ShareAction.markdown:
return LocaleKeys.shareAction_markdown.tr();
case ShareAction.copyLink:
return LocaleKeys.shareAction_copyLink.tr();
}
}
}
@@ -1,143 +0,0 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:app_flowy/plugins/doc/presentation/banner.dart';
import 'package:app_flowy/plugins/doc/presentation/toolbar/tool_bar.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'application/doc_bloc.dart';
import 'styles.dart';
class DocumentPage extends StatefulWidget {
final ViewPB view;
DocumentPage({Key? key, required this.view}) : super(key: ValueKey(view.id));
@override
State<DocumentPage> createState() => _DocumentPageState();
}
class _DocumentPageState extends State<DocumentPage> {
late DocumentBloc documentBloc;
final scrollController = ScrollController();
final FocusNode _focusNode = FocusNode();
@override
void initState() {
documentBloc = getIt<DocumentBloc>(param1: super.widget.view)
..add(const DocumentEvent.initial());
super.initState();
}
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<DocumentBloc>.value(value: documentBloc),
],
child:
BlocBuilder<DocumentBloc, DocumentState>(builder: (context, state) {
return state.loadingState.map(
// loading: (_) => const FlowyProgressIndicator(),
loading: (_) =>
SizedBox.expand(child: Container(color: Colors.transparent)),
finish: (result) => result.successOrFail.fold(
(_) {
if (state.forceClose) {
return _renderAppPage();
} else {
return _renderDocument(context, state);
}
},
(err) => FlowyErrorPage(err.toString()),
),
);
}),
);
}
@override
Future<void> dispose() async {
documentBloc.close();
_focusNode.dispose();
super.dispose();
}
Widget _renderDocument(BuildContext context, DocumentState state) {
quill.QuillController controller = quill.QuillController(
document: context.read<DocumentBloc>().document,
selection: const TextSelection.collapsed(offset: 0),
);
return Column(
children: [
if (state.isDeleted) _renderBanner(context),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_renderEditor(controller),
const VSpace(10),
_renderToolbar(controller),
const VSpace(10),
],
),
),
],
);
}
Widget _renderBanner(BuildContext context) {
return DocumentBanner(
onRestore: () =>
context.read<DocumentBloc>().add(const DocumentEvent.restorePage()),
onDelete: () => context
.read<DocumentBloc>()
.add(const DocumentEvent.deletePermanently()),
);
}
Widget _renderEditor(quill.QuillController controller) {
final editor = quill.QuillEditor(
controller: controller,
focusNode: _focusNode,
scrollable: true,
paintCursorAboveText: true,
autoFocus: controller.document.isEmpty(),
expands: false,
padding: const EdgeInsets.symmetric(horizontal: 8.0),
readOnly: false,
scrollBottomInset: 0,
scrollController: scrollController,
customStyles: customStyles(context),
);
return Expanded(
child: ScrollbarListStack(
axis: Axis.vertical,
controller: scrollController,
barSize: 6.0,
child: SizedBox.expand(child: editor),
),
);
}
Widget _renderToolbar(quill.QuillController controller) {
return ChangeNotifierProvider.value(
value: Provider.of<AppearanceSettingModel>(context, listen: true),
child: EditorToolbar.basic(
controller: controller,
),
);
}
Widget _renderAppPage() {
return Container(
color: Colors.black,
);
}
}
@@ -1,74 +0,0 @@
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_quill/flutter_quill.dart';
class StyleWidgetBuilder {
static QuillCheckboxBuilder checkbox(AppTheme theme) {
return EditorCheckboxBuilder(theme);
}
}
class EditorCheckboxBuilder extends QuillCheckboxBuilder {
final AppTheme theme;
EditorCheckboxBuilder(this.theme);
@override
Widget build(
{required BuildContext context,
required bool isChecked,
required ValueChanged<bool> onChanged}) {
return FlowyEditorCheckbox(
theme: theme,
isChecked: isChecked,
onChanged: onChanged,
);
}
}
class FlowyEditorCheckbox extends StatefulWidget {
final bool isChecked;
final ValueChanged<bool> onChanged;
final AppTheme theme;
const FlowyEditorCheckbox({
required this.theme,
required this.isChecked,
required this.onChanged,
Key? key,
}) : super(key: key);
@override
FlowyEditorCheckboxState createState() => FlowyEditorCheckboxState();
}
class FlowyEditorCheckboxState extends State<FlowyEditorCheckbox> {
late bool isChecked;
@override
void initState() {
isChecked = widget.isChecked;
super.initState();
}
@override
Widget build(BuildContext context) {
final icon = isChecked
? svgWidget('editor/editor_check')
: svgWidget('editor/editor_uncheck');
return Align(
alignment: Alignment.centerLeft,
child: FlowyIconButton(
onPressed: () {
isChecked = !isChecked;
widget.onChanged(isChecked);
setState(() {});
},
iconPadding: EdgeInsets.zero,
icon: icon,
width: 23,
),
);
}
}
@@ -1,97 +0,0 @@
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/models/documents/style.dart';
import 'package:flutter/material.dart';
import 'toolbar_icon_button.dart';
class FlowyCheckListButton extends StatefulWidget {
const FlowyCheckListButton({
required this.controller,
required this.attribute,
required this.tooltipText,
this.iconSize = defaultIconSize,
this.fillColor,
this.childBuilder = defaultToggleStyleButtonBuilder,
Key? key,
}) : super(key: key);
final double iconSize;
final Color? fillColor;
final QuillController controller;
final ToggleStyleButtonBuilder childBuilder;
final Attribute attribute;
final String tooltipText;
@override
FlowyCheckListButtonState createState() => FlowyCheckListButtonState();
}
class FlowyCheckListButtonState extends State<FlowyCheckListButton> {
bool? _isToggled;
Style get _selectionStyle => widget.controller.getSelectionStyle();
void _didChangeEditingValue() {
setState(() {
_isToggled =
_getIsToggled(widget.controller.getSelectionStyle().attributes);
});
}
@override
void initState() {
super.initState();
_isToggled = _getIsToggled(_selectionStyle.attributes);
widget.controller.addListener(_didChangeEditingValue);
}
bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key) {
final attribute = attrs[widget.attribute.key];
if (attribute == null) {
return false;
}
return attribute.value == widget.attribute.value ||
attribute.value == Attribute.checked.value;
}
return attrs.containsKey(widget.attribute.key);
}
@override
void didUpdateWidget(covariant FlowyCheckListButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue);
widget.controller.addListener(_didChangeEditingValue);
_isToggled = _getIsToggled(_selectionStyle.attributes);
}
}
@override
void dispose() {
widget.controller.removeListener(_didChangeEditingValue);
super.dispose();
}
@override
Widget build(BuildContext context) {
return ToolbarIconButton(
onPressed: _toggleAttribute,
width: widget.iconSize * kIconButtonFactor,
iconName: 'editor/checkbox',
isToggled: _isToggled ?? false,
tooltipText: widget.tooltipText,
);
}
void _toggleAttribute() {
widget.controller.formatSelection(_isToggled!
? Attribute.clone(Attribute.unchecked, null)
: Attribute.unchecked);
}
}
@@ -1,280 +0,0 @@
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/models/documents/style.dart';
import 'package:flutter_quill/utils/color.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'toolbar_icon_button.dart';
class FlowyColorButton extends StatefulWidget {
const FlowyColorButton({
required this.icon,
required this.controller,
required this.background,
this.iconSize = defaultIconSize,
this.iconTheme,
Key? key,
}) : super(key: key);
final IconData icon;
final double iconSize;
final bool background;
final QuillController controller;
final QuillIconTheme? iconTheme;
@override
FlowyColorButtonState createState() => FlowyColorButtonState();
}
class FlowyColorButtonState extends State<FlowyColorButton> {
late bool _isToggledColor;
late bool _isToggledBackground;
late bool _isWhite;
late bool _isWhitebackground;
Style get _selectionStyle => widget.controller.getSelectionStyle();
void _didChangeEditingValue() {
setState(() {
_isToggledColor =
_getIsToggledColor(widget.controller.getSelectionStyle().attributes);
_isToggledBackground = _getIsToggledBackground(
widget.controller.getSelectionStyle().attributes);
_isWhite = _isToggledColor &&
_selectionStyle.attributes['color']!.value == '#ffffff';
_isWhitebackground = _isToggledBackground &&
_selectionStyle.attributes['background']!.value == '#ffffff';
});
}
@override
void initState() {
super.initState();
_isToggledColor = _getIsToggledColor(_selectionStyle.attributes);
_isToggledBackground = _getIsToggledBackground(_selectionStyle.attributes);
_isWhite = _isToggledColor &&
_selectionStyle.attributes['color']!.value == '#ffffff';
_isWhitebackground = _isToggledBackground &&
_selectionStyle.attributes['background']!.value == '#ffffff';
widget.controller.addListener(_didChangeEditingValue);
}
bool _getIsToggledColor(Map<String, Attribute> attrs) {
return attrs.containsKey(Attribute.color.key);
}
bool _getIsToggledBackground(Map<String, Attribute> attrs) {
return attrs.containsKey(Attribute.background.key);
}
@override
void didUpdateWidget(covariant FlowyColorButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue);
widget.controller.addListener(_didChangeEditingValue);
_isToggledColor = _getIsToggledColor(_selectionStyle.attributes);
_isToggledBackground =
_getIsToggledBackground(_selectionStyle.attributes);
_isWhite = _isToggledColor &&
_selectionStyle.attributes['color']!.value == '#ffffff';
_isWhitebackground = _isToggledBackground &&
_selectionStyle.attributes['background']!.value == '#ffffff';
}
}
@override
void dispose() {
widget.controller.removeListener(_didChangeEditingValue);
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final fillColor = _isToggledColor && !widget.background && _isWhite
? stringToColor('#ffffff')
: (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor);
final fillColorBackground =
_isToggledBackground && widget.background && _isWhitebackground
? stringToColor('#ffffff')
: (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor);
return Tooltip(
message: LocaleKeys.toolbar_highlight.tr(),
showDuration: Duration.zero,
child: QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: widget.iconSize * kIconButtonFactor,
icon: Icon(widget.icon,
size: widget.iconSize, color: theme.iconTheme.color),
fillColor: widget.background ? fillColorBackground : fillColor,
onPressed: _showColorPicker,
),
);
}
void _changeColor(BuildContext context, Color color) {
var hex = color.value.toRadixString(16);
if (hex.startsWith('ff')) {
hex = hex.substring(2);
}
hex = '#$hex';
widget.controller.formatSelection(
widget.background ? BackgroundAttribute(hex) : ColorAttribute(hex));
Navigator.of(context).pop();
}
void _showColorPicker() {
final style = widget.controller.getSelectionStyle();
final values = style.values
.where((v) => v.key == Attribute.background.key)
.map((v) => v.value);
int initialColor = 0;
if (values.isNotEmpty) {
assert(values.length == 1);
initialColor = stringToHex(values.first);
}
StyledDialog(
child: SingleChildScrollView(
child: FlowyColorPicker(
onColorChanged: (color) {
if (color == null) {
widget.controller.formatSelection(BackgroundAttribute(null));
Navigator.of(context).pop();
} else {
_changeColor(context, color);
}
},
initialColor: initialColor,
),
),
).show(context);
}
}
int stringToHex(String code) {
return int.parse(code.substring(1, 7), radix: 16) + 0xFF000000;
}
class FlowyColorPicker extends StatefulWidget {
final List<int> colors = [
0xffe8e0ff,
0xffffe7fd,
0xffffe7ee,
0xffffefe3,
0xfffff2cd,
0xfff5ffdc,
0xffddffd6,
0xffdefff1,
];
final Function(Color?) onColorChanged;
final int initialColor;
FlowyColorPicker(
{Key? key, required this.onColorChanged, this.initialColor = 0})
: super(key: key);
@override
State<FlowyColorPicker> createState() => _FlowyColorPickerState();
}
// if (shrinkWrap) {
// innerContent = IntrinsicWidth(child: IntrinsicHeight(child: innerContent));
// }
class _FlowyColorPickerState extends State<FlowyColorPicker> {
@override
Widget build(BuildContext context) {
const double width = 480;
const int crossAxisCount = 6;
const double mainAxisSpacing = 10;
const double crossAxisSpacing = 10;
final numberOfRows = (widget.colors.length / crossAxisCount).ceil();
const perRowHeight =
((width - ((crossAxisCount - 1) * mainAxisSpacing)) / crossAxisCount);
final totalHeight =
numberOfRows * perRowHeight + numberOfRows * crossAxisSpacing;
return Container(
constraints: BoxConstraints.tightFor(width: width, height: totalHeight),
child: CustomScrollView(
scrollDirection: Axis.vertical,
controller: ScrollController(),
physics: const ClampingScrollPhysics(),
slivers: [
SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (widget.colors.length > index) {
final isSelected =
widget.colors[index] == widget.initialColor;
return ColorItem(
color: Color(widget.colors[index]),
onPressed: widget.onColorChanged,
isSelected: isSelected,
);
} else {
return null;
}
},
childCount: widget.colors.length,
),
),
],
),
);
}
}
class ColorItem extends StatelessWidget {
final Function(Color?) onPressed;
final bool isSelected;
final Color color;
const ColorItem({
Key? key,
required this.color,
required this.onPressed,
this.isSelected = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (!isSelected) {
return RawMaterialButton(
onPressed: () {
onPressed(color);
},
elevation: 0,
hoverElevation: 0.6,
fillColor: color,
shape: const CircleBorder(),
);
} else {
return RawMaterialButton(
shape: const CircleBorder(
side: BorderSide(color: Colors.white, width: 8)) +
CircleBorder(side: BorderSide(color: color, width: 4)),
onPressed: () {
if (isSelected) {
onPressed(null);
} else {
onPressed(color);
}
},
elevation: 1.0,
hoverElevation: 0.6,
fillColor: color,
);
}
}
}
@@ -1,101 +0,0 @@
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/models/documents/style.dart';
import 'package:flutter/material.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'toolbar_icon_button.dart';
class FlowyHeaderStyleButton extends StatefulWidget {
const FlowyHeaderStyleButton({
required this.controller,
this.iconSize = defaultIconSize,
Key? key,
}) : super(key: key);
final QuillController controller;
final double iconSize;
@override
FlowyHeaderStyleButtonState createState() => FlowyHeaderStyleButtonState();
}
class FlowyHeaderStyleButtonState extends State<FlowyHeaderStyleButton> {
Attribute? _value;
Style get _selectionStyle => widget.controller.getSelectionStyle();
@override
void initState() {
super.initState();
setState(() {
_value =
_selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
});
widget.controller.addListener(_didChangeEditingValue);
}
@override
Widget build(BuildContext context) {
final valueToText = <Attribute, String>{
Attribute.h1: 'H1',
Attribute.h2: 'H2',
Attribute.h3: 'H3',
};
final valueAttribute = <Attribute>[
Attribute.h1,
Attribute.h2,
Attribute.h3
];
final valueString = <String>['H1', 'H2', 'H3'];
final attributeImageName = <String>['editor/H1', 'editor/H2', 'editor/H3'];
return Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(3, (index) {
// final child =
// _valueToText[_value] == _valueString[index] ? svg('editor/H1', color: Colors.white) : svg('editor/H1');
final headerTitle = "${LocaleKeys.toolbar_header.tr()} ${index + 1}";
final isToggled = valueToText[_value] == valueString[index];
return ToolbarIconButton(
onPressed: () {
if (isToggled) {
widget.controller.formatSelection(Attribute.header);
} else {
widget.controller.formatSelection(valueAttribute[index]);
}
},
width: widget.iconSize * kIconButtonFactor,
iconName: attributeImageName[index],
isToggled: isToggled,
tooltipText: headerTitle,
);
}),
);
}
void _didChangeEditingValue() {
setState(() {
_value =
_selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
});
}
@override
void didUpdateWidget(covariant FlowyHeaderStyleButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue);
widget.controller.addListener(_didChangeEditingValue);
_value =
_selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
}
}
@override
void dispose() {
widget.controller.removeListener(_didChangeEditingValue);
super.dispose();
}
}
@@ -1,33 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
class FlowyHistoryButton extends StatelessWidget {
final IconData icon;
final double iconSize;
final bool undo;
final QuillController controller;
final String tooltipText;
const FlowyHistoryButton({
required this.icon,
required this.controller,
required this.undo,
required this.tooltipText,
required this.iconSize,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Tooltip(
message: tooltipText,
showDuration: Duration.zero,
child: HistoryButton(
icon: icon,
iconSize: iconSize,
controller: controller,
undo: undo,
),
);
}
}
@@ -1,85 +0,0 @@
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter/material.dart';
import 'toolbar_icon_button.dart';
class FlowyImageButton extends StatelessWidget {
const FlowyImageButton({
required this.controller,
required this.tooltipText,
this.iconSize = defaultIconSize,
this.onImagePickCallback,
this.fillColor,
this.filePickImpl,
this.webImagePickImpl,
this.mediaPickSettingSelector,
Key? key,
}) : super(key: key);
final double iconSize;
final Color? fillColor;
final QuillController controller;
final OnImagePickCallback? onImagePickCallback;
final WebImagePickImpl? webImagePickImpl;
final FilePickImpl? filePickImpl;
final MediaPickSettingSelector? mediaPickSettingSelector;
final String tooltipText;
@override
Widget build(BuildContext context) {
return ToolbarIconButton(
iconName: 'editor/image',
width: iconSize * 1.77,
onPressed: () => _onPressedHandler(context),
isToggled: false,
tooltipText: tooltipText,
);
}
Future<void> _onPressedHandler(BuildContext context) async {
// if (onImagePickCallback != null) {
// final selector = mediaPickSettingSelector ?? ImageVideoUtils.selectMediaPickSetting;
// final source = await selector(context);
// if (source != null) {
// if (source == MediaPickSetting.Gallery) {
// _pickImage(context);
// } else {
// _typeLink(context);
// }
// }
// } else {
// _typeLink(context);
// }
}
// void _pickImage(BuildContext context) => ImageVideoUtils.handleImageButtonTap(
// context,
// controller,
// ImageSource.gallery,
// onImagePickCallback!,
// filePickImpl: filePickImpl,
// webImagePickImpl: webImagePickImpl,
// );
// void _typeLink(BuildContext context) {
// TextFieldDialog(
// title: 'URL',
// value: "",
// confirm: (newValue) {
// if (newValue.isEmpty) {
// return;
// }
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// controller.replaceText(index, length, BlockEmbed.image(newValue), null);
// },
// ).show(context);
// }
}
@@ -1,98 +0,0 @@
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
import 'package:flutter_quill/flutter_quill.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:provider/provider.dart';
import 'toolbar_icon_button.dart';
class FlowyLinkStyleButton extends StatefulWidget {
const FlowyLinkStyleButton({
required this.controller,
this.iconSize = defaultIconSize,
Key? key,
}) : super(key: key);
final QuillController controller;
final double iconSize;
@override
FlowyLinkStyleButtonState createState() => FlowyLinkStyleButtonState();
}
class FlowyLinkStyleButtonState extends State<FlowyLinkStyleButton> {
void _didChangeSelection() {
setState(() {});
}
@override
void initState() {
super.initState();
widget.controller.addListener(_didChangeSelection);
}
@override
void didUpdateWidget(covariant FlowyLinkStyleButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeSelection);
widget.controller.addListener(_didChangeSelection);
}
}
@override
void dispose() {
super.dispose();
widget.controller.removeListener(_didChangeSelection);
}
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
final isEnabled = !widget.controller.selection.isCollapsed;
final pressedHandler = isEnabled ? () => _openLinkDialog(context) : null;
final icon = isEnabled
? svgWidget(
'editor/share',
color: theme.iconColor,
)
: svgWidget(
'editor/share',
color: theme.disableIconColor,
);
return FlowyIconButton(
onPressed: pressedHandler,
iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
icon: icon,
fillColor: theme.shader6,
hoverColor: theme.shader5,
width: widget.iconSize * kIconButtonFactor,
);
}
void _openLinkDialog(BuildContext context) {
final style = widget.controller.getSelectionStyle();
final values = style.values
.where((v) => v.key == Attribute.link.key)
.map((v) => v.value);
String value = "";
if (values.isNotEmpty) {
assert(values.length == 1);
value = values.first;
}
TextFieldDialog(
title: 'URL',
value: value,
confirm: (newValue) {
if (newValue.isEmpty) {
return;
}
widget.controller.formatSelection(LinkAttribute(newValue));
},
).show(context);
}
}
@@ -1,84 +0,0 @@
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/models/documents/style.dart';
import 'package:flutter/material.dart';
import 'toolbar_icon_button.dart';
class FlowyToggleStyleButton extends StatefulWidget {
final Attribute attribute;
final String normalIcon;
final double iconSize;
final QuillController controller;
final String tooltipText;
const FlowyToggleStyleButton({
required this.attribute,
required this.normalIcon,
required this.controller,
required this.tooltipText,
this.iconSize = defaultIconSize,
Key? key,
}) : super(key: key);
@override
ToggleStyleButtonState createState() => ToggleStyleButtonState();
}
class ToggleStyleButtonState extends State<FlowyToggleStyleButton> {
bool? _isToggled;
Style get _selectionStyle => widget.controller.getSelectionStyle();
@override
void initState() {
super.initState();
_isToggled = _getIsToggled(_selectionStyle.attributes);
widget.controller.addListener(_didChangeEditingValue);
}
@override
Widget build(BuildContext context) {
return ToolbarIconButton(
onPressed: _toggleAttribute,
width: widget.iconSize * kIconButtonFactor,
isToggled: _isToggled ?? false,
iconName: widget.normalIcon,
tooltipText: widget.tooltipText,
);
}
@override
void didUpdateWidget(covariant FlowyToggleStyleButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue);
widget.controller.addListener(_didChangeEditingValue);
_isToggled = _getIsToggled(_selectionStyle.attributes);
}
}
@override
void dispose() {
widget.controller.removeListener(_didChangeEditingValue);
super.dispose();
}
void _didChangeEditingValue() {
setState(() => _isToggled = _getIsToggled(_selectionStyle.attributes));
}
bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key) {
final attribute = attrs[widget.attribute.key];
if (attribute == null) {
return false;
}
return attribute.value == widget.attribute.value;
}
return attrs.containsKey(widget.attribute.key);
}
void _toggleAttribute() {
widget.controller.formatSelection(_isToggled!
? Attribute.clone(widget.attribute, null)
: widget.attribute);
}
}
@@ -1,308 +0,0 @@
import 'dart:async';
import 'dart:math';
import 'package:app_flowy/workspace/presentation/widgets/emoji_picker/emoji_picker.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart';
import 'check_button.dart';
import 'color_picker.dart';
import 'header_button.dart';
import 'history_button.dart';
import 'link_button.dart';
import 'toggle_button.dart';
import 'toolbar_icon_button.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
class EditorToolbar extends StatelessWidget implements PreferredSizeWidget {
final List<Widget> children;
final double toolBarHeight;
final Color? color;
const EditorToolbar({
required this.children,
this.toolBarHeight = 46,
this.color,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).canvasColor,
constraints: BoxConstraints.tightFor(height: preferredSize.height),
child: ToolbarButtonList(buttons: children)
.padding(horizontal: 4, vertical: 4),
);
}
@override
Size get preferredSize => Size.fromHeight(toolBarHeight);
factory EditorToolbar.basic({
required QuillController controller,
double toolbarIconSize = defaultIconSize,
OnImagePickCallback? onImagePickCallback,
OnVideoPickCallback? onVideoPickCallback,
MediaPickSettingSelector? mediaPickSettingSelector,
FilePickImpl? filePickImpl,
WebImagePickImpl? webImagePickImpl,
WebVideoPickImpl? webVideoPickImpl,
Key? key,
}) {
return EditorToolbar(
key: key,
toolBarHeight: toolbarIconSize * 2,
children: [
FlowyHistoryButton(
icon: Icons.undo_outlined,
iconSize: toolbarIconSize,
controller: controller,
undo: true,
tooltipText: LocaleKeys.toolbar_undo.tr(),
),
FlowyHistoryButton(
icon: Icons.redo_outlined,
iconSize: toolbarIconSize,
controller: controller,
undo: false,
tooltipText: LocaleKeys.toolbar_redo.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.bold,
normalIcon: 'editor/bold',
iconSize: toolbarIconSize,
controller: controller,
tooltipText: LocaleKeys.toolbar_bold.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.italic,
normalIcon: 'editor/italic',
iconSize: toolbarIconSize,
controller: controller,
tooltipText: LocaleKeys.toolbar_italic.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.underline,
normalIcon: 'editor/underline',
iconSize: toolbarIconSize,
controller: controller,
tooltipText: LocaleKeys.toolbar_underline.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.strikeThrough,
normalIcon: 'editor/strikethrough',
iconSize: toolbarIconSize,
controller: controller,
tooltipText: LocaleKeys.toolbar_strike.tr(),
),
FlowyColorButton(
icon: Icons.format_color_fill,
iconSize: toolbarIconSize,
controller: controller,
background: true,
),
// FlowyImageButton(
// iconSize: toolbarIconSize,
// controller: controller,
// onImagePickCallback: onImagePickCallback,
// filePickImpl: filePickImpl,
// webImagePickImpl: webImagePickImpl,
// mediaPickSettingSelector: mediaPickSettingSelector,
// ),
FlowyHeaderStyleButton(
controller: controller,
iconSize: toolbarIconSize,
),
FlowyToggleStyleButton(
attribute: Attribute.ol,
controller: controller,
normalIcon: 'editor/numbers',
iconSize: toolbarIconSize,
tooltipText: LocaleKeys.toolbar_numList.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.ul,
controller: controller,
normalIcon: 'editor/bullet_list',
iconSize: toolbarIconSize,
tooltipText: LocaleKeys.toolbar_bulletList.tr(),
),
FlowyCheckListButton(
attribute: Attribute.unchecked,
controller: controller,
iconSize: toolbarIconSize,
tooltipText: LocaleKeys.toolbar_checkList.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.inlineCode,
controller: controller,
normalIcon: 'editor/inline_block',
iconSize: toolbarIconSize,
tooltipText: LocaleKeys.toolbar_inlineCode.tr(),
),
FlowyToggleStyleButton(
attribute: Attribute.blockQuote,
controller: controller,
normalIcon: 'editor/quote',
iconSize: toolbarIconSize,
tooltipText: LocaleKeys.toolbar_quote.tr(),
),
FlowyLinkStyleButton(
controller: controller,
iconSize: toolbarIconSize,
),
FlowyEmojiStyleButton(
normalIcon: 'editor/insert_emoticon',
controller: controller,
tooltipText: "Emoji Picker",
),
],
);
}
}
class ToolbarButtonList extends StatefulWidget {
const ToolbarButtonList({required this.buttons, Key? key}) : super(key: key);
final List<Widget> buttons;
@override
ToolbarButtonListState createState() => ToolbarButtonListState();
}
class ToolbarButtonListState extends State<ToolbarButtonList>
with WidgetsBindingObserver {
final ScrollController _controller = ScrollController();
bool _showLeftArrow = false;
bool _showRightArrow = false;
@override
void initState() {
super.initState();
_controller.addListener(_handleScroll);
// Listening to the WidgetsBinding instance is necessary so that we can
// hide the arrows when the window gets a new size and thus the toolbar
// becomes scrollable/unscrollable.
WidgetsBinding.instance.addObserver(this);
// Workaround to allow the scroll controller attach to our ListView so that
// we can detect if overflow arrows need to be shown on init.
Timer.run(_handleScroll);
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
List<Widget> children = [];
double width =
(widget.buttons.length + 2) * defaultIconSize * kIconButtonFactor;
final isFit = constraints.maxWidth > width;
if (!isFit) {
children.add(_buildLeftArrow());
width = width + 18;
}
children.add(_buildScrollableList(constraints, isFit));
if (!isFit) {
children.add(_buildRightArrow());
width = width + 18;
}
return SizedBox(
width: min(constraints.maxWidth, width),
child: Row(
children: children,
),
);
},
);
}
@override
void didChangeMetrics() => _handleScroll();
@override
void dispose() {
_controller.dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
void _handleScroll() {
if (!mounted) return;
setState(() {
_showLeftArrow =
_controller.position.minScrollExtent != _controller.position.pixels;
_showRightArrow =
_controller.position.maxScrollExtent != _controller.position.pixels;
});
}
Widget _buildLeftArrow() {
return SizedBox(
width: 8,
child: Transform.translate(
// Move the icon a few pixels to center it
offset: const Offset(-5, 0),
child: _showLeftArrow ? const Icon(Icons.arrow_left, size: 18) : null,
),
);
}
// [[sliver: https://medium.com/flutter/slivers-demystified-6ff68ab0296f]]
Widget _buildScrollableList(BoxConstraints constraints, bool isFit) {
Widget child = Expanded(
child: CustomScrollView(
scrollDirection: Axis.horizontal,
controller: _controller,
physics: const ClampingScrollPhysics(),
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return widget.buttons[index];
},
childCount: widget.buttons.length,
addAutomaticKeepAlives: false,
),
)
],
),
);
if (!isFit) {
child = ScrollConfiguration(
// Remove the glowing effect, as we already have the arrow indicators
behavior: _NoGlowBehavior(),
// The CustomScrollView is necessary so that the children are not
// stretched to the height of the toolbar, https://bit.ly/3uC3bjI
child: child,
);
}
return child;
}
Widget _buildRightArrow() {
return SizedBox(
width: 8,
child: Transform.translate(
// Move the icon a few pixels to center it
offset: const Offset(-5, 0),
child: _showRightArrow ? const Icon(Icons.arrow_right, size: 18) : null,
),
);
}
}
class _NoGlowBehavior extends ScrollBehavior {
@override
Widget buildViewportChrome(BuildContext _, Widget child, AxisDirection __) {
return child;
}
}
@@ -1,38 +0,0 @@
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flowy_infra/theme.dart';
import 'package:provider/provider.dart';
const double defaultIconSize = 18;
class ToolbarIconButton extends StatelessWidget {
final double width;
final VoidCallback? onPressed;
final bool isToggled;
final String iconName;
final String tooltipText;
const ToolbarIconButton({
Key? key,
required this.onPressed,
required this.isToggled,
required this.width,
required this.iconName,
required this.tooltipText,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return FlowyIconButton(
iconPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
onPressed: onPressed,
width: width,
icon: isToggled == true ? svgWidget(iconName, color: Colors.white) : svgWidget(iconName, color: theme.iconColor),
fillColor: isToggled == true ? theme.main1 : theme.shader6,
hoverColor: isToggled == true ? theme.main1 : theme.hover,
tooltipText: tooltipText,
);
}
}
@@ -1,133 +0,0 @@
import 'package:app_flowy/plugins/doc/presentation/style_widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
import 'package:flowy_infra/theme.dart';
DefaultStyles customStyles(BuildContext context) {
const baseSpacing = Tuple2<double, double>(6, 0);
final theme = context.watch<AppTheme>();
final themeData = theme.themeData;
final fontFamily = makeFontFamily(themeData);
final defaultTextStyle = DefaultTextStyle.of(context);
final baseStyle = defaultTextStyle.style.copyWith(
fontSize: 18,
height: 1.3,
fontWeight: FontWeight.w300,
letterSpacing: 0.6,
fontFamily: fontFamily,
);
return DefaultStyles(
h1: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 34,
color: defaultTextStyle.style.color!.withOpacity(0.70),
height: 1.15,
fontWeight: FontWeight.w300,
),
const Tuple2(16, 0),
const Tuple2(0, 0),
null),
h2: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 24,
color: defaultTextStyle.style.color!.withOpacity(0.70),
height: 1.15,
fontWeight: FontWeight.normal,
),
const Tuple2(8, 0),
const Tuple2(0, 0),
null),
h3: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20,
color: defaultTextStyle.style.color!.withOpacity(0.70),
height: 1.25,
fontWeight: FontWeight.w500,
),
const Tuple2(8, 0),
const Tuple2(0, 0),
null),
paragraph: DefaultTextBlockStyle(
baseStyle, const Tuple2(10, 0), const Tuple2(0, 0), null),
bold: const TextStyle(fontWeight: FontWeight.bold),
italic: const TextStyle(fontStyle: FontStyle.italic),
small: const TextStyle(fontSize: 12, color: Colors.black45),
underline: const TextStyle(decoration: TextDecoration.underline),
strikeThrough: const TextStyle(decoration: TextDecoration.lineThrough),
inlineCode: TextStyle(
color: Colors.blue.shade900.withOpacity(0.9),
fontFamily: fontFamily,
fontSize: 13,
),
link: TextStyle(
color: themeData.colorScheme.secondary,
decoration: TextDecoration.underline,
),
color: theme.textColor,
placeHolder: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20,
height: 1.5,
color: Colors.grey.withOpacity(0.6),
),
const Tuple2(0, 0),
const Tuple2(0, 0),
null),
lists: DefaultListBlockStyle(baseStyle, baseSpacing, const Tuple2(0, 6),
null, StyleWidgetBuilder.checkbox(theme)),
quote: DefaultTextBlockStyle(
TextStyle(color: baseStyle.color!.withOpacity(0.6)),
baseSpacing,
const Tuple2(6, 2),
BoxDecoration(
border: Border(
left: BorderSide(width: 4, color: theme.shader5),
),
)),
code: DefaultTextBlockStyle(
TextStyle(
color: Colors.blue.shade900.withOpacity(0.9),
fontFamily: fontFamily,
fontSize: 13,
height: 1.15,
),
baseSpacing,
const Tuple2(0, 0),
BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(2),
)),
indent: DefaultTextBlockStyle(
baseStyle, baseSpacing, const Tuple2(0, 6), null),
align: DefaultTextBlockStyle(
baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null),
leading: DefaultTextBlockStyle(
baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null),
sizeSmall: const TextStyle(fontSize: 10),
sizeLarge: const TextStyle(fontSize: 18),
sizeHuge: const TextStyle(fontSize: 22));
}
String makeFontFamily(ThemeData themeData) {
String fontFamily;
switch (themeData.platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
fontFamily = 'Mulish';
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.windows:
case TargetPlatform.linux:
fontFamily = 'Roboto Mono';
break;
default:
throw UnimplementedError();
}
return fontFamily;
}
@@ -1,11 +1,12 @@
import 'dart:convert';
import 'package:app_flowy/plugins/trash/application/trash_service.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart';
import 'package:app_flowy/plugins/doc/application/doc_service.dart';
import 'package:app_flowy/plugins/document/application/doc_service.dart';
import 'package:appflowy_editor/appflowy_editor.dart'
show EditorState, Document, Transaction;
import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_quill/flutter_quill.dart' show Document, Delta;
import 'package:flowy_sdk/log.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@@ -14,27 +15,26 @@ import 'dart:async';
part 'doc_bloc.freezed.dart';
typedef FlutterQuillDocument = Document;
class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
final ViewPB view;
final DocumentService service;
final DocumentService _documentService;
final ViewListener listener;
final TrashService trashService;
late FlutterQuillDocument document;
final ViewListener _listener;
final TrashService _trashService;
late EditorState editorState;
StreamSubscription? _subscription;
DocumentBloc({
required this.view,
required this.service,
required this.listener,
required this.trashService,
}) : super(DocumentState.initial()) {
}) : _documentService = DocumentService(),
_listener = ViewListener(view: view),
_trashService = TrashService(),
super(DocumentState.initial()) {
on<DocumentEvent>((event, emit) async {
await event.map(
initial: (Initial value) async {
await _initial(value, emit);
_listenOnViewChange();
},
deleted: (Deleted value) async {
emit(state.copyWith(isDeleted: true));
@@ -43,7 +43,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
emit(state.copyWith(isDeleted: false));
},
deletePermanently: (DeletePermanently value) async {
final result = await trashService
final result = await _trashService
.deleteViews([Tuple2(view.id, TrashType.TrashView)]);
final newState = result.fold(
@@ -51,7 +51,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
emit(newState);
},
restorePage: (RestorePage value) async {
final result = await trashService.putback(view.id);
final result = await _trashService.putback(view.id);
final newState = result.fold(
(l) => state.copyWith(isDeleted: false), (r) => state);
emit(newState);
@@ -62,18 +62,41 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
@override
Future<void> close() async {
await listener.stop();
await _listener.stop();
if (_subscription != null) {
await _subscription?.cancel();
}
await service.closeDocument(docId: view.id);
await _documentService.closeDocument(docId: view.id);
return super.close();
}
Future<void> _initial(Initial value, Emitter<DocumentState> emit) async {
listener.start(
final result = await _documentService.openDocument(view: view);
result.fold(
(block) {
final document = Document.fromJson(jsonDecode(block.snapshot));
editorState = EditorState(document: document);
_listenOnDocumentChange();
emit(
state.copyWith(
loadingState: DocumentLoadingState.finish(left(unit)),
),
);
},
(err) {
emit(
state.copyWith(
loadingState: DocumentLoadingState.finish(right(err)),
),
);
},
);
}
void _listenOnViewChange() {
_listener.start(
onViewDeleted: (result) {
result.fold(
(view) => add(const DocumentEvent.deleted()),
@@ -87,50 +110,20 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
);
},
);
final result = await service.openDocument(docId: view.id);
result.fold(
(block) {
document = _decodeJsonToDocument(block.deltaStr);
_subscription = document.changes.listen((event) {
final delta = event.item2;
final documentDelta = document.toDelta();
_composeDelta(delta, documentDelta);
});
emit(state.copyWith(
loadingState: DocumentLoadingState.finish(left(unit))));
},
(err) {
emit(state.copyWith(
loadingState: DocumentLoadingState.finish(right(err))));
},
);
}
// Document _decodeListToDocument(Uint8List data) {
// final json = jsonDecode(utf8.decode(data));
// final document = Document.fromJson(json);
// return document;
// }
void _composeDelta(Delta composedDelta, Delta documentDelta) async {
final json = jsonEncode(composedDelta.toJson());
Log.debug("doc_id: $view.id - Send json: $json");
final result = await service.composeDelta(docId: view.id, data: json);
result.fold((rustDoc) {
// final json = utf8.decode(doc.data);
final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaStr));
if (documentDelta != rustDelta) {
Log.error("Receive : $rustDelta");
Log.error("Expected : $documentDelta");
}
}, (r) => null);
}
Document _decodeJsonToDocument(String data) {
final json = jsonDecode(data);
final document = Document.fromJson(json);
return document;
void _listenOnDocumentChange() {
_subscription = editorState.transactionStream.listen((transaction) {
final json = jsonEncode(TransactionAdaptor(transaction).toJson());
_documentService
.applyEdit(docId: view.id, operations: json)
.then((result) {
result.fold(
(l) => null,
(err) => Log.error(err),
);
});
});
}
}
@@ -164,3 +157,44 @@ class DocumentLoadingState with _$DocumentLoadingState {
const factory DocumentLoadingState.finish(
Either<Unit, FlowyError> successOrFail) = _Finish;
}
/// Uses to erase the different between appflowy editor and the backend
class TransactionAdaptor {
final Transaction transaction;
TransactionAdaptor(this.transaction);
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (transaction.operations.isNotEmpty) {
// The backend uses [0,0] as the beginning path, but the editor uses [0].
// So it needs to extend the path by inserting `0` at the head for all
// operations before passing to the backend.
json['operations'] = transaction.operations
.map((e) => e.copyWith(path: [0, ...e.path]).toJson())
.toList();
}
if (transaction.afterSelection != null) {
final selection = transaction.afterSelection!;
final start = selection.start;
final end = selection.end;
json['after_selection'] = selection
.copyWith(
start: start.copyWith(path: [0, ...start.path]),
end: end.copyWith(path: [0, ...end.path]),
)
.toJson();
}
if (transaction.beforeSelection != null) {
final selection = transaction.beforeSelection!;
final start = selection.start;
final end = selection.end;
json['before_selection'] = selection
.copyWith(
start: start.copyWith(path: [0, ...start.path]),
end: end.copyWith(path: [0, ...end.path]),
)
.toJson();
}
return json;
}
}
@@ -0,0 +1,42 @@
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart';
class DocumentService {
Future<Either<DocumentSnapshotPB, FlowyError>> openDocument({
required ViewPB view,
}) async {
await FolderEventSetLatestView(ViewIdPB(value: view.id)).send();
final payload = OpenDocumentContextPB()
..documentId = view.id
..documentVersion = DocumentVersionPB.V1;
// switch (view.dataFormat) {
// case ViewDataFormatPB.DeltaFormat:
// payload.documentVersion = DocumentVersionPB.V0;
// break;
// default:
// break;
// }
return DocumentEventGetDocument(payload).send();
}
Future<Either<Unit, FlowyError>> applyEdit({
required String docId,
required String operations,
}) {
final payload = EditPayloadPB.create()
..docId = docId
..operations = operations;
return DocumentEventApplyEdit(payload).send();
}
Future<Either<Unit, FlowyError>> closeDocument({required String docId}) {
final request = ViewIdPB(value: docId);
return FolderEventCloseView(request).send();
}
}
@@ -1,14 +1,14 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:app_flowy/startup/tasks/rust_sdk.dart';
import 'package:app_flowy/workspace/application/markdown/delta_markdown.dart';
import 'package:app_flowy/plugins/doc/application/share_service.dart';
import 'package:flowy_sdk/protobuf/flowy-text-block/entities.pb.dart';
import 'package:app_flowy/plugins/document/application/share_service.dart';
import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.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';
import 'package:dartz/dartz.dart';
import 'package:appflowy_editor/appflowy_editor.dart'
show Document, documentToMarkdown;
part 'share_bloc.freezed.dart';
class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
@@ -18,11 +18,14 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
: super(const DocShareState.initial()) {
on<DocShareEvent>((event, emit) async {
await event.map(
shareMarkdown: (ShareMarkdown value) async {
await service.exportMarkdown(view.id).then((result) {
shareMarkdown: (ShareMarkdown shareMarkdown) async {
await service.exportMarkdown(view).then((result) {
result.fold(
(value) => emit(
DocShareState.finish(left(_convertDeltaToMarkdown(value)))),
DocShareState.finish(
left(_saveMarkdown(value, shareMarkdown.path)),
),
),
(error) => emit(DocShareState.finish(right(error))),
);
});
@@ -35,38 +38,23 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
});
}
ExportDataPB _convertDeltaToMarkdown(ExportDataPB value) {
final result = deltaToMarkdown(value.data);
value.data = result;
writeFile(result);
ExportDataPB _saveMarkdown(ExportDataPB value, String path) {
final markdown = _convertDocumentToMarkdown(value);
value.data = markdown;
File(path).writeAsStringSync(markdown);
return value;
}
Future<Directory> get _exportDir async {
Directory documentsDir = await appFlowyDocumentDirectory();
return documentsDir;
}
Future<String> get _localPath async {
final dir = await _exportDir;
return dir.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/${view.name}.md');
}
Future<File> writeFile(String md) async {
final file = await _localFile;
return file.writeAsString(md);
String _convertDocumentToMarkdown(ExportDataPB value) {
final json = jsonDecode(value.data);
final document = Document.fromJson(json);
return documentToMarkdown(document);
}
}
@freezed
class DocShareEvent with _$DocShareEvent {
const factory DocShareEvent.shareMarkdown() = ShareMarkdown;
const factory DocShareEvent.shareMarkdown(String path) = ShareMarkdown;
const factory DocShareEvent.shareText() = ShareText;
const factory DocShareEvent.shareLink() = ShareLink;
}
@@ -0,0 +1,30 @@
import 'dart:async';
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-document/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
class ShareService {
Future<Either<ExportDataPB, FlowyError>> export(
ViewPB view, ExportType type) {
var payload = ExportPayloadPB.create()
..viewId = view.id
..exportType = type
..documentVersion = DocumentVersionPB.V1;
return DocumentEventExportDocument(payload).send();
}
Future<Either<ExportDataPB, FlowyError>> exportText(ViewPB view) {
return export(view, ExportType.Text);
}
Future<Either<ExportDataPB, FlowyError>> exportMarkdown(ViewPB view) {
return export(view, ExportType.Markdown);
}
Future<Either<ExportDataPB, FlowyError>> exportURL(ViewPB view) {
return export(view, ExportType.Link);
}
}
@@ -0,0 +1,231 @@
library document_plugin;
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugins/util.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/plugins/document/application/share_bloc.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart';
import 'package:app_flowy/workspace/presentation/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:appflowy_popover/appflowy_popover.dart';
import 'package:clipboard/clipboard.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'document_page.dart';
class DocumentPluginBuilder extends PluginBuilder {
@override
Plugin build(dynamic data) {
if (data is ViewPB) {
return DocumentPlugin(pluginType: pluginType, view: data);
} else {
throw FlowyPluginException.invalidData;
}
}
@override
String get menuName => LocaleKeys.document_menuName.tr();
@override
String get menuIcon => "editor/documents";
@override
PluginType get pluginType => PluginType.editor;
@override
ViewDataFormatPB get dataFormatType => ViewDataFormatPB.TreeFormat;
}
class DocumentPlugin extends Plugin<int> {
late PluginType _pluginType;
@override
final ViewPluginNotifier notifier;
DocumentPlugin({
required PluginType pluginType,
required ViewPB view,
Key? key,
}) : notifier = ViewPluginNotifier(view: view) {
_pluginType = pluginType;
}
@override
PluginDisplay get display => DocumentPluginDisplay(notifier: notifier);
@override
PluginType get ty => _pluginType;
@override
PluginId get id => notifier.view.id;
}
class DocumentPluginDisplay extends PluginDisplay with NavigationItem {
final ViewPluginNotifier notifier;
ViewPB get view => notifier.view;
int? deletedViewIndex;
DocumentPluginDisplay({required this.notifier, Key? key});
@override
Widget buildWidget(PluginContext context) {
notifier.isDeleted.addListener(() {
notifier.isDeleted.value.fold(() => null, (deletedView) {
if (deletedView.hasIndex()) {
deletedViewIndex = deletedView.index;
}
});
});
return DocumentPage(
view: view,
onDeleted: () => context.onDeleted(view, deletedViewIndex),
key: ValueKey(view.id),
);
}
@override
Widget get leftBarItem => ViewLeftBarItem(view: view);
@override
Widget? get rightBarItem => DocumentShareButton(view: view);
@override
List<NavigationItem> get navigationItems => [this];
}
class DocumentShareButton extends StatelessWidget {
final ViewPB view;
DocumentShareButton({Key? key, required this.view})
: super(key: ValueKey(view.hashCode));
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<DocShareBloc>(param1: view),
child: BlocListener<DocShareBloc, DocShareState>(
listener: (context, state) {
state.map(
initial: (_) {},
loading: (_) {},
finish: (state) {
state.successOrFail.fold(
_handleExportData,
_handleExportError,
);
},
);
},
child: BlocBuilder<DocShareBloc, DocShareState>(
builder: (context, state) => ConstrainedBox(
constraints: const BoxConstraints.expand(
height: 30,
width: 100,
),
child: ShareActionList(view: view),
),
),
),
);
}
void _handleExportData(ExportDataPB exportData) {
switch (exportData.exportType) {
case ExportType.Link:
break;
case ExportType.Markdown:
FlutterClipboard.copy(exportData.data)
.then((value) => Log.info('copied to clipboard'));
break;
case ExportType.Text:
break;
}
}
void _handleExportError(FlowyError error) {}
}
class ShareActionList extends StatelessWidget {
const ShareActionList({
Key? key,
required this.view,
}) : super(key: key);
final ViewPB view;
@override
Widget build(BuildContext context) {
final docShareBloc = context.read<DocShareBloc>();
return PopoverActionList<ShareActionWrapper>(
direction: PopoverDirection.bottomWithCenterAligned,
actions: ShareAction.values
.map((action) => ShareActionWrapper(action))
.toList(),
buildChild: (controller) {
return RoundedTextButton(
title: LocaleKeys.shareAction_buttonText.tr(),
onPressed: () => controller.show(),
);
},
onSelected: (action, controller) async {
switch (action.inner) {
case ShareAction.markdown:
final exportPath = await FilePicker.platform.saveFile(
dialogTitle: '',
fileName: '${view.name}.md',
);
if (exportPath != null) {
docShareBloc.add(DocShareEvent.shareMarkdown(exportPath));
showMessageToast('Exported to: $exportPath');
}
break;
case ShareAction.copyLink:
NavigatorAlertDialog(
title: LocaleKeys.shareAction_workInProgress.tr())
.show(context);
break;
}
controller.close();
},
);
}
}
enum ShareAction {
markdown,
copyLink,
}
class ShareActionWrapper extends ActionCell {
final ShareAction inner;
ShareActionWrapper(this.inner);
@override
Widget? leftIcon(Color iconColor) => null;
@override
String get name => inner.name;
}
extension QuestionBubbleExtension on ShareAction {
String get name {
switch (this) {
case ShareAction.markdown:
return LocaleKeys.shareAction_markdown.tr();
case ShareAction.copyLink:
return LocaleKeys.shareAction_copyLink.tr();
}
}
}
Loaded 100 of 1206 files, more files were not shown because too many files have changed in this diff. Show more