Compare commits

..
215 Commits
Author SHA1 Message Date
Richard Shiue e788c71602 fix: padding issue with the select tags (#3929)
* fix: padding issue with the select tags

* chore: better solution from Lucas
2023-11-13 21:41:25 +08:00
Emil 7de2131431 chore: update Russian translations (#3823) 2023-11-13 19:36:41 +08:00
Richard Shiue 47f3702ca9 fix: integration test on kanban (#3928) 2023-11-13 19:32:11 +08:00
Lucas.Xu 3708a5b86a feat: add alignment and indent/outdent toolbar item (#3927)
* chore: rename mobile list toolbar item

* feat: add alignment and indent/outdent toolbar item

* feat: adjust link menu on mobile platform
2023-11-13 18:08:39 +08:00
Richard ShiueandMathias Mogensen a63a7ea611 feat: hidden kanban groups (#3907)
* feat: hide/unhide ui

* chore: implement collapsible side bar and adjust group header (#2)

* refactor: hidden columns into own file

* chore: adjust new group button position

* fix: flowy icon buton secondary color bleed

* chore: some UI adjustments

* fix: some regressions

* chore: proper group is_visible fetching

* chore: use a bloc to manage hidden groups

* fix: hiding groups not working

* chore: implement hidden group popups

* chore: proper ungrouped item column management

* chore: remove ungrouped items button

* chore: flowy hover build

* fix: clean up code

* test: integration tests

* fix: not null promise on null value

* fix: hide and unhide multiple groups

* chore: i18n and code review

* chore: missed review

* fix: rust-lib-test

* fix: dont completely remove flowyiconhovercolor

* chore: apply suggest

* fix: number of rows inside hidden groups not updating properly

* fix: hidden groups disappearing after collapse

* fix: hidden group title alignment

* fix: insert newly unhidden groups into the correct position

* chore: adjust padding all around

* feat: reorder hidden groups

* chore: adjust padding

* chore: collapse hidden groups section persist

* chore: no status group at beginning

* fix: hiding groups when grouping with other types

* chore: disable rename groups that arent supported

* chore: update appflowy board ref

* chore: better naming

* test: fix tests

---------

Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
2023-11-13 16:14:31 +08:00
Kilu.He 7867f0366e feat: support the operations of field in the grid of tauri (#3906)
* feat: support the operations of field in the grid of tauri

* fix: performance optimizate
2023-11-13 14:16:32 +08:00
Lucas.Xu 251c6d22b2 fix: 0.3.8 known issues (#3912)
* fix: add a left padding to align the document and grid field

* fix: emoji picker in the slash menu is too small

* fix: replace the delete icon color with black

* fix: improve snackbar background color

* fix: cannot add new line after toggle list

* feat: set ⭐ as the default icon of getting started

* fix: the titlebar overflows when the title level is too deep

* fix: integration test

* fix: openAI hint text overflow

* fix: integration tests
2023-11-13 12:00:03 +08:00
Lucas.Xu 7cee8e392f feat: adjust cover plugin and support recent section on mobile platform (#3921) 2023-11-13 10:07:46 +08:00
Richard Shiue 765103dd22 chore: share button text color (#3913) 2023-11-12 23:41:10 +08:00
Nathan.fooo 50e612511d feat: using workspace crate deps (#3924)
* chore: workspace deps

* chore: use workspace deps
2023-11-12 21:18:27 +08:00
Nathan.fooo 7eb20b232a feat: adding suffix for user data folder when current cloud type is appflowy cloud (#3918)
* fix: load database fail caused by spawning long run task

* chore: yield long run task

* chore: fmt

* chore: update client api

* feat: copy data between server

* ci: fix af cloud test
2023-11-12 18:00:07 +08:00
Kritarth Sharma 3c7e636b65 fix: added missing hover tooltip to toolbar item (#3786) 2023-11-10 15:42:40 +08:00
Mathias Mogensen 889a313cc2 chore: update to version 0.3.8 (#3902)
* chore: update to version 0.3.8

* chore: Update CHANGELOG.md

* chore: Update CHANGELOG.md
2023-11-09 13:11:33 +08:00
Lucas.Xu 9586ea0e6f feat: display the titles of a view's ancestors and the view's title on the title bar. (#3898)
* feat: add no pages inside tips

* feat: show view's ancestors (include itself) title on bar

* feat: show view's ancestors (include itself) title on bar

* test: add integration tests

* fix: integration tests
2023-11-09 13:11:13 +08:00
Mathias Mogensen 42e7317cd4 fix: notifications setting (#3903)
* fix: notifications setting

* fix: remove dependency in reminder bloc

* test: remove redundant lines
2023-11-09 00:32:10 +01:00
Mathias Mogensen 17651bf64c feat: show notes icon when notes is not empty (#3893)
* feat: show notes icon when notes is not empty

* fix: redundant clone

* chore: update collab and fix after merging main
2023-11-09 00:30:50 +01:00
Nathan.fooo 73f1c211c2 fix: Invalid refresh token (#3879)
* chore: update client api

* chore: update client api

* chore: update client api

* chore: fix clippy

* chore: fix clippy

* ci: fix

* chore: update client api
2023-11-08 21:48:17 +08:00
Lucas.Xu afc6473582 feat: adjust toggle list, callout, quote and divider on mobile (#3894)
* feat: adjust toggle list block

* feat: show block actions when tapping divider

* feat: add toggle list and callout to toolbar

* feat: refactor the emoji picker button

* fix: toggle list integration tests
2023-11-08 21:10:29 +08:00
Kilu.He 663f9d3423 fix: support inserting grid block in editor (#3875)
* fix: support inserting grid block in editor

* feat: support adding view in table

* feat: support the operations of row in tauri grid
2023-11-08 14:13:17 +08:00
Generic-Ripe 5d4142d5b6 chore: update sv.json (#3896)
* Update sv.json

Some small typos

* Rename sv.json to sv-SE.json
2023-11-08 10:14:13 +08:00
Mathias Mogensen fe23183aef feat: add placeholder to card editor (#3870) 2023-11-07 15:58:22 +01:00
Lucas.Xu 8116ea1dba feat: adjust math_equation block and image block on mobile platform (#3890)
* feat: add image toolbar entry

* feat: add ... buttos on math_equation and image block

* fix: review issues

* feat: add copy link and save image to gallery

* feat: support redo / undo on mobile toolbar
2023-11-07 15:24:32 +08:00
Lucas.Xu 3e6529aeb8 chore: add Roboto Mono font family and its regular and italic variants as assets (#3876) 2023-11-06 16:44:21 +08:00
Richard Shiueandnathan c4fc60612f feat: add new group (#3854)
* feat: implement backend logic

* fix: did_create_row not working properly

* fix: did_delete_group not working properly

* fix: test

* chore: fix clippy

* fix: new card not editable and in wrong position

* feat: imlement UI for add new stack

* test: add integration test

* chore: i18n

* chore: remove debug message

* chore: merge conflict

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-11-06 16:17:05 +08:00
Richard Shiue 4d82bb5322 chore: move field width to field settings (#3830)
* refactor: remove unnecessary builder

* feat: add width to field settings

* refactor: field settings logic

* chore: oopsies

* chore: implement UI

* chore: remove GridFieldCellEquatable

* test: rust-lib test fix
2023-11-06 14:48:59 +08:00
Nathan.foooandRichard Shiue 2b684ae7bf test: rename group test (#3790)
* refactor: rename group

* test: add rename group test

* chore: add group operation interceptor

* refactor: impl interceptor trait

* chore: update type option when group change

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2023-11-06 14:39:31 +08:00
Richard Shiue eb54cf99d4 fix: calendar event editor field name overflow (#3877) 2023-11-06 13:03:32 +08:00
Affif MukhlashinandLucas.Xu 85af82acbe chore: update translations for Indonesian (#3864)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-11-06 11:05:42 +08:00
Nathan.fooo 3434d447a7 chore: update collab rev (#3874) 2023-11-06 00:47:20 +08:00
Nathan.fooo 1025b6d553 fix: af cloud sync auth (#3873)
* feat: open workspace

* chore: update env docs

* fix: invalid user callback

* fix: token invalid

* chore: update

* chore: update

* chore: update

* chore: fix test

* chore: fix tauri build
2023-11-05 14:00:24 +08:00
Mathias Mogensen b35d6131d4 feat: inline page reference (#3859)
* feat: more methods of inserting page reference

* test: add tests for inserting document reference

* chore: remove unused import

* chore: update editor ref

* tests: fix test with an interim solution
2023-11-03 21:30:24 +01:00
Yijing Huang bc502c9c5b chore: improve share button text color (#3868) 2023-11-03 12:09:12 -07:00
Kilu.Heandfangwufeng-v 5f49c1748f Fix/tauri warning to error (#3869)
* feat: sort basic function

* fix: eslint error

* fix: deal with conflict

* fix: prevent submit eslint warning code

* fix: modify tauri warning to error

---------

Co-authored-by: fangwufeng-v <fangwufeng.v@gmail.com>
2023-11-03 15:13:49 +08:00
Yijing HuangandLucas.Xu 73ea1a0685 feat:add toast in trash and confirm dialog + fix issues from launch review (#3787)
* chore: improve trash button

* feat: improve restore all&delete all

* refactor: add showFlowyMobileConfirmDialog

* feat: add toast in delete/restore single file

* refactor: refactor to TrashActionType enum

* fix: text invisible in signin page in dark mode

* feat: add FlowyMobileErrorStateContainer to display error state

* refactor: add FlowyMobileStateContainer to handle empty or error state

- Replace MobileErrorPage by FlowyMobileStateContainer.error
- Implement app version in reporting issue on github
- Implement FlowyMobileStateContainer in trash,setting,favorite and mobile view page

* refactor: unify bottom sheet style

- Unify bottom sheet style in add new page, page action, and trash action
- Add icon color in BottomSheetActionWidget for future use
- Add theme color in MobileBottomSheetDragHandle

* chore: unify Appbar style

* chore: remove the more button when trash list is empty

* fix: show bottom sheet error

* fix: fix merge and ui issue

* refactor: refactor ViewPageBottomSheet and origanize code

* chore: add icon color for favorite button

* fix: add missing icon color and delete comments

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-11-02 11:15:15 -07:00
Mathias Mogensen a93d325e6a fix: notification actions lemonade darkmode (#3862) 2023-11-02 17:17:30 +01:00
Kilu.He dc0af0f4c1 feat: support convert external data to nested json (#3848)
* feat: support convert external data to nested json

* fix: add some comment

* fix: code review

* fix: code review

* fix: code view

* fix: code view

* fix: update tauri cargo lock file

* fix: remove reduant function

* fix: parse dir attribute in element

* fix: add comment about parse dir

* fix: code review

* fix: code review

* fix: code review

* fix: code review
2023-11-02 22:13:29 +08:00
Lucas.Xu 1ad85416d8 fix: unable to build macOS universal package on x86 machine (#3863)
* chore: don't use cache when building release package

* fix: set ARCHS = ARCHS_STANDARD on macOS
2023-11-02 15:24:35 +08:00
Lucas.Xu c34a7a92fb feat: support customizing page icon (#3849)
* chore: don't use cache when building release package

* feat: refactor icon widget design

* feat: sync the emoji between page and view

* feat: use cache to store the emoji data to prevent reloading

* feat: customize the emoji item builder

* feat: add i18n and shuffle emoji button

* fix: integration test

* feat: replace emoji picker in Grid and slash menu

* feat: support adding icon on mobile platform

* feat: support adding and removing icon on mobile

* test: add integration tests
2023-11-02 15:24:17 +08:00
Nathan.fooo 21d34d1fe0 chore: update collab rev (#3852) 2023-11-01 14:47:25 +08:00
Nathan.fooo 3e088d48ac refactor: fav and workspace (#3837)
* refactor: workspace

* chore: update collab rev

* test: add data migration test

* fix: test

* fix: tauri build

* test: fix bloc test

* test: fix bloc test

* test: fix bloc test

* chore: restore magic codde
2023-11-01 11:45:35 +08:00
Mathias Mogensen 54dbcb7c5e fix: link to page dialog offset (#3840) 2023-10-31 20:11:32 +01:00
Lucas.Xu 59dff54edb chore: bump version 0.3.7 (#3832) 2023-10-31 09:49:14 +08:00
Mathias Mogensen d358e18f33 fix: add card at the beginning (#3835) 2023-10-30 17:34:37 +01:00
Kilu.He dd9b1fb78f feat: support converting documents to JSON, HTML, or TEXT. (#3811)
* feat: support converting documents to JSON, HTML, or TEXT

* fix: modify the comment

* fix: modify the comment
2023-10-30 12:50:31 +08:00
Nathan.fooo e08a1a6974 feat: enable dispatch event using single thread (#3828)
* refactor: lib dispatch

* chore: type def

* chore: type def

* fix: local set spawn

* chore: replace tokio spawn

* chore: update log

* chore: boxed event

* chore: tauri lock
2023-10-30 12:35:06 +08:00
Richard Shiue 7f4e7e6aa0 chore: bump af board ver (#3825)
* chore: bump af board ver

* fix: select card cell popover opening
2023-10-30 10:13:47 +08:00
Richard Shiue 18bd91936c fix: more board fixes (#3821)
* fix: null check value

* refactor: remove unnecessary blocbuilder

* fix: missing checkbox icon at top of board column
2023-10-29 12:51:34 +08:00
Richard Shiue b9a25f449f refactor: hide ungrouped feature (#3817)
* refactor: remove unused notification and listener

* revert: remove hide_ungrouped from group settings

* chore: add board layout setting

* chore: listen to layout settings on ui

* fix: duplicated group controller initialization

* chore: add a tooltip to the ungrouped items button

* chore: trailing comma
2023-10-29 11:26:49 +08:00
Richard Shiue 993532a2f0 fix: edit card title not working (#3819) 2023-10-28 23:13:27 +08:00
Nikhil RajandRichard Shiue 8a735799c6 Added tooltip when hovering over No-Data (#3612)
* Added tooltip when hovering over NO-Data

* chore: i18n for tooltip

* fix: wrong token

* chore: use flowytooltip

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2023-10-28 22:11:32 +08:00
Kritarth Sharma 197da5f425 fix: removed the parent padding and instead applied padding individually. (#3814)
* fix: Removed the parent padding and instead applied individual padding to each child to ensure it doesn't affect the sidebar divider.

* chore: Addressed comments and made changes
2023-10-28 19:11:52 +08:00
Nathan.fooo e28e5a0649 refactor: rename group (#3815)
* chore: add group operation interceptor

* refactor: impl interceptor trait

* chore: update type option when group change

* test: fix test
2023-10-28 11:48:28 +08:00
Lucas.Xu 09b4e19c9d feat: enable mobile view item drag-and-drop reordering (#3812)
* feat: enable mobile view item draggable

* fix: dragging the view doesn't disable hover effect
2023-10-27 22:42:35 +08:00
Richard Shiue 653c831473 fix: board unit test fix (#3813)
* fix: board unit test fix

* fix: oopsies
2023-10-27 22:33:45 +08:00
Lucas.Xu a2f2cdebb7 feat: set the default font family to Poppins on mobile (#3810) 2023-10-27 15:19:37 +08:00
Lucas.Xu 59e0a1325e fix: mobile page issues and improvements (#3809)
* chore: update connectivity plus to 5.0.1

* feat: update favorite status on time

* fix: text overflow

* feat: implement ... button in editor page

* fix: align the icon and the text on the favorite page

* feat: enable feedback when tapping icons
2023-10-27 13:36:09 +08:00
Mayur Mahajan c0446d7a96 chore: update de translation for select option (#3804) 2023-10-27 13:34:44 +08:00
Devas45 1fbee02731 fix: german date format (#3806) 2023-10-27 11:44:44 +08:00
dodaucy 102fdbce5c fix: change appflowy.io link from http to https (#3808) 2023-10-27 11:38:58 +08:00
Richard Shiue 71c6beb882 chore: adjust placeholder color for dark theme (#3799) 2023-10-26 22:39:43 +08:00
Richard Shiue ce83042317 chore: improve checklist ui (#3798) 2023-10-26 22:24:23 +08:00
Bryan Olivares 03598d3f22 fix: plus symbol in select option overflows (#3789)
* Fixed overflow problem for plus symbol

* Wrapping SizedBox with Flexible is not needed
2023-10-26 22:03:43 +08:00
Shreesh Nautiyal c2eb2014a3 feat: segmented checklist progress bar (#3770)
* feat: added segments to the checklist progress bar

* chore: display empty progress bar in checklist editor when no tasks added

* refactor: used Container to represent segments

* refactor: implemented segments using Flexible and generated them using List.generate
2023-10-26 18:28:55 +08:00
Lucas.Xu 9416ba1bfc feat: add new database on mobile platform (#3788)
* chore: downgrade clipboard package

* fix: update i18n in the favorite page

* fix: update the favorite icon

* feat: support add new database

* chore: disable cache in unit test

* chore: bump version 0.3.7
2023-10-26 11:57:14 +08:00
Richard Shiue 8c3984d21a feat: allow hiding ungrouped stack (#3752)
* feat: allow hiding ungrouped stack

* chore: add notifications and listeners

* chore: implement UI

* fix: field info update

* chore: more responsive notification

* chore: read the right configurations

* feat: add ungrouped button

* fix: new board not getting isGroupField

* feat: refresh the counter

* fix: item count update

* chore: apply code suggestions from Mathias

* chore: yolo through tests

* chore: UI fix

* chore: code cleanup

* chore: ungrouped item count fix

* chore: same as above
2023-10-26 11:48:58 +08:00
Generic-Ripe 1883dd6d7c Update sv.json (#3778)
Some small changes of errors and small improvements of readability.
2023-10-26 10:44:50 +08:00
Regulus Corneas a354f9fe52 chore: update french translation (#3774)
* inlang: update translations

* inlang: update translations

* inlang: update translations
2023-10-26 10:44:18 +08:00
Richard Shiue 41e2c74b5e feat: save card orders (#3730) 2023-10-26 10:05:43 +08:00
Mathias Mogensen 74d9d427bd feat: show block in notification item (#3736)
* feat: show block in notification item

* feat: jump to block action

* fix: conflict after merge main

* fix: missing import after merge main
2023-10-26 09:41:03 +08:00
Mathias MogensenandRichard Shiue aa27c4e6d4 Feat: rename stack inline (#3781)
* feat: rename stack in-line

* feat: rename stack in-line

* chore: compiler issues

* fix: conflicts and cleaning

* fix: code lost after merge

* test: fix failing rust tests

* fix: tauri localization wrong keys

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2023-10-26 09:38:37 +08:00
Mathias Mogensen f40ae9ff25 fix: what is new button broken link (#3785) 2023-10-25 21:05:28 +02:00
Mathias Mogensen e66087861b feat: insert date from slash menu (#3783) 2023-10-25 19:31:21 +02:00
Lucas.Xu 147637fcf5 fix: iOS TestFlight issues (#3776)
* fix: transparent icons on iOS platform

* fix: remove unused unit tests

* chore: update flutter version

* feat: support building release packages for iOS and Android

* fix: integration test failed randomly

* chore: remove windows CI cache

* chore: update info.plist

* feat: build iOS and Android in Release mode

* chore: update editor version

* chore: don't cache flutter when testing

* chore: run unit test on Windwos
2023-10-25 23:33:46 +08:00
Nathan.fooo 48582cb718 test: Af cloud workspace member (#3779)
* chore: implement workspace memeber events

* chore: add workspace member test

* chore: fix fmt
2023-10-25 21:35:47 +08:00
Yijing Huang ad21a61ffb feat: mobile setting page, trash page and recent file UI with mock data (#3734) 2023-10-25 21:29:50 +08:00
Nathan.fooo d34eec1d99 chore: rename files name that might cause ci fail (#3777) 2023-10-25 15:25:31 +08:00
Lucas.Xu 95aeac201f chore: remove the unit tests of Windows and macOS (#3771)
* chore: remove the unit tests of Windows and macOS

* chore: update pubspec

* chore: update languages
2023-10-25 09:21:20 +08:00
Nathan.fooo cceee80799 fix: anon user error (#3772)
* fix: anon user error

* ci: fix tests
2023-10-24 23:13:51 +08:00
Nathan.fooo 71f80be8f7 feat: save user metadata (#3754)
* feat: save user metadata

* chore: update client api

* refactor: separate test methods

* chore: save updated at

* chore: clippy

* chore: fix test
2023-10-24 20:11:06 +08:00
16a4babdca fix: The appearance of slash menu didn't change along with theme mode changes (#3630) (#3706)
* fix: The appearance of slash menu didn't change along with theme mode changes (#3630)

* revert: pubspec.lock change

* fix: use context inside of function

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: Yijing Huang <hyj891204@gmail.com>
2023-10-24 17:43:25 +08:00
Nebiyu 85c0622245 feat: add amharic translation (#3732) 2023-10-24 17:41:46 +08:00
Pedro Coelho e3410ec568 chore: update pt-PT translations (#3712)
* inlang: update translations

* inlang: update translations
2023-10-24 17:16:48 +08:00
ZakandLucas.Xu c0b0f12b0d fix: font size text being displayed out of range. (#3766)
* fix: font size text being displayed out of range.

* chore: refactor code

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-10-24 14:04:13 +08:00
Mayur Mahajan 70a2b7d9ab fix: add light and dark theme for codeblock (#3748)
* feat: add separate themes for codeblock

* feat: light and dark themes in codeblock
2023-10-24 14:01:34 +08:00
Lucas.Xu a84c47dc33 feat: android deeplink and update icons (#3769)
* feat: android deeplink and update icons

* chore: remove integration test
2023-10-24 13:52:55 +08:00
Lucas.Xu 56c5d69b0f feat: redefine i18n for editor (#3768) 2023-10-24 13:39:05 +08:00
Richard Shiue 6c3d7d2079 feat: show checklist items inline in row page (#3737)
* feat: show checklist items inline in row page

* fix: tauri build
2023-10-24 10:15:28 +08:00
Mohammad Zolfaghari 25a98cda81 ci: reduce build time (#3519) 2023-10-23 22:17:11 +08:00
Mathias Mogensen cd6e133c86 fix: notification settings initial state (#3763) 2023-10-23 14:51:59 +02:00
Richard Shiue b16a102f85 chore: improve setting tab bar dropdown (#3756)
* chore: improve setting tab bar dropdown

* test: fix integration tests
2023-10-23 19:23:27 +08:00
Lucas.Xu d51c7f382f feat: implement personal / favorites folder on the mobile platform (#3723) 2023-10-23 18:35:07 +08:00
Richard Shiue a57ca5c0cb fix: integration tests failing on Sundays (#3753) 2023-10-23 11:44:04 +08:00
Nathan.fooo 1e9137fcfe chore: update client api commit id (#3745)
* chore: update client api commit id

* chore: fix test

* chore: remove check_visual_studio_installation task

* chore: update client api
2023-10-23 11:43:31 +08:00
Shreesh Nautiyal 8e5b6b6e27 fix: the horizontal scrollbar disappearing in grid view (#3751) 2023-10-23 10:30:47 +08:00
Kilu.He 7e101b8bf1 fix: slash command panel bugs (#3722) 2023-10-23 10:25:47 +08:00
Lucas.Xu bf0cfa798c fix: windows CI build failed (#3741) 2023-10-22 01:04:38 +08:00
Richard Shiue 1793a28cbc fix: calendar event card not displaying as intended (#3731) 2023-10-19 18:19:50 +08:00
Lucas.Xu e565d0ee32 feat: support building on Android (#3713)
* feat: support building on Android

* chore: add CI for mobile platform
2023-10-19 09:55:23 +08:00
Sumit BanwakadeandRichard Shiue f60462a853 fix: side panel animation (#3605)
* fix: side panel animation

* Fix: Side Panel Animation Changes

* Fix:Panel Animation

* fix:updated animation to easeOutQuad

* fix: updated animation to easeOutQuad

* Fix:Panel Side Animation

* fix:panel side animation

* chore: restore settings.json

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2023-10-18 15:48:26 +08:00
Mathias Mogensen 966547faa0 fix: reminder launch review (#3716) 2023-10-17 14:48:58 +08:00
Muhammad Saad Tanveer 3647af44c9 fix: Shortcut settings Reset to default is missing bottom margin #3710 (#3715) 2023-10-17 05:47:07 +02:00
Lucas.Xu 25b4a647b0 fix: unable to export image to markdown (#3709) 2023-10-16 15:56:30 +08:00
Lucas.Xu c6e3c1fd7c feat: customizing the background of a block with theme color (#3691) 2023-10-16 14:11:05 +08:00
ルビーDog 4fd35d0de4 feat: improve translations ja_JP (#3702) (#3705) 2023-10-16 10:56:06 +08:00
Lucas.Xu 7406c5e6a5 feat: add toggle list and callout node parser (#3700) 2023-10-16 10:09:33 +08:00
CrazyRikin aa70885b21 feat: added hindi translation (#3575) 2023-10-15 22:13:14 +08:00
Yijing Huang 8699c9c125 fix: lemonade theme issues (#3686) 2023-10-15 22:12:25 +08:00
Pedro Coelho bc758e0b06 chore: update translations pt-PT (#3687) 2023-10-15 22:12:01 +08:00
Jakob Gerhardt e38980ccc3 chore: update translations de-DE (#3693) 2023-10-15 22:11:28 +08:00
Verdy Bangkit 8dd180046f chore: update translations id_ID and ru_RU (#3701) 2023-10-15 22:10:41 +08:00
Lucas.Xu 0cd2726752 chore: disable toolbar in code block (#3682) 2023-10-15 22:01:17 +08:00
Lucas.Xu 11daa15b89 feat: auto pop up the menu after inserting image block (#3698) 2023-10-15 13:04:24 +08:00
Lucas.Xu 8436bc6144 fix: the disk space of CI machines always runs out (#3689) 2023-10-14 20:37:44 +08:00
Ekaksh JanwejaandLucas.Xu 59851f46b7 feat: edit the field by clicking on the drag icon (#3656)
* feat: edit the field by clicking on the drag icon

* Added localization

* Added .tr() function

* fix: BlockActionButton only show when _isFieldHover is true.

* fix: BlockActionButton only show when _isFieldHover is true.

* fix: Worked on requested changes

* fix: Fixed Location of Field Popover

* fixed pubspec.lock

* Updated pubspec.lock

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-10-13 23:47:49 +08:00
Sarthak Kimtani 62f1d6eb82 fix: 3620 unchecked checkbox color (#3685) 2023-10-13 21:06:13 +08:00
Nathan.fooo ec80f72c8f feat: af cloud database (#3684)
* chore: forece user to logout when token is invalid

* chore: update client api rev
2023-10-12 20:25:00 +08:00
Richard Shiue b2c80981cc fix: build app (#3681) 2023-10-11 22:46:32 -07:00
Yijing Huang 8fa425a76c chore: bump version 0.3.6 (#3680) 2023-10-12 13:14:37 +08:00
Mathias Mogensen ebe112581d feat: toggle notifications on/off (#3672) 2023-10-12 12:54:08 +08:00
Mathias Mogensen bc8f35d7db feat: reminder improvements (#3658) 2023-10-12 10:19:36 +08:00
Nathan.fooo 058eeec932 feat: implement file storage using appflowy cloud (#3675)
* feat: implement file storage using appflowy cloud

* chore: clippy
2023-10-12 09:54:45 +08:00
Lucas.Xu 8e10cba8e5 feat: support toggling the markdown style by shortcuts (#3674) 2023-10-11 23:12:23 +08:00
Yijing Huang 7a24f6b6f0 feat: add lemonade theme color (#3666) 2023-10-11 22:01:05 +08:00
Richard Shiue 4f40945458 fix: integration tests (#3673)
* fix: fix integration tests

* fix: initiate isScreenSmall properly
2023-10-11 20:36:10 +08:00
Nathan.fooo e59870e421 refactor: rename flowy-test to event-integration (#3667) 2023-10-11 20:02:09 +08:00
Tran Nguyen Sinh cf521fe20b chore: update translations for Vietnamese (#3632) 2023-10-11 17:15:59 +07:00
Mathias Mogensen f0d47ee50c fix: esc to close date picker dialog (#3648) 2023-10-11 05:49:32 +02:00
Lucas.Xu 2a5d393c9f fix: missing dependency (libnotify) in appimage (#3665) 2023-10-11 09:46:59 +08:00
Shreesh Nautiyal 98e0b832ec feat: 1674 Auto-hide sidebar when re-sizing the window (#3659)
* feat: 1674 Auto-hide sidebar when re-sizing the window

* chore: removed unnecessary print statements

* chore: updated to a more approprite name for 'screenSmall' event
2023-10-10 19:26:11 +02:00
Nathan.fooo 77e7cbe9ec chore: sync document (#3653)
* chore: sync document

* chore: update collab rev

* chore: update collab rev
2023-10-10 19:05:55 +08:00
Dhruv Sharma acd53eb640 fix: correct svg for row actions (#3664)
Closes: #3450
2023-10-10 17:30:44 +08:00
Lucas.Xu ffdf5d24a0 fix: openAI image expiration (#3660)
* feat: save the openAI image to local storage

* feat: support rendering error block

* fix: enter on Toggle list moves heading down without contents
2023-10-10 12:43:31 +08:00
Dhruv Sharma b247a49417 chore: resolve issue (#3621) 2023-10-09 20:47:24 +02:00
Lucas.Xu dace02d34d feat: generate image by Stability AI / openAI (#3642) 2023-10-09 23:14:24 +08:00
Muhammad Saad Tanveer 41d4351176 feat: 3625 Added Ukrainian Language (#3644) 2023-10-09 12:19:35 +08:00
Lucas.Xu d4bc575c03 fix: image block issues (#3637) 2023-10-07 13:45:38 +08:00
Nathan.fooo a59561aee3 chore: sign in with provider (#3592)
* chore: sign in with provider

* feat: implement oauth flow of appflowy cloud

* chore: rename env

* chore: fix deadlock

* fix: login bugs

* chore: clippyt

* chore: update client api

* chore: fmt
2023-10-07 09:58:44 +08:00
Mathias Mogensen 92523321f1 fix: notification button delayed tooltip (#3635) 2023-10-06 09:29:36 +02:00
Richard Shiue 537c9d0865 fix: wrong date selected in CDT (#3627) 2023-10-06 10:13:46 +08:00
Richard Shiue b4051c7e9f fix: url underline issue (#3618) 2023-10-05 17:35:50 +08:00
Richard Shiue 9e61133886 chore: bump version 0.3.5 (#3616) 2023-10-05 12:01:38 +08:00
Lucas.Xu 36f47f3636 feat: image block revamp (#3615) 2023-10-05 10:40:41 +08:00
Mayur Mahajan 40dcd13394 refactor: ui improvement in appearance (#3553) 2023-10-05 09:48:19 +08:00
Yijing Huang eb20c7c117 feat: emoji picker improvement (#3591) 2023-10-05 09:36:29 +08:00
Devanshu Rawat e9852a3934 fix: restore page banner ui improvement (#3604) 2023-10-05 09:34:36 +08:00
Alazar GeneneandAlazar Genene 78d8ec9a3e fix: use Image.file instead of DecoratedBox and FileImage (#3606)
Co-authored-by: Alazar Genene <alazargenene@Alazars-MacBook-Pro-2.local>
2023-10-04 23:48:31 +02:00
Juan David 4220309cf8 Updated translation part in project readme (#3609) 2023-10-04 15:50:42 +02:00
Jaskeerat Singh 812af0979e Fix: Missing WhiteSpace b/w Primary Field Text and Row Icon (#3602)
* Update link to OS Specific Development

* fix: Missing white space b/w primary field text & row's icon

* fix: Updated emoji padding
2023-10-04 11:50:26 +02:00
Narayan cca5005541 fix: remove current page link option in page reference (#3600)
* fix: remove current page link option in page reference

* fix: removed context and added view id as parameter
2023-10-04 11:49:22 +02:00
Mathias Mogensen 9306d4a4ee docs: update links in readm (#3589) 2023-10-04 11:35:37 +02:00
Ahsan AhmadandLucas.Xu 3ab1ff5e73 fix:The placeholder text for URL cells shouldn't be underlined (#3565)
* fix:The placeholder text for URL cells shouldn't be underlined

* Update frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/url_cell/url_cell.dart

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-10-04 11:35:02 +02:00
Aditya AroraandMathias Mogensen 05fa306782 feat: Delay tooltip presentations by 300ms (#3558)
* feat:added wait duration to ToolTip widgets

* feat:added wait Duration to more tooltips

* feat:added wait Duration to more_button tooltip

* fix: use flowytooltip

* fix:undo install_macos.sh file

* fix:undo install_macos.sh file

* fix:refactored FlowyTooltip.delayedTooltip to FlowyTooltip.delayed

---------

Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
2023-10-04 11:34:44 +02:00
Mathias Mogensen d054439df4 fix: provide default options for inline actions always (#3601) 2023-10-03 18:07:46 +02:00
Jaskeerat Singh 15aaacc4b7 Update link to OS Specific Development (#3590) 2023-10-02 20:12:02 +02:00
Mathias Mogensen ef9de52cbc docs: update link to conventions (#3581) 2023-10-02 15:48:02 +02:00
Lucas.Xu 8d9d0e9358 chore: bump version 0.3.4 (#3572)
* chore: bump version 0.3.4

* fix: docker file build
2023-10-02 20:48:56 +08:00
7f44b181bd feat: integrate client-api (#3430)
* chore: update client-api rev

* chore: update collab rev id

* feat: add sign_in_request and import shared entity

* feat: added to userworkspace from af_workspace

* chore: add script to update the client-api rev id

* chore: update client-api rev

* feat: add workspaces api

* feat: added check user

* chore: config

* chore: update client_api version

* chore: ws connect

* chore: ws connect

* chore: update crate versions

* chore: rename event

* chore: update client-appi

* chore: set appflowy cloud env

* chore: add env template

* chore: update env name

* docs: update docs

* fix: check_user

* feat: impl sign_in_with_url

* feat: add file storage placeholders

* chore: update client-api

* chore: disable test

* feat: impl workspace add and remove

* chore: sign up test

* feat: select cover image on upload (#3488)

* fix: close popover after item selection in settings view (#3362)

* fix: close popover after item selection in settings view

* fix: add missing await before closing popover

* fix: find popover container by context instead of passing controllers around

* fix: add requested changes

* feat: close text direction settings popups after selection

* fix: clean up

* fix: restore theme value dropdown as StatefulWidget

* feat: openai and stabilityai integration (#3439)

* chore: create trait

* test: add tests

* chore: remove log

* chore: disable log

* chore: checklist ux flow redesign (#3418)

* chore: ux flow redesign

* chore: remove unused imports

* fix: allow creation of tasks of the same name

* chore: apply code suggestions from Mathias

* fix: add padding below field title text field (#3440)

* Fixed Issue no #3426

* Reversed the pubspec.lock mistaken update

* FIXED PADDING

* Fixed Padding issue on calender field edit popup

* chore: rename package name (#3501)

* fix: right icon size sam as left one (#3494)

* feat: enable removing user icon (#3487)

* feat: enable removing user icon

* fix: generate to true

* fix: review comments

* fix: more review comments

* fix: integration test and final changes

* fix: made cursor grab and background color when hovering on Appearance Options Buttons (#3498)

* chore: calendar UI polish (#3484)

* chore: update calendar theming

* feat: add event popup editor

* chore: new event button redesign and add card shadows

* chore: unscheduled events button

* chore: event title text field

* fix: focus node double dispose

* chore: show popover when create new event

* test: integrate some tests for integration testing purposes

* fix: some fixes and more integration tests

* chore: add more space between font item and font menu

* feat: add reset font button in toolbar

* feat: only show text direction toolbar item when RTL is enabled

* fix:  unable to change RTL of heading block

* test: add integration test for ltr/rtl mode

* chore: update inlang project settings (#3441)

* feat: using script to update the collab source. (#3508)

* chore: add script

* chore: update script

* chore: update bytes version

* chore: submit lock file

* chore: update test

* chore: update test

* chore: bump version

* chore: update

* ci: fix

* ci: fix

* chore: update commit id

* chore: update commit id

* chore: update commit id

* fix: is cloud enable

---------

Co-authored-by: Fu Zi Xiang <speed2exe@live.com.sg>
Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
Co-authored-by: Vincenzo De Petris <37916223+vincendep@users.noreply.github.com>
Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
Co-authored-by: Aryan More <61151896+aryan-more@users.noreply.github.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com>
Co-authored-by: Nitin-Poojary <70025277+Nitin-Poojary@users.noreply.github.com>
Co-authored-by: Jannes Blobel <72493222+jannesblobel@users.noreply.github.com>
2023-10-02 17:22:22 +08:00
Aman Negi 01c3fec5aa feat: improve snackbar UI style (#3562) 2023-10-02 15:14:40 +08:00
Mathias Mogensen 94a3a59001 fix: avoid non-null promise on null value (#3569) 2023-10-02 15:13:39 +08:00
Mathias Mogensen 4a433a3176 feat: reminder (#3374) 2023-10-02 15:12:24 +08:00
Ricky Putra f7749bdccc chore: add integration tests for user language settings (#3560) 2023-10-02 13:55:57 +08:00
Lucas.Xu c864e836ee feat: integrate find and replace into AppFlowy (#3566)
* chore: update editor version

* feat: redesign find and replace ui

* chore: update language file
2023-10-02 13:54:51 +08:00
Richard Shiue 0738b5f87d feat: show hidden fields in row detail page (#3545) 2023-10-02 10:52:22 +08:00
Anurag De 6198c3907f fix: updated githook helper link (#3563) 2023-10-02 10:07:51 +08:00
Ahsan AhmadandMathias Mogensen 891d794900 fix:Spacing above New row in grid (#3564)
* fix:Spacing above New row in grid

* revert: update frontend/appflowy_flutter/ios/Podfile.lock

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2023-10-01 23:22:21 +02:00
Yijing Huang 890f52a00a feat: dandelion theme improvement (#3550) 2023-09-28 14:18:40 +08:00
Yijing Huang d007f98af6 fix: emoji picker menu issue (#3551) 2023-09-28 14:18:01 +08:00
Yijing Huang 15e9d65798 feat: go_router refactor and bottom navigation bar in mobile (#3459) 2023-09-28 14:17:38 +08:00
Lakhan Baheti 0626f0deb7 fix: on hover change_cover button correct mouse cursor (#3548) 2023-09-27 22:59:33 +08:00
Richard Shiue 007c649c31 fix: still show drag icon while dragging (#3547)
* fix: still show drag icon while dragging

* chore: use click cursor on windows
2023-09-27 20:02:44 +08:00
Norbert 34ea508f5b chore: update pl-PL translations (#3539) 2023-09-27 15:35:45 +08:00
fangwufeng-v f70aef68be feat: drag and drop a row in the Grid (#3376)
* feat: new style ui

* feat: drag row

* feat: hooks for auto scroll feature when dragging

* feat: shared UI status that control auto scroll when dragging row.

* feat: optimize the drag interaction UI effect

* feat: refactor drag positon

* feat: drag column header

* feat: fix review issue
2023-09-27 15:13:25 +08:00
Borris 61a31c90ee chore: update translations for id-ID (#3518) 2023-09-27 11:32:49 +08:00
Richard Shiue c7e3ed805a fix: checklist cell style for checklist cells (#3538) 2023-09-26 22:31:15 +08:00
Lucas.Xu d36a846425 chore: update CHANGELOG.md 2023-09-26 16:55:49 +08:00
Lucas.Xu a02ec98e9c fix: undo failed in nested list 2023-09-26 16:55:49 +08:00
Lucas.Xu 32c06cf1bf fix: clear selection when editing inline database view 2023-09-26 16:55:49 +08:00
Lucas.Xu cf1096b516 fix: undo failed in nested list 2023-09-26 16:55:49 +08:00
Lucas.Xu 938953d7b3 fix: unable to parse html text which contains <mark> tag (#3529) 2023-09-26 14:37:10 +08:00
Mathias Mogensen 949dab9afe fix: on hover/enter issue for view items (#3528) 2023-09-25 12:12:43 +02:00
Narayan 0996f5fd24 fix: missing the hand gesture icon in the text alignment options (#3509) 2023-09-24 21:42:11 +08:00
Lucas.Xu 6e887f1f12 chore: bump version 0.3.3 (#3517) 2023-09-24 20:28:31 +08:00
Richard Shiue ab9338eb89 fix: some issues with the end date (#3495) 2023-09-24 20:26:18 +08:00
Lakhan Baheti fd4088aed0 fix: grid theming to bottom row count number (#3510)
* fix: theming to bottom count number

* refactor: Row to RichText
2023-09-24 20:25:47 +08:00
Richard Shiue 375ff5ed6d refactor: use same bloc in grid and cards (#3511) 2023-09-24 20:24:38 +08:00
Ahsan Ahmad 847290d9a4 fix: remove max length of 30 while creating a new select option (#3513) 2023-09-24 19:14:25 +08:00
Nathan.fooo 56687581f2 feat: using script to update the collab source. (#3508)
* chore: add script

* chore: update script

* chore: update bytes version

* chore: submit lock file
2023-09-24 15:50:58 +08:00
Jannes Blobel 3be39f5e7b chore: update inlang project settings (#3441) 2023-09-23 23:41:56 +08:00
Lucas.Xu 1997231adf Merge pull request #3500 from LucasXu0/fix_032_launch_review_issues
fix launch review(v0.3.3) issues
2023-09-23 12:50:57 +08:00
Lucas.Xu 89face4f02 test: add integration test for ltr/rtl mode 2023-09-23 11:31:08 +08:00
Richard Shiue 37ddce3a29 chore: calendar UI polish (#3484)
* chore: update calendar theming

* feat: add event popup editor

* chore: new event button redesign and add card shadows

* chore: unscheduled events button

* chore: event title text field

* fix: focus node double dispose

* chore: show popover when create new event

* test: integrate some tests for integration testing purposes

* fix: some fixes and more integration tests
2023-09-23 09:47:48 +08:00
Nitin-Poojary 593df96b10 fix: made cursor grab and background color when hovering on Appearance Options Buttons (#3498) 2023-09-22 19:03:18 +02:00
Mathias Mogensen 1b966171c4 feat: enable removing user icon (#3487)
* feat: enable removing user icon

* fix: generate to true

* fix: review comments

* fix: more review comments

* fix: integration test and final changes
2023-09-22 15:20:07 +02:00
Lakhan Baheti 047f1a0b39 fix: right icon size sam as left one (#3494) 2023-09-22 12:25:27 +02:00
Lucas.Xu f2f3506b29 fix: unable to change RTL of heading block 2023-09-22 17:13:08 +08:00
Lucas.Xu 0ccced4b54 chore: rename package name (#3501) 2023-09-22 16:32:18 +08:00
Lucas.Xu f762a564b5 feat: only show text direction toolbar item when RTL is enabled 2023-09-22 15:59:21 +08:00
Lucas.Xu 57b78ee3c6 feat: add reset font button in toolbar 2023-09-22 15:49:11 +08:00
Lucas.Xu 5dfc470873 chore: add more space between font item and font menu 2023-09-22 13:53:14 +08:00
Aryan More d5f8ce5435 fix: add padding below field title text field (#3440)
* Fixed Issue no #3426

* Reversed the pubspec.lock mistaken update

* FIXED PADDING

* Fixed Padding issue on calender field edit popup
2023-09-22 11:15:18 +08:00
Richard Shiue 3c65a96b04 chore: checklist ux flow redesign (#3418)
* chore: ux flow redesign

* chore: remove unused imports

* fix: allow creation of tasks of the same name

* chore: apply code suggestions from Mathias
2023-09-22 09:33:24 +08:00
Nathan.fooo 6ba7fc0317 feat: openai and stabilityai integration (#3439)
* chore: create trait

* test: add tests

* chore: remove log

* chore: disable log
2023-09-21 12:41:52 +08:00
Vincenzo De Petris 37a5054ebd fix: close popover after item selection in settings view (#3362)
* fix: close popover after item selection in settings view

* fix: add missing await before closing popover

* fix: find popover container by context instead of passing controllers around

* fix: add requested changes

* feat: close text direction settings popups after selection

* fix: clean up

* fix: restore theme value dropdown as StatefulWidget
2023-09-21 11:23:28 +08:00
Mathias Mogensen 048434024b feat: select cover image on upload (#3488) 2023-09-21 04:02:39 +02:00
Nitin-Poojary 2c757e9b6c fix: set minimum width for grid fields to 50px (#3397)
* fix: set minimum width for grid field to 100px

* test: add grid field width test

* fix: field width should not be less then 50px

* test: grid field width should not be less then 50px

* fix: cursor-based resizing issue

* test: updated tests
2023-09-21 09:39:13 +08:00
Lucas.Xu 9c59e1487e feat: customize text font (#3467)
* feat: update UI in settings page

* feat: customzing font in document page

* fix: flutter analyze and format issues
2023-09-21 09:12:25 +08:00
Mathias Mogensen 4b9b723521 fix: add bottom border to new property column (#3486) 2023-09-21 03:10:41 +02:00
Vyshnav Ajith a389836897 Added Language Support for Urdu. Issue#3372 (#3469)
* Create ur.json

* Add files via upload

* changes

* Added Locale change to the supported Locales List

* Added Urdu in Language.dart

* Delete .vscode/launch.json

* Changed the icon for Calendar
2023-09-20 17:31:17 +02:00
Mathias Mogensen eec7723ce0 fix: tests for interacting with viewitem (#3472) 2023-09-20 23:14:04 +08:00
Lucas.Xu 2f938a331f Merge pull request #3468 from LucasXu0/fix_build_error_on_xcode15
fix: build error on Xcode 15
2023-09-20 20:32:28 +08:00
Lucas.Xu 847d7cb35a fix: build error on Xcode 15 2023-09-20 15:28:27 +08:00
Onyedika Israel Ukwueze 094f8fc307 fix: visual bug on board accessory 2023-09-19 16:02:19 +08:00
Yatendra Kumarandnathan e3f11ea9c0 feat: integrated openAI rust plugin (#3302)
* feat: create flowy-plugins

* feat: integrated openai service with interface

* feat: integrated openai api call

* fix: response in api

* fix: removed unused imports

* fix: remove parse.rs

* fix: macos version + removed print

* fix: removed debugPrint + changed deployment target

* fix: android project+removed gesture detector

* fix: removed unused imports

* chore: fix compile

* chore: rever changes

* chore: rever changes

* chore: fix clippy warnings

* chore: rename

* chore: fix compile error

* chore: remove dart ai

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-09-19 10:37:37 +08:00
Richard Shiueandnathan 124d435f09 feat: add end date to time cell data (#3369)
* feat: add end date to time cell data

* feat: implement ui for end time

* test: add date to text test

* chore: clippy warnings

* fix: unexpected time parsing

* fix: fix the date logic when toggling end date

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-09-19 09:58:15 +08:00
Mathias Mogensen b700f95c7f fix: do not rebuild hover on item selection (#3423) 2023-09-18 16:39:30 +08:00
1383 changed files with 56024 additions and 22364 deletions

No files matched your search

+1 -1
View File
@@ -44,7 +44,7 @@ test "" = "$(grep '^Signed-off-by: ' "$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/code-submission-guidelines#commit-message-guidelines"
printError "https://docs.appflowy.io/docs/documentation/software-contributions/conventions/git-conventions"
exit 1
fi
+1 -1
View File
@@ -21,7 +21,7 @@ Before you mark this PR ready for review, run through this checklist!
#### PR Checklist
- [ ] My code adheres to the [AppFlowy Style Guide](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/style-guides)
- [ ] My code adheres to [AppFlowy's Conventions](https://docs.appflowy.io/docs/documentation/software-contributions/conventions)
- [ ] I've listed at least one issue that this PR fixes in the description above.
- [ ] I've added a test(s) to validate changes in this PR, or this PR only contains semantic changes.
- [ ] All existing tests are passing.
+301 -45
View File
@@ -22,15 +22,297 @@ on:
- "!frontend/appflowy_tauri/**"
env:
FLUTTER_VERSION: "3.10.1"
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.10.4"
RUST_TOOLCHAIN: "1.70"
CARGO_MAKE_VERSION: "0.36.6"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
prepare:
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
target: x86_64-unknown-linux-gnu
- os: macos-latest
flutter_profile: development-mac-x86_64
target: x86_64-apple-darwin
- os: windows-latest
flutter_profile: development-windows-x86
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
# the following step is required to avoid running out of space
- name: Maximize build space
if: matrix.os == 'ubuntu-latest'
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- name: Checkout source code
uses: actions/checkout@v2
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
target: ${{ matrix.target }}
override: true
profile: minimal
- name: Install flutter
id: flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ matrix.os }}
workspaces: |
frontend/rust-lib
cache-all-crates: true
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}, duckscript_cli
- name: Install prerequisites
working-directory: frontend
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 libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
elif [ "$RUNNER_OS" == "Windows" ]; then
vcpkg integrate install
elif [ "$RUNNER_OS" == "macOS" ]; then
echo 'do nothing'
fi
cargo make appflowy-flutter-deps-tools
shell: bash
- name: Build AppFlowy
working-directory: frontend
run: |
cargo make --profile ${{ matrix.flutter_profile }} appflowy-core-dev
- name: Run code generation
working-directory: frontend
run: |
cargo make code_generation
- name: Flutter Analyzer
working-directory: frontend/appflowy_flutter
run: |
flutter analyze .
- name: Compress appflowy_flutter
run: tar -czf appflowy_flutter.tar.gz frontend/appflowy_flutter
- uses: actions/upload-artifact@v3
with:
name: ${{ github.run_id }}-${{ matrix.os }}
path: appflowy_flutter.tar.gz
unit_test:
needs: [prepare]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [macos-latest]
include:
- os: macos-latest
flutter_profile: development-mac-x86_64
target: x86_64-apple-darwin
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
target: ${{ matrix.target }}
override: true
profile: minimal
- name: Install flutter
id: flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ matrix.os }}
workspaces: |
frontend/rust-lib
cache-all-crates: true
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}, duckscript_cli
- name: Install prerequisites
working-directory: frontend
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
cargo make appflowy-flutter-deps-tools
fi
shell: bash
- name: Run Flutter unit tests
working-directory: frontend
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
flutter config --enable-macos-desktop
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
cargo make dart_unit_test
else
cargo make dart_unit_test_no_build
fi
shell: bash
- name: Upload coverage to Codecov
uses: Wandalen/wretry.action@v1.0.36
with:
action: codecov/codecov-action@v3
with: |
name: appflowy
flags: appflowy_flutter_unit_test
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 20
attempt_delay: 10000
integration_test:
needs: [prepare]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest,windows-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
target: x86_64-unknown-linux-gnu
- os: windows-latest
flutter_profile: development-windows-x86
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
target: ${{ matrix.target }}
override: true
profile: minimal
- name: Install flutter
id: flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
- name: Install prerequisites
working-directory: frontend
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 libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
fi
shell: bash
- name: Enable Flutter Desktop
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
flutter config --enable-linux-desktop
elif [ "$RUNNER_OS" == "macOS" ]; then
flutter config --enable-macos-desktop
elif [ "$RUNNER_OS" == "Windows" ]; then
git config --system core.longpaths true
flutter config --enable-windows-desktop
fi
shell: bash
- uses: actions/download-artifact@v3
with:
name: ${{ github.run_id }}-${{ matrix.os }}
- name: Uncompress appflowy_flutter
run: tar -xf appflowy_flutter.tar.gz
- name: Run code generation
working-directory: frontend
run: |
cargo make code_generation
- name: Run Flutter integration tests
working-directory: frontend/appflowy_flutter
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
export DISPLAY=:99
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
sudo apt-get install network-manager
flutter test integration_test/runner.dart -d Linux --coverage
elif [ "$RUNNER_OS" == "macOS" ]; then
flutter test integration_test/runner.dart -d macOS --coverage
elif [ "$RUNNER_OS" == "Windows" ]; then
flutter test integration_test/runner.dart -d Windows --coverage
fi
shell: bash
- name: Upload coverage to Codecov
uses: Wandalen/wretry.action@v1.0.36
with:
action: codecov/codecov-action@v3
with: |
name: appflowy
flags: appflowy_flutter_integrateion_test
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 20
attempt_delay: 10000
build:
needs: [prepare]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
@@ -67,34 +349,20 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
prefix-key: ${{ matrix.os }}
workspaces: |
frontend/rust-lib
- uses: davidB/rust-cargo-make@v1
with:
version: '0.36.6'
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
- name: Install prerequisites
working-directory: frontend
run: |
cargo install --force duckscript_cli
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 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'
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
fi
cargo make appflowy-flutter-deps-tools
shell: bash
- name: Enable Flutter Desktop
@@ -109,32 +377,20 @@ jobs:
fi
shell: bash
- name: Build AppFlowy
working-directory: frontend
run: |
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
- name: Flutter Analyzer
working-directory: frontend/appflowy_flutter
run: |
flutter analyze .
- name: Run Flutter unit tests
working-directory: frontend
run: |
cargo make dart_unit_test
- name: Upload coverage to Codecov
uses: Wandalen/wretry.action@v1.0.36
- uses: actions/download-artifact@v3
with:
action: codecov/codecov-action@v3
with: |
name: appflowy
flags: appflowy_flutter_unit_test
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 20
attempt_delay: 10000
name: ${{ github.run_id }}-${{ matrix.os }}
- name: Uncompress appflowy_flutter
run: tar -xf appflowy_flutter.tar.gz
- name: Run code generation
if: matrix.os == 'windows-latest'
working-directory: frontend
run: |
cargo make code_generation
- name: Build flutter product
working-directory: frontend
run: |
cargo make --profile ${{ matrix.flutter_profile }} appflowy-make-product-dev
@@ -1,26 +1,23 @@
name: integration test
name: Mobile-CI
on:
push:
branches:
- "main"
- "release/*"
paths:
- ".github/workflows/integration_test.yml"
- ".github/workflows/mobile_ci.yaml"
- "frontend/**"
- "!frontend/appflowy_tauri/**"
pull_request:
branches:
- "main"
- "release/*"
paths:
- ".github/workflows/integration_test.yml"
- ".github/workflows/mobile_ci.yaml"
- "frontend/**"
- "!frontend/appflowy_tauri/**"
env:
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.10.1"
RUST_TOOLCHAIN: "1.70"
@@ -34,17 +31,22 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
target: x86_64-unknown-linux-gnu
- os: windows-latest
flutter_profile: development-windows-x86
target: x86_64-pc-windows-msvc
target: aarch64-linux-android
runs-on: ${{ matrix.os }}
steps:
# the following step is required to avoid running out of space
- name: Maximize build space
if: matrix.os == 'ubuntu-latest'
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- name: Checkout source code
uses: actions/checkout@v2
@@ -65,27 +67,36 @@ jobs:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: "r24"
add-to-path: true
- uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ matrix.os }}
workspaces: |
frontend/rust-lib
cache-all-crates: true
- uses: davidB/rust-cargo-make@v1
with:
version: '0.36.6'
version: "0.36.6"
- name: Install prerequisites
working-directory: frontend
run: |
rustup target install aarch64-linux-android
rustup target install x86_64-linux-android
cargo install --force duckscript_cli
cargo install cargo-ndk
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 libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
sudo apt-get install keybinder-3.0 libnotify-dev
sudo apt-get install gcc-multilib
elif [ "$RUNNER_OS" == "Windows" ]; then
vcpkg integrate install
elif [ "$RUNNER_OS" == "macOS" ]; then
@@ -94,48 +105,9 @@ jobs:
cargo make appflowy-flutter-deps-tools
shell: bash
- name: Enable Flutter Desktop
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
flutter config --enable-linux-desktop
elif [ "$RUNNER_OS" == "macOS" ]; then
flutter config --enable-macos-desktop
elif [ "$RUNNER_OS" == "Windows" ]; then
git config --system core.longpaths true
flutter config --enable-windows-desktop
fi
shell: bash
- name: Build AppFlowy
working-directory: frontend
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
cargo make --profile ${{ matrix.flutter_profile }} appflowy-dev
- name: Run Flutter integration tests
working-directory: frontend/appflowy_flutter
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
export DISPLAY=:99
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
sudo apt-get install network-manager
flutter test integration_test/runner.dart -d Linux --coverage
elif [ "$RUNNER_OS" == "macOS" ]; then
flutter test integration_test/runner.dart -d macOS --coverage
elif [ "$RUNNER_OS" == "Windows" ]; then
flutter test integration_test/runner.dart -d Windows --coverage
fi
shell: bash
- name: Upload coverage to Codecov
uses: Wandalen/wretry.action@v1.0.36
with:
action: codecov/codecov-action@v3
with: |
name: appflowy
flags: appflowy_flutter_integrateion_test
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 20
attempt_delay: 10000
cargo make --profile development-android appflowy-android-dev
+39 -39
View File
@@ -35,13 +35,15 @@ jobs:
release_name: v${{ github.ref }}
body_path: ${{ env.RELEASE_NOTES_PATH }}
# the package name should be with the format: AppFlowy-<version>-<os>-<arch>
build-for-windows:
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
needs: create-release
env:
WINDOWS_APP_RELEASE_PATH: frontend\appflowy_flutter\product\${{ github.ref_name }}\windows
WINDOWS_ZIP_NAME: AppFlowy_${{ github.ref_name }}_windows-x86_64.zip
WINDOWS_INSTALLER_NAME: AppFlowy_${{ github.ref_name }}_windows-x86_64
WINDOWS_ZIP_NAME: AppFlowy-${{ github.ref_name }}-windows-x86_64.zip
WINDOWS_INSTALLER_NAME: AppFlowy-${{ github.ref_name }}-windows-x86_64
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
@@ -57,7 +59,6 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
@@ -68,11 +69,6 @@ jobs:
components: rustfmt
profile: minimal
- uses: Swatinem/rust-cache@v2
with:
prefix-key: appflowy-lib-cache
key: ${{ matrix.job.os }}-${{ matrix.job.target }}
- name: Install prerequisites
working-directory: frontend
run: |
@@ -133,8 +129,8 @@ jobs:
needs: create-release
env:
MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/macos/Release
MACOS_X86_ZIP_NAME: AppFlowy_${{ github.ref_name }}_macos-x86_64.zip
MACOS_DMG_NAME: AppFlowy_${{ github.ref_name }}_macos-x86_64
MACOS_X86_ZIP_NAME: AppFlowy-${{ github.ref_name }}-macos-x86_64.zip
MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-x86_64
strategy:
fail-fast: false
matrix:
@@ -149,7 +145,6 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
@@ -160,11 +155,6 @@ jobs:
components: rustfmt
profile: minimal
- uses: Swatinem/rust-cache@v2
with:
prefix-key: appflowy-lib-cache
key: ${{ matrix.job.os }}-${{ matrix.job.target }}
- name: Install prerequisites
working-directory: frontend
run: |
@@ -235,8 +225,8 @@ jobs:
needs: create-release
env:
MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/macos/Release
MACOS_AARCH64_ZIP_NAME: AppFlowy_${{ github.ref_name }}_macos-universal.zip
MACOS_DMG_NAME: AppFlowy_${{ github.ref_name }}_macos-universal
MACOS_AARCH64_ZIP_NAME: AppFlowy-${{ github.ref_name }}-macos-universal.zip
MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-universal
strategy:
fail-fast: false
matrix:
@@ -255,7 +245,6 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
@@ -264,11 +253,6 @@ jobs:
targets: ${{ matrix.job.targets }}
components: rustfmt
- uses: Swatinem/rust-cache@v2
with:
prefix-key: appflowy-lib-cache
key: ${{ matrix.job.os }}-${{ matrix.job.target }}
- name: Install prerequisites
working-directory: frontend
run: |
@@ -339,9 +323,11 @@ jobs:
needs: create-release
env:
LINUX_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/linux/Release
LINUX_ZIP_NAME: AppFlowy_${{ matrix.job.target }}_${{ matrix.job.os }}.tar.gz
LINUX_PACKAGE_NAME: AppFlowy_${{ github.ref_name }}_${{ matrix.job.os }}.deb
# PKG_CONFIG_SYSROOT_DIR: /
LINUX_ZIP_NAME: AppFlowy-${{ matrix.job.target }}-x86_64.tar.gz
LINUX_PACKAGE_DEB_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.deb
LINUX_PACKAGE_RPM_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.rpm
LINUX_PACKAGE_TMP_RPM_NAME: AppFlowy-${{ github.ref_name }}-2.x86_64.rpm
strategy:
fail-fast: false
matrix:
@@ -362,7 +348,6 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
@@ -373,18 +358,14 @@ jobs:
components: rustfmt
profile: minimal
- uses: Swatinem/rust-cache@v2
with:
prefix-key: appflowy-lib-cache
key: ${{ matrix.job.os }}-${{ matrix.job.target }}
- name: Install prerequisites
working-directory: frontend
run: |
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo apt-get update
sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
sudo apt-get install keybinder-3.0 libnotify-dev
sudo apt-get -y install alien
source $HOME/.cargo/env
cargo install --force cargo-make
cargo install --force duckscript_cli
@@ -409,8 +390,17 @@ jobs:
- name: Build Linux package (.deb)
working-directory: frontend
run: |
sh scripts/linux_distribution/deb/build_deb.sh appflowy_flutter/product/${{ github.ref_name }}/linux/Release ${{ github.ref_name }} ${{ env.LINUX_PACKAGE_NAME }}
sh scripts/linux_distribution/deb/build_deb.sh appflowy_flutter/product/${{ github.ref_name }}/linux/Release ${{ github.ref_name }} ${{ env.LINUX_PACKAGE_DEB_NAME }}
- name: Build Linux package (.rpm)
working-directory: ${{ env.LINUX_APP_RELEASE_PATH }}
run: |
ls -a
sudo alien -r ${{ env.LINUX_PACKAGE_DEB_NAME }}
echo '------------'
cp -r ${{ env.LINUX_PACKAGE_TMP_RPM_NAME }} ${{ env.LINUX_PACKAGE_RPM_NAME }}
ls -a
- name: Upload Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
@@ -423,15 +413,25 @@ jobs:
asset_content_type: application/octet-stream
- name: Upload Debian package
id: upload-release-asset-install-package
id: upload-release-asset-install-package-deb
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_path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_DEB_NAME }}
asset_name: ${{ env.LINUX_PACKAGE_DEB_NAME }}
asset_content_type: application/octet-stream
asset_name: ${{ env.LINUX_PACKAGE_NAME }}
- name: Upload RPM package
id: upload-release-asset-install-package-rpm
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_RPM_NAME }}
asset_name: ${{ env.LINUX_PACKAGE_RPM_NAME }}
asset_content_type: application/octet-stream
build-for-docker:
+2 -2
View File
@@ -60,8 +60,8 @@ jobs:
echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
- name: Create .env file in flowy-test
working-directory: frontend/rust-lib/flowy-test
- name: Create .env file in event-integration
working-directory: frontend/rust-lib/event-integration
run: |
touch .env.ci
echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
-23
View File
@@ -1,23 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ProtoBuf_Gen" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --manifest-path ${flowy_tool} -- pb-gen --rust_sources=${rust_lib},${shared_lib} --derive_meta=${derive_meta} --flutter_package_lib=${flutter_package_lib}" />
<option name="workingDirectory" value="file://$PROJECT_DIR$/frontend" />
<option name="channel" value="DEFAULT" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="backtrace" value="SHORT" />
<envs>
<env name="flowy_tool" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/scripts/flowy-tool/Cargo.toml" />
<env name="rust_lib" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/rust-lib/" />
<env name="shared_lib" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/../shared_lib" />
<env name="flutter_lib" value="${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/appflowy_flutter/packages" />
<env name="derive_meta" value="${shared_lib}/flowy-derive/src/derive_cache/derive_cache.rs" />
<env name="flutter_package_lib" value="${flutter_lib}/flowy_sdk/lib" />
</envs>
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
-18
View File
@@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run backend" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package backend --bin backend" />
<option name="workingDirectory" value="file://$PROJECT_DIR$/backend" />
<option name="channel" value="DEFAULT" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="backtrace" value="SHORT" />
<envs>
<env name="APP_ENVIRONMENT" value="production" />
</envs>
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
-16
View File
@@ -1,16 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="dart-event" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --manifest-path $PROJECT_DIR$/scripts/flowy-tool/Cargo.toml -- dart-event --rust_source=$PROJECT_DIR$/rust-lib/ --output=$PROJECT_DIR$/appflowy_flutter/packages/flowy_sdk/lib/dispatch/dart_event.dart" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="channel" value="DEFAULT" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
+95
View File
@@ -1,5 +1,100 @@
# Release Notes
## Version 0.3.8 - 11/13/2023
### New Features
- Support hiding any stack in a board
- Support customizing page icons in menu
- Display visual hint when card contains notes
- Quick action for adding new stack to a board
- Support more ways of inserting page references in documents
- Shift + click on a checkbox to power toggle its children
### Bug fixes
- Improved color of the "Share"-button text
- Text overflow issue in Calendar properties
- Default font (Roboto) added to application
- Placeholder added for the editor inside a Card
- Toggle notifications in settings have been fixed
- Dialog for linking board/grid/calendar opens in correct position
- Quick add Card in Board at top, correctly adds a new Card at the top
## Version 0.3.7 - 10/30/2023
### New Features
- Support showing checklist items inline in row page.
- Support inserting date from slash menu.
- Support renaming a stack directly by clicking on the stack name.
- Show the detailed reminder content in the notification center.
- Save card order in Board view.
- Allow to hide the ungrouped stack.
- Segmented the checklist progress bar.
### Bug fixes
- Optimize side panel animation.
- Fix calendar with hidden date or title doesn't show options correctly.
- Fix the horizontal scroll bar disappears in Grid view.
- Improve setting tab UI in Grid view.
- Improve theme of the code block.
- Fix some UI issues.
## Version 0.3.6 - 10/16/2023
### New Features
- Support setting Markdown styles through keyboard shortcuts.
- Added Ukrainian language.
- Support auto-hiding sidebar feature, ensuring a streamlined view even when resizing to a smaller window.
- Support toggling the notifitcation on/off.
- Added Lemonade theme.
### Bug fixes
- Improve Vietnamese translations.
- Improve reminder feature.
- Fix some UI issues.
## Version 0.3.5 - 10/09/2023
### New Features
- Added support for browsing and inserting images from Unsplash.
- Revamp and unify the emoji picker throughout AppFlowy.
### Bug fixes
- Improve layout of the settings page.
- Improve design of the restore page banner.
- Improve UX of the reminders.
- Other UI fixes.
## Version 0.3.4 - 10/02/2023
### New Features
- Added support for creating a reminder.
- Added support for finding and replacing in the document page.
- Added support for showing the hidden fields in row detail page.
- Adjust the toolbar style in RTL mode.
### Bug fixes
- Improve snackbar UI design.
- Improve dandelion theme.
- Improve id-ID and pl-PL language translations.
## Version 0.3.3 - 09/24/2023
### New Features
- Added an end date field to the time cell in the database.
- Added Support for customizing the font family from GoogleFonts in the editor.
- Set the uploaded image to cover by default.
- Added Support for resetting the user icon on settings page
- Add Urdu language translations.
### Bug fixes
- Default colors for the blocks except for the callout were not transparent.
- Option/Alt + click to add a block above didn't work on the first line.
- Unable to paste HTML content containing `<mark>` tag.
- Unable to select the text from anywhere in the line.
- The selection in the editor didn't clear when editing the inline database.
- Added a bottom border to new property column in the database.
- Set minimum width of 50px for grid fields.
## Version 0.3.2 - 09/18/2023
### New Features
+3 -3
View File
@@ -18,7 +18,7 @@ You are in charge of your data and customizations.
</p>
<p align="center">
<a href="http://www.appflowy.io"><b>Website</b></a> •
<a href="https://www.appflowy.io"><b>Website</b></a> •
<a href="https://discord.gg/9Q2xaN37tV"><b>Discord</b></a> •
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
</p>
@@ -47,7 +47,7 @@ You are in charge of your data and customizations.
## Getting Started with development
Please view the [documentation](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy) for OS specific development instructions
Please view the [documentation](https://docs.appflowy.io/docs/documentation/appflowy/from-source) for OS specific development instructions
## Roadmap
@@ -73,7 +73,7 @@ Proudly wear your T-shirt and show it to us by tagging [@appflowy](https://twitt
[![translation badge](https://inlang.com/badge?url=github.com/AppFlowy-IO/AppFlowy)](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy?ref=badge)
To add translations, you can manually edit the JSON translation files in `/frontend/appflowy_flutter/assets/translations`, use the [inlang online editor](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy), or run `npx inlang machine translate` to add missing translations.
To add translations, you can manually edit the JSON translation files in `/frontend/resources/translations`, use the [inlang online editor](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy), or run `npx inlang machine translate` to add missing translations.
## Join the community to build AppFlowy together
+23 -11
View File
@@ -4,6 +4,18 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
// This task only builds the Dart code of AppFlowy.
// It supports both the desktop and mobile version.
"name": "AF: Build Dart Only",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"env": {
"RUST_LOG": "debug",
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
// This task builds the Rust and Dart code of AppFlowy.
"name": "AF-desktop: Build All",
@@ -17,17 +29,6 @@
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
// This task only builds the Dart code of AppFlowy.
"name": "AF-desktop: Build Dart Only",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"env": {
"RUST_LOG": "debug",
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
// This task builds will:
// - call the clean task,
@@ -65,6 +66,17 @@
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-Android: Clean + Rebuild All",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"preLaunchTask": "AF: Clean + Rebuild All (Android)",
"env": {
"RUST_LOG": "trace"
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-desktop: Debug Rust",
"request": "attach",
+29 -1
View File
@@ -84,6 +84,34 @@
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Clean + Rebuild All (Android)",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"AF: Dart Clean",
"AF: Flutter Clean",
"AF: Build Appflowy Core For Android",
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
],
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "AF: Build Appflowy Core For Android",
"type": "shell",
"command": "cargo make --profile development-android appflowy-core-dev-android",
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Build Appflowy Core",
"type": "shell",
@@ -285,6 +313,6 @@
"options": {
"cwd": "${workspaceFolder}/appflowy_flutter"
}
}
},
]
}
+24 -16
View File
@@ -25,7 +25,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.3.2"
CURRENT_APP_VERSION = "0.3.8"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
PRODUCT_NAME = "AppFlowy"
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
@@ -186,6 +186,29 @@ RUST_COMPILE_TARGET = "aarch64-apple-ios"
BUILD_ARCHS = "arm64"
CRATE_TYPE = "staticlib"
[env.production-ios-arm64]
BUILD_FLAG = "release"
TARGET_OS = "ios"
FLUTTER_OUTPUT_DIR = "Release"
RUST_COMPILE_TARGET = "aarch64-apple-ios"
BUILD_ARCHS = "arm64"
CRATE_TYPE = "staticlib"
[env.development-android]
BUILD_FLAG = "debug"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Debug"
LIB_EXT = "so"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[env.production-android]
BUILD_FLAG = "release"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Release"
LIB_EXT = "so"
[tasks.echo_env]
script = ['''
echo "-------- Env Parameters --------"
@@ -201,21 +224,6 @@ script = ['''
''']
script_runner = "@shell"
[env.development-android]
BUILD_FLAG = "debug"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Debug"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[env.production-android]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Release"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[tasks.setup-crate-type]
private = true
script = [
+2 -2
View File
@@ -69,8 +69,8 @@ windows/flutter/dart_ffi/
**/.sandbox
**/.vscode/
*.env
*.env.*
.env
.env.*
coverage/
+7 -7
View File
@@ -4,8 +4,8 @@
# This file should be version controlled.
version:
revision: 135454af32477f815a7525073027a3ff9eff1bfd
channel: stable
revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
channel: unknown
project_type: app
@@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- platform: windows
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
- platform: android
create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66
# User provided section
+14 -16
View File
@@ -13,11 +13,13 @@ This Repository contains the codebase for the frontend of the application, curre
- Linux
- macOS
- Windows
> We later expect to extend support to Android and iOS devices using Flutter.
> We are actively working on support for Android & iOS!
_Additionally, we are working on a Web version built with Tauri!_
### Am I Eligible to Contribute?
Yes! You are eligible to contribute, check out the ways in which you can [contribute to AppFlowy](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/contributing-to-appflowy). Some of the ways in which you can contribute are:
Yes! You are eligible to contribute, check out the ways in which you can [contribute to AppFlowy](https://docs.appflowy.io/docs/documentation/software-contributions/contributing-to-appflowy). Some of the ways in which you can contribute are:
- Non-Coding Contributions
- Documentation
@@ -26,27 +28,23 @@ Yes! You are eligible to contribute, check out the ways in which you can [contri
- Improve Translations
- Coding Contributions
To contribute to `AppFlowy_Flutter` codebase specifically (coding contribution) we suggest you to have basic knowledge of Flutter. In case you are new to Flutter, we may suggest you to learn the basics and then try to contribute, get started with Flutter [here](https://flutter.dev/docs/get-started/codelab).
To contribute to `AppFlowy_Flutter` codebase specifically (coding contribution) we suggest you to have basic knowledge of Flutter. In case you are new to Flutter, we suggest you learn the basics, and then contribute afterwards. To get started with Flutter read [here](https://flutter.dev/docs/get-started/codelab).
### What OS Should I Use for Development?
### What OS should I use for development?
We support all OS for Development i.e Linux, macOS and Windows. However, most of us promote macOS and Linux over Windows. We have detailed [docs](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/environment-setup) on How to Setup `AppFlowy_Flutter` in your local system in each OS.
We support all OS for Development i.e. Linux, MacOS and Windows. However, most of us promote macOS and Linux over Windows. We have detailed [docs](https://docs.appflowy.io/docs/documentation/appflowy/from-source/environment-setup) on how to setup `AppFlowy_Flutter` on your local system respectively per operating system.
### Getting Started ❇
We have a detailed documentation, on how to [get started](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/contributing-to-appflowy) with the project, and make your first contribution. However, we do have some specific picks for you.
We have detailed documentation on how to [get started](https://docs.appflowy.io/docs/documentation/software-contributions/contributing-to-appflowy) with the project, and make your first contribution. However, we do have some specific picks for you:
- [Code Architecture](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/frontend/codemap)
- [Making Your First PR](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/submitting-your-first-pull-request)
- [The Style Guide](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/style-guides)
- [How to run/debug the application](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/launcher-and-tasks)
- [Styleguide & Conventions](https://docs.appflowy.io/docs/documentation/software-contributions/conventions/naming-conventions)
- [Making Your First PR](https://docs.appflowy.io/docs/documentation/software-contributions/submitting-code/submitting-your-first-pull-request)
- [All AppFlowy Documentation](https://docs.appflowy.io/docs/documentation/appflowy) - Contribution guide, build and run, debugging, testing, localization, etc.
### Need Help?
- New to GitHub? Follow [these](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/setting-up-your-repositories) steps to get started
- Stuck Somewhere? Join the [Discord](https://discord.gg/9Q2xaN37tV) Group and we are there to help you!
<!--
## release check
1. [entitlements](https://flutter.dev/desktop#setting-up-entitlements)
2. [symbols stripped](https://flutter.dev/docs/development/platform-integration/c-interop) -->
- New to GitHub? Follow [these](https://docs.appflowy.io/docs/documentation/software-contributions/submitting-code/setting-up-your-repositories) steps to get started
- Stuck Somewhere? Join our [Discord](https://discord.gg/9Q2xaN37tV), we're there to help you!
- Find out more about the [community initiatives](https://docs.appflowy.io/docs/appflowy/community).
@@ -11,3 +11,5 @@ GeneratedPluginRegistrant.java
key.properties
**/*.keystore
**/*.jks
.cxx
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 31
compileSdkVersion 33
ndkVersion "24.0.8215888"
compileOptions {
@@ -46,11 +46,16 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "io.appflowy.appflowy"
minSdkVersion 19
minSdkVersion 23
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
externalNativeBuild {
cmake {
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_STL=c++_shared"
}
}
}
buildTypes {
@@ -63,6 +68,14 @@ android {
signingConfig signingConfigs.debug
}
}
namespace 'io.appflowy.appflowy'
externalNativeBuild {
cmake {
path "src/main/CMakeLists.txt"
}
}
}
flutter {
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.appflowy.appflowy">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
@@ -1,42 +1,48 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.appflowy.appflowy">
<application
android:label="appflowy_flutter"
android:icon="@mipmap/ic_launcher"
android:name="${applicationName}">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:label="AppFlowy" android:icon="@mipmap/ic_launcher"
android:name="${applicationName}">
<activity android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<!--
Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI.
-->
<meta-data android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<!--
Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame.
-->
<meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="appflowy-flutter" />
<!-- <data android:host="login-callback" /> -->
</intent-filter>
</activity>
<!--
Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java
-->
<meta-data android:name="flutterEmbedding" android:value="2" />
</application>
</manifest>
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.10.0)
project(AppFlowy)
# arm64-v8a
file(COPY
${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/arm64-v8a
)
# x86_64
file(COPY
${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_shared.so
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/jniLibs/x86_64
)
@@ -0,0 +1,18 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
int64_t init_sdk(char *path);
void async_event(int64_t port, const uint8_t *input, uintptr_t len);
const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
int32_t set_stream_port(int64_t port);
void link_me_please(void);
void backend_log(int64_t level, const char *data);
void set_env(const char *data);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.appflowy.appflowy">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.8.0'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -24,6 +24,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
@@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
org.gradle.caching=true
android.suppressUnsupportedCompileSdk=33
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1 @@
use_precompiled_binaries: true
+41
View File
@@ -0,0 +1,41 @@
# Initial Setup
# 1. Copy the dev.env file to .env:
# cp dev.env .env
# Update the environment parameters as needed.
# 2. Generate the env.dart from this .env file:
# You can use the "Generate Env File" task in VSCode.
# Alternatively, execute the following commands:
# cd appflowy_flutter
# dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
# Cloud Type Configuration
# Use this configuration file to specify the cloud type and its associated settings. The available cloud types are:
# Local: 0
# Supabase: 1
# AppFlowy Cloud: 2
# By default, it's set to Local.
CLOUD_TYPE=0
# Supabase Configuration
# If using Supabase (CLOUD_TYPE=1), provide the following details:
SUPABASE_URL=
SUPABASE_ANON_KEY=
# AppFlowy Cloud Configuration
# If using AppFlowy Cloud (CLOUD_TYPE=2), provide the following details:
# For instance:
# APPFLOWY_CLOUD_BASE_URL=https://xxxxxxxxx
# APPFLOWY_CLOUD_WS_BASE_URL=wss://xxxxxxxxx
# APPFLOWY_CLOUD_GOTRUE_URL=https://xxxxxxxxx
#
# Local host machine(For local develop)
# APPFLOWY_CLOUD_BASE_URL=http://localhost:8000
# APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws
# APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998
APPFLOWY_CLOUD_BASE_URL=
APPFLOWY_CLOUD_WS_BASE_URL=
APPFLOWY_CLOUD_GOTRUE_URL=
@@ -80,7 +80,8 @@ void main() {
await tester.openSettingsPage(SettingsPage.files);
await tester.openSettingsPage(SettingsPage.appearance);
expect(find.textContaining(DefaultAppearanceSettings.kDefaultFontFamily),
expect(
find.textContaining(DefaultAppearanceSettings.kDefaultFontFamily),
findsOneWidget,
);
});
@@ -25,8 +25,8 @@ void main() {
await tester.openSettingsPage(SettingsPage.user);
await tester.tapButton(find.byType(SettingLogoutButton));
tester.expectToSeeText(LocaleKeys.button_OK.tr());
await tester.tapButtonWithName(LocaleKeys.button_OK.tr());
tester.expectToSeeText(LocaleKeys.button_ok.tr());
await tester.tapButtonWithName(LocaleKeys.button_ok.tr());
// Go to the sign in page again
await tester.pumpAndSettle(const Duration(seconds: 1));
@@ -0,0 +1,104 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
const defaultFirstCardName = 'Card 1';
const defaultLastCardName = 'Card 3';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board add row test', () {
testWidgets('Add card from header', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
final findFirstCard = find.descendant(
of: find.byType(AppFlowyGroupCard),
matching: find.byType(FlowyText),
);
FlowyText firstCardText = tester.firstWidget(findFirstCard);
expect(firstCardText.text, defaultFirstCardName);
await tester.tap(
find
.descendant(
of: find.byType(BoardColumnHeader),
matching: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.add_s,
),
)
.at(1),
);
await tester.pumpAndSettle();
const newCardName = 'Card 4';
await tester.enterText(
find.descendant(
of: find.byType(IntrinsicHeight),
matching: find.byType(TextField),
),
newCardName,
);
await tester.pumpAndSettle();
await tester.tap(find.byType(AppFlowyBoard));
await tester.pumpAndSettle();
firstCardText = tester.firstWidget(findFirstCard);
expect(firstCardText.text, newCardName);
});
testWidgets('Add card from footer', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
final findLastCard = find.descendant(
of: find.byType(AppFlowyGroupCard),
matching: find.byType(FlowyText),
);
FlowyText? lastCardText =
tester.widgetList(findLastCard).last as FlowyText;
expect(lastCardText.text, defaultLastCardName);
await tester.tap(
find
.descendant(
of: find.byType(AppFlowyGroupFooter),
matching: find.byType(FlowySvg),
)
.at(1),
);
await tester.pumpAndSettle();
const newCardName = 'Card 4';
await tester.enterText(
find.descendant(
of: find.byType(IntrinsicHeight),
matching: find.byType(TextField),
),
newCardName,
);
await tester.pumpAndSettle();
await tester.tap(find.byType(AppFlowyBoard));
await tester.pumpAndSettle();
lastCardText = tester.widgetList(findLastCard).last as FlowyText;
expect(lastCardText.text, newCardName);
});
});
}
@@ -0,0 +1,98 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_hidden_groups.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board hide groups test', () {
testWidgets('expand/collapse hidden groups', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
final collapseFinder = find.byFlowySvg(FlowySvgs.pull_left_outlined_s);
final expandFinder = find.byFlowySvg(FlowySvgs.hamburger_s_s);
// Is expanded by default
expect(collapseFinder, findsOneWidget);
expect(expandFinder, findsNothing);
// Collapse hidden groups
await tester.tap(collapseFinder);
await tester.pumpAndSettle();
// Is collapsed
expect(collapseFinder, findsNothing);
expect(expandFinder, findsOneWidget);
// Expand hidden groups
await tester.tap(expandFinder);
await tester.pumpAndSettle();
// Is expanded
expect(collapseFinder, findsOneWidget);
expect(expandFinder, findsNothing);
});
testWidgets('hide first group, and show it again', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
// Tap the options of the first group
final optionsFinder = find
.descendant(
of: find.byType(BoardColumnHeader),
matching: find.byFlowySvg(FlowySvgs.details_horizontal_s),
)
.first;
await tester.tap(optionsFinder);
await tester.pumpAndSettle();
// Tap the hide option
await tester.tap(find.byFlowySvg(FlowySvgs.hide_s));
await tester.pumpAndSettle();
int shownGroups =
tester.widgetList(find.byType(BoardColumnHeader)).length;
// We still show Doing, Done, No Status
expect(shownGroups, 3);
final hiddenCardFinder = find.byType(HiddenGroupCard);
await tester.hoverOnWidget(hiddenCardFinder);
await tester.tap(find.byFlowySvg(FlowySvgs.show_m));
await tester.pumpAndSettle();
shownGroups = tester.widgetList(find.byType(BoardColumnHeader)).length;
expect(shownGroups, 4);
});
});
}
extension FlowySvgFinder on CommonFinders {
Finder byFlowySvg(FlowySvgData svg) => _FlowySvgFinder(svg);
}
class _FlowySvgFinder extends MatchFinder {
_FlowySvgFinder(this.svg);
final FlowySvgData svg;
@override
String get description => 'flowy_svg "$svg"';
@override
bool matches(Element candidate) {
final Widget widget = candidate.widget;
return widget is FlowySvg && widget.svg == svg;
}
}
@@ -1,11 +1,14 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/widgets/card/card.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
import '../util/database_test_op.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -46,5 +49,56 @@ void main() {
await tester.tapButtonWithName(LocaleKeys.button_duplicate.tr());
expect(find.textContaining(name, findRichText: true), findsNWidgets(2));
});
testWidgets('add new group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
// assert number of groups
tester.assertNumberOfGroups(4);
// scroll the board horizontally to ensure add new group button appears
await tester.scrollBoardToEnd();
// assert and click on add new group button
tester.assertNewGroupTextField(false);
await tester.tapNewGroupButton();
tester.assertNewGroupTextField(true);
// enter new group name and submit
await tester.enterNewGroupName('needs design', submit: true);
// assert number of groups has increased
tester.assertNumberOfGroups(5);
// assert text field has disappeared
await tester.scrollBoardToEnd();
tester.assertNewGroupTextField(false);
// click on add new group button
await tester.tapNewGroupButton();
tester.assertNewGroupTextField(true);
// type some things
await tester.enterNewGroupName('needs planning', submit: false);
// click on clear button and assert empty contents
await tester.clearNewGroupTextField();
// press escape to cancel
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
tester.assertNewGroupTextField(false);
// click on add new group button
await tester.tapNewGroupButton();
tester.assertNewGroupTextField(true);
// press elsewhere to cancel
await tester.tap(find.byType(AppFlowyBoard));
await tester.pumpAndSettle();
tester.assertNewGroupTextField(false);
});
});
}
@@ -1,10 +1,12 @@
import 'package:integration_test/integration_test.dart';
import 'board_row_test.dart' as board_row_test;
import 'board_add_row_test.dart' as board_add_row_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Board integration tests
board_row_test.main();
board_add_row_test.main();
}
@@ -79,33 +79,33 @@ void main() {
// Tap on create new event button
await tester.tapAddCalendarEventButton();
// Make sure that the row details page is opened
tester.assertRowDetailPageOpened();
// Dismiss the row details page
await tester.dismissRowDetailPage();
// Make sure that the event editor popup is shown
tester.assertEventEditorOpen();
tester.assertNumberOfEventsInCalendar(1);
// Dismiss the event editor popup
await tester.dismissEventEditor();
// Double click on today's calendar cell to create a new event
await tester.doubleClickCalendarCell(DateTime.now());
// Make sure that the row details page is opened
tester.assertRowDetailPageOpened();
// Dismiss the row details page
await tester.dismissRowDetailPage();
// Make sure that the event editor popup is shown
tester.assertEventEditorOpen();
// Make sure that the event is inserted in the cell
tester.assertNumberOfEventsInCalendar(2);
// Dismiss the event editor popup
await tester.dismissEventEditor();
// Click on the event
await tester.openCalendarEvent(index: 0);
tester.assertRowDetailPageOpened();
tester.assertEventEditorOpen();
// Change the title of the event
await tester.editTitleInRowDetailPage('hello world');
await tester.dismissRowDetailPage();
await tester.editEventTitle('hello world');
await tester.dismissEventEditor();
// Make sure that the event is edited
tester.assertNumberOfEventsInCalendar(1, title: 'hello world');
@@ -113,6 +113,10 @@ void main() {
// Click on the event
await tester.openCalendarEvent(index: 1);
tester.assertEventEditorOpen();
// Click on the open icon
await tester.openEventToRowDetailPage();
tester.assertRowDetailPageOpened();
// Duplicate the event
@@ -126,12 +130,23 @@ void main() {
// Delete an event
await tester.openCalendarEvent(index: 1);
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDeleteRowButton();
await tester.deleteEventFromEventEditor();
// Check that there is 1 event
tester.assertNumberOfEventsInCalendar(1, title: 'hello world');
tester.assertNumberOfEventsOnSpecificDay(2, DateTime.now());
// Delete event from row detail page
await tester.openCalendarEvent(index: 1);
await tester.openEventToRowDetailPage();
tester.assertRowDetailPageOpened();
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDeleteRowButton();
// Check that there is 0 event
tester.assertNumberOfEventsInCalendar(0, title: 'hello world');
tester.assertNumberOfEventsOnSpecificDay(1, DateTime.now());
});
testWidgets('rescheduling events', (tester) async {
@@ -145,7 +160,7 @@ void main() {
final today = DateTime.now();
final firstOfThisMonth = DateTime(today.year, today.month, 1);
await tester.doubleClickCalendarCell(firstOfThisMonth);
await tester.dismissRowDetailPage();
await tester.dismissEventEditor();
// Drag and drop the event onto the next week, same day
await tester.dragDropRescheduleCalendarEvent(firstOfThisMonth);
@@ -157,37 +172,65 @@ void main() {
// Delete the event
await tester.openCalendarEvent(index: 0, date: sameDayNextWeek);
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDeleteRowButton();
await tester.deleteEventFromEventEditor();
// Create a new event in today's calendar cell
await tester.scrollToToday();
await tester.doubleClickCalendarCell(today);
await tester.dismissRowDetailPage();
// Create another event on the 5th of this month
final fifthOfThisMonth = DateTime(today.year, today.month, 5);
await tester.doubleClickCalendarCell(fifthOfThisMonth);
await tester.dismissEventEditor();
// Make sure that the event is today
tester.assertNumberOfEventsOnSpecificDay(1, today);
// Make sure that the event is on the 4t
tester.assertNumberOfEventsOnSpecificDay(1, fifthOfThisMonth);
// Click on the event
await tester.openCalendarEvent(index: 0);
await tester.openCalendarEvent(index: 0, date: fifthOfThisMonth);
// Open the date editor of the event
await tester.tapDateCellInRowDetailPage();
await tester.findDateEditor(findsOneWidget);
// Edit the event's date. To avoid selecting a day outside of the current month, the new date will be one day closer to the middle of the month.
final newDate = today.day < 15
? today.add(const Duration(days: 1))
: today.subtract(const Duration(days: 1));
// Edit the event's date
final newDate = fifthOfThisMonth.add(const Duration(days: 1));
await tester.selectDay(content: newDate.day);
await tester.dismissCellEditor();
// Dismiss the row details page
await tester.dismissRowDetailPage();
// Dismiss the event editor
await tester.dismissEventEditor();
// Make sure that the event is edited
tester.assertNumberOfEventsInCalendar(1);
tester.assertNumberOfEventsOnSpecificDay(1, newDate);
// Click on the unscheduled events button
await tester.openUnscheduledEventsPopup();
// Assert that nothing shows up
tester.findUnscheduledPopup(findsNothing, 0);
// Click on the event in the calendar
await tester.openCalendarEvent(index: 0, date: newDate);
// Open the date editor of the event
await tester.tapDateCellInRowDetailPage();
await tester.findDateEditor(findsOneWidget);
// Clear the date of the event
await tester.clearDate();
// Dismiss the event editor
await tester.dismissEventEditor();
tester.assertNumberOfEventsInCalendar(0);
// Click on the unscheduled events button
await tester.openUnscheduledEventsPopup();
// Assert that a popup appears and 1 unscheduled event
tester.findUnscheduledPopup(findsOneWidget, 1);
// Click on the unscheduled event
await tester.clickUnscheduledEvent();
tester.assertRowDetailPageOpened();
});
});
}
@@ -185,7 +185,7 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('edit time cell', (tester) async {
testWidgets('edit date time cell', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
@@ -456,9 +456,6 @@ void main() {
// assert that the checklist editor is shown
tester.assertChecklistEditorVisible(visible: true);
// assert that new task editor is shown
tester.assertNewCheckListTaskEditorVisible(visible: true);
// create a new task with enter
await tester.createNewChecklistTask(name: "task 0", enter: true);
@@ -481,7 +478,6 @@ void main() {
// dismiss new task editor
await tester.dismissCellEditor();
tester.assertNewCheckListTaskEditorVisible(visible: false);
// dismiss checklist cell editor
await tester.dismissCellEditor();
@@ -489,11 +485,8 @@ void main() {
// assert that progress bar is shown in grid at 0%
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 0);
// start editing the first checklist cell again, click on new task button
// start editing the first checklist cell again
await tester.tapChecklistCellInGrid(rowIndex: 0);
tester.assertNewCheckListTaskEditorVisible(visible: false);
await tester.tapChecklistNewTaskButton();
tester.assertNewCheckListTaskEditorVisible(visible: true);
// create another task with the create button
await tester.createNewChecklistTask(name: "task 2", button: true);
@@ -540,9 +533,6 @@ void main() {
// delete the remaining task
await tester.deleteChecklistTask(index: 0);
// assert that the new task editor is shown
tester.assertNewCheckListTaskEditorVisible(visible: true);
// dismiss the cell editor
await tester.dismissCellEditor();
@@ -42,7 +42,6 @@ void main() {
await tester.hoverRowBanner();
await tester.openEmojiPicker();
await tester.switchToEmojiList();
await tester.tapEmoji('😀');
// After select the emoji, the EmojiButton will show up
@@ -60,12 +59,10 @@ void main() {
await tester.openFirstRowDetailPage();
await tester.hoverRowBanner();
await tester.openEmojiPicker();
await tester.switchToEmojiList();
await tester.tapEmoji('😀');
// Update existing selected emoji
await tester.tapButton(find.byType(EmojiButton));
await tester.switchToEmojiList();
await tester.tapEmoji('😅');
// The emoji already displayed in the row banner
@@ -89,7 +86,6 @@ void main() {
await tester.openFirstRowDetailPage();
await tester.hoverRowBanner();
await tester.openEmojiPicker();
await tester.switchToEmojiList();
await tester.tapEmoji('😀');
// Remove the emoji
@@ -146,7 +142,7 @@ void main() {
await tester.openFirstRowDetailPage();
// Assert that the first field in the row details page is the select
// option tyoe
// option type
tester.assertFirstFieldInRowDetailByType(FieldType.SingleSelect);
// Reorder first field in list
@@ -168,6 +164,54 @@ void main() {
tester.assertFirstFieldInRowDetailByType(FieldType.SingleSelect);
});
testWidgets('hide and show hidden fields', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
// Assert that the show hidden fields button isn't visible
tester.assertToggleShowHiddenFieldsVisibility(false);
// Hide the first field in the field list
await tester.tapGridFieldWithNameInRowDetailPage("Type");
await tester.tapHidePropertyButtonInFieldEditor();
// Assert that the field is now hidden
tester.noFieldWithName("Type");
// Assert that the show hidden fields button appears
tester.assertToggleShowHiddenFieldsVisibility(true);
// Click on the show hidden fields button
await tester.toggleShowHiddenFields();
// Assert that the hidden field is shown again and that the show
// hidden fields button is still present
tester.findFieldWithName("Type");
tester.assertToggleShowHiddenFieldsVisibility(true);
// Click hide hidden fields
await tester.toggleShowHiddenFields();
// Assert that the hidden field has vanished
tester.noFieldWithName("Type");
// Click show hidden fields
await tester.toggleShowHiddenFields();
// delete the hidden field
await tester.tapGridFieldWithNameInRowDetailPage("Type");
await tester.tapDeletePropertyInFieldEditor();
// Assert that the that the show hidden fields button is gone
tester.assertToggleShowHiddenFieldsVisibility(false);
});
testWidgets('check document exists in row detail page', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
@@ -197,7 +241,7 @@ void main() {
await tester.wait(500);
// Focus on the editor
final textBlock = find.byType(TextBlockComponentWidget);
final textBlock = find.byType(ParagraphBlockComponentWidget);
await tester.tapAt(tester.getCenter(textBlock));
await tester.pumpAndSettle();
@@ -24,7 +24,7 @@ void main() {
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
);
// and with one paragraph block
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
expect(find.byType(ParagraphBlockComponentWidget), findsOneWidget);
});
testWidgets('delete the readme page and restore it', (tester) async {
@@ -0,0 +1,136 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/link_to_page_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/keyboard.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('insert inline document reference', () {
testWidgets('insert by slash menu', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final name = await createDocumentToReference(tester);
await tester.editor.tapLineOfEditorAt(0);
await tester.pumpAndSettle();
await triggerReferenceDocumentBySlashMenu(tester);
// Search for prefix of document
await enterDocumentText(tester);
// Select result
final optionFinder = find.descendant(
of: find.byType(LinkToPageMenu),
matching: find.text(name),
);
await tester.tap(optionFinder);
await tester.pumpAndSettle();
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
});
testWidgets('insert by `[[` character shortcut', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final name = await createDocumentToReference(tester);
await tester.editor.tapLineOfEditorAt(0);
await tester.pumpAndSettle();
await tester.ime.insertText('[[');
await tester.pumpAndSettle();
// Select result
await tester.editor.tapAtMenuItemWithName(name);
await tester.pumpAndSettle();
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
});
testWidgets('insert by `+` character shortcut', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final name = await createDocumentToReference(tester);
await tester.editor.tapLineOfEditorAt(0);
await tester.pumpAndSettle();
await tester.ime.insertText('+');
await tester.pumpAndSettle();
// Select result
await tester.editor.tapAtMenuItemWithName(name);
await tester.pumpAndSettle();
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
});
});
}
Future<String> createDocumentToReference(WidgetTester tester) async {
final name = 'document_${uuid()}';
await tester.createNewPageWithName(
name: name,
layout: ViewLayoutPB.Document,
openAfterCreated: false,
);
// This is a workaround since the openAfterCreated
// option does not work in createNewPageWithName method
await tester.tap(find.byType(SingleInnerViewItem).first);
await tester.pumpAndSettle();
return name;
}
Future<void> triggerReferenceDocumentBySlashMenu(WidgetTester tester) async {
await tester.editor.showSlashMenu();
await tester.pumpAndSettle();
// Search for referenced document action
await enterDocumentText(tester);
// Select item
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.enter,
],
tester: tester,
);
await tester.pumpAndSettle();
}
Future<void> enterDocumentText(WidgetTester tester) async {
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.keyD,
LogicalKeyboardKey.keyO,
LogicalKeyboardKey.keyC,
LogicalKeyboardKey.keyU,
LogicalKeyboardKey.keyM,
LogicalKeyboardKey.keyE,
LogicalKeyboardKey.keyN,
LogicalKeyboardKey.keyT,
],
tester: tester,
);
await tester.pumpAndSettle();
}
@@ -0,0 +1,44 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// +, ... button beside the block component.
group('document with option action button', () {
testWidgets(
'click + to add a block after current selection, and click + and option key to add a block before current selection',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
var editorState = tester.editor.getCurrentEditorState();
expect(editorState.getNodeAtPath([1])?.delta?.toPlainText(), isNotEmpty);
// add a new block after the current selection
await tester.editor.hoverAndClickOptionAddButton([0], false);
// await tester.pumpAndSettle();
expect(editorState.getNodeAtPath([1])?.delta?.toPlainText(), isEmpty);
// cancel the selection menu
await tester.tapAt(Offset.zero);
await tester.editor.hoverAndClickOptionAddButton([0], true);
await tester.pumpAndSettle();
expect(editorState.getNodeAtPath([0])?.delta?.toPlainText(), isEmpty);
// cancel the selection menu
await tester.tapAt(Offset.zero);
await tester.tapAt(Offset.zero);
await tester.createNewPageWithName(name: 'test');
await tester.openPage(gettingStarted);
// check the status again
editorState = tester.editor.getCurrentEditorState();
expect(editorState.getNodeAtPath([0])?.delta?.toPlainText(), isEmpty);
expect(editorState.getNodeAtPath([2])?.delta?.toPlainText(), isEmpty);
});
});
}
@@ -5,14 +5,19 @@ import 'document_codeblock_paste_test.dart' as document_codeblock_paste_test;
import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
import 'document_create_and_delete_test.dart'
as document_create_and_delete_test;
import 'document_option_action_test.dart' as document_option_action_test;
import 'document_text_direction_test.dart' as document_text_direction_test;
import 'document_with_cover_image_test.dart' as document_with_cover_image_test;
import 'document_with_database_test.dart' as document_with_database_test;
import 'document_with_image_block_test.dart' as document_with_image_block_test;
import 'document_with_inline_math_equation_test.dart'
as document_with_inline_math_equation_test;
import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
import 'document_with_outline_block_test.dart' as document_with_outline_block;
import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
import 'edit_document_test.dart' as document_edit_test;
import 'document_inline_page_reference_test.dart'
as document_inline_page_reference_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -29,4 +34,8 @@ void startTesting() {
document_copy_and_paste_test.main();
document_codeblock_paste_test.main();
document_alignment_test.main();
document_text_direction_test.main();
document_option_action_test.main();
document_with_image_block_test.main();
document_inline_page_reference_test.main();
}
@@ -0,0 +1,58 @@
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('text direction', () {
testWidgets(
'''no text direction items will be displayed in the default/LTR mode,and three text direction items will be displayed in the RTL mode.''',
(tester) async {
// combine the two tests into one to avoid the time-consuming process of initializing the app
await tester.initializeAppFlowy();
await tester.tapGoButton();
final selection = Selection.single(
path: [0],
startOffset: 0,
endOffset: 1,
);
// click the first line of the readme
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.updateSelection(selection);
await tester.pumpAndSettle();
// because this icons are defined in the appflowy_editor package, we can't fetch the icons by SVG data. [textDirectionItems]
final textDirectionIconNames = [
'toolbar/text_direction_auto',
'toolbar/text_direction_left',
'toolbar/text_direction_right',
];
// no text direction items in default/LTR mode
var button = find.byWidgetPredicate(
(widget) =>
widget is SVGIconItemWidget &&
textDirectionIconNames.contains(widget.iconName),
);
expect(button, findsNothing);
// switch to the RTL mode
await tester.switchLayoutDirectionMode(LayoutDirection.rtlLayout);
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.updateSelection(selection);
await tester.pumpAndSettle();
button = find.byWidgetPredicate(
(widget) =>
widget is SVGIconItemWidget &&
textDirectionIconNames.contains(widget.iconName),
);
expect(button, findsNWidgets(3));
});
});
}
@@ -1,4 +1,9 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:emoji_mart/emoji_mart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -17,7 +22,6 @@ void main() {
// Hover over cover toolbar to show 'Add Cover' and 'Add Icon' buttons
await tester.editor.hoverOnCoverToolbar();
tester.expectToSeePluginAddCoverAndIconButton();
// Insert a document cover
await tester.editor.tapOnAddCover();
@@ -53,15 +57,10 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeDocumentIcon(null);
// Hover over cover toolbar to show the 'Add Cover' and 'Add Icon' buttons
await tester.editor.hoverOnCoverToolbar();
tester.expectToSeePluginAddCoverAndIconButton();
tester.expectToSeeDocumentIcon('⭐️');
// Insert a document icon
await tester.editor.tapAddIconButton();
await tester.switchToEmojiList();
await tester.editor.tapGettingStartedIcon();
await tester.tapEmoji('😀');
tester.expectToSeeDocumentIcon('😀');
@@ -73,13 +72,11 @@ void main() {
// Add the icon back for further testing
await tester.editor.hoverOnCoverToolbar();
await tester.editor.tapAddIconButton();
await tester.switchToEmojiList();
await tester.tapEmoji('😀');
tester.expectToSeeDocumentIcon('😀');
// Change the document icon
await tester.editor.tapOnIconWidget();
await tester.switchToEmojiList();
await tester.tapEmoji('😅');
tester.expectToSeeDocumentIcon('😅');
@@ -93,19 +90,15 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeDocumentIcon(null);
tester.expectToSeeDocumentIcon('⭐️');
tester.expectToSeeNoDocumentCover();
// Hover over cover toolbar to show the 'Add Cover' and 'Add Icon' buttons
await tester.editor.hoverOnCoverToolbar();
tester.expectToSeePluginAddCoverAndIconButton();
// Insert a document icon
await tester.editor.tapAddIconButton();
await tester.switchToEmojiList();
await tester.editor.tapGettingStartedIcon();
await tester.tapEmoji('😀');
// Insert a document cover
await tester.editor.hoverOnCoverToolbar();
await tester.editor.tapOnAddCover();
// Expect to see the icon and cover at the same time
@@ -116,5 +109,48 @@ void main() {
await tester.editor.hoverOnCoverToolbar();
tester.expectToSeeEmptyDocumentHeaderToolbar();
});
testWidgets('shuffle icon', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.editor.tapGettingStartedIcon();
// click the shuffle button
await tester.tapButton(
find.byTooltip(LocaleKeys.emoji_random.tr()),
);
tester.expectDocumentIconNotNull();
});
testWidgets('change skin tone', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.editor.tapGettingStartedIcon();
final searchEmojiTextField = find.byWidgetPredicate(
(widget) =>
widget is TextField &&
widget.decoration!.hintText == LocaleKeys.emoji_search.tr(),
);
await tester.enterText(
searchEmojiTextField,
'hand',
);
// change skin tone
await tester.editor.changeEmojiSkinTone(EmojiSkinTone.dark);
// select an icon with skin tone
const hand = '👋🏿';
await tester.tapEmoji(hand);
tester.expectToSeeDocumentIcon(hand);
tester.expectViewHasIcon(
gettingStarted,
ViewLayoutPB.Document,
hand,
);
});
});
}
@@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/text_cell/text_cell.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/link_to_page_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
@@ -31,6 +32,18 @@ void main() {
),
findsOneWidget,
);
// https://github.com/AppFlowy-IO/AppFlowy/issues/3533
// test: the selection of editor should be clear when editing the grid
await tester.editor.updateSelection(
Selection.collapsed(
Position(path: [1]),
),
);
final gridTextCell = find.byType(GridTextCell).first;
await tester.tapButton(gridTextCell);
expect(tester.editor.getCurrentEditorState().selection, isNull);
});
testWidgets('insert a referenced board', (tester) async {
@@ -0,0 +1,163 @@
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/embed_image_url_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/unsplash_image_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/upload_image_menu.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide UploadImageMenu;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:run_with_network_images/run_with_network_images.dart';
import '../util/mock/mock_file_picker.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
TestWidgetsFlutterBinding.ensureInitialized();
group('image block in document', () {
testWidgets('insert an image from local file', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(
find.descendant(
of: find.byType(ImagePlaceholder),
matching: find.byType(AppFlowyPopover),
),
findsOneWidget,
);
expect(find.byType(UploadImageMenu), findsOneWidget);
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final tempDirectory = await getTemporaryDirectory();
final imagePath = p.join(tempDirectory.path, 'sample.jpeg');
final file = File(imagePath)
..writeAsBytesSync(image.buffer.asUint8List());
mockPickFilePaths(
paths: [imagePath],
);
await tester.tapButtonWithName(
LocaleKeys.document_imageBlock_upload_placeholder.tr(),
);
await tester.pumpAndSettle();
expect(find.byType(ResizableImage), findsOneWidget);
final node = tester.editor.getCurrentEditorState().getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotEmpty);
// remove the temp file
file.deleteSync();
});
testWidgets('insert an image from network', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(
find.descendant(
of: find.byType(ImagePlaceholder),
matching: find.byType(AppFlowyPopover),
),
findsOneWidget,
);
expect(find.byType(UploadImageMenu), findsOneWidget);
await tester.tapButtonWithName(
LocaleKeys.document_imageBlock_embedLink_label.tr(),
);
const url =
'https://images.unsplash.com/photo-1469474968028-56623f02e42e?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&dl=david-marcu-78A265wPiO4-unsplash.jpg&w=640';
await tester.enterText(
find.descendant(
of: find.byType(EmbedImageUrlWidget),
matching: find.byType(TextField),
),
url,
);
await tester.tapButton(
find.descendant(
of: find.byType(EmbedImageUrlWidget),
matching: find.text(
LocaleKeys.document_imageBlock_embedLink_label.tr(),
findRichText: true,
),
),
);
await tester.pumpAndSettle();
expect(find.byType(ResizableImage), findsOneWidget);
final node = tester.editor.getCurrentEditorState().getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], url);
});
testWidgets('insert an image from unsplash', (tester) async {
await runWithNetworkImages(() async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName('Image');
expect(find.byType(CustomImageBlockComponent), findsOneWidget);
expect(find.byType(ImagePlaceholder), findsOneWidget);
expect(
find.descendant(
of: find.byType(ImagePlaceholder),
matching: find.byType(AppFlowyPopover),
),
findsOneWidget,
);
expect(find.byType(UploadImageMenu), findsOneWidget);
await tester.tapButtonWithName(
'Unsplash',
);
expect(find.byType(UnsplashImageWidget), findsOneWidget);
});
});
});
}
@@ -15,7 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await insertingInlinePage(tester, ViewLayoutPB.Grid);
await insertInlinePage(tester, ViewLayoutPB.Grid);
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
@@ -26,7 +26,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await insertingInlinePage(tester, ViewLayoutPB.Board);
await insertInlinePage(tester, ViewLayoutPB.Board);
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
@@ -37,7 +37,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await insertingInlinePage(tester, ViewLayoutPB.Calendar);
await insertInlinePage(tester, ViewLayoutPB.Calendar);
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
@@ -48,7 +48,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await insertingInlinePage(tester, ViewLayoutPB.Document);
await insertInlinePage(tester, ViewLayoutPB.Document);
final mentionBlock = find.byType(MentionPageBlock);
expect(mentionBlock, findsOneWidget);
@@ -59,7 +59,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Document);
final pageName = await insertInlinePage(tester, ViewLayoutPB.Document);
// rename
const newName = 'RenameToNewPageName';
@@ -78,7 +78,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Grid);
final pageName = await insertInlinePage(tester, ViewLayoutPB.Grid);
// rename
await tester.hoverOnPageName(
@@ -98,7 +98,7 @@ void main() {
}
/// Insert a referenced database of [layout] into the document
Future<String> insertingInlinePage(
Future<String> insertInlinePage(
WidgetTester tester,
ViewLayoutPB layout,
) async {
@@ -110,15 +110,19 @@ Future<String> insertingInlinePage(
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
name: 'insert_a_inline_page_${layout.name}',
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
// insert a inline page
await tester.editor.showAtMenu();
await tester.editor.tapAtMenuItemWithName(name);
return name;
}
@@ -15,14 +15,23 @@ void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('toggle list in document', () {
Finder findToggleListIcon({
required bool isExpanded,
}) {
final turns = isExpanded ? 0.25 : 0.0;
return find.byWidgetPredicate(
(widget) => widget is AnimatedRotation && widget.turns == turns,
);
}
void expectToggleListOpened() {
expect(find.byIcon(Icons.arrow_drop_down), findsOneWidget);
expect(find.byIcon(Icons.arrow_right), findsNothing);
expect(findToggleListIcon(isExpanded: true), findsOneWidget);
expect(findToggleListIcon(isExpanded: false), findsNothing);
}
void expectToggleListClosed() {
expect(find.byIcon(Icons.arrow_drop_down), findsNothing);
expect(find.byIcon(Icons.arrow_right), findsOneWidget);
expect(findToggleListIcon(isExpanded: false), findsOneWidget);
expect(findToggleListIcon(isExpanded: true), findsNothing);
}
testWidgets('convert > to toggle list, and click the icon to close it',
@@ -63,7 +72,7 @@ void main() {
expect(find.text(text2, findRichText: true), findsOneWidget);
// Click the toggle list icon to close it
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
final toggleListIcon = find.byIcon(Icons.arrow_right);
await tester.tapButton(toggleListIcon);
// expect the toggle list to be closed
@@ -88,7 +97,7 @@ void main() {
await tester.ime.insertText('> $text');
// Click the toggle list icon to close it
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
final toggleListIcon = find.byIcon(Icons.arrow_right);
await tester.tapButton(toggleListIcon);
// Press the enter key
@@ -164,7 +173,7 @@ void main() {
// Press the enter key
// Click the toggle list icon to close it
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
final toggleListIcon = find.byIcon(Icons.arrow_right);
await tester.tapButton(toggleListIcon);
await tester.editor.updateSelection(
@@ -113,9 +113,9 @@ const _sample = r'''
[] Type followed by bullet or num to create a list.
[x] Click `+ New Page` button at the bottom of your sidebar to add a new page.
[x] Click `New Page` button at the bottom of your sidebar to add a new page.
[] Click `+` next to any page title in the sidebar to quickly add a new subpage, `Document`, `Grid`, or `Kanban Board`.
[] Click the plus sign next to any page title in the sidebar to quickly add a new subpage, `Document`, `Grid`, or `Kanban Board`.
---
* bulleted list 1
@@ -0,0 +1,16 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'util/util.dart';
// This test is meaningless, just for preventing the CI from failing.
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Empty', () {
testWidgets('toggle theme mode', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
});
});
}
@@ -0,0 +1,118 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
import 'package:appflowy/user/application/user_settings_service.dart';
import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-user/date_time.pbenum.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:calendar_view/calendar_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/base.dart';
import '../util/common_operations.dart';
import '../util/editor_test_operations.dart';
import '../util/keyboard.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Reminder in Document', () {
testWidgets('Add reminder for tomorrow, and include time', (tester) async {
const time = "23:59";
await tester.initializeAppFlowy();
await tester.tapGoButton();
final dateTimeSettings =
await UserSettingsBackendService().getDateTimeSettings();
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.getCurrentEditorState().insertNewLine();
await tester.pumpAndSettle();
// Trigger iline action menu and type 'remind tomorrow'
final tomorrow = await _insertReminderTomorrow(tester);
Node node = tester.editor.getCurrentEditorState().getNodeAtPath([1])!;
Map<String, dynamic> mentionAttr =
node.delta!.first.attributes![MentionBlockKeys.mention];
expect(node.type, 'paragraph');
expect(mentionAttr['type'], MentionType.reminder.name);
expect(mentionAttr['date'], tomorrow.toIso8601String());
await tester.tap(
find.text(dateTimeSettings.dateFormat.formatDate(tomorrow, false)),
);
await tester.pumpAndSettle();
await tester.tap(find.byType(Toggle));
await tester.pumpAndSettle();
await tester.enterText(find.byType(FlowyTextField), time);
// Leave text field to submit
await tester.tap(find.text(LocaleKeys.grid_field_includeTime.tr()));
await tester.pumpAndSettle();
node = tester.editor.getCurrentEditorState().getNodeAtPath([1])!;
mentionAttr = node.delta!.first.attributes![MentionBlockKeys.mention];
final tomorrowWithTime =
_dateWithTime(dateTimeSettings.timeFormat, tomorrow, time);
expect(node.type, 'paragraph');
expect(mentionAttr['type'], MentionType.reminder.name);
expect(mentionAttr['date'], tomorrowWithTime.toIso8601String());
});
});
}
Future<DateTime> _insertReminderTomorrow(WidgetTester tester) async {
await tester.editor.showAtMenu();
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.keyR,
LogicalKeyboardKey.keyE,
LogicalKeyboardKey.keyM,
LogicalKeyboardKey.keyI,
LogicalKeyboardKey.keyN,
LogicalKeyboardKey.keyD,
LogicalKeyboardKey.space,
LogicalKeyboardKey.keyT,
LogicalKeyboardKey.keyO,
LogicalKeyboardKey.keyM,
LogicalKeyboardKey.keyO,
LogicalKeyboardKey.keyR,
LogicalKeyboardKey.keyR,
LogicalKeyboardKey.keyO,
LogicalKeyboardKey.keyW,
],
tester: tester,
);
await FlowyTestKeyboard.simulateKeyDownEvent(
[LogicalKeyboardKey.enter],
tester: tester,
);
return DateTime.now().add(const Duration(days: 1)).withoutTime;
}
DateTime _dateWithTime(UserTimeFormatPB format, DateTime date, String time) {
final t = format == UserTimeFormatPB.TwelveHour
? DateFormat.jm().parse(time)
: DateFormat.Hm().parse(time);
return DateTime.parse(
'${date.year}${_padZeroLeft(date.month)}${_padZeroLeft(date.day)} ${_padZeroLeft(t.hour)}:${_padZeroLeft(t.minute)}',
);
}
String _padZeroLeft(int a) => a.toString().padLeft(2, '0');
@@ -1,10 +1,13 @@
import 'package:appflowy/env/env.dart';
import 'package:integration_test/integration_test.dart';
import 'appearance_settings_test.dart' as appearance_test_runner;
import 'auth/auth_test.dart' as auth_test_runner;
import 'board/board_test_runner.dart' as board_test_runner;
import 'database_calendar_test.dart' as database_calendar_test;
import 'database_cell_test.dart' as database_cell_test;
import 'database_field_test.dart' as database_field_test;
import 'database_field_settings_test.dart' as database_field_settings_test;
import 'database_field_test.dart' as database_field_test;
import 'database_filter_test.dart' as database_filter_test;
import 'database_row_page_test.dart' as database_row_page_test;
import 'database_row_test.dart' as database_row_test;
@@ -13,15 +16,14 @@ import 'database_share_test.dart' as database_share_test;
import 'database_sort_test.dart' as database_sort_test;
import 'database_view_test.dart' as database_view_test;
import 'document/document_test_runner.dart' as document_test_runner;
import 'import_files_test.dart' as import_files_test;
import 'share_markdown_test.dart' as share_markdown_test;
import 'switch_folder_test.dart' as switch_folder_test;
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
import 'board/board_test_runner.dart' as board_test_runner;
import 'tabs_test.dart' as tabs_test;
import 'empty_test.dart' as first_test;
import 'hotkeys_test.dart' as hotkeys_test;
import 'appearance_settings_test.dart' as appearance_test_runner;
import 'auth/auth_test.dart' as auth_test_runner;
import 'import_files_test.dart' as import_files_test;
import 'settings/settings_runner.dart' as settings_test_runner;
import 'share_markdown_test.dart' as share_markdown_test;
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
import 'switch_folder_test.dart' as switch_folder_test;
import 'tabs_test.dart' as tabs_test;
/// The main task runner for all integration tests in AppFlowy.
///
@@ -32,6 +34,10 @@ import 'auth/auth_test.dart' as auth_test_runner;
/// as the test target.
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
first_test.main();
switch_folder_test.main();
share_markdown_test.main();
import_files_test.main();
@@ -67,7 +73,10 @@ void main() {
// Appearance integration test
appearance_test_runner.main();
if (isSupabaseEnabled) {
// User settings
settings_test_runner.main();
if (isCloudEnabled) {
auth_test_runner.main();
}
@@ -0,0 +1,41 @@
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board add row test', () {
testWidgets('Add card from header', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.notifications);
await tester.pumpAndSettle();
final switchFinder = find.byType(Switch);
// Defaults to enabled
Switch switchWidget = tester.widget(switchFinder);
expect(switchWidget.value, true);
// Disable
await tester.tap(switchFinder);
await tester.pumpAndSettle();
switchWidget = tester.widget(switchFinder);
expect(switchWidget.value, false);
// Enable again
await tester.tap(switchFinder);
await tester.pumpAndSettle();
switchWidget = tester.widget(switchFinder);
expect(switchWidget.value, true);
});
});
}
@@ -0,0 +1,13 @@
import 'package:integration_test/integration_test.dart';
import 'notifications_settings_test.dart' as notifications_settings_test;
import 'user_icon_test.dart' as user_icon_test;
import 'user_language_test.dart' as user_language_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
notifications_settings_test.main();
user_icon_test.main();
user_language_test.main();
}
@@ -0,0 +1,54 @@
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Settings: user icon tests', () {
testWidgets('select icon, select default option', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userAvatarFinder = find.descendant(
of: find.byType(SettingsUserView),
matching: find.byType(UserAvatar),
);
// Open icon picker dialog
await tester.tap(userAvatarFinder);
await tester.pumpAndSettle();
// Select first option that isn't default
await tester.tap(find.byType(IconOption).first);
await tester.pumpAndSettle();
UserAvatar userAvatar = tester.widget(userAvatarFinder) as UserAvatar;
expect(userAvatar.iconUrl, isNotEmpty);
// Open icon picker dialog again
await tester.tap(userAvatarFinder);
await tester.pumpAndSettle();
// Tap the default option
await tester.tap(
find.descendant(
of: find.byType(IconGallery),
matching: find.byType(UserAvatar),
),
);
await tester.pumpAndSettle();
userAvatar = tester.widget(userAvatarFinder) as UserAvatar;
expect(userAvatar.iconUrl, isEmpty);
});
});
}
@@ -0,0 +1,69 @@
import 'dart:ui';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart';
import '../util/util.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Settings: user language tests', () {
testWidgets('select language, language changed', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.language);
final userLanguageFinder = find.descendant(
of: find.byType(SettingsLanguageView),
matching: find.byType(LanguageSelector),
);
// Grab current locale
LanguageSelector userLanguage =
tester.widget<LanguageSelector>(userLanguageFinder);
Locale currentLocale = userLanguage.currentLocale;
// Open language selector
await tester.tap(userLanguageFinder);
await tester.pumpAndSettle();
// Select first option that isn't default
await tester.tap(find.byType(LanguageItem).at(1));
await tester.pumpAndSettle();
// Make sure the new locale is not the same as previous one
userLanguage = tester.widget<LanguageSelector>(userLanguageFinder);
expect(
userLanguage.currentLocale,
isNot(equals(currentLocale)),
reason: "new language shouldn't equal the previous selected language",
);
// Update the current locale to a new one
currentLocale = userLanguage.currentLocale;
// Tried the same flow for the second time
// Open language selector
await tester.tap(userLanguageFinder);
await tester.pumpAndSettle();
// Select second option that isn't default
await tester.tap(find.byType(LanguageItem).at(2));
await tester.pumpAndSettle();
// Make sure the new locale is not the same as previous one
userLanguage = tester.widget<LanguageSelector>(userLanguageFinder);
expect(
userLanguage.currentLocale,
isNot(equals(currentLocale)),
reason: "new language shouldn't equal the previous selected language",
);
});
});
}
@@ -4,6 +4,7 @@ import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'util/mock/mock_file_picker.dart';
import 'util/util.dart';
@@ -15,9 +16,6 @@ void main() {
final context = await tester.initializeAppFlowy();
await tester.tapGoButton();
// expect to see a readme page
tester.expectToSeePageName(gettingStarted);
// mock the file picker
final path = await mockSaveFilePath(
p.join(context.applicationDataDirectory, 'test.md'),
@@ -78,7 +76,7 @@ void main() {
});
}
const expectedMarkdown = r'''
const expectedMarkdown = '''
# Welcome to AppFlowy!
## Here are the basics
- [ ] Click anywhere and just start typing.
@@ -105,6 +103,15 @@ fn main() {
## Have a question❓
> Click `?` at the bottom right for help and support.
> 🥰
>
> Like AppFlowy? Follow us:
> [GitHub](https://github.com/AppFlowy-IO/AppFlowy)
> [Twitter](https://twitter.com/appflowy): @appflowy
> [Newsletter](https://blog-appflowy.ghost.io/)
>
''';
@@ -99,7 +99,7 @@ void main() {
);
expect(
tester.findFavoritePageName(name),
findsNothing,
findsOneWidget,
);
},
);
@@ -127,7 +127,7 @@ void main() {
expect(
find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget is SingleInnerViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
),
@@ -144,12 +144,7 @@ void main() {
);
expect(
find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
),
tester.findAllFavoritePages(),
findsNWidgets(3),
);
@@ -163,12 +158,7 @@ void main() {
);
expect(
find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
),
tester.findAllFavoritePages(),
findsNothing,
);
},
@@ -0,0 +1,76 @@
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/base.dart';
import '../util/common_operations.dart';
import '../util/expectation.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
const emoji = '😁';
group('Icon', () {
testWidgets('Update page icon in sidebar', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
await tester.createNewPageWithName(
name: value.name,
parentName: gettingStarted,
layout: value,
);
// update its icon
await tester.updatePageIconInSidebarByName(
name: value.name,
parentName: gettingStarted,
layout: value,
icon: emoji,
);
tester.expectViewHasIcon(
value.name,
value,
emoji,
);
}
});
testWidgets('Update page icon in title bar', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
await tester.createNewPageWithName(
name: value.name,
parentName: gettingStarted,
layout: value,
);
// update its icon
await tester.updatePageIconInTitleBarByName(
name: value.name,
layout: value,
icon: emoji,
);
tester.expectViewHasIcon(
value.name,
value,
emoji,
);
tester.expectViewTitleHasIcon(
value.name,
value,
emoji,
);
}
});
});
}
@@ -30,7 +30,7 @@ void main() {
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
);
// and with one paragraph block
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
expect(find.byType(ParagraphBlockComponentWidget), findsOneWidget);
});
testWidgets('create a new document, grid, board and calendar',
@@ -55,7 +55,7 @@ void main() {
switch (layout) {
case ViewLayoutPB.Document:
// and with one paragraph block
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
expect(find.byType(ParagraphBlockComponentWidget), findsOneWidget);
break;
case ViewLayoutPB.Grid:
expect(find.byType(GridPage), findsOneWidget);
@@ -1,8 +1,9 @@
import 'package:integration_test/integration_test.dart';
import 'sidebar_test.dart' as sidebar_test;
import 'sidebar_expand_test.dart' as sidebar_expanded_test;
import 'sidebar_favorites_test.dart' as sidebar_favorite_test;
import 'sidebar_icon_test.dart' as sidebar_icon_test;
import 'sidebar_test.dart' as sidebar_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -11,4 +12,5 @@ void startTesting() {
sidebar_test.main();
sidebar_expanded_test.main();
sidebar_favorite_test.main();
sidebar_icon_test.main();
}
@@ -1,9 +1,12 @@
import 'dart:io';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/prelude.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'util/mock/mock_file_picker.dart';
import 'util/util.dart';
@@ -11,6 +14,10 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('customize the folder path', () {
if (Platform.isWindows) {
return;
}
testWidgets('switch to B from A, then switch to A again', (tester) async {
const userA = 'UserA';
const userB = 'UserB';
@@ -1,9 +1,11 @@
import 'dart:async';
import 'dart:io';
import 'package:appflowy/env/env.dart';
import 'package:appflowy/startup/entry_point.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/presentation.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -81,9 +83,15 @@ extension AppFlowyTestBase on WidgetTester {
}
Future<void> waitUntilSignInPageShow() async {
final finder = find.byType(GoButton);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
if (isCloudEnabled) {
final finder = find.byType(SignInAnonymousButton);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
} else {
final finder = find.byType(GoButton);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
}
}
Future<void> pumpUntilFound(
@@ -1,16 +1,21 @@
import 'dart:io';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart';
import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/screens/screens.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -20,13 +25,25 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'emoji.dart';
import 'util.dart';
extension CommonOperations on WidgetTester {
/// Tap the GetStart button on the launch page.
Future<void> tapGoButton() async {
// local version
final goButton = find.byType(GoButton);
await tapButton(goButton);
if (goButton.evaluate().isNotEmpty) {
await tapButton(goButton);
} else {
// cloud version
final anonymousButton = find.byType(SignInAnonymousButton);
await tapButton(anonymousButton);
}
if (Platform.isWindows) {
await pumpAndSettle(const Duration(milliseconds: 200));
}
}
/// Tap the + button on the home page.
@@ -230,7 +247,7 @@ extension CommonOperations on WidgetTester {
final okButton = find.byWidgetPredicate(
(widget) =>
widget is PrimaryTextButton &&
widget.label == LocaleKeys.button_OK.tr(),
widget.label == LocaleKeys.button_ok.tr(),
);
await tapButton(okButton);
}
@@ -428,6 +445,47 @@ extension CommonOperations on WidgetTester {
);
await tapButton(button);
}
// update the page icon in the sidebar
Future<void> updatePageIconInSidebarByName({
required String name,
required String parentName,
required ViewLayoutPB layout,
required String icon,
}) async {
final iconButton = find.descendant(
of: findPageName(
name,
layout: layout,
parentName: parentName,
),
matching:
find.byTooltip(LocaleKeys.document_plugins_cover_changeIcon.tr()),
);
await tapButton(iconButton);
await tapEmoji(icon);
await pumpAndSettle();
}
// update the page icon in the sidebar
Future<void> updatePageIconInTitleBarByName({
required String name,
required ViewLayoutPB layout,
required String icon,
}) async {
await openPage(
name,
layout: layout,
);
final title = find.descendant(
of: find.byType(ViewTitleBar),
matching: find.text(name),
);
await tapButton(title);
await tapButton(find.byType(EmojiPickerButton));
await tapEmoji(icon);
await pumpAndSettle();
}
}
extension ViewLayoutPBTest on ViewLayoutPB {
@@ -3,9 +3,11 @@ import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database_view/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_day.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_event_card.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_event_editor.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
@@ -25,6 +27,7 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_list.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/timestamp.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/create_sort_list.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/order_panel.dart';
@@ -36,7 +39,6 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_header.dart';
import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
import 'package:appflowy/plugins/database_view/widgets/field/grid_property.dart';
import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_cell_editor.dart';
@@ -45,20 +47,20 @@ import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/select_option_editor.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/text_field.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/timestamp_cell/timestamp_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/database_setting.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/setting_property_list.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:calendar_view/calendar_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -330,7 +332,17 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> toggleIncludeTime() async {
final findDateEditor = find.byType(DateCellEditor);
final findDateEditor = find.byType(IncludeTimeButton);
final findToggle = find.byType(Toggle);
final finder = find.descendant(
of: findDateEditor,
matching: findToggle,
);
await tapButton(finder);
}
Future<void> toggleDateRange() async {
final findDateEditor = find.byType(EndTimeButton);
final findToggle = find.byType(Toggle);
final finder = find.descendant(
of: findDateEditor,
@@ -483,15 +495,6 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
}
void assertNewCheckListTaskEditorVisible({required bool visible}) {
final editor = find.byType(NewTaskItem);
if (visible) {
expect(editor, findsOneWidget);
} else {
expect(editor, findsNothing);
}
}
Future<void> createNewChecklistTask({
required String name,
enter = false,
@@ -504,10 +507,10 @@ extension AppFlowyDatabaseTest on WidgetTester {
);
await enterText(textField, name);
await pumpAndSettle(const Duration(milliseconds: 300));
await pumpAndSettle();
if (enter) {
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle(const Duration(milliseconds: 300));
await pumpAndSettle();
} else {
await tapButton(
find.descendant(
@@ -527,7 +530,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
final widget = this.widget<ChecklistItem>(task);
assert(
widget.option.data.name == name && widget.option.isSelected == isChecked,
widget.task.data.name == name && widget.task.isSelected == isChecked,
);
}
@@ -544,11 +547,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await enterText(textField, name);
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle(const Duration(milliseconds: 300));
}
Future<void> tapChecklistNewTaskButton() async {
await tapButton(find.byType(ChecklistNewTaskButton));
await pumpAndSettle();
}
Future<void> checkChecklistTask({required int index}) async {
@@ -620,7 +619,6 @@ extension AppFlowyDatabaseTest on WidgetTester {
Future<void> openEmojiPicker() async {
await tapButton(find.byType(EmojiPickerButton));
await tapButton(find.byType(EmojiSelectionMenu));
}
Future<void> tapDateCellInRowDetailPage() async {
@@ -675,6 +673,31 @@ extension AppFlowyDatabaseTest on WidgetTester {
await pumpAndSettle();
}
void assertToggleShowHiddenFieldsVisibility(bool shown) {
final button = find.byType(ToggleHiddenFieldsVisibilityButton);
if (shown) {
expect(button, findsOneWidget);
} else {
expect(button, findsNothing);
}
}
Future<void> toggleShowHiddenFields() async {
final button = find.byType(ToggleHiddenFieldsVisibilityButton);
await tapButton(button);
}
Future<void> tapDeletePropertyInFieldEditor() async {
final deleteButton = find.byType(DeleteFieldButton);
await tapButton(deleteButton);
final confirmButton = find.descendant(
of: find.byType(NavigatorAlertDialog),
matching: find.byType(PrimaryTextButton),
);
await tapButton(confirmButton);
}
Future<void> scrollGridByOffset(Offset offset) async {
await drag(find.byType(GridPage), offset);
await pumpAndSettle();
@@ -724,7 +747,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
final field = find.byWidgetPredicate(
(widget) =>
widget is PrimaryTextButton &&
widget.label == LocaleKeys.button_OK.tr(),
widget.label == LocaleKeys.button_ok.tr(),
);
await tapButton(field);
}
@@ -748,7 +771,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> tapHidePropertyButtonInFieldEditor() async {
final button = find.byType(HideFieldButton);
final button = find.byType(FieldVisibilityToggleButton);
await tapButton(button);
}
@@ -901,9 +924,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> assertRowCountInGridPage(int num) async {
final text = find.byWidgetPredicate(
(widget) => widget is FlowyText && widget.text == rowCountString(num),
);
final text = find.text('${rowCountString()} $num', findRichText: true);
expect(text, findsOneWidget);
}
@@ -1110,7 +1131,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
/// Should call [tapDatabaseSettingButton] first.
Future<void> tapViewPropertiesButton() async {
final findSettingItem = find.byType(DatabaseSettingItem);
final findSettingItem = find.byType(DatabaseSettingListPopover);
final findLayoutButton = find.byWidgetPredicate(
(widget) =>
widget is FlowyText &&
@@ -1127,7 +1148,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
/// Should call [tapDatabaseSettingButton] first.
Future<void> tapDatabaseLayoutButton() async {
final findSettingItem = find.byType(DatabaseSettingItem);
final findSettingItem = find.byType(DatabaseSettingListPopover);
final findLayoutButton = find.byWidgetPredicate(
(widget) =>
widget is FlowyText &&
@@ -1143,7 +1164,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> tapCalendarLayoutSettingButton() async {
final findSettingItem = find.byType(DatabaseSettingItem);
final findSettingItem = find.byType(DatabaseSettingListPopover);
final findLayoutButton = find.byWidgetPredicate(
(widget) =>
widget is FlowyText &&
@@ -1280,7 +1301,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await doubleTapAt(location);
}
Future<void> openCalendarEvent({required index, DateTime? date}) async {
Future<void> openCalendarEvent({required int index, DateTime? date}) async {
final findDayCell = find.byWidgetPredicate(
(widget) =>
widget is CalendarDayCard &&
@@ -1294,12 +1315,72 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(cards.at(index));
}
void assertEventEditorOpen() {
expect(find.byType(CalendarEventEditor), findsOneWidget);
}
Future<void> dismissEventEditor() async {
await simulateKeyEvent(LogicalKeyboardKey.escape);
}
Future<void> editEventTitle(String title) async {
final textField = find.descendant(
of: find.byType(CalendarEventEditor),
matching: find.byType(FlowyTextField),
);
await enterText(textField, title);
await pumpAndSettle(const Duration(milliseconds: 300));
}
Future<void> openEventToRowDetailPage() async {
final button = find.descendant(
of: find.byType(CalendarEventEditor),
matching: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.full_view_s,
),
);
await tapButton(button);
}
Future<void> deleteEventFromEventEditor() async {
final button = find.descendant(
of: find.byType(CalendarEventEditor),
matching: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.delete_s,
),
);
await tapButton(button);
}
Future<void> dragDropRescheduleCalendarEvent(DateTime startDate) async {
final findEventCard = find.byType(EventCard);
await drag(findEventCard.first, const Offset(0, 300));
await pumpAndSettle();
}
Future<void> openUnscheduledEventsPopup() async {
final button = find.byType(UnscheduledEventsButton);
await tapButton(button);
}
void findUnscheduledPopup(Matcher matcher, int numUnscheduledEvents) {
expect(find.byType(UnscheduleEventsList), matcher);
if (matcher != findsNothing) {
expect(
find.byType(UnscheduledEventCell),
findsNWidgets(numUnscheduledEvents),
);
}
}
Future<void> clickUnscheduledEvent() async {
final unscheduledEvent = find.byType(UnscheduledEventCell);
await tapButton(unscheduledEvent);
}
Future<void> tapCreateLinkedDatabaseViewButton(AddButtonAction action) async {
final findAddButton = find.byType(AddDatabaseViewButton);
await tapButton(findAddButton);
@@ -1311,6 +1392,84 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(findCreateButton);
}
void assertNumberOfGroups(int number) {
final groups = find.byType(BoardColumnHeader, skipOffstage: false);
expect(groups, findsNWidgets(number));
}
Future<void> scrollBoardToEnd() async {
final scrollable = find
.descendant(
of: find.byType(AppFlowyBoard),
matching: find.byWidgetPredicate(
(widget) => widget is Scrollable && widget.axis == Axis.horizontal,
),
)
.first;
await scrollUntilVisible(
find.byType(BoardTrailing),
300,
scrollable: scrollable,
);
}
Future<void> tapNewGroupButton() async {
final button = find.descendant(
of: find.byType(BoardTrailing),
matching: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.add_s,
),
);
expect(button, findsOneWidget);
await tapButton(button);
}
void assertNewGroupTextField(bool isVisible) {
final textField = find.descendant(
of: find.byType(BoardTrailing),
matching: find.byType(TextField),
);
if (isVisible) {
expect(textField, findsOneWidget);
} else {
expect(textField, findsNothing);
}
}
Future<void> enterNewGroupName(String name, {required bool submit}) async {
final textField = find.descendant(
of: find.byType(BoardTrailing),
matching: find.byType(TextField),
);
await enterText(textField, name);
await pumpAndSettle();
if (submit) {
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle();
}
}
Future<void> clearNewGroupTextField() async {
final textField = find.descendant(
of: find.byType(BoardTrailing),
matching: find.byType(TextField),
);
await tapButton(
find.descendant(
of: textField,
matching: find.byWidgetPredicate(
(widget) =>
widget is FlowySvg && widget.svg == FlowySvgs.close_filled_m,
),
),
);
final textFieldWidget = widget<TextField>(textField);
assert(
textFieldWidget.controller != null &&
textFieldWidget.controller!.text.isEmpty,
);
}
Future<void> tapTabBarLinkedViewByViewName(String name) async {
final viewButton = findTabBarLinkViewByViewName(name);
await tapButton(viewButton);
@@ -1351,7 +1510,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
final field = find.byWidgetPredicate(
(widget) =>
widget is PrimaryTextButton &&
widget.label == LocaleKeys.button_OK.tr(),
widget.label == LocaleKeys.button_ok.tr(),
);
await tapButton(field);
}
@@ -1371,7 +1530,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
final okButton = find.byWidgetPredicate(
(widget) =>
widget is PrimaryTextButton &&
widget.label == LocaleKeys.button_OK.tr(),
widget.label == LocaleKeys.button_ok.tr(),
);
await tapButton(okButton);
}
@@ -1423,7 +1582,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
) async {
final field = find.byWidgetPredicate(
(widget) =>
widget is GridPropertyCell && widget.fieldInfo.name == fieldName,
widget is DatabasePropertyCell && widget.fieldInfo.name == fieldName,
);
final toggleVisibilityButton =
find.descendant(of: field, matching: find.byType(FlowyIconButton));
@@ -1,13 +1,18 @@
import 'dart:ui';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_add_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/cover_editor.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/custom_cover_picker.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_popover.dart';
import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
import 'package:emoji_mart/emoji_mart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -52,7 +57,27 @@ class EditorOperations {
await tester.tapButtonWithName(
LocaleKeys.document_plugins_cover_addIcon.tr(),
);
expect(find.byType(EmojiPopover), findsOneWidget);
expect(find.byType(FlowyEmojiPicker), findsOneWidget);
}
Future<void> tapGettingStartedIcon() async {
await tester.tapButton(
find.descendant(
of: find.byType(DocumentHeaderNodeWidget),
matching: find.findTextInFlowyText('⭐️'),
),
);
}
/// Taps on the 'Skin tone' button
///
/// Must call [tapAddIconButton] first.
Future<void> changeEmojiSkinTone(EmojiSkinTone skinTone) async {
await tester.tapButton(
find.byTooltip(LocaleKeys.emoji_selectSkinTone.tr()),
);
final skinToneButton = find.byKey(emojiSkinToneKey(skinTone.icon));
await tester.tapButton(skinToneButton);
}
/// Taps the 'Remove Icon' button in the cover toolbar and the icon popover
@@ -60,7 +85,10 @@ class EditorOperations {
Finder button =
find.text(LocaleKeys.document_plugins_cover_removeIcon.tr());
if (isInPicker) {
button = find.descendant(of: find.byType(EmojiPopover), matching: button);
button = find.descendant(
of: find.byType(FlowyIconPicker),
matching: button,
);
}
await tester.tapButton(button);
@@ -141,7 +169,7 @@ class EditorOperations {
await tester.ime.insertCharacter('/');
}
/// trigger the slash command (selection menu)
/// trigger the mention (@) command
Future<void> showAtMenu() async {
await tester.ime.insertCharacter('@');
}
@@ -159,7 +187,7 @@ class EditorOperations {
/// Must call [showAtMenu] first.
Future<void> tapAtMenuItemWithName(String name) async {
final atMenuItem = find.descendant(
of: find.byType(SelectionMenuWidget),
of: find.byType(InlineActionsHandler),
matching: find.text(name, findRichText: true),
);
await tester.tapButton(atMenuItem);
@@ -174,4 +202,34 @@ class EditorOperations {
);
await tester.pumpAndSettle(const Duration(milliseconds: 200));
}
/// hover and click on the + button beside the block component.
Future<void> hoverAndClickOptionAddButton(
Path path,
bool withModifiedKey, // alt on windows or linux, option on macos
) async {
final optionAddButton = find.byWidgetPredicate(
(widget) =>
widget is BlockComponentActionWrapper &&
widget.node.path.equals(path),
);
await tester.hoverOnWidget(
optionAddButton,
onHover: () async {
if (withModifiedKey) {
await tester.sendKeyDownEvent(LogicalKeyboardKey.altLeft);
}
await tester.tapButton(
find.byWidgetPredicate(
(widget) =>
widget is BlockAddButton &&
widget.blockComponentContext.node.path.equals(path),
),
);
if (withModifiedKey) {
await tester.sendKeyUpEvent(LogicalKeyboardKey.altLeft);
}
},
);
}
}
@@ -1,17 +1,14 @@
import 'package:flutter/material.dart';
import 'package:emoji_mart/emoji_mart.dart';
import 'package:flutter_test/flutter_test.dart';
import 'base.dart';
extension EmojiTestExtension on WidgetTester {
/// Must call [openEmojiPicker] first
Future<void> switchToEmojiList() async {
final icon = find.byIcon(Icons.tag_faces);
await tapButton(icon);
}
Future<void> tapEmoji(String emoji) async {
final emojiWidget = find.text(emoji);
final emojiWidget = find.descendant(
of: find.byType(EmojiPicker),
matching: find.text(emoji),
);
await tapButton(emojiWidget);
}
}
@@ -5,13 +5,14 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emo
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_stack.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_test/flutter_test.dart';
// const String readme = 'Read me';
const String gettingStarted = '⭐️ Getting started';
const String gettingStarted = 'Getting started';
extension Expectation on WidgetTester {
/// Expect to see the home page and with a default read me page.
@@ -108,6 +109,13 @@ extension Expectation on WidgetTester {
expect(iconWidget, findsOneWidget);
}
void expectDocumentIconNotNull() {
final iconWidget = find.byWidgetPredicate(
(widget) => widget is EmojiIconWidget && widget.emoji.isNotEmpty,
);
expect(iconWidget, findsOneWidget);
}
void expectToSeeDocumentCover(CoverType type) {
final findCover = find.byWidgetPredicate(
(widget) => widget is DocumentCover && widget.coverType == type,
@@ -157,7 +165,7 @@ extension Expectation on WidgetTester {
}) {
return find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget is SingleInnerViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite &&
widget.view.name == name &&
@@ -166,6 +174,15 @@ extension Expectation on WidgetTester {
);
}
Finder findAllFavoritePages() {
return find.byWidgetPredicate(
(widget) =>
widget is SingleInnerViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
);
}
Finder findPageName(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
@@ -193,4 +210,24 @@ extension Expectation on WidgetTester {
matching: findPageName(name, layout: layout),
);
}
void expectViewHasIcon(String name, ViewLayoutPB layout, String emoji) {
final pageName = findPageName(
name,
layout: layout,
);
final icon = find.descendant(
of: pageName,
matching: find.text(emoji),
);
expect(icon, findsOneWidget);
}
void expectViewTitleHasIcon(String name, ViewLayoutPB layout, String emoji) {
final icon = find.descendant(
of: find.byType(ViewTitleBar),
matching: find.text(emoji),
);
expect(icon, findsOneWidget);
}
}
@@ -12,8 +12,11 @@ class MyMockClient extends Mock implements http.Client {
final requestType = request.method;
final requestUri = request.url;
if (requestType == 'POST' && requestUri == OpenAIRequestType.textCompletion.uri) {
final responseHeaders = <String, String>{'content-type': 'text/event-stream'};
if (requestType == 'POST' &&
requestUri == OpenAIRequestType.textCompletion.uri) {
final responseHeaders = <String, String>{
'content-type': 'text/event-stream'
};
final responseBody = Stream.fromIterable([
utf8.encode(
'{ "choices": [{"text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula ", "index": 0, "logprobs": null, "finish_reason": null}]}',
@@ -51,7 +54,9 @@ class MockOpenAIRepository extends HttpOpenAIRepository {
var previousSyntax = '';
if (response.statusCode == 200) {
await for (final chunk in response.stream.transform(const Utf8Decoder()).transform(const LineSplitter())) {
await for (final chunk in response.stream
.transform(const Utf8Decoder())
.transform(const LineSplitter())) {
await onStart();
final data = chunk.trim().split('data: ');
if (data[0] != '[DONE]') {
@@ -1,9 +1,11 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'base.dart';
@@ -72,4 +74,35 @@ extension AppFlowySettings on WidgetTester {
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle();
}
// go to settings page and switch the layout direction
Future<void> switchLayoutDirectionMode(
LayoutDirection layoutDirection,
) async {
await openSettings();
await openSettingsPage(SettingsPage.appearance);
final button = find.byKey(const ValueKey('layout_direction_option_button'));
expect(button, findsOneWidget);
await tapButton(button);
switch (layoutDirection) {
case LayoutDirection.ltrLayout:
final ltrButton = find.text(
LocaleKeys.settings_appearance_layoutDirection_ltr.tr(),
);
await tapButton(ltrButton);
break;
case LayoutDirection.rtlLayout:
final rtlButton = find.text(
LocaleKeys.settings_appearance_layoutDirection_rtl.tr(),
);
await tapButton(rtlButton);
break;
}
// tap anywhere to close the settings page
await tapAt(Offset.zero);
await pumpAndSettle();
}
}
+16
View File
@@ -38,4 +38,20 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
installer.aggregate_targets.each do |target|
target.xcconfigs.each do |variant, xcconfig|
xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)
IO.write(xcconfig_path, IO.read(xcconfig_path).gsub("DT_TOOLCHAIN_DIR", "TOOLCHAIN_DIR"))
end
end
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference
xcconfig_path = config.base_configuration_reference.real_path
IO.write(xcconfig_path, IO.read(xcconfig_path).gsub("DT_TOOLCHAIN_DIR", "TOOLCHAIN_DIR"))
end
end
end
end
+28 -4
View File
@@ -48,6 +48,13 @@ PODS:
- fluttertoast (0.0.2):
- Flutter
- Toast
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- image_gallery_saver (2.0.2):
- Flutter
- image_picker_ios (0.0.1):
- Flutter
- integration_test (0.0.1):
- Flutter
- irondash_engine_context (0.0.1):
@@ -68,6 +75,9 @@ PODS:
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- Flutter
- sqflite (0.0.3):
- Flutter
- FMDB (>= 2.7.5)
- super_native_extensions (0.0.1):
- Flutter
- SwiftyGif (5.4.3)
@@ -86,6 +96,8 @@ DEPENDENCIES:
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
- Flutter (from `Flutter`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
@@ -93,6 +105,7 @@ DEPENDENCIES:
- rich_clipboard_ios (from `.symlinks/plugins/rich_clipboard_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
@@ -101,6 +114,7 @@ SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- FMDB
- ReachabilitySwift
- SDWebImage
- SwiftyGif
@@ -123,6 +137,10 @@ EXTERNAL SOURCES:
:path: Flutter
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
image_gallery_saver:
:path: ".symlinks/plugins/image_gallery_saver/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
irondash_engine_context:
@@ -137,6 +155,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sign_in_with_apple:
:path: ".symlinks/plugins/sign_in_with_apple/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
super_native_extensions:
:path: ".symlinks/plugins/super_native_extensions/ios"
url_launcher_ios:
@@ -147,7 +167,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
@@ -155,6 +175,9 @@ SPEC CHECKSUMS:
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
integration_test: 13825b8a9334a850581300559b8839134b124670
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
@@ -164,12 +187,13 @@ SPEC CHECKSUMS:
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
super_native_extensions: 49e897b6039bb784226e7354e502a3c68e1659b5
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac
COCOAPODS: 1.11.3
COCOAPODS: 1.12.1
@@ -13,22 +13,9 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
9D1D47ADD7F5DE8237063BCA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 197F72694BED43249F1523E8 /* Pods_Runner.framework */; };
FB3C2A642AE0D57700490715 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 197F72694BED43249F1523E8 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
@@ -47,6 +34,7 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FBE00AD62AE8E46A006B563F /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -54,7 +42,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9D1D47ADD7F5DE8237063BCA /* Pods_Runner.framework in Frameworks */,
FB3C2A642AE0D57700490715 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -102,6 +90,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
FBE00AD62AE8E46A006B563F /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -121,7 +110,6 @@
580A1ED8E012CA1552E5EFD3 /* Pods-Runner.release.xcconfig */,
4C2CB38DA64605A62D45B098 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@@ -137,7 +125,6 @@
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
08FAA63113168DEC7FB74204 /* [CP] Embed Pods Frameworks */,
);
@@ -358,14 +345,26 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.appflowy;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@@ -482,15 +481,27 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.appflowy;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@@ -501,14 +512,26 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.appflowy.appflowy;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

@@ -1,122 +1 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Loaded 100 of 1383 files, more files were not shown because too many files have changed in this diff. Show more