Compare commits

...
Author SHA1 Message Date
Mathias Mogensen 6a14ba8047 feat: initial date text input 2024-03-05 13:18:48 +01:00
Mathias Mogensen 5daf9d23f5 fix: update view names in page reference menu (#4802) 2024-03-04 18:24:49 +01:00
Mathias Mogensen b087a9aeb3 fix: filter keydownevents in actions handler (#4817) 2024-03-04 13:42:42 +01:00
Mathias Mogensen 107e3cea4f feat: duplicate calendar event (#4816)
* feat: duplicate calendar event

* test: add simple test
2024-03-04 12:42:00 +01:00
Mathias Mogensen ba965caa8f fix: stop hover when scrolling (#4801) 2024-03-04 12:41:34 +01:00
Zack 2af93a9bcb feat: add support for renaming and updating the icon for workspaces (#4806) 2024-03-04 16:05:16 +08:00
Nathan.fooo f8962edfd7 chore: bump client api (#4804)
* chore: bump client api

* chore: bump client api

* chore: bump client api
2024-03-04 14:05:04 +08:00
Lucas.Xu b236afd0c3 chore: update version to 0.5.1 (#4811) 2024-03-04 12:28:28 +08:00
Lucas.Xu 8944edf75f feat: support clearing caches and fix unable to load image (#4809)
* feat: support clearing caches

* fix: try to clear the image cache when loading failed.

* feat: clear cache on mobile

* chore: add error log
2024-03-04 12:24:25 +08:00
Richard Shiue 6b05be2362 fix: remove dup translation token and rearrange (#4810) 2024-03-04 12:01:31 +08:00
Lucas.Xu 90146148b6 feat: show the workspace list on top-left corner (#4799) 2024-03-04 10:43:00 +08:00
Mathias Mogensen 63464cbf2e fix: launch url on all platforms (#4797)
* fix: error handled launchUrl

* chore: update links to use new subdomain

* feat: show toast if onFailure is not provided
2024-03-03 22:04:59 +01:00
Daniil 1fadb15351 chore: update russian translations (#4796) 2024-03-03 09:41:33 +08:00
Lucas.Xu 8732c3c28b feat: members settings (#4788)
* feat: add member settings

* feat: fetch workspace members from server

* feat: add translations

* feat: implement invite feature

* feat: support inviting people via email

* feat: support updating member role

* feat: add feature flag to control the visibilty of members settings
2024-03-03 09:36:12 +08:00
YiHeCN f7233f6949 chore: update zh-CN translations (#4795) 2024-03-03 00:05:43 +08:00
Sore 8c7ed808a7 chore: rename ckb-KUR.json to ckb-KU.json (#4786) 2024-03-02 22:51:20 +08:00
Richard Shiue b38fc43300 feat: checklist cell editor a11y improvement (#4784) 2024-03-02 19:14:00 +08:00
Richard Shiue f4170755fa fix: reorder grid field updating all views (#4791) 2024-03-02 18:27:34 +08:00
Richard Shiue 79585d0835 fix: flutter_ci (#4793) 2024-03-02 17:30:27 +08:00
Kilu.He 835563f81b feat: support image block (#4783) 2024-03-01 10:48:07 +08:00
Richard Shiue 37bc5b3fbf chore: type option handler cleanup (#4787) 2024-03-01 10:26:38 +08:00
Richard Shiue 682bf19838 chore: type option cell data trait cleanup (#4782)
* chore: remove dead code

* chore: remove legacy FromCellStringTrait
2024-02-29 15:48:06 +08:00
Richard Shiue f4ca3ef782 feat: add basic relation field (#4397)
* feat: add basic relation field

* fix: clippy

* fix: tauri build 🤞

* chore: merge changes

* fix: merge main

* chore: initial code review pass

* fix: rust-lib test

* chore: code cleanup

* fix: unwrap or default
2024-02-29 14:38:18 +08:00
Richard Shiue f826d05f03 fix: mobile ui fixes (#4780)
* fix: adjust mobile grid padding

* fix: reorder field not working
2024-02-29 09:44:48 +08:00
Richard Shiue 01f2b15f70 fix: type option transform for checklists (#4779) 2024-02-28 22:04:32 +08:00
Mathias Mogensen 2d6856a23d fix: edit column sheet uniform ui (#4774) 2024-02-28 22:04:16 +08:00
Mohammad Zolfaghari 2286a1c726 feat: rtl toolbar item setting (#3958) 2024-02-28 21:56:18 +08:00
domenico code ef90c35175 chore: update translations (#4753) 2024-02-28 21:55:52 +08:00
Mathias Mogensen af12beb1c3 fix: remove empty space if no email (#4777) 2024-02-28 13:23:06 +01:00
Mathias Mogensen 0d68c42aab fix: symmetric padding in mobile database header (#4773) 2024-02-28 13:21:23 +01:00
Mathias Mogensen 0cffe42d80 fix: add time to view meta info (#4769) 2024-02-28 12:34:02 +01:00
Lucas.Xu abd08e5e53 feat: support customizing font and color before typing (#4765)
* fix: bius buttons highlight status

* feat: support customizing font family before typing

* feat: support customizing text color before typing
2024-02-28 15:51:50 +08:00
Kilu.He e250f780a4 feat: support to show condition in filter chip label (#4751)
* feat: support to show condition in filter chip label

* fix: improve the performance of inline formula with selection
2024-02-28 14:26:08 +08:00
Lucas.XuandMathias Mogensen 980bebf86a fix: mobile UI regression (#4754)
* fix: aa menu item selected status

* feat: support selecting word on iOS throught long pressing

* chore: update editor version

* feat: update add block menu colors

* feat: add scrollbar in bottom sheet

* fix: aa menu should not dimiss after changing block type

* fix: add link menu ui issues

* feat: sync bius status

* Update frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/appflowy_mobile_toolbar_item.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* chore: update editor version

* fix: flutter analyze

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-02-28 13:32:24 +08:00
Mathias Mogensen 26f8397624 feat: duplicate field with cell data (#4737)
* feat: duplicate field with cell data

* chore: code review remove extra option
2024-02-27 14:42:16 +01:00
Lucas.Xu d67e904f56 chore: cleanup disk space before running mobile ci (#4744)
* chore: use macos instead of linux in ci to avoid no spaces error

* chore: optimize disk space
2024-02-27 21:41:47 +08:00
Lucas.Xu f36ca3777b fix: unable to resize the image (#4750) 2024-02-27 21:41:14 +08:00
Richard Shiue 74233d2606 fix: mobile regression (#4747) 2024-02-27 10:51:32 +08:00
Nathan.fooo faea0fa532 chore: Update CHANGELOG.md 2024-02-27 03:37:56 +08:00
Lucas.Xu 3454af1caa chore: update privacy and terms link (#4742) 2024-02-26 15:29:55 +08:00
Nathan.fooo 8d50ad2936 chore: fix log (#4740)
* chore: fix log

* chore: fix log

* chore: bump client api
2024-02-26 15:27:12 +08:00
Richard Shiue daedf95c95 fix: some mobile database bugs (#4738)
* chore: no autofocus on field name

* refactor: one, two, many

* chore: reduce spacing between tabbar header and grid header

* fix: update field type

* fix: cannot edit view name

* fix: title for select field type bottom sheet

* fix: forget checks, just do it
2024-02-26 15:13:38 +08:00
Lucas.Xu 95bfda9dc6 chore: update changelog (#4743) 2024-02-26 15:02:04 +08:00
Lucas.Xu 93664167e0 fix: unable to redo/undo in lists and data loss issues (#4739) 2024-02-26 14:21:36 +08:00
Lucas.Xu dfe3b0a929 fix: the button sizes in math equation input field are not same (#4741) 2024-02-26 14:21:27 +08:00
Kilu.He e2028ac5a0 fix: database bugs (#4632)
* fix: database bugs

* fix: calendar picker

* fix: the position of collapse menu button

* fix: modified some style

* fix: slash command

* fix: selection style

* fix: support toggle inline formula

* fix: block color effect grid block

* fix: if isRange and date is greater than endDate, swap date and endDate

* fix: remove sorting before insert row

* fix: toggle property visible status

* fix: modified tauri window size

* fix: placeholder should be hidden when composing

* fix: support href shortcut

* fix: prevent submit when the formula has error

* fix: modified layout selection

* fix: add padding for record edit

* fix: remove sorts before drag row

* fix: modified chip style

* fix: if previous node is an embed, merge the current node to another node which is not an embed

* fix: modified emoji picker
2024-02-26 10:19:21 +08:00
Mathias Mogensen c9dc24a13c fix: launch review 0.5.0 (#4735)
* fix: top bar buttons slow respond

* fix: fav button responsive

* fix: add favorite button to database views

* fix: add overflow to calculation

* fix: minor workaround for showing number format prefix

* fix: clear calculation on empty field cells

* fix: average calculation should not have def value

* fix: cargo fmt
2024-02-25 21:32:44 +01:00
Mathias Mogensen 609557c357 feat: word and char count (#4705)
* feat: word and char count

* chore: lints after merge

* feat: add create time of view in more action

* fix: missing comma lint

* feat: add duplicate/delete + database view more

* fix: dispose logic

* feat: code cleanup

* fix: add false for isDocument in databases

* feat: register view info bloc on plugin basis

* fix: accidental removal

* chore: clean up

* fix: add ViewInfoBloc above Row Document Editor

* chore: final clean up
2024-02-25 16:46:13 +01:00
Lucas.Xu 93af6e69a1 feat: convert link preview block to url text (#4734) 2024-02-25 22:59:23 +08:00
Lucas.Xu b75947b630 fix: unable to click the items in a long list (#4733) 2024-02-25 21:36:46 +08:00
Lucas.Xu b60d25a0e3 fix: unable to upload image from clipboard (#4728)
* fix: unable to upload image from clipboard

* chore: apply suggestion
2024-02-25 18:50:35 +08:00
Richard Shiue 537fa52e77 chore: move database domain code to its own folder (#4556) 2024-02-25 18:38:18 +08:00
Richard Shiue d861ce6227 fix: mobile view and field list bottom sheets (#4727) 2024-02-25 11:51:18 +08:00
Nathan.fooo c3e5aa29fc fix: doc open sync (#4732)
* chore: bump client api

* fix: open document and folder

* chore: bump collab rev

* chore: fix wasm build

* chore: fix warnings
2024-02-25 07:49:44 +08:00
Richard Shiue 4ca3ba8e08 fix: cjk input in calendar and row detail (#4726) 2024-02-24 22:55:35 +08:00
Richard Shiue f5cc6521fb chore: clean up db sort blocs (#4725) 2024-02-24 22:55:22 +08:00
Lucas.Xu cea1c17b76 feat: improve outline block (#4722) 2024-02-24 21:54:21 +08:00
Lucas.Xu 2abb396467 feat: use result instead of either (#4724)
* feat: use result instead of either

* chore: remove dartz
2024-02-24 21:54:10 +08:00
Lucas.Xu 236b5bfe90 feat: error message should persist on the image block (#4710) 2024-02-24 11:05:20 +08:00
Dev-for-fun fa3bc97698 fix: remove duplicated button labels for done, cancel and ok (#4718) 2024-02-23 23:01:01 +08:00
Richard Shiue c0796e8ae5 feat: mobile sort editor (#4714) 2024-02-23 20:47:19 +08:00
Richard Shiue acd75befbc fix: disable onTap when quick action button is disabled (#4713) 2024-02-23 16:56:31 +08:00
Richard Shiue 746f0817bc fix: show database view options for inline as disabled (#4711) 2024-02-23 10:49:34 +08:00
Lucas.Xu c0b667b4ea chore: optimize image block actions menu (#4707) 2024-02-23 09:46:21 +08:00
Lucas.XuandMathias Mogensen ef83688907 fix: the keyboard blocked the content of bottom sheet (#4706)
* fix: the keyboard blocked the content of bottom sheet

* chore: apply suggestion

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-02-22 22:54:56 +08:00
Lucas.Xu c06a0346d8 chore: bump version 0.5.0 (#4700) 2024-02-22 10:22:33 +08:00
Richard Shiue 4a0c48f419 feat: bottom sheets with transition (#4608)
* feat: shiny new bottom sheets

* chore: code review
2024-02-22 09:54:54 +08:00
Lucas.Xu 7802c75d7c feat: support scaling text on mobile (#4690) 2024-02-22 09:50:24 +08:00
Richard Shiueandnathan f1831d07af chore: re-implement get_filter_by_field_id function (#4678)
* chore: remove inaccurate database view function

* chore: update collab rev

* chore: fix clippy

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-02-22 08:07:59 +08:00
Richard ShiueandNathan.fooo 6636731487 feat: checklist sort (#4659)
* refactor: use BoxAny for dynamically-typed cell changesets

* fix: rust-lib tests and clippy

* feat: enable sorting by checklist type option

* test: checklist sort rust-lib tests

* chore: update related tests

* fix: clippy

---------

Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2024-02-22 08:00:59 +08:00
Richard Shiue a4a2a4088b refactor: use BoxAny for dynamically-typed cell changesets (#4655)
* refactor: use BoxAny for dynamically-typed cell changesets

* fix: rust-lib tests and clippy
2024-02-22 07:12:52 +08:00
Richard Shiue c500cd1287 refactor: improve type option filter logic (#4652) 2024-02-22 07:09:12 +08:00
Richard Shiue 6f173c2ada chore: adjust show mobile bottom sheet (#4689) 2024-02-21 21:06:46 +08:00
Richard Shiue 34fb1bcfa4 fix: disappearing sorts (#4691)
* chore: copy the field type

* chore: don't store field type in Sort

* fix: sorts disappearing
2024-02-21 20:01:57 +08:00
HY 58aa73b5be fix: resolve lexical ambiguity between "row" and "col" in zh-TW translation (#4683)
ref: https://terms.naer.edu.tw/detail/5e94c72b55cc73ebf81d71ca2b5d57e6/?seq=1
2024-02-20 22:40:03 +08:00
Richard Shiue 334aedd6c6 refactor: checkbox field type (#4682) 2024-02-20 14:02:32 +08:00
Richard Shiue a6c6aa819c fix: newly-created rows aren't being automatically sorted (#4661)
* fix: newly-created rows aren't being automatically sorted

* chore: new database view collab notification and add tests
2024-02-20 13:17:46 +08:00
Jayaprakash 15c9a67028 feat: implement outline block component depth control (#4642)
* feat: add support to control the depth of outline block component

* feat: update localization keys

* feat: add depth option to `BlockOptionButton`

* feat: retrive outline block heading components upto the depth level

* feat: add depth option config to editor configuration

* test: outline block depth control

* feat: add outline block placeholder

* refactor: remove redundant codes

* ci: trigger github actions

* chore: refactor `OptionDepthType` enum

* fix: flutter ci error

* refactor: removed `finalHeadingLevel` from outline keys

* fix: flutter ci error
2024-02-20 10:52:06 +08:00
Lucas.Xu 42cb032bca fix: flutter analyze (#4680) 2024-02-19 21:48:06 +08:00
Mathias Mogensen a3a5709b70 fix: dispose of previous applaunch tasks (#4631) 2024-02-19 21:32:01 +08:00
Ansah Mohammad 3a4247c304 feat: convert time format from HHmm to HH:mm in time field (#4641)
* feat: add a HHmm to HH:mm function

* fix: Replaced string.parse() with string.parseStrict() to address time input bug

* feat: add TextFormatter for formatting the time input
2024-02-19 21:30:28 +08:00
Sore 8eaadccda0 chore: add ckb-KUR translations (#4658)
* Create ckb-KUR.json

Add Translate (Kurdish-ckb Language)

* Update language.dart

i added ckb lang(kurdish).

* Update app_widget.dart
2024-02-19 17:43:01 +08:00
ArcesilasandLucas.Xu 2b6b10788d chore: update fr-FR and fr-CA translations (#4676)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-02-19 17:25:00 +08:00
Lucas.Xu 26f8bbf7c6 feat: optimize image upload process and display an error message if upload fails (#4679)
* chore: optimize image upload

* feat: show upload image status

* chore: upload the ai image to cloud server
2024-02-19 17:24:47 +08:00
Lucas.Xu 252699d249 chore: upgrade to flutter 3.19.0 (#4677)
* chore: upgrade to flutter 3.19.0

* chore: adjust to the latest flutter convention

* chore: update CI flutter version

* fix: flutter analyze

* fix: flutter analyze

* fix: flutter analyze

* chore: fix docker build
2024-02-19 13:49:55 +08:00
Nathan.fooo b2e55c4e2e Fix: init state (#4672)
* chore: fix login state

* chore: change log

* chore: fix flutter version
2024-02-18 16:40:18 +08:00
Bastian Leichtandnathan d5ee372131 chore: update translations (#4615)
Co-authored-by: nathan <nathan@appflowy.io>
2024-02-18 07:36:23 +08:00
Arcesilasandnathan 39588a4731 chore: update translations (#4664)
Co-authored-by: nathan <nathan@appflowy.io>
2024-02-18 00:44:39 +08:00
HYandnathan 211559ed6e chore: Update translations for Traditional Chinese (#4662)
* chore: update zh-TW translations

* inlang: update translations

* inlang: update translations

* chore: update zh tw

* chore: update zh tw

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-02-18 00:40:22 +08:00
kosei a637517413 feat: update ja-JP translations (#4627) 2024-02-18 00:25:52 +08:00
Mathias Mogensen ddbe0fa698 fix: tauri build (#4669)
* ci: update workflows

* chore: add back translations used on web
2024-02-17 14:38:12 +01:00
TeddyFlink ee61ef3f12 feat: update translations (#4654) 2024-02-17 16:31:25 +08:00
PWandnathan 54bfc65664 feat: translate to traditional Chinese (#4505)
* inlang: update translations

* inlang: update translations

* inlang: update translations

* inlang: update translations

* inlang: update translations

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-02-17 16:28:10 +08:00
Richard Shiue c159a5e42b chore: enable number filter (#4653)
* chore: enable filtering by number field type

* chore: code cleanup

* fix: integration test

* chore: remove unnecessary async from event handler
2024-02-17 15:28:49 +08:00
Richard Shiue 1311e2d379 fix: build regression (#4667) 2024-02-17 14:42:01 +08:00
Hassam Sulehriaandjazima e6aa57275a feat: open emoji selection menu with keyboard short (#4133)
* feat: Implement emoji shortcut event (#2038)

* test: emoji shortcut integration test (#2038)

* test: Fixed testcase for emoji_shortcut_test (#2038)

* fix: remove _showEmojiPickerMenu (#4133)

* fix: change local variables with underscore

---------

Co-authored-by: jazima <jazim.a.29@gmail.com>
2024-02-16 18:47:23 +01:00
Danilo Barion Nogueiraandnathan d690ca2751 chore: update translations (#4270)
Co-authored-by: nathan <nathan@appflowy.io>
2024-02-17 01:44:05 +08:00
Richard Shiue 3e0a003872 fix: deleting a sort doesn't allow creating a new sort on that field (#4660) 2024-02-16 13:39:49 +08:00
Nathan.fooo e81a2ff577 fix: token refresh on local (#4650)
* fix: refresh user token on local

* chore: add test
2024-02-14 09:38:05 +08:00
Mathias Mogensen b356927e60 feat: improve more action in document (#4639) 2024-02-09 15:54:05 +01:00
Mathias Mogensen 1894409dc3 ci: resolve mobile build failing due to missing space (#4640)
* chore: remove additionally unused tools

* chore: test

* chore: bunch cleanup commands
2024-02-09 14:40:06 +01:00
nathan f29f1bae32 chore: update error message 2024-02-09 10:18:52 +08:00
Nathan.fooo 45054e7639 chore: bump version 047 (#4635) 2024-02-09 00:18:51 +08:00
Nathan.fooo 3b51a6e6be chore: reload workspace when fail to load at the first time (#4633)
* chore: reload workspace when fail to load at the first time

* fix: clippy

* chore: update client api

* chore: fix wasm build

* chore: fix test
2024-02-08 23:53:05 +08:00
Ansah Mohammad 747fe40648 feat: toggle favourites from the documents top bar. (#4382)
* feat: init star button

* feat: implemented star button on the right bar

* feat: Implemented toggle logic

* chore: Added ToolTip for favorite button

* refactor: renamed star to favorite

* refactor: moved appplication logic into favorite_cubit

* chore: arranged imports in alphabetical order

* refactor: reused favorite_bloc for toggle

* fix: fixed the icon no rebuild

* refactor: moved the FavoriteBloc higher in the widget tree

* refactor: moved FavoriteBloc inside multiBlocProvider of desktop_home_screen

* chore: specified bloc type

* chore: cleaned code

* refactor: use any instead of map
2024-02-08 10:45:54 +01:00
Kilu.He 60fc5bb2c8 fix: tauri folder bugs (#4589) 2024-02-08 14:22:44 +08:00
Mathias Mogensen 9d71464f1a fix: select name by default (#4630) 2024-02-07 21:49:17 +01:00
Mathias Mogensen 92ceb2cd7d fix: dispose of resources in time (#4625)
* fix: limit length when renaming views

* chore: clean up database listeners

* fix: dispose of controllers properly

* fix: dispose of resources properly

* fix: deleting filters with same name

* chore: extend DatabaseTabBarItemBuilder

* fix: null check on null value
2024-02-07 18:38:53 +01:00
Richard Shiue 0db21b91a3 fix: unequal grid header and body widths (#4626) 2024-02-07 17:49:53 +01:00
Richard Shiue 88e9d63a13 fix: show newChecklistTask on hover over entire list item in row detail page (#4622) 2024-02-07 23:20:26 +08:00
Mathias Mogensen 3129fa6cc1 fix: use cmd+. to toggle sidebar on macOS (#4621)
* fix: use cmd+. to hide sidebar on macOS

* fix: update missed tooltip
2024-02-07 12:18:13 +08:00
Mathias Mogensen db5372c18e feat: hotkey to open settings dialog (#4620)
* feat: hotkey to open settings dialog

* chore: change to cmd/ctrl+,
2024-02-07 12:17:48 +08:00
Richard Shiue b781c9aa0f fix: deleting a sorting field doesn't delete existing sorts (#4611) 2024-02-07 10:47:17 +08:00
Richard Shiue a9c6b80f4a chore: add spacing between field buttons in setting popover (#4612) 2024-02-07 10:46:36 +08:00
Lucas.Xu 271f781cce fix: application will raise an error when selecting unsplash image in local mode (#4604) 2024-02-05 21:53:14 +07:00
Richard Shiue ef4bce25d8 feat: sort by last modified time or created time (#4601) 2024-02-05 21:54:42 +08:00
ansizheshi 95c4cb241a chore: update zh-CN translations (#4599) 2024-02-05 17:39:45 +08:00
Dorian Péron e20d938ce3 chore: update translations (#4581) 2024-02-05 16:53:18 +08:00
Richard Shiue a515715543 feat: reorder sort precedence (#4592)
* feat: reorder sorts

* chore: add tests, fix tests, fix tauri build and fix clippy

* fix: add missing import
2024-02-05 13:52:59 +08:00
Nathan.fooo fda70ff560 feat: folder web (#4580)
* chore: folder wasm

* chore: folder wasm

* chore: resolve deps

* chore: fix trait

* chore: try localset

* chore: fix

* chore: fix

* chore: fix

* chore: async init sdk

* chore: fix test

* chore: fix test
2024-02-04 05:50:23 +08:00
Zackandnathan 08938b8c70 feat: cloud workspace api (#4469)
* feat: workspace api

* feat: added cloud apis for add and delete workspace

* feat: add and delete workspace event handlers

* chore: rust fmt

* chore: save user workspace

* test: add test

* test: add test

* chore: add to gitignore

* feat: update api add name to workspace

* chore: cargo clippy and rename to create

* chore: add envrc and direnv to gitignore

* chore: change name to create workspace instead of add workspace

* chore: update client api rev

* feat: add create workspace impl

* chore: restore gitignore to original

* test: fix create workspace event test

* fix: change delete workspace input

* fix: compile

* fix: create workspace test

* feat: add error code for request payload too large

* chore: remove cargo backup files

* feat: add is async option for upload file handler

* chore: update client api version

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-02-04 05:49:45 +08:00
Richard Shiueandnathan 250f29f325 chore: clean up sort and filter code (#4585)
* refactor: port away from extra SortType struct

* refactor: add validator to flowy_database and clean up unused structs

* refactor: port away from extra FilterType struct

* chore: analysis options

* fix: clippy and dart/ts compile

* fix: tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-02-04 05:49:28 +08:00
Yijing Huang d117cd6b5b chore: delete placeholder code and clean code (#4503) 2024-02-04 00:56:50 +08:00
Richard Shiue ca93cb20ec chore: revamp mobile database toolbar (#4579)
* chore: revamp mobile database toolbar

* chore: code cleanup
2024-02-04 00:55:44 +08:00
Richard Shiue 8c1d0106dd chore: inkwell mobile quick action sheets (#4576)
* chore: inkwell mobile quick action sheets

* chore: more subtle tap effect

* chore: improve code style
2024-02-04 00:55:05 +08:00
Mathias Mogensenandnathan 5cbc8b1e18 feat: calculations (#4473)
* feat: initial calculation controller

* fix: entities

* feat: calculations

* fix: review comments and support floats

* fix: abstract business logic into calculations service

* fix: clean calculation entities after merge

* feat: react to changes to row/cell/field_type

* chore: changes after merging main

* feat: handle delete field

* test: add grid calculations tests

* fix: add validation + format numbers

* refactor: get cell number

* chore: bump collab

* chore: fix clippy

* chore: update docs

* chore: update docs

* chore: fmt

* chore: fix flutter

* chore: collab rev

* fix: cleanup and hover to show

* fix: localization

* test: add basic rust test

* fix: clippy

* fix: support updating calculation on duplicate row

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-02-04 00:52:38 +08:00
Nathan.fooo 274742e334 chore: bump version v0.4.6 (#4595)
* chore: bump version

* chore: bump client api version
2024-02-03 19:45:46 +08:00
Lucas.Xu 792f56db79 chore: remove unused build and add build bot (#4586) 2024-02-02 17:42:23 +08:00
nathan 458d3f971b chore: bump client api 2024-02-02 09:35:55 +08:00
Nathan.fooo 2ffd6bf7ea chore: bump version (#4583) 2024-02-02 09:30:27 +08:00
Nathan.fooo 722691c922 chore: fix ws conn (#4582)
* chore: fix ws conn

* chore: flutter analyzer

* chore: update client api
2024-02-02 09:27:11 +08:00
Kilu.He 9746852b5f fix: fixed editor bugs (#4552)
* fix: fixed editor bugs

* fix: add error boundary
2024-02-02 05:47:41 +08:00
Lucas.Xu 5b030303a6 fix: appimage build (#4578)
* chore: force exec flutter package pub get

* feat: support building appimage on github ci
2024-02-01 20:58:58 +08:00
XiaoFans 1e4f342fc3 chore: update translations (#4577) 2024-02-01 20:53:49 +08:00
Richard Shiue 4f0379bdd7 fix: size of hitbox in app bar button (#4575) 2024-02-01 20:53:21 +08:00
Lucas.Xu ce261c9128 fix: keyboard not show automatically (#4572) 2024-02-01 15:41:14 +08:00
Richard Shiue 20391bfec4 chore: revamp database setting action sheets (#4570)
* chore: revamp database setting action sheets

* chore: field picker improvement

* chore: fix comments
2024-02-01 15:41:02 +08:00
Richard Shiue 9d28360887 fix: mobile ui improv and bugs (#4567)
* fix: quick edit field bottom sheet header

* fix: field editor appbar regression

This stems from moving to a standardized FlowyAppBar
2024-02-01 10:27:03 +08:00
Lucas.Xu 99f9cb2a09 chore: bump version 0.4.4 (#4566) 2024-01-31 22:37:04 +08:00
Mathias MogensenandLucas.Xu 247405ff51 fix: launch review reminder (#4514)
* fix: dismiss menu on enter on no result

* fix: add drag handle to mobile reminder dialog

* fix: show reminder icon  in date cell in grid

* fix: auto select day when selecting reminder

* fix: increase height of notification hub

* fix: let some reminder options require time and show time

* fix: handling of non-time reminder options

* test: fix edit date time cell test

* fix: close popover when pressing child again

* fix: add time of now when setting include time

* fix: clean logic

* fix: tests

* fix: add test and include time in notification hub

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-01-31 21:17:36 +08:00
Nguyễn Thái Lâm d27e2179cc chore: update vietnamese translations (#4536) 2024-01-31 21:16:39 +08:00
indar 100cc19747 chore: update translations id-ID (#4548) 2024-01-31 21:16:11 +08:00
Richard Shiue fa66a119ed fix: mobile UI issues (#4561)
* fix: don't re-request focus after editing a cell

* fix: card detail more actions

* fix: select option indicators

* fix: add field bottom sheet revamp

* fix: edit field type bottom sheet

* chore: bump spacing between header and first row of field types

* fix: grid spacing

* refactor: use svg and background colors

* refactor: use shared component
2024-01-31 21:15:38 +08:00
Lucas.Xu a9787546b4 chore: update add block menu icons (#4565) 2024-01-31 21:15:23 +08:00
Peter Dave Hello 5cbe90c79f chore: further improve and update zh-TW translation (#4558)
This is a follow up of #4345, to continue improve the translation
quality, as the original translation was more Simplified-Chinese, and
there are also some new strings need to be translated.
2024-01-31 20:17:35 +08:00
Lucas.Xu a143a030a9 feat: reafactor add block menu (#4563) 2024-01-31 17:47:02 +08:00
Richard Shiue caede19267 chore: get rid of space in code block of readme (#4547) 2024-01-31 10:47:51 +08:00
Lucas.Xu d410ffbaa8 feat: support exporting log files (#4559)
* feat: support exporting log files

* feat: support uploading log files on Android
2024-01-31 10:07:50 +08:00
Nathan.foooandRichard Shiue 0483e305e7 chore: rename (#4551)
Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2024-01-31 00:43:55 +08:00
Lucas.Xu f6242f1cc7 feat: add signout dialog (#4557) 2024-01-31 00:40:52 +08:00
Richard Shiue 18c7fff34b refactor: clean up select type option logic (#4554) 2024-01-30 23:20:11 +08:00
Lucas.Xu 792573f46d feat: optimize image block (#4553)
* feat: add tooltip for maximum image size

* feat: add maximum upload image size tooltip

* feat: limit image size to 10MB

* fix: disable copy link option for cloud image

* fix: disable copy link option for cloud image

* feat: use regex to match the appflowy.cloud image
2024-01-30 22:39:42 +08:00
Lucas.Xu e9d7d0b7b3 fix: incorrect background color using in view action menu (#4513) 2024-01-30 16:07:51 +08:00
Lucas.Xu 0b7ae734a1 fix: potential dependency conflict (#4550)
* fix: potential dependency conflict

* fix: ci issues
2024-01-30 16:05:56 +08:00
Nathan.fooo c0aef8f4fe fix: login issue (#4546)
* fix: reset server url when using appflowy cloud the first time

* refactor: set authenticator in frontend

* chore: log version

* chore: show hint when changing the server type

* chore: bump version

* chore: fix test

* chore: bump collab
2024-01-30 09:33:34 +08:00
Nathan.fooo 55c97b56a3 feat: calling user event from web (#4535)
* refactor: user manager

* refactor: user manager

* refactor: session location

* refactor: user manager

* chore: gen ts files

* feat: implement indexeddb persistence

* chore: integrate user manager

* chore: update

* chore: run on web thread

* chore: run on web thread

* chore: fix test

* chore: add test

* chore: add test

* chore: add user & sign in with password

* chore: fix test

* chore: update docs

* chore: fix warnings

* chore: gen files

* chore: add user

* chore: add files

* chore: update config

* chore: update scirpt

* chore: update scirpt

* fix: build

* chore: update command

* fix: ci

* ci: fix

* fix: compile

* fix: compile

* fix: ci

* fix: compile

* fix: tauri build

* chore: fix test

* chore: fix test
2024-01-30 05:36:27 +08:00
Mathias Mogensen 86a0569d84 feat: f2 to rename current view (#4522)
* feat: cmd+shift+r to rename current view

* test: change cmd to f2 and add test

* chore: code review

* fix: unawaited future
2024-01-29 20:55:37 +01:00
Lucas.Xu 5b3b0e54d9 feat: refactor app bar (#4539)
* feat: refactor appbar

* fix: flutter analyze
2024-01-29 23:13:06 +08:00
Lucas.Xu f1e380c276 fix: add more padding in bottom sheet widget (#4542) 2024-01-29 23:12:56 +08:00
Mathias Mogensen ea93f0e141 fix: idiomatic dow can be 1 character (#4543) 2024-01-29 13:10:47 +01:00
Abhijeet SinghandLucas.Xu c1433ce38a chore: update translations (#4510)
* Update es-VE.json

* inlang: update translations

* Delete project.inlang/project_id

* inlang: update translations

* Delete project.inlang directory

* Create settings.json

* inlang: update translations

* inlang: update translations

* inlang: update translations

* inlang: update translations

* inlang: update translations

* inlang: update translations

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-01-29 17:33:58 +08:00
XiaoFansandLucas.Xu 831586293e chore: update Chinese translations (#4521)
* inlang: update translations

* Revert "inlang: update translations"

This reverts commit a6e1d945c1.

* chore: update Chinese translations

The translation this time is tailored to the reading habits of Chinese readers, correcting some machine-translated content. Additionally, I have included some content that was not translated before.

* chore: update frontend/resources/translations/zh-CN.json

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-01-29 17:28:47 +08:00
Richard Shiue 5c5b6d02e8 fix: don't show ungrouped column when the field type is checkbox (#4538) 2024-01-29 17:27:59 +08:00
Lucas.Xu 8937856d36 feat: new UI design for number format list (#4537) 2024-01-29 16:34:19 +08:00
Richard Shiue 63c22feb8f fix: mobile field editing related bugs (#4534)
* fix: mobile field editing related bugs

* chore: review

* chore: restore podfile.lock
2024-01-29 13:19:35 +08:00
Richard Shiue 05a06980b9 chore: add unwaited futures to analysis options (#4485) 2024-01-29 10:26:45 +08:00
Lucas.Xu 7be29c04a2 fix: unable to delete image and refactor image actions menu (#4525)
* feat: refacotr image block action

* fix: unable to delete the image placeholder

* fix: unable to delete the image placeholder
2024-01-29 10:15:48 +08:00
Lucas.Xu 5a9a1e60e6 fix: bottom sheet issues (#4523)
* fix: bottom sheet padding

* fix: set divider width to 0.5px

* feat: optimize number select menu

* chore: update edit field icons

* chore: use short form in add block menu

* feat: optimize select and multi-select menu

* feat: refactor font settings page, theme mode menu and rtl menu
2024-01-28 22:50:25 +08:00
Richard Shiue 4811e65efa chore: reorganize cell code (#4516)
* chore: move cell bloc files to application

* chore: move cell editor widgets to its own folder
2024-01-27 10:57:09 +08:00
Lucas.Xu 72a23bfe82 feat: update recentViews list to only keep the first 20 items (#4512) 2024-01-26 22:35:33 +08:00
Lucas.Xu ed78cb4efc fix: the items in database field menu are not aligned (#4511)
* fix: title in settings page overflow

* fix: the icon and text in database field menu aren't aligned

* fix: the icon and text in database field menu aren't aligned
2024-01-26 22:35:16 +08:00
Richard Shiue d2cc799861 fix: mobile row detail title not being updated (#4507) 2024-01-26 22:23:59 +08:00
Richard Shiue 2e7a97c8a2 chore: enable timestamp field on mobile (#4506) 2024-01-26 22:23:47 +08:00
Lucas.Xu 64cd7d41ca fix: the text and icon in + menu are not aligned in the same baseline (#4500) 2024-01-26 10:06:49 +08:00
Lucas.Xu 0e3ffa8fd5 feat: action sheet revamp (#4497) 2024-01-26 00:33:45 +08:00
Lucas.Xu be00980fdd chore: optimize android UI (#4498) 2024-01-26 00:24:33 +08:00
Abhijeet Singh 7fbaf204ef chore: update translations (#4493) 2024-01-25 23:46:42 +08:00
Mathias Mogensen acc03b8cc4 chore: code cleanup according to unintroduced lints (#4488)
* chore: remove redundant arguments

* chore: remove unused constructor params

* chore: reorganize constructors

* chore: remove unnecessary awaits in returns

* chore: remove unnecessary paranthesis

* chore: add lints

* chore: clean up after merge

* chore: add sort constructors first

* chore: organize constructors in blocs

* chore: use sizedbox.shrink over empty container
2024-01-25 23:37:36 +08:00
Richard Shiue 747abba87f fix(mobile): remove elevation from edit field page and remove inksplash in card detail if disabled (#4491) 2024-01-25 13:20:48 +08:00
Richard Shiue e88fb533c8 fix: composing in select option text field doesn't work (#4470)
* fix: composing in select option text field doesn't work

* style: improve code style
2024-01-25 13:17:13 +08:00
Richard Shiue 3f896ad64f chore: reorganize code (#4490)
* rename select_option.rs to select_option_entities.rs

* move checklist_filter.rs from select_type_option to checklist_type_option
2024-01-25 12:56:43 +08:00
Richard Shiue 6591d5de52 chore: dart code cleanup (#4484)
* chore: use when instead of map in bloc event dispatch

* chore: dart code formatting, remove white space

* chore: remove unneeded hashmap for cell context

* fix: rebuild card content
2024-01-25 12:26:18 +08:00
Richard Shiue a1abcd7626 refactor: database cell controller and builder (#4398)
* refactor: get row/field data from row cache and field controller in cell controller

* refactor: reorganize cell controller tasks and builder

* refactor: rename cell_builder.dart

* refactor: database editable cell builder

* refactor: database card cell builder

* fix: make it work

* fix: start cell listener and adjust cell style on desktop

* fix: build card cell

* fix: remove unnecessary await in tests

* fix: cell cache validation

* fix: row detail banner bugs

* fix: row detail field doesn't update

* fix: calendar event card

* test: fix integration tests

* fix: adjust cell builders to fix cell controller getting disposed

* chore: code review

* fix: bugs on mobile

* test: add grid header integration tests

* test: suppress warnings, reduce flaky test and group tests
2024-01-24 23:59:45 +08:00
Abhijeet Singh 18a355601a chore: update translations (#4481) 2024-01-24 22:46:11 +08:00
Lucas.Xu c2fdfb6e89 fix: font shown in AA has _r as a suffix (#4482) 2024-01-24 22:45:13 +08:00
Mathias Mogensen baa7c8d826 feat: reminder on date (#4288)
* feat: support reminder on date

* feat: support reminder on date in database

* fix: include time static

* fix: do not force unwrap

* chore: clean flutter code

* test: add test for reminder in database

* fix: interpret reminder option

* feat: date and reminder on mobile

* feat: improve notification actions and support open row

* feat: support dates in document

* fix: minor changes + review

* feat: support reminder on mobile in document

* feat: support open row on database reminder mobile

* test: add more tests

* fix: first part of review

* fix: open row responsibility

* fix: abstract application logic from presentation layer

* fix: update reminder on date cell update

* test: fix failing test

* fix: show correct selected day after end date toggled
2024-01-24 15:15:57 +01:00
Mathias Mogensen 8105da1c2b Fix: mobile improvements (#4480)
* fix: copy on notifications screen is caught off

* fix: mobile event screen no events copy

* fix: hide notifications toggle from settings

* fix: cannot change type of field in grid
2024-01-24 12:07:02 +01:00
Lucas.Xu 827e41348b feat: keep the offset of the recent section (#4466) 2024-01-23 16:54:04 +08:00
Lucas.Xu e239ba46aa feat: customize self host url on launch page (#4465) 2024-01-23 16:38:15 +08:00
Lucas.Xu 2554ba81b5 feat: optimize cloud settings on mobile (#4444) 2024-01-23 01:37:02 +08:00
Nathan.fooo 84d171b1db chore: bump client api to fix user session issue (#4445) 2024-01-23 01:33:52 +08:00
Lucas.Xu 38902ed599 feat: enable anonymous sign in on mobile (#4442)
* feat: enable anoymous login on mobile

* feat: support signin with third party serices
2024-01-22 22:36:16 +08:00
Lucas.Xu 2cdee386c2 chore: add zip package for Windows (#4441) 2024-01-22 22:36:07 +08:00
Nathan.fooo 90516b6adc feat: wasm build (#4412)
* chore: enable wasm build

* chore: bump collab

* chore: fix build

* chore: flowy-document wasm

* chore: fix compile

* chore: fix compile

* chore: fix compile

* chore: fix compile

* chore: fix ci

* chore: fix ci

* chore: fix ci
2024-01-22 13:34:15 +08:00
Lucas.Xu c4acba8216 fix: mobile sign-in issue (#4424)
* Revert "chore: remove zip package for windows and macOS (#4404)"

This reverts commit f612d9b701.

* Revert "chore: remove zip package for windows and macOS (#4404)"

This reverts commit f612d9b701.

* fix: mobile signin
2024-01-21 21:47:14 +08:00
Continy 4404e0d727 chore: update translations (#4428)
* inlang: update translations

* inlang: update translations

* inlang: update translations
2024-01-20 23:24:10 +08:00
Abhijeet SinghandLucas.Xu 48c6c635f7 chore: update translations (#4406)
* Update es-VE.json

* inlang: update translations

* Delete project.inlang/project_id

* inlang: update translations

* Delete project.inlang directory

* Create settings.json

* inlang: update translations

* inlang: update translations

* inlang: update translations

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-01-20 23:23:44 +08:00
Zsombor 332f40c915 choreL: update Hungarian translations (#4416) 2024-01-20 23:22:33 +08:00
Lecanora 2b32f0eff0 chore: update french translations for inlang (#4419) 2024-01-20 23:21:47 +08:00
Juliano Penna 7d20ca5a77 fix: print correct package name (#4425) 2024-01-20 23:18:50 +08:00
0a0f2adf76 feat: support uploading image to cloud storage (#4413)
* feat: add object ext

* feat: integrate upload image api

* feat: support uploading local file to cloud

* feat: abstact the CachedNetworkImage as FlowyNetworkImage

* ci: fix tauri ci

* fix: integration test

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: nathan <nathan@appflowy.io>
2024-01-20 23:16:18 +08:00
Richard Shiue 4852e5c8d4 fix: don't parse unexpected files while generating protobuf (#4411) 2024-01-17 11:20:02 +08:00
Nathan.fooo 65f1db776b chore: bump version 043 (#4409) 2024-01-17 05:55:47 +08:00
Zackandnathan 38c3e700e9 feat: initial file upload api (#4299)
* feat: initial file upload api

* feat: initial file upload api

* fix: add pb index

* feat: remove file name

* feat: read everything to mem

* feat: revamp object storage

* chore: cargo format

* chore: update deps

* feat: revised implementations and style

* chore: use deploy env instead

* chore: use deploy env instead

* chore: use deploy env instead

* refactor: move logic to handler to manager

* fix: format issues

* fix: cargo clippy

* chore: cargo check tauri

* fix: debug docker integration test

* fix: debug docker integration test

* fix: debug docker integration test gotrue

* fix: debug docker integration test docker compose version

* fix: docker scripts

* fix: cargo fmt

* fix: add sleep after docker compose up

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-01-17 02:59:15 +08:00
Abhijeet Singh 15cb1b5f19 chore: update translations (#4395) 2024-01-16 15:32:04 +08:00
Lucas.Xu 1bf1d03676 chore: set minimum supported android version to android 10 (#4402) 2024-01-16 15:31:27 +08:00
Lucas.Xu f612d9b701 chore: remove zip package for windows and macOS (#4404) 2024-01-16 14:13:40 +08:00
Lucas.Xu 595f1f6ef8 chore: use openai default model (#4368)
* chore: use openai default model

* feat: update openai mode
2024-01-15 16:26:45 +08:00
Lucas.Xu c8e9adb81d fix: unable to use slide gesture to close keyboard (#4391) 2024-01-15 16:26:37 +08:00
Lucas.Xu 6d3a7545a6 chore: update editor version (#4392) 2024-01-15 16:26:27 +08:00
Lucas.Xu 6739af2be1 fix: the aa menu disappear after clicking the inactive indent itemg (#4390) 2024-01-15 15:39:04 +08:00
Nathan.fooo c41a7aaacf chore: support localhost and development mode (#4384)
* chore: update local port for development

* chore: support localhost development

* chore: fix rust test

* chore: update setting

* fix: ci

* fix: ci

* fix: ci

* fix: ci

* chore: fix docker build

* chore: fix ci
2024-01-15 12:53:53 +08:00
ilyes-cedandLucas.Xu d200c409d6 fix: removed space under grid (#4352)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-01-14 22:56:11 +08:00
Lucas.Xu cd28dee7bd chore: bump new version (#4374) 2024-01-14 22:55:17 +08:00
Yijing Huang 7e82a08b54 fix: secondary button outline color (#4381)
* chore: restore the default outline color in SecondaryButton

* chore: improve outline color for learn more button
2024-01-14 22:54:59 +08:00
Jia Hang f0bd50b246 fix: change copyright year to 2024 (#4379) 2024-01-14 22:54:31 +08:00
ferreira-fp e571eb9881 chore: update translations (#4370) 2024-01-14 22:54:10 +08:00
Nathan.fooo c4f4bcf457 feat: using appflowy cloud as the default cloud type (#4380)
* feat: using appflowy cloud as the default cloud type

* fix: test

* Update cloud_env.dart
2024-01-13 03:08:07 +08:00
Nathan.fooo 9500abb363 feat: workspace service in user crate (#4373)
* refactor: user manager

* feat: implement workspace service

* refactor: migrate user data when sign up

* chore: fmt

* chore: enable beta cloud

* chore: update ci

* chore: trim slash
2024-01-12 14:34:59 +08:00
Lucas.Xu 690a3746fa feat: optimize the align toolbar item (#4364) 2024-01-12 10:18:52 +08:00
Nathan.fooo cd82c13753 feat: Stream collab objects (#4361)
* feat: stream collab object

* chore: disable snapshot
2024-01-12 06:26:43 +08:00
Lucas.Xu 032a648204 chore: reduce package size (#4353) 2024-01-11 21:45:20 +08:00
Abhijeet Singh f64ee912d0 chore: update translations (#4354) 2024-01-11 21:45:07 +08:00
Nathan.fooo 307556b7dd refactor: deps crates (#4362)
* refactor: rename flowy-folder-deps to flowy-folder-pub

* chore: rename crates

* chore: move flowy-task to lib-infra

* chore: rename crates

* refactor: user manager dir
2024-01-11 14:42:03 +08:00
Lucas.Xu dd8b9dd43e fix: unable to get the device info in test mode (#4359) 2024-01-11 14:26:25 +08:00
Nathan.foooandMathias Mogensen 6e41359fc5 feat: show indicator when importing appflowy data (#4357)
* feat: show indicator when importing appflowy data

* Update frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_file_import_appflowy_data_view.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* chore: fix analyzer

* chore: fix test

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-01-11 09:44:33 +08:00
Yijing Huang b1cc4e485b fix: upload custom theme issue (#4317)
* fix: FlowyDynamicPlugin encode issue

* chore: improve the default theme color

* fix: learn more button text invisiable

* fix: fix read the wrong theme mode file

* fix: prevent current custom theme being deleted

* chore: improve theme upload UI and error prompts

* chore: delete unnecessary LocaleKeys
2024-01-10 21:21:05 +08:00
Kilu.He 239bf2fa70 refactor: adjust tauri codes (#4332)
* fix: some bugs

* refactor: delete code that is no longer needed
2024-01-10 19:24:40 +08:00
Peter Dave Hello a6baabbafc chore: improve zh-TW translation (#4345) 2024-01-10 18:48:05 +08:00
Nathan.fooo a954b5ffd8 fix: create offline document (#4350) 2024-01-10 18:43:13 +08:00
Lucas.Xu 36b88c602c feat: update privacy policy and add version code (#4343) 2024-01-10 18:42:33 +08:00
Nathan.fooo 190fae196f chore: bump collab (#4348)
* chore: bump collab

* chore: optimize import

* chore: bump

* chore: disable ai test
2024-01-10 11:15:05 +08:00
Jayaprakash 347698f68f feat: support aligning the text block using shortcuts (#4319) 2024-01-09 20:27:08 +07:00
Lucas.Xu db2e23172a feat: support canceling the sign-in event (#4342) 2024-01-09 17:09:44 +08:00
Lucas.Xu dcb070909c feat: support RTL layout on mobile (#4335)
* feat: revamp theme mode settings

* feat: support RTL layout on mobile
2024-01-09 10:12:54 +08:00
Mathias Mogensen 332a677d20 feat: improve reference menus (#4301)
* feat: improve reference menus

* fix: limit page results in reference menus

* fix: custom title for specific type refs

* fix: insert pages

* fix: enable scrolling on item focus change

* fix: enable shift+tab to navigate

* fix: properly offset menu

* fix: review comments

* fix: remove bottom padding on last group
2024-01-08 15:28:36 +01:00
trattaa 75d394fb6e chore: update translations (#4320) 2024-01-08 15:34:25 +08:00
Lucas.Xu 875b9d6cfc feat: improve mobile touch gesture experience (#4328) 2024-01-08 15:06:59 +08:00
occhiodipesce e9326d49c0 chore: update it-IT translations (#4325)
* inlang: update translations

* inlang: update translations
2024-01-08 10:11:36 +08:00
Nathan.fooo 4ee6e297c6 chore: bump collab (#4327) 2024-01-08 08:21:57 +08:00
Richard Shiue c4ebccafd4 fix: adjust select option button hover and padding (#4323) 2024-01-07 21:16:48 +08:00
Richard Shiue 94bdefbf01 chore: update .gitignore (#4324) 2024-01-07 21:16:38 +08:00
Nathan.fooo ba482a30a3 chore: recreate snapshot table & remove old data (#4322)
* chore: recreate snapshot table & remove old data

* chore: disable test

* chore: fmt
2024-01-07 13:59:39 +08:00
Nathan.fooo 76416cfdba test: Import folder test (#4321)
* fix: import old version appflowy data

* chore: add 037 test

* chore: add default appflowy cloud url

* chore: bump collab
2024-01-07 11:12:05 +08:00
Nathan.fooo 2557e4f3cc chore: using zstd as collab_db compression method and Deflated as zip file compression method (#4318) 2024-01-06 12:46:11 +08:00
Kilu.Heandnathan 79c912219d feat: appflowy_web build (#4302)
* chore: create web folder

* fix: support lib-dispatch and notification compiling to wasm

* refactor: wasm

* refactor: call async evnet

* chore: add web ci

* ci: fix

* ci: fix

* ci: fix

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-01-06 11:50:05 +08:00
Nathan.fooo 89370b4a55 chore: lib-dispatch wasm build (#4307)
* chore: lib-dispatch wasm build

* chore: add wasm crate

* chore: add wasm demo

* chore: fix test
2024-01-06 00:37:26 +08:00
Baraa Al-Masri ecbc2601c4 chore: update ar-SA translations (#4131)
* chore: update translations from inlang

* Resync translations from upstream
2024-01-06 00:34:40 +08:00
TasseDo f3753435e6 chore: update fr-FR and fr-CA translations (#4305)
* inlang: update translations

* inlang: update translations
2024-01-05 21:21:57 +08:00
Richard Shiue 1eeb812a1c refactor: rename database code path from database_view to database (#4310) 2024-01-05 17:30:54 +08:00
Lucas.Xu 6dba118413 fix: macos universal build (#4311) 2024-01-05 15:28:47 +08:00
Richard Shiue ee7fc5d77d fix: number field editor full height (#4308) 2024-01-05 12:21:51 +08:00
Nathan.fooo e7533c149f chore: bump client api (#4306) 2024-01-05 11:49:28 +08:00
maTh bdec917a35 chore: update de-DE translations (#4272)
* fix: labels from bottom of list started to translate

* fix: finished the last labels

* fix: Comma

* fix: typo

* fix: better wording for forstDayOfWeek

* fix: better wording for incluceTime
2024-01-05 11:13:54 +08:00
Abhijeet SinghandLucas.Xu 76a3daecaf chore: update es-VE translations (#4267)
* Update es-VE.json

* inlang: update translations

* Delete project.inlang/project_id

* inlang: update translations

* Delete project.inlang directory

* Create settings.json

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-01-05 11:09:02 +08:00
Nathan.fooo ed1952d6a9 chore: bump client api (#4303) 2024-01-05 06:12:21 +08:00
Nathan.fooo 5a87229fe9 chore: Collab wasm build (#4297)
* fix: ci

* fix: ci

* fix: build

* chore: bump collab
2024-01-05 00:05:38 +08:00
Nathan.fooo eac878d563 fix: import document from database row (#4295)
* fix: import document from database row

* chore: update test

* chore: fix test

* chore: fix test

* chore: fix test

* chore: fix local user on appflowy cloud error

* chore: clippy

* chore: bump pubspec version
2024-01-04 08:02:12 +08:00
Nathan.fooo de08c01c4c chore: bump version (#4294)
* chore: bump version

* chore: bump version
2024-01-03 12:35:26 +08:00
Nathan.fooo 7937fd1f3a fix: 040 bugs (#4285)
* test: add tests

* chore: set maximum log files

* fix: import row document

* chore: bump client api

* chore: fix analyzer

* chore: fix flutter unit test
2024-01-03 11:41:29 +08:00
maTh eef5c2bf66 fix: more labels translated to German and improved (#4261) 2024-01-01 13:33:28 +08:00
dependabot[bot] 9c769cd7e5 chore: bump @babel/traverse in /frontend/appflowy_tauri (#4260)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.5 to 7.23.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-31 13:42:43 +08:00
dependabot[bot] eac58dc212 chore: bump @tauri-apps/cli in /frontend/appflowy_tauri (#4263)
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 1.3.1 to 1.5.6.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/cli.js-v1.3.1...@tauri-apps/cli-v1.5.6)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-31 13:42:11 +08:00
nathan d3241cdecb chore: update changelog 2023-12-31 13:41:17 +08:00
Lucas.Xu 857f645131 fix: windows package output path (#4265) 2023-12-31 11:54:55 +08:00
Nathan.fooo 2521611d6a chore: bump sqlite system deps (#4262)
* chore: bump sqlite system deps

* chore: bump open ssl

* chore: fix clippy

* chore: remove unused deps

* chore: fix test
2023-12-31 10:23:43 +08:00
Nathan.fooo 5facb61e23 refactor: crates (#4258)
* chore: rename flowy-folder2 to flowy-folder

* chore: rename flowy-document2 to flowy-document

* chore: fix test

* chore: move lib-infra crate

* chore: remove shared-lib

* chore: fix clippy
2023-12-31 07:29:40 +08:00
Lucas.Xu 2f6a4f8c7b chore: adjust flutter windows release path (#4257) 2023-12-31 02:23:27 +08:00
Lucas.Xu 84b8b92582 chore: upgrade flutter dependencies (#4256) 2023-12-30 22:23:01 +08:00
Lucas.Xu 827d7c381e chore: bump version 0.4.0 (#4255) 2023-12-30 15:52:09 +08:00
maTh b0bf99da34 fix: more labels to German translated and improved (#4248) 2023-12-30 15:49:09 +08:00
Yijing Huang ca50e56474 chore: update fontFamily in button theme (#4251) 2023-12-30 15:48:20 +08:00
Nathan.fooo 36cf653d64 chore: support import appflowy data into current workspace (#4254)
* chore: support import appflowy data into current workspace

* refactor: code

* chore: unused ref

* chore: update url
2023-12-30 13:44:09 +08:00
Nathan.fooo 8ccd1ec72c chore: remove anon user when sign up with a new user (#4253)
* chore: remove anon user when sign up with a new user

* chore: clippy
2023-12-30 09:36:22 +08:00
Nathan.fooo 7ba3020ab3 chore: skip create sync plugin when the authenticator for given user … (#4252)
* chore: skip create sync plugin when the authenticator for given user is local

* chore: bump collab
2023-12-30 07:05:26 +08:00
Nathan.fooo 50694bb589 chore: support Rust 1.75 (#4246)
* chore: fix wanrings

* chore: update rust version
2023-12-30 01:22:06 +08:00
Nathan.fooo 206ccb2c43 fix: supabase sync (#4243)
* chore: fix supabse sync

* chore: bump collab

* chore: fmt

* chore: remove unused key
2023-12-29 15:03:24 +08:00
Kilu.He d2ccec79e4 feat: support block align (#4219)
* fix: mention bugs

* feat: support to align block range

* fix: inline formula bugs

* fix: adjust UI of color picker

* fix: tab bugs
2023-12-29 13:50:06 +08:00
Nathan.fooo 69469e9989 feat: Import appflowy data (#4236)
* refactor: traits

* feat: import data

* chore: track database view

* fix: import

* refactor: collab doc state

* refactor: get collab doc state

* feat: batch create collab object

* fix: test

* ci: run docker compose if the server is not up

* chore: bump collab

* chore: update ci

* chore: update ci

* chore: update ci

* chore: implement ui

* chore: implement ui

* chore: implement ui
2023-12-29 13:02:27 +08:00
Richard Shiue c821b8c4fe fix: field editor bugs (#4241) 2023-12-29 11:35:53 +08:00
Lucas.Xu 93786bad44 fix: disable unsupported buttons (#4242)
* fix: disable ... button and recover selection after changing text font

* fix: add image block will close keyboard on Android

* fix: the padding of align items are not equal

* fix: callout block issues
2023-12-29 11:35:39 +08:00
Lucas.Xu f5bfcdcb98 fix: unable to see the text of link menu in dark mode (#4239) 2023-12-29 11:18:00 +08:00
Lucas.Xu d57b61b213 fix: mobile ci (#4232) 2023-12-29 11:17:50 +08:00
Yijing Huang 43a3a1e4b2 chore: remove showFlowyMobileBottomSheet and replaced by showMobileBottomSheet (#4234) 2023-12-29 09:47:03 +08:00
Yijing Huang 65f3296508 chore: update board package ref version (#4233) 2023-12-29 09:46:29 +08:00
Yijing Huang 5cede74c89 fix: remove keyboard when tap outside text field (#4235) 2023-12-29 09:46:10 +08:00
Richard Shiue 54fcc4ac5b fix: notify all views of field type option (#4229) 2023-12-29 08:11:26 +08:00
Lucas.Xu 2ca911950c chore: adjust configuration for google play console (#4231) 2023-12-28 21:02:17 +08:00
Abhijeet SinghandLucas.Xu 462b67def9 chore: update translations (#4198)
* Update es-VE.json

* inlang: update translations

* Delete project.inlang/project_id

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-12-28 20:47:12 +08:00
Lucas.Xu 30a28b12d1 feat: add image block on mobile (#4230) 2023-12-28 20:39:18 +08:00
Lucas.Xu 0b3c904984 feat: add block menu (#4222)
* feat: add block menu

* fix: android add block issue
2023-12-28 12:37:10 +08:00
maTh 1e16168a3d fix: better wording for German i18n (#4227) 2023-12-28 11:05:23 +08:00
Nathan.fooo f5db384fc2 chore: bump collab (#4224)
* chore: bump collab

* chore: fix compile
2023-12-28 03:30:04 +08:00
Richard Shiue ce58737ec5 fix: bottom sheet updates apply immediately (#4220)
* fix: mobile field editor

* fix: immediately update select option

* fix: insert left and right field flow

* fix: create row behavior
2023-12-27 23:52:54 +08:00
Richard Shiue ca7b186325 chore: remove misleading vscode launch task (#4217) 2023-12-27 23:28:55 +08:00
Lucas.Xu d05b633b9b feat: improve toolbar dark mode (#4218) 2023-12-27 20:29:14 +08:00
Richard Shiue 1cde5a0df6 fix: mobile launch review (#4214)
* fix: text for changing field type

* fix: field name text field autofocus

* fix: don't allow insert left on primary field

* fix: edit field from view setting

* fix: edit non-current database view

* fix: row detail toggle hidden fields button

* fix: database view name autofocus

* fix: mobile date picker

* fix: deleting select option not deleting column

* fix: duplicate and delete view

* fix: mobile tab bar header left  padding
2023-12-27 11:56:06 +08:00
Nathan.fooo df8409178b refactor: remove singleton db (#4208)
* refactor: remove singleton db

* chore: fix warning

* chore: fix warning

* chore: update test

* chore: only resotre or backup when init call

* test: fix

* test: fix

* test: fix

* fix: timeout notification

* chore: rename

* chore: rename

* chore: disable test

* chore: remove log

* chore: remove log

* chore: add log

* chore: rename test functions

* chore: add test asset

* chore: bump client api

* chore: disable some tests
2023-12-27 11:42:39 +08:00
Lucas.Xu 121ed5a06e fix: tooltips and overlay related issues (#4206)
* fix: align button tooltip

* chore: upgrade Flutter to latest beta version

* chore: bump version 0.4.0

* chore: minor ui update

* chore: update dependencies

* chore: upgrade flutter api

* chore: use beta channel

* chore: disable search bar and optimize toolbar ui

* chore: rename extra info keys

* feat: highlight text again after changing color

* chore: update iOS icon

* fix: lose children issues when converting block type

* chore: update editor version

* chore: update iOS icon and android navigation bar color

* fix: docker build issue

* fix: android keyboard issues

* chore: update icon
2023-12-27 11:11:14 +08:00
Kilu.He 29e80a0f32 refactor: support nested block struct (#4200)
* refactor: support nested block struct

* fix: pasted bugs

* fix: fix lift node

* fix: unit test

* fix: selection style

* feat: support block color

* fix: turn to block bugs

* fix: code block bugs
2023-12-26 18:15:35 +08:00
Nathan.fooo a49b009980 tests: more cloud test (#4204)
* test: add anon user test

* chore: add to runner

* test: fix

* test: fix

* test: add tests

* chore: add test

* chore: fix warn

* chore: fix warn

* fix: build

* fix: test

* chore: rename

* chore: fix test

* chore: fix test

* chore: fix test

* chore: disable test
2023-12-26 02:03:42 +08:00
Ansah Mohammad 9b55f5bc7f fix: renamed duplicate shortcut commands (#4196) 2023-12-24 22:12:16 +08:00
Daniil 0371a28a42 chore: sync russian translation (#4202) 2023-12-24 22:10:31 +08:00
Lucas.Xu ce51491cf6 feat: support menu action in aa toolbar item (#4201) 2023-12-24 22:08:49 +08:00
Nathan.fooo c033d56978 chore: rename folder event (#4205) 2023-12-24 07:44:08 +08:00
Jiraffe7andnathan a4a21c7e94 chore: Update Diesel to 2.1.x (#4197)
* chore: update diesel to 2.1.x

* chore: commit tauri cargo lock file

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-12-23 23:27:15 +08:00
Kilu.He 851296fa0e fix: document title operation & copy & pasted
* fix: pasted html

* fix: document title operation

* fix: code review

* fix: jest test

* fix: copy & pasted

* fix: remove default style when pasted html

* fix: link selection

* fix: rust test
2023-12-23 21:14:32 +08:00
Lucas.Xu c3b183504f feat: mobile toolbar revamp (#4194)
* feat: toolbar ui revamp

* feat: implement bius and blocks

* feat: implement converting heading block

* feat: implement bius logic

* feat: implement numbered/bulleted/quote list logic

* feat: indent/outdent logic

* feat: implement link logic

* feat: toolbar ui improvement

* feat: implement toolbar biu logic

* feat: focus on biu if the selection is not collapsed

* feat: implement changing font logic'

* feat: implement color picker logic

* feat: support customzing text and background color

* fix: draghandler padding
2023-12-23 14:31:49 +08:00
Nathan.fooo 363bb3e45e test: add tests (#4199) 2023-12-23 13:35:24 +08:00
Yijing Huang acc93a603d fix: remove italic in inlined code (#4192) 2023-12-22 16:28:28 +08:00
Richard Shiue 8045042e78 chore: adjust mobile grid cell design (#4190) 2023-12-21 20:41:58 +08:00
Nathan.fooo 1401ba5960 feat: anon user save (#4185)
* feat: anon user save

* chore: add missing files

* chore: remove error
2023-12-21 14:13:21 +08:00
Richard Shiue 0730a0caf4 fix: select field type option editor overflow (#4188) 2023-12-21 12:16:18 +08:00
Richard Shiue 13260e1db8 feat: mobile view editor improvements (#4186)
* feat: database view editor improvements

* feat: implement calendar settings

* fix: wrong view being opened
2023-12-21 11:51:42 +08:00
Richard Shiue 4fa08fda02 fix: translation into the wrong language (#4187) 2023-12-21 11:03:27 +08:00
iMiaoandLucas.Xu 2042394501 chore: update translations (#4156)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-12-21 09:34:49 +08:00
Yijing Huang bbeae74ebd feat: customized cursor and selection color (#4168) 2023-12-21 09:34:25 +08:00
Abhijeet Singh 3aad1c5bcd chore: update es-VE.json (#4173) 2023-12-21 09:33:39 +08:00
Yijing Huang f760e3d12a fix: close emoji menu by ESC key (#4182) 2023-12-21 09:32:56 +08:00
Yijing Huang 890285bb7b fix: exclude hyphen in code block (#4183) 2023-12-21 09:32:01 +08:00
AslamandLucas.Xu 366e28752c fix: text overflow issue of font family dropdown (#3348)
* fixed text overflow issue of font family dropdown

* added tooltip delay

* code review fixes: unwanted key removed; tooltip added for all fonts;
delay time reduces;

* Update frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_appearance/font_family_setting.dart

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-12-21 09:31:37 +08:00
Nathan.fooo 6ecc3c9076 test: add document sync test on appflowy cloud (#4163)
* test: add document sync test on appflowy cloud

* chore: add runner

* test: Stream has already been listened to.

* fix: using singleton subscription

* fix: using singleton subscription
2023-12-21 08:12:40 +08:00
Mohammad Zolfaghari f5a9f2bf4d fix: persist group order on reopenning AppFlowy (#4080)
* fix: persist group order on reopenning AppFlowy

Currently if you change groups order, on restarting AppFlowy they
will go back to what they were before.
This was because merge_groups function was not respecting the group
orders which were saved before as group settings.

* refactor: enhance the merge_group function

* refactor: use extend instead of for loop
2023-12-20 12:31:00 +08:00
Richard Shiue d68c847d59 refactor: database field type option (#4136)
* refactor: include field type option in FieldPB

* refactor: adapt changes on flutter

* refactor: adapt changes on new tauri grid

* refactor: adapt changes on old tauri grid/board

* chore: merge
2023-12-20 11:11:38 +08:00
Lucas.Xu 9a1ea138fc feat: sync the icon & title (#4150)
* feat: sync the icon & title

* feat: diff the view data when refreshing

* fix: unable to update folder

* test: refactor bloc tests
2023-12-20 10:08:35 +08:00
Bowling b466b425a5 chore: update translations (#4138) 2023-12-19 22:43:35 +08:00
Ansah Mohammad 15aefaa956 feat: add confirmation when deleting/restoring a page in the trash. (#4170)
* feat: added prompt before delete and restore

* feat: added prompts before delete all and restore all

* chore: fixed indendation

* refactor: changed the confirmation dialogue to use NavigatorAlertDialog

* chore: replaced text with localisable string and removed message from confirmationDialog

* refactor: Use alert directly from NavigatorAlertDialog
2023-12-19 22:42:37 +08:00
Lucas.Xu e7bdce0997 feat: mobile UI improvement (#4172)
* chore: use 1.0 as default textScaler

* feat: mobile editor ui improvement
2023-12-19 22:31:23 +08:00
Nathan.fooo 44e48712a6 chore: bump client api and collab (#4162) 2023-12-19 04:36:24 +08:00
Mathias Mogensen 7d512578b2 refactor: date picker abstraction (#4159)
* refactor: date picker abstraction

* refactor: move include time button
2023-12-18 13:10:12 +01:00
Kilu.He 0783f94cd6 chore: optimize the experience of the document (#4152)
* fix: scroll bug of grid

* chore: optimize the experience of the document

* fix: drag folder

* fix: add unit test to provider
2023-12-18 17:44:47 +08:00
Richard Shiue eef34caf27 feat: revamp mobile database tab bar (#4160) 2023-12-18 17:04:20 +08:00
Nathan.fooo 5ef9d55dca fix: open local folder when fail to init with remote server data (#4158) 2023-12-18 03:14:05 +08:00
Richard Shiue 781fbf1b30 refactor: some code organization and date picker ui improv (#4148)
* chore: use appflowy_editor's platform extensions

* chore: organize code

* chore: improve mobile date picker
2023-12-15 18:20:44 +08:00
Lucas.Xu 60ba775bed fix: scheme doesn't work on macOS with flutter 3.16 (#4147)
* fix: scheme doesn't work on macOS with flutter 3.16

* chore: revert code
2023-12-15 16:07:08 +08:00
Richard Shiue d862455342 feat: add borders on mobile grid (#4146)
* feat: mobile grid ui improvements

* chore: restore Podfile.lock
2023-12-14 23:15:26 +08:00
Lucas.Xu d26606d3d3 fix: unable to sync the folder data (#4141) 2023-12-14 20:33:00 +08:00
mahynotch 6cece56ca7 chore: update translations (#4144)
* inlang: update translations

* inlang: update translations

* inlang: update translations
2023-12-14 15:15:05 +07:00
Camus Qiu 2b096e967d fix: chinese translation error (#4115) (#4142) 2023-12-14 15:13:50 +07:00
Ansah Mohammad 7884fd1913 chore: added settings.json in gitignore (#4130)
* added settings.json in .gitignore

* Stop tracking .vscode/settings.json
2023-12-13 15:26:21 +08:00
Lucas.Xu 3f9b598493 feat: add link preview block (#4137)
* feat: add link preview block

* test: add integration test
2023-12-13 15:21:38 +08:00
Lucas.Xu d5b9063f78 chore: revert flutterMode (#4135) 2023-12-12 17:01:23 +08:00
watchakorn-18kandLucas.Xu b80b222527 chore: update translated into the most recent version in Thai, with extra words fixed. (#4132)
* Added Thai language

* Complete Thai translation

* feat: Added Thai translation

* chore: Translate more Thai using modern terminology and avoid outdated slang.

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-12-12 10:03:56 +08:00
Nathan.fooo c175947818 chore: bump up client api (#4128)
* chore: bump up client api

* chore: bump up collab rev

* chore: bump up client api
2023-12-11 22:25:07 +08:00
Richard Shiue b7b8713cd9 chore: code cleanup (#4129) 2023-12-11 20:49:21 +08:00
Lucas.Xu 81e09ae72e fix: database memory leaks (#4126) 2023-12-11 20:48:58 +08:00
Richard Shiue 4e6643eca8 refactor: order object position and field service (#4118)
* refactor: create OrderObjectPositionPB

* refactor: use ObjectOrderPosition for creating rows

* refactor: field backend service

* refactor: use field_id for reordering fields

* style: reorder dependencies

* fix: changes on tauri

* feat: insert row above

* chore: don't pass group_id while duplicating a row
2023-12-11 11:19:20 +08:00
Lucas.Xu 7586930ef0 chore: disable material3 (#4124) 2023-12-11 10:23:48 +08:00
Richard Shiue e9a4efb67d chore: reorganize vscode tasks (#4125) 2023-12-11 09:01:12 +08:00
Richard Shiue eff06a1f74 chore: bump protobuf version (#4123)
makes it compatible with protoc_plugin 21.x.x
2023-12-10 21:26:53 +08:00
Lucas.Xu 775955df5c feat: optimize editor memory usage (#4120) 2023-12-10 21:26:23 +08:00
Yijing Huang 8cf6ab32f0 fix: mobile UI (#4121)
* fix: use default splash color

* chore: improve card border UI
2023-12-10 21:25:11 +08:00
Mathias Mogensen 177cca60c4 fix: notes disappears (#4122) 2023-12-10 13:44:37 +02:00
Mathias Mogensen 649545cdf3 feat: mobile notifications screen (#4100)
* fix: update username on mobile header on change

* feat: notifications page

* feat: refactor and refinement

* fix: code review
2023-12-08 21:04:09 +08:00
Henrique Miossi de Araújo 2a421034d9 chore: update pt-BR translations (#4109) 2023-12-08 21:02:27 +08:00
Lucas.Xu ef49cb6577 feat: upgrade to flutter 3.16 (#4119)
* feat: upgrade to flutter 3.16

* chore: adjust flutter 3.16 new api

* chore: code format

* fix: ci lint

* chore: code format

* chore: dart format
2023-12-08 21:01:54 +08:00
Lucas.Xu 6338ca1417 feat: support building apk on github action (#4117) 2023-12-08 15:49:06 +08:00
Nathan.fooo acb3c795d0 chore: bump client api (#4112) 2023-12-07 10:33:25 +08:00
Lucas.Xu 4405b597cd chore: bump version 0.3.9.1 (#4113) 2023-12-07 09:36:12 +08:00
Richard Shiue a7ce21e941 fix: mobile board card title not updating (#4110) 2023-12-07 09:09:18 +08:00
nathan 05bdd052ab chore: fmt 2023-12-07 08:05:33 +08:00
Nathan.fooo d86431dfbc fix: migrate cloud document when the document content is not sync to … (#4108)
* fix: migrate cloud document when the document content is not sync to local

* chore: clippy
2023-12-07 01:14:02 +08:00
Nathan.fooo 4837d7f7fe fix: migrate anon user to appflowy cloud (#4106)
* chore: fix migrate anon user to appflowy cloud

* chore: remove log

* fix: test

* chore: fmt
2023-12-06 22:54:17 +08:00
Kilu.He d765806337 feat: parity features for flutter grid (#4082)
* feat: parity features of flutter grid

* feat: replace another virtual scroll component

* fix: fix eslint error

* fix: modify the drag style

* fix: remove log

* fix: add css style for row when context menu display
2023-12-06 14:54:41 +08:00
2896 changed files with 99752 additions and 85799 deletions

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
name: Build Bot
on:
issue_comment:
types: [created]
jobs:
dispatch_slash_command:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
# get build name from pubspec.yaml
- name: Get build version
working-directory: frontend/appflowy_flutter
id: get_build_name
run: |
echo "fetching version from pubspec.yaml..."
echo "build_name=$(grep 'version: ' pubspec.yaml | awk '{print $2}')" >> $GITHUB_OUTPUT
- uses: peter-evans/slash-command-dispatch@v4
with:
token: ${{ secrets.PAT }}
commands: build
static-args: |
ref=refs/pull/${{ github.event.issue.number }}/head
build_name=${{ steps.get_build_name.outputs.build_name }}
+42
View File
@@ -0,0 +1,42 @@
name: build
on:
repository_dispatch:
types: [build-command]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: notify appflowy_builder
run: |
platform=${{ github.event.client_payload.slash_command.args.unnamed.arg1 }}
build_name=${{ github.event.client_payload.slash_command.args.named.build_name }}
branch=${{ github.event.client_payload.slash_command.args.named.ref }}
build_type=""
arch=""
if [ "$platform" = "android" ]; then
build_type="apk"
elif [ "$platform" = "macos" ]; then
arch="universal"
fi
params=$(jq -n \
--arg ref "main" \
--arg repo "LucasXu0/AppFlowy" \
--arg branch "$branch" \
--arg build_name "$build_name" \
--arg build_type "$build_type" \
--arg arch "$arch" \
'{ref: $ref, inputs: {repo: $repo, branch: $branch, build_name: $build_name, build_type: $build_type, arch: $arch}} | del(.inputs | .. | select(. == ""))')
echo "params: $params"
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/AppFlowy-IO/AppFlowy-Builder/actions/workflows/$platform.yaml/dispatches \
-d "$params"
+1 -2
View File
@@ -5,8 +5,7 @@ jobs:
commitlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: wagoid/commitlint-github-action@v4
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Build the app
shell: bash
+115 -131
View File
@@ -4,27 +4,27 @@ on:
push:
branches:
- "main"
- "develop"
- "release/*"
paths:
- ".github/workflows/flutter_ci.yaml"
- "frontend/**"
- "!frontend/appflowy_tauri/**"
- "frontend/rust-lib/**"
- "frontend/appflowy_flutter/**"
- "frontend/resources/**"
pull_request:
branches:
- "main"
- "develop"
- "release/*"
paths:
- ".github/workflows/flutter_ci.yaml"
- "frontend/**"
- "!frontend/appflowy_tauri/**"
- "frontend/rust-lib/**"
- "frontend/appflowy_flutter/**"
- "frontend/resources/**"
env:
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.13.9"
RUST_TOOLCHAIN: "1.70"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75"
CARGO_MAKE_VERSION: "0.36.6"
concurrency:
@@ -61,7 +61,7 @@ jobs:
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
@@ -72,12 +72,20 @@ jobs:
override: true
profile: minimal
- name: Export pub environment variables and add to PATH
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
echo "PUB_CACHE=$LOCALAPPDATA\\Pub\\Cache" >> $GITHUB_ENV
fi
shell: bash
- name: Install flutter
id: flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: Swatinem/rust-cache@v2
with:
@@ -122,7 +130,7 @@ jobs:
run: |
tar -czf appflowy_flutter.tar.gz frontend/appflowy_flutter
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: ${{ github.run_id }}-${{ matrix.os }}
path: appflowy_flutter.tar.gz
@@ -142,7 +150,7 @@ jobs:
steps:
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
@@ -159,6 +167,7 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: Swatinem/rust-cache@v2
with:
@@ -194,7 +203,7 @@ jobs:
fi
shell: bash
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: ${{ github.run_id }}-${{ matrix.os }}
@@ -217,20 +226,93 @@ jobs:
fi
shell: bash
# disable coverage for now as it's not working
# - 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
cloud_integration_test:
needs: [prepare]
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
target: x86_64-unknown-linux-gnu
runs-on: ${{ matrix.os }}
steps:
- name: Checkout appflowy cloud code
uses: actions/checkout@v4
with:
repository: AppFlowy-IO/AppFlowy-Cloud
path: AppFlowy-Cloud
- name: Prepare appflowy cloud env
working-directory: AppFlowy-Cloud
run: |
# log level
cp deploy.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's/GOTRUE_EXTERNAL_GOOGLE_ENABLED=.*/GOTRUE_EXTERNAL_GOOGLE_ENABLED=true/' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Run Docker-Compose
working-directory: AppFlowy-Cloud
run: |
docker compose down -v --remove-orphans
docker compose pull
docker compose up -d
sleep 10
- name: Checkout source code
uses: actions/checkout@v4
- name: Install flutter
id: flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
- 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 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
shell: bash
- name: Enable Flutter Desktop
run: |
flutter config --enable-linux-desktop
shell: bash
- uses: actions/download-artifact@v4
with:
name: ${{ github.run_id }}-${{ matrix.os }}
- name: Uncompressed appflowy_flutter
run: |
tar -xf appflowy_flutter.tar.gz
ls -al
- name: Run flutter pub get
working-directory: frontend
run: cargo make pub_get
- name: Run Flutter integration tests
working-directory: frontend/appflowy_flutter
run: |
export DISPLAY=:99
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
sudo apt-get install network-manager
docker ps -a
flutter test integration_test/cloud/cloud_runner.dart -d Linux --coverage
shell: bash
integration_test:
needs: [prepare]
@@ -238,19 +320,16 @@ 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
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
@@ -267,6 +346,7 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: taiki-e/install-action@v2
with:
@@ -295,7 +375,7 @@ jobs:
fi
shell: bash
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: ${{ github.run_id }}-${{ matrix.os }}
@@ -320,103 +400,6 @@ jobs:
flutter test integration_test/runner.dart -d Windows --coverage
fi
shell: bash
cloud_integration_test:
needs: [prepare]
# if: github.event_name != 'pull_request'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
target: x86_64-unknown-linux-gnu
runs-on: ${{ matrix.os }}
steps:
- name: Checkout appflowy cloud code
uses: actions/checkout@v3
with:
repository: AppFlowy-IO/AppFlowy-Cloud
path: AppFlowy-Cloud
depth: 1
- name: Prepare appflowy cloud env
working-directory: AppFlowy-Cloud
run: |
# log level
cp dev.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's/GOTRUE_SMTP_USER=.*/GOTRUE_SMTP_USER=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_USER }}/' .env
sed -i 's/GOTRUE_SMTP_PASS=.*/GOTRUE_SMTP_PASS=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_PASS }}/' .env
sed -i 's/GOTRUE_SMTP_ADMIN_EMAIL=.*/GOTRUE_SMTP_ADMIN_EMAIL=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_ADMIN_EMAIL }}/' .env
sed -i 's/GOTRUE_EXTERNAL_GOOGLE_ENABLED=.*/GOTRUE_EXTERNAL_GOOGLE_ENABLED=true/' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
cat .env
- name: Run Docker-Compose
working-directory: AppFlowy-Cloud
run: |
docker compose up -d
- name: Checkout source code
uses: actions/checkout@v2
- 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: |
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
shell: bash
- name: Enable Flutter Desktop
run: |
flutter config --enable-linux-desktop
shell: bash
- uses: actions/download-artifact@v3
with:
name: ${{ github.run_id }}-${{ matrix.os }}
- name: Uncompressed appflowy_flutter
run: |
tar -xf appflowy_flutter.tar.gz
ls -al
- name: Enable localhost env
working-directory: frontend/appflowy_flutter
run: |
echo 'APPFLOWY_CLOUD_URL=http://localhost' >> .env
dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs
- name: Run flutter pub get
working-directory: frontend
run: cargo make pub_get
- name: Run Flutter integration tests
working-directory: frontend/appflowy_flutter
run: |
export DISPLAY=:99
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
sudo apt-get install network-manager
flutter test integration_test/cloud_runner.dart -d Linux --coverage
shell: bash
build:
needs: [prepare]
if: github.event.pull_request.draft != true
@@ -438,7 +421,7 @@ jobs:
steps:
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
@@ -455,6 +438,7 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: taiki-e/install-action@v2
with:
@@ -483,7 +467,7 @@ jobs:
fi
shell: bash
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: ${{ github.run_id }}-${{ matrix.os }}
+25 -21
View File
@@ -18,8 +18,7 @@ on:
- "!frontend/appflowy_tauri/**"
env:
FLUTTER_VERSION: "3.13.9"
RUST_TOOLCHAIN: "1.70"
FLUTTER_VERSION: "3.19.0"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -38,7 +37,17 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
# the following step is required to avoid running out of space
- name: Check storage space
run: df -h
- name: Maximize build space
uses: easimon/maximize-build-space@master
with:
root-reserve-mb: 2048
swap-size-mb: 1024
remove-dotnet: 'true'
# the following step is required to avoid running out of space
- name: Maximize build space
if: matrix.os == 'ubuntu-latest'
run: |
@@ -46,18 +55,16 @@ jobs:
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
sudo docker image prune --all --force
sudo rm -rf /opt/hostedtoolcache/codeQL
sudo rm -rf ${GITHUB_WORKSPACE}/.git
sudo rm -rf $ANDROID_HOME/ndk
- name: Check storage space
run: df -h
- 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
uses: actions/checkout@v4
- name: Install flutter
id: flutter
@@ -65,19 +72,16 @@ jobs:
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: "r24"
add-to-path: true
ndk-version: "r24"
add-to-path: true
- uses: Swatinem/rust-cache@v2
- uses: gradle/gradle-build-action@v3
with:
prefix-key: ${{ matrix.os }}
workspaces: |
frontend/rust-lib
gradle-version: 7.6.3
- uses: davidB/rust-cargo-make@v1
with:
@@ -110,4 +114,4 @@ jobs:
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
cargo make --profile development-android appflowy-android-dev
cargo make --profile development-android appflowy-android-dev-ci
+32 -15
View File
@@ -6,8 +6,8 @@ on:
- "*"
env:
FLUTTER_VERSION: "3.13.9"
RUST_TOOLCHAIN: "1.70"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75"
jobs:
create-release:
@@ -18,7 +18,7 @@ jobs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Build release notes
run: |
@@ -52,7 +52,7 @@ jobs:
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install flutter
uses: subosito/flutter-action@v2
@@ -138,7 +138,7 @@ jobs:
- { target: x86_64-apple-darwin, os: macos-11, extra-build-args: "" }
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install flutter
uses: subosito/flutter-action@v2
@@ -238,7 +238,7 @@ jobs:
}
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install flutter
uses: subosito/flutter-action@v2
@@ -263,7 +263,7 @@ jobs:
working-directory: frontend
run: |
flutter config --enable-macos-desktop
sh scripts/flutter_release_build/build_universal_package_for_macos.sh
sh scripts/flutter_release_build/build_universal_package_for_macos.sh ${{ github.ref_name }}
- name: Codesign AppFlowy
run: |
@@ -327,6 +327,8 @@ jobs:
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
LINUX_PACKAGE_TMP_APPIMAGE_NAME: AppFlowy-${{ github.ref_name }}-x86_64.AppImage
LINUX_PACKAGE_APPIMAGE_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.AppImage
strategy:
fail-fast: false
@@ -341,7 +343,7 @@ jobs:
}
steps:
- name: Checkout source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install flutter
uses: subosito/flutter-action@v2
@@ -395,11 +397,15 @@ jobs:
- 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: Build Linux package (.AppImage)
working-directory: frontend
continue-on-error: true
run: |
sh scripts/linux_distribution/appimage/build_appimage.sh ${{ github.ref_name }}
cp -r ${{ env.LINUX_PACKAGE_TMP_APPIMAGE_NAME }} ${{ env.LINUX_PACKAGE_APPIMAGE_NAME }}
- name: Upload Asset
id: upload-release-asset
@@ -434,23 +440,34 @@ jobs:
asset_name: ${{ env.LINUX_PACKAGE_RPM_NAME }}
asset_content_type: application/octet-stream
- name: Upload AppImage package
id: upload-release-asset-install-package-appimage
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_APPIMAGE_NAME }}
asset_name: ${{ env.LINUX_PACKAGE_APPIMAGE_NAME }}
asset_content_type: application/octet-stream
build-for-docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
with:
context: .
file: ./frontend/scripts/docker-buildfiles/Dockerfile
+29 -22
View File
@@ -8,7 +8,6 @@ on:
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
pull_request:
branches:
@@ -17,19 +16,17 @@ on:
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
env:
CARGO_TERM_COLOR: always
RUST_TOOLCHAIN: "1.70"
RUST_TOOLCHAIN: "1.75"
jobs:
test-on-ubuntu:
environment: SUPABASE_CI
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
@@ -48,34 +45,44 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
prefix-key: 'ubuntu-latest'
prefix-key: "ubuntu-latest"
workspaces: |
frontend/rust-lib
- name: Create .env file in flowy-server
working-directory: frontend/rust-lib/flowy-server
run: |
touch .env.ci
echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
- name: Checkout appflowy cloud code
uses: actions/checkout@v4
with:
repository: AppFlowy-IO/AppFlowy-Cloud
path: AppFlowy-Cloud
- name: Create .env file in event-integration
working-directory: frontend/rust-lib/event-integration
- name: Prepare appflowy cloud env
working-directory: AppFlowy-Cloud
run: |
touch .env.ci
echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
# log level
cp deploy.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Run Docker-Compose
working-directory: AppFlowy-Cloud
run: |
docker pull appflowyinc/appflowy_cloud:latest
docker compose up -d
- name: Run rust-lib tests
working-directory: frontend/rust-lib
run: RUST_LOG=info RUST_BACKTRACE=1 cargo test --no-default-features --features="rev-sqlite"
env:
RUST_LOG: info
RUST_BACKTRACE: 1
af_cloud_test_base_url: http://localhost
af_cloud_test_ws_url: ws://localhost/ws
af_cloud_test_gotrue_url: http://localhost/gotrue
run: cargo test --no-default-features --features="rev-sqlite,dart" -- --nocapture
- name: rustfmt rust-lib
run: cargo fmt --all -- --check
working-directory: frontend/rust-lib/
- name: clippy rust-lib
run: cargo clippy --all
working-directory: frontend/rust-lib
run: cargo clippy --all-targets -- -D warnings
working-directory: frontend/rust-lib
+3 -4
View File
@@ -7,19 +7,18 @@ on:
- "release/*"
paths:
- "frontend/rust-lib/**"
- "shared-lib/**"
env:
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.13.9"
RUST_TOOLCHAIN: "1.70"
FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75"
jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
+3 -3
View File
@@ -5,11 +5,12 @@ on:
- ".github/workflows/tauri_ci.yaml"
- "frontend/rust-lib/**"
- "frontend/appflowy_tauri/**"
- "frontend/resources/**"
env:
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.70"
RUST_TOOLCHAIN: "1.75"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -21,8 +22,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# platform: [macos-latest, ubuntu-latest, windows-latest]
platform: [ubuntu-latest]
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
+84
View File
@@ -0,0 +1,84 @@
name: WEB-CI
on:
pull_request:
branches:
- "main"
paths:
- ".github/workflows/web_ci.yaml"
- "frontend/rust-lib/**"
- "frontend/appflowy_web/**"
env:
CARGO_TERM_COLOR: always
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.75"
CARGO_MAKE_VERSION: "0.36.6"
jobs:
web-build:
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Cache Rust Dependencies
uses: Swatinem/rust-cache@v2
with:
key: rust-dependencies-${{ runner.os }}
workspaces: |
frontend/rust-lib
frontend/appflowy_web/appflowy_wasm
# TODO: Can combine caching deps and node_modules in one
# See Glob patterns: https://github.com/actions/toolkit/tree/main/packages/glob
- name: Cache Node.js dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}
- name: Cache node_modules
uses: actions/cache@v4
with:
path: frontend/appflowy_web/node_modules
key: node-modules-${{ runner.os }}
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
profile: minimal
- name: Install wasm-pack
run: cargo install wasm-pack
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
- name: install dependencies
if: matrix.platform == 'ubuntu-latest'
working-directory: frontend
run: |
sudo apt-get update
npm install -g pnpm@${{ env.PNPM_VERSION }}
cargo make install_web_protobuf
- name: Build
working-directory: frontend/appflowy_web
run: |
pnpm install
pnpm run build_release_wasm
+3 -6
View File
@@ -21,11 +21,8 @@ node_modules
**/resources/proto
!frontend/.vscode/settings.json
!frontend/.vscode/tasks.json
!frontend/.vscode/launch.json
!frontend/.vscode/extensions.json
!frontend/.vscode/*.code-snippets
# ignore settings.json
frontend/.vscode/settings.json
# Commit the highest level pubspec.lock, but ignore the others
pubspec.lock
@@ -38,7 +35,7 @@ pubspec.lock
**/AppFlowy-Collab/
# ignore the deb filegit
# ignore generated assets
frontend/package
frontend/*.deb
+93
View File
@@ -1,4 +1,97 @@
# Release Notes
## Version 0.5.0 - 02/26/2024
### New Features
- Added support for scaling text on mobile platforms for better readability.
- Introduced a toggle for favorites directly from the documents' top bar.
- Optimized the image upload process and added error messaging for failed uploads.
- Implemented depth control for outline block components.
- New checklist task creation is now more intuitive, with prompts appearing on hover over list items in the row detail page.
- Enhanced sorting capabilities, allowing reordering and addition of multiple sorts.
- Expanded sorting and filtering options to include more field types like checklist, creation time, and modification time.
- Added support for field calculations within databases.
### Bug Fixes
- Fixed an issue where inserting an image from Unsplash in local mode was not possible.
- Fixed undo/redo functionality in lists.
- Fixed data loss issues when converting between block types.
- Fixed a bug where newly created rows were not being automatically sorted.
- Fixed issues related to deleting a sorting field or sort not removing existing sorts properly.
### Notes
- Windows 7, Windows 8, and iOS 11 are not yet supported due to the upgrade to Flutter 3.19.0.
## Version 0.4.9 - 02/17/2024
### Bug Fixes
- Resolved the issue that caused users to be redirected to the Sign In page
## Version 0.4.8 - 02/13/2024
### Bug Fixes
- Fixed a possible error when loading workspaces
## Version 0.4.6 - 02/03/2024
### Bug Fixes
- Fixed refresh token bug
## Version 0.4.5 - 02/01/2024
### Bug Fixes
- Fixed WebSocket connection issue
## Version 0.4.4 - 01/31/2024
### New Features
- Added functionality for uploading images to cloud storage.
- Enabled anonymous sign-in option for mobile platform users.
- Introduced the ability to customize cloud settings directly from the startup page.
- Added support for inserting reminders on the mobile platform.
- Overhauled the user interface on mobile devices, including improvements to the action bottom sheet, editor toolbar, database details page, and app bar.
- Implemented a shortcut (F2 key) to rename the current view.
### Bug Fixes
- Fixed an issue where the font family was not displaying correctly on the mobile platform.
- Resolved a problem with the mobile row detail title not updating correctly.
- Fixed issues related to deleting images and refactored the image actions menu for better usability.
- Fixed other known issues.
# Release Notes
## Version 0.4.3 - 01/16/2024
### Bug Fixes
- Fixed file name too long issue
## Version 0.4.2 - 01/15/2024
AppFlowy for Android is available to download on GitHub.
If you’ve been using our desktop app, it’s important to read [this guide](https://docs.appflowy.io/docs/guides/sync-desktop-and-mobile) before logging into the mobile app.
### New Features
- Enhanced RTL (Right-to-Left) support for mobile platforms.
- Optimized selection gesture system on mobile.
- Optimized the mobile toolbar menu.
- Improved reference menu (‘@’ menu).
- Updated privacy policy.
- Improved the data import process for AppFlowy by implementing a progress indicator and compressing the data to enhance efficiency.
- Enhanced the utilization of local disk space to optimize storage consumption.
### Bug Fixes
- Fixed sign-in cancellation issue on mobile.
- Resolved keyboard close bug on Android.
## Version 0.4.1 - 01/03/2024
### Bug fixes
- Fix import AppFlowy data folder
## Version 0.4.0 - 12/30/2023
1. Added capability to import data from an AppFlowy data folder. For detailed information, please see [AppFlowy Data Storage Documentation](https://docs.appflowy.io/docs/appflowy/product/data-storage).
2. Enhanced user interface and fixed various bugs.
3. Improved the efficiency of data synchronization in AppFlowy Cloud
## Version 0.3.9.1 - 12/07/2023
### Bug fixes
- Fix potential blank pages that may occur in an empty document
## Version 0.3.9 - 12/07/2023
### New Features
- Support inserting a new field to the left or right of an existing one
### Bug fixes
- Fix some emojis are shown in black/white
- Fix unable to rename a subpage of subpage
## Version 0.3.8 - 11/13/2023
+3 -10
View File
@@ -13,7 +13,10 @@
"type": "dart",
"env": {
"RUST_LOG": "debug",
"RUST_BACKTRACE": "1"
},
// uncomment the following line to testing performance.
// "flutterMode": "profile",
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
@@ -66,16 +69,6 @@
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-iOS-Simulator: Build Dart only",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"env": {
"RUST_LOG": "trace"
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-iOS-Simulator: Build All",
"request": "launch",
-36
View File
@@ -1,36 +0,0 @@
{
"[dart]": {
"editor.formatOnSave": true,
"editor.formatOnType": true,
"editor.rulers": [80],
"editor.selectionHighlight": false,
"editor.suggest.snippetsPreventQuickSuggestions": false,
"editor.suggestSelection": "first",
"editor.tabCompletion": "onlySnippets",
"editor.wordBasedSuggestions": false,
},
"[javascript]": {
"editor.formatOnSave": true,
"editor.rulers": [80],
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.rulers": [80],
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"svgviewer.enableautopreview": true,
"svgviewer.previewcolumn": "Active",
"svgviewer.showzoominout": true,
"editor.wordWrapColumn": 80,
"editor.minimap.maxColumn": 140,
"editor.wordWrap": "wordWrapColumn",
"dart.lineLength": 80,
"typescript.validate.enable": true,
"javascript.validate.enable": true,
"files.associations": {
"*.log.*": "log"
},
"editor.formatOnSave": true,
"files.eol": "\n",
}
+60 -72
View File
@@ -14,10 +14,10 @@
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"AF: Dart Clean",
"AF: Flutter Clean",
"AF: Build Appflowy Core",
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
@@ -32,10 +32,10 @@
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"AF: Dart Clean",
"AF: Flutter Clean",
"AF: Build Appflowy Core For iOS",
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
@@ -50,10 +50,10 @@
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"AF: Dart Clean",
"AF: Flutter Clean",
"AF: Build Appflowy Core For iOS Simulator",
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
@@ -63,6 +63,41 @@
"panel": "new"
}
},
{
"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: Generate Language Files",
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
],
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "AF: Build Appflowy Core",
"type": "shell",
"windows": {
"command": "cargo make --profile development-windows-x86 appflowy-core-dev"
},
"linux": {
"command": "cargo make --profile \"development-linux-$(uname -m)\" appflowy-core-dev"
},
"osx": {
"command": "cargo make --profile \"development-mac-$(uname -m)\" appflowy-core-dev"
},
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Build Appflowy Core For iOS",
"type": "shell",
@@ -81,24 +116,6 @@
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Clean + Rebuild All (Android)",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"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",
@@ -108,23 +125,6 @@
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Build Appflowy Core",
"type": "shell",
"windows": {
"command": "cargo make --profile development-windows-x86 appflowy-core-dev"
},
"linux": {
"command": "cargo make --profile \"development-linux-$(uname -m)\" appflowy-core-dev"
},
"osx": {
"command": "cargo make --profile \"development-mac-$(uname -m)\" appflowy-core-dev"
},
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Code Gen",
"type": "shell",
@@ -132,7 +132,6 @@
"dependsOn": [
"AF: Flutter Clean",
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
@@ -146,6 +145,15 @@
"panel": "new"
}
},
{
"label": "AF: Dart Clean",
"type": "shell",
"command": "cargo make flutter_clean",
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Flutter Clean",
"type": "shell",
@@ -162,14 +170,6 @@
"cwd": "${workspaceFolder}/appflowy_flutter"
}
},
{
"label": "AF: Flutter Package Get",
"type": "shell",
"command": "flutter packages pub get",
"options": {
"cwd": "${workspaceFolder}/appflowy_flutter"
}
},
{
"label": "AF: Generate Freezed Files",
"type": "shell",
@@ -233,34 +233,18 @@
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Flutter Clean",
"type": "shell",
"command": "cargo make flutter_clean",
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: flutter build aar",
"type": "flutter",
"command": "flutter",
"args": ["build", "aar"],
"args": [
"build",
"aar"
],
"group": "build",
"problemMatcher": [],
"detail": "appflowy_flutter"
},
{
"label": "AF: Tauri UI Dev",
"type": "shell",
"isBackground": true,
"command": "yarn",
"args": ["dev"],
"options": {
"cwd": "${workspaceFolder}/appflowy_tauri"
}
},
{
"label": "AF: Tauri UI Build",
"type": "shell",
@@ -270,9 +254,10 @@
}
},
{
"label": "AF: Tauri Dev",
"label": "AF: Tauri UI Dev",
"type": "shell",
"command": "npm run tauri:dev",
"isBackground": true,
"command": "pnpm run tauri:dev",
"options": {
"cwd": "${workspaceFolder}/appflowy_tauri"
}
@@ -289,7 +274,10 @@
"label": "AF: Tauri Clean + Dev",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": ["AF: Tauri Clean", "AF: Tauri UI Dev"],
"dependsOn": [
"AF: Tauri Clean",
"AF: Tauri UI Dev"
],
"options": {
"cwd": "${workspaceFolder}"
}
@@ -309,6 +297,6 @@
"options": {
"cwd": "${workspaceFolder}/appflowy_flutter"
}
},
}
]
}
}
+8 -1
View File
@@ -10,6 +10,7 @@ extend = [
{ path = "scripts/makefile/flutter.toml" },
{ path = "scripts/makefile/tool.toml" },
{ path = "scripts/makefile/tauri.toml" },
{ path = "scripts/makefile/web.toml" },
]
[config]
@@ -25,7 +26,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.9"
APPFLOWY_VERSION = "0.5.1"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0"
@@ -48,6 +49,8 @@ LIB_EXT = "a"
APP_ENVIRONMENT = "local"
FLUTTER_FLOWY_SDK_PATH = "appflowy_flutter/packages/appflowy_backend"
TAURI_BACKEND_SERVICE_PATH = "appflowy_tauri/src/services/backend"
WEB_BACKEND_SERVICE_PATH = "appflowy_web/src/services/backend"
WEB_LIB_PATH= "appflowy_web/wasm-libs/af-wasm"
# Test default config
TEST_CRATE_TYPE = "cdylib"
TEST_LIB_EXT = "dylib"
@@ -127,6 +130,7 @@ FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "exe"
CRATE_TYPE = "cdylib"
LIB_EXT = "dll"
BUILD_ARCHS = "x64"
APP_ENVIRONMENT = "production"
[env.development-linux-x86_64]
@@ -201,6 +205,7 @@ TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Debug"
LIB_EXT = "so"
PRODUCT_EXT = "apk"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[env.production-android]
@@ -208,6 +213,7 @@ BUILD_FLAG = "release"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "apk"
LIB_EXT = "so"
[tasks.echo_env]
@@ -222,6 +228,7 @@ script = ['''
echo APP_ENVIRONMENT: ${APP_ENVIRONMENT}
echo ${platforms}
echo ${BUILD_ARCHS}
echo ${BUILD_VERSION}
''']
script_runner = "@shell"
@@ -30,10 +30,27 @@ linter:
rules:
- require_trailing_commas
- prefer_collection_literals
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- sized_box_for_whitespace
- use_decorated_box
- unnecessary_parenthesis
- unnecessary_await_in_return
- unnecessary_raw_strings
- avoid_unnecessary_containers
- avoid_redundant_argument_values
- avoid_unused_constructor_parameters
- always_declare_return_types
- sort_constructors_first
- unawaited_futures
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
@@ -25,8 +25,14 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 33
compileSdkVersion 34
ndkVersion "24.0.8215888"
compileOptions {
@@ -46,8 +52,8 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "io.appflowy.appflowy"
minSdkVersion 23
targetSdkVersion 31
minSdkVersion 29
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
@@ -58,13 +64,18 @@ android {
}
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
minifyEnabled true
shrinkResources true
// use release instead when publishing the application to google play.
// signingConfig signingConfigs.release
signingConfig signingConfigs.debug
}
}
@@ -47,4 +47,9 @@
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<queries>
<intent>
<action android:name="android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
</manifest>
@@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.10.0)
project(AppFlowy)
message(CONFIGURE_LOG "NDK PATH: ${ANDROID_NDK}")
message(CONFIGURE_LOG "Copying libc++_shared.so")
# arm64-v8a
file(COPY
${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so
@@ -3,7 +3,7 @@
#include <stdint.h>
#include <stdlib.h>
int64_t init_sdk(char *data);
int64_t init_sdk(int64_t port, char *data);
void async_event(int64_t port, const uint8_t *input, uintptr_t len);
@@ -13,6 +13,6 @@ int32_t set_stream_port(int64_t port);
void link_me_please(void);
void backend_log(int64_t level, const char *data);
void rust_log(int64_t level, const char *data);
void set_env(const char *data);
@@ -73,9 +73,9 @@
"attributes": { "subtype": "checkbox", "checkbox": true },
"delta": [
{ "insert": "Click " },
{ "insert": "+ New Page ", "attributes": { "code": true } },
{ "insert": "+ New Page", "attributes": { "code": true } },
{
"insert": "button at the bottom of your sidebar to add a new page."
"insert": " button at the bottom of your sidebar to add a new page."
}
]
},
@@ -0,0 +1 @@
extensions:
-5
View File
@@ -1,5 +0,0 @@
SUPABASE_URL=
SUPABASE_ANON_KEY=
APPFLOWY_CLOUD_URL=
@@ -16,7 +16,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@@ -48,7 +48,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@@ -1,9 +1,8 @@
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/widgets/card/container/card_container.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/widgets/card/container/card_container.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/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';
@@ -21,15 +20,15 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final findFirstCard = find.descendant(
of: find.byType(AppFlowyGroupCard),
matching: find.byType(FlowyText),
matching: find.byType(Text),
);
FlowyText firstCardText = tester.firstWidget(findFirstCard);
expect(firstCardText.text, defaultFirstCardName);
Text firstCardText = tester.firstWidget(findFirstCard);
expect(firstCardText.data, defaultFirstCardName);
await tester.tap(
find
@@ -51,29 +50,28 @@ void main() {
),
newCardName,
);
await tester.pumpAndSettle();
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.tap(find.byType(AppFlowyBoard));
await tester.pumpAndSettle();
firstCardText = tester.firstWidget(findFirstCard);
expect(firstCardText.text, newCardName);
expect(firstCardText.data, newCardName);
});
testWidgets('from footer', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final findLastCard = find.descendant(
of: find.byType(AppFlowyGroupCard),
matching: find.byType(FlowyText),
matching: find.byType(Text),
);
FlowyText? lastCardText =
tester.widgetList(findLastCard).last as FlowyText;
expect(lastCardText.text, defaultLastCardName);
Text? lastCardText = tester.widgetList(findLastCard).last as Text;
expect(lastCardText.data, defaultLastCardName);
await tester.tap(
find
@@ -93,13 +91,13 @@ void main() {
),
newCardName,
);
await tester.pumpAndSettle();
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.tap(find.byType(AppFlowyBoard));
await tester.pumpAndSettle();
lastCardText = tester.widgetList(findLastCard).last as FlowyText;
expect(lastCardText.text, newCardName);
lastCardText = tester.widgetList(findLastCard).last as Text;
expect(lastCardText.data, newCardName);
});
});
}
@@ -1,7 +1,7 @@
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
import 'package:appflowy/plugins/database/widgets/row/row_property.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:appflowy_board/appflowy_board.dart';
@@ -17,17 +17,17 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final card1 = find.ancestor(
of: find.findTextInFlowyText(card1Name),
of: find.text(card1Name),
matching: find.byType(AppFlowyGroupCard),
);
final doingGroup = find.findTextInFlowyText('Doing');
final doingGroup = find.text('Doing');
final doingGroupCenter = tester.getCenter(doingGroup);
final card1Center = tester.getCenter(card1);
await tester.timedDrag(
card1,
card1,
doingGroupCenter.translate(-card1Center.dx, -card1Center.dy),
const Duration(seconds: 1),
);
@@ -36,14 +36,14 @@ void main() {
await tester.pumpAndSettle();
final card1StatusFinder = find.descendant(
of: find.byType(RowPropertyList),
of: find.byType(RowPropertyList),
matching: find.descendant(
of: find.byType(SelectOptionTag),
matching: find.byType(FlowyText),
of: find.byType(SelectOptionTag),
matching: find.byType(Text),
),
);
expect(card1StatusFinder, findsNWidgets(1));
final card1StatusText = tester.widget<FlowyText>(card1StatusFinder).text;
final card1StatusText = tester.widget<Text>(card1StatusFinder).data;
expect(card1StatusText, 'Doing');
});
});
@@ -1,7 +1,7 @@
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:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_hidden_groups.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -17,7 +17,7 @@ void main() {
testWidgets('expand/collapse hidden groups', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final collapseFinder = find.byFlowySvg(FlowySvgs.pull_left_outlined_s);
final expandFinder = find.byFlowySvg(FlowySvgs.hamburger_s_s);
@@ -46,7 +46,7 @@ void main() {
testWidgets('hide first group, and show it again', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
// Tap the options of the first group
final optionsFinder = find
@@ -82,7 +82,7 @@ void main() {
testWidgets('delete a group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 4);
@@ -1,6 +1,6 @@
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/plugins/database/widgets/card/card.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
@@ -18,31 +18,31 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.findTextInFlowyText(name);
final card1 = find.text(name);
await tester.hoverOnWidget(
card1,
onHover: () async {
final moreOption = find.byType(CardMoreOption);
final moreOption = find.byType(MoreCardOptionsAccessory);
await tester.tapButton(moreOption);
},
);
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
expect(find.findTextInFlowyText(name), findsNothing);
expect(find.text(name), findsNothing);
});
testWidgets('duplicate item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.findTextInFlowyText(name);
final card1 = find.text(name);
await tester.hoverOnWidget(
card1,
onHover: () async {
final moreOption = find.byType(CardMoreOption);
final moreOption = find.byType(MoreCardOptionsAccessory);
await tester.tapButton(moreOption);
},
);
@@ -53,7 +53,7 @@ void main() {
testWidgets('add new group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
// assert number of groups
tester.assertNumberOfGroups(4);
@@ -32,8 +32,8 @@ void main() {
const service = TestWorkspaceService(TestWorkspace.board);
group('board', () {
setUpAll(() async => await service.setUpAll());
setUp(() async => await service.setUp());
setUpAll(() async => service.setUpAll());
setUp(() async => service.setUp());
testWidgets('open the board with data structure in v0.2.0', (tester) async {
await tester.initializeAppFlowy();
@@ -0,0 +1,69 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:integration_test/integration_test.dart';
import '../util/dir.dart';
import '../util/mock/mock_file_picker.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('appflowy cloud', () {
testWidgets('anon user and then sign in', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr());
await tester.tapGoButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// reanme the name of the anon user
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userNameFinder = find.descendant(
of: find.byType(SettingsUserView),
matching: find.byType(UserNameInput),
);
await tester.enterText(userNameFinder, 'local_user');
await tester.openSettingsPage(SettingsPage.user);
await tester.pumpAndSettle();
// sign up with Google
await tester.tapGoogleLoginInButton();
// sign out
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.logout();
await tester.pumpAndSettle();
// tap the continue as anonymous button
await tester
.tapButton(find.text(LocaleKeys.signIn_loginStartWithAnonymous.tr()));
await tester.expectToSeeHomePage();
// New anon user name
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
final userNameInput = tester.widget(userNameFinder) as UserNameInput;
expect(userNameInput.name, 'Me');
});
});
}
@@ -22,15 +22,15 @@ void main() {
group('appflowy cloud auth', () {
testWidgets('sign in', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloud,
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
});
testWidgets('sign out', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloud,
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
@@ -49,7 +49,7 @@ void main() {
testWidgets('sign in as annoymous', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloud,
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapSignInAsGuest();
@@ -61,7 +61,7 @@ void main() {
testWidgets('enable sync', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloud,
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
@@ -80,54 +80,5 @@ void main() {
await tester.toggleEnableSync(AppFlowyCloudEnableSync);
tester.assertAppFlowyCloudEnableSyncSwitchValue(true);
});
// testWidgets('custom folder sign in', (tester) async {
// const userA = 'UserA';
// final userAEmail = "${uuid()}@appflowy.io";
// final initialPath = p.join(userA, appFlowyDataFolder);
// final context = await tester.initializeAppFlowy(
// cloudType: AuthenticatorType.appflowyCloud,
// pathExtension: initialPath,
// );
// getIt.registerFactory<AuthService>(
// () => AppFlowyCloudMockAuthService(
// email: userAEmail,
// ),
// );
// // remove the last extension
// final rootPath = context.applicationDataDirectory.replaceFirst(
// initialPath,
// '',
// );
// await tester.tapGoogleLoginInButton();
// // Open the setting page and sign out
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.user);
// await tester.enterUserName(userA);
// await tester.openSettingsPage(SettingsPage.files);
// await tester.pumpAndSettle();
// // mock the file_picker result
// await mockGetDirectoryPath(
// p.join(rootPath, "random_folder"),
// );
// // after selecting the folder, an annoymous user should be signed in
// await tester.tapCustomLocationButton();
// tester.expectToSeeHomePage();
// await tester.pumpAndSettle();
// // Login as userA in custom folder
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.user);
// await tester.tapGoogleLoginInButton();
// await tester.pumpAndSettle(const Duration(seconds: 1));
// tester.expectToSeeHomePage();
// // UserA should be displayed
// tester.expectToSeeUserName(userA);
// });
});
}
@@ -0,0 +1,17 @@
import 'empty_test.dart' as preset_af_cloud_env_test;
import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
// import 'document_sync_test.dart' as document_sync_test;
import 'user_setting_sync_test.dart' as user_sync_test;
import 'anon_user_continue_test.dart' as anon_user_continue_test;
Future<void> main() async {
preset_af_cloud_env_test.main();
appflowy_cloud_auth_test.main();
// document_sync_test.main();
user_sync_test.main();
anon_user_continue_test.main();
}
@@ -0,0 +1,70 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:integration_test/integration_test.dart';
import '../util/dir.dart';
import '../util/mock/mock_file_picker.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final email = '${uuid()}@appflowy.io';
const inputContent = 'Hello world, this is a test document';
// The test will create a new document called Sample, and sync it to the server.
// Then the test will logout the user, and login with the same user. The data will
// be synced from the server.
group('appflowy cloud document', () {
testWidgets('sync local docuemnt to server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// create a new document called Sample
await tester.createNewPage();
// focus on the editor
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText(inputContent);
expect(find.text(inputContent, findRichText: true), findsOneWidget);
// TODO(nathan): remove the await
// 6 seconds for data sync
await tester.waitForSeconds(6);
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.logout();
});
testWidgets('sync doc from server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
// the latest document will be opened, so the content must be the inputContent
await tester.pumpAndSettle();
expect(find.text(inputContent, findRichText: true), findsOneWidget);
});
});
}
@@ -0,0 +1,18 @@
import 'package:appflowy/env/cloud_env.dart';
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('set appflowy cloud', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
});
});
}
@@ -15,7 +15,7 @@ void main() {
testWidgets('sign in with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
});
testWidgets('sign out with supabase', (tester) async {
@@ -0,0 +1,100 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:integration_test/integration_test.dart';
import '../util/database_test_op.dart';
import '../util/dir.dart';
import '../util/emoji.dart';
import '../util/mock/mock_file_picker.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final email = '${uuid()}@appflowy.io';
const name = 'nathan';
group('appflowy cloud setting', () {
testWidgets('sync user name and icon to server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
// final userAvatarFinder = find.descendant(
// of: find.byType(SettingsUserView),
// matching: find.byType(UserAvatar),
// );
// Open icon picker dialog and select emoji
// await tester.tap(userAvatarFinder);
// await tester.pumpAndSettle();
// await tester.tapEmoji('😁');
// await tester.pumpAndSettle();
// final UserAvatar userAvatar =
// tester.widget(userAvatarFinder) as UserAvatar;
// expect(userAvatar.iconUrl, '😁');
// enter user name
final userNameFinder = find.descendant(
of: find.byType(SettingsUserView),
matching: find.byType(UserNameInput),
);
await tester.enterText(userNameFinder, name);
await tester.pumpAndSettle();
await tester.tapEscButton();
// wait 2 seconds for the sync to finish
await tester.pumpAndSettle(const Duration(seconds: 2));
});
});
testWidgets('get user icon and name from server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
// verify icon
// final userAvatarFinder = find.descendant(
// of: find.byType(SettingsUserView),
// matching: find.byType(UserAvatar),
// );
// final UserAvatar userAvatar = tester.widget(userAvatarFinder) as UserAvatar;
// expect(userAvatar.iconUrl, '😁');
// verify name
final userNameFinder = find.descendant(
of: find.byType(SettingsUserView),
matching: find.byType(UserNameInput),
);
final UserNameInput userNameInput =
tester.widget(userNameFinder) as UserNameInput;
expect(userNameInput.name, name);
});
}
@@ -1,13 +0,0 @@
import 'package:integration_test/integration_test.dart';
import 'auth/appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
import 'empty_test.dart' as first_test;
Future<void> main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// This test must be run first, otherwise the CI will fail.
first_test.main();
appflowy_cloud_auth_test.main();
}
@@ -1,5 +1,7 @@
import 'package:appflowy/plugins/database/calendar/presentation/calendar_event_editor.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -14,7 +16,9 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// open setting
await tester.tapDatabaseSettingButton();
@@ -36,7 +40,7 @@ void main() {
// Create calendar view
const name = 'calendar';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: ViewLayoutPB.Calendar,
);
@@ -68,7 +72,9 @@ void main() {
await tester.tapGoButton();
// Create the calendar view
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// Scroll until today's date cell is visible
await tester.scrollToToday();
@@ -76,7 +82,7 @@ void main() {
// Hover over today's calendar cell
await tester.hoverOnTodayCalendarCell(
// Tap on create new event button
onHover: () async => await tester.tapAddCalendarEventButton(),
onHover: () async => tester.tapAddCalendarEventButton(),
);
// Make sure that the event editor popup is shown
@@ -143,16 +149,61 @@ void main() {
tester.assertNumberOfEventsOnSpecificDay(1, DateTime.now());
});
testWidgets('create and duplicate calendar event', (tester) async {
const customTitle = "EventTitleCustom";
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create the calendar view
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// Scroll until today's date cell is visible
await tester.scrollToToday();
// Hover over today's calendar cell
await tester.hoverOnTodayCalendarCell(
// Tap on create new event button
onHover: () async => tester.tapAddCalendarEventButton(),
);
// Make sure that the event editor popup is shown
tester.assertEventEditorOpen();
tester.assertNumberOfEventsInCalendar(1);
// Change the title of the event
await tester.editEventTitle(customTitle);
// Duplicate event
final duplicateBtnFinder = find
.descendant(
of: find.byType(CalendarEventEditor),
matching: find.byType(
FlowyIconButton,
),
)
.first;
await tester.tap(duplicateBtnFinder);
await tester.pumpAndSettle();
tester.assertNumberOfEventsInCalendar(2, title: customTitle);
});
testWidgets('rescheduling events', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create the calendar view
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// Create a new event on the first of this month
final today = DateTime.now();
final firstOfThisMonth = DateTime(today.year, today.month, 1);
final firstOfThisMonth = DateTime(today.year, today.month);
await tester.doubleClickCalendarCell(firstOfThisMonth);
await tester.dismissEventEditor();
@@ -1,5 +1,5 @@
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:intl/intl.dart';
@@ -15,7 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.editCell(
rowIndex: 0,
@@ -23,7 +23,7 @@ void main() {
input: 'hello world',
);
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.RichText,
content: 'hello world',
@@ -37,7 +37,7 @@ void main() {
testWidgets('multiple text cells', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'my grid',
layout: ViewLayoutPB.Grid,
);
@@ -56,14 +56,13 @@ void main() {
cellIndex: 1,
);
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.RichText,
content: 'hello',
cellIndex: 0,
);
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.RichText,
content: 'world',
@@ -77,7 +76,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Number;
@@ -96,7 +95,7 @@ void main() {
input: '0.2',
);
// -1 -> -1
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: 0,
fieldType: fieldType,
content: '-1',
@@ -109,7 +108,7 @@ void main() {
input: '.1',
);
// 0.2 -> 0.2
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: 1,
fieldType: fieldType,
content: '0.2',
@@ -122,7 +121,7 @@ void main() {
input: '',
);
// .1 -> 0.1
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: 2,
fieldType: fieldType,
content: '0.1',
@@ -135,7 +134,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.assertCheckboxCell(rowIndex: 0, isSelected: false);
await tester.tapCheckboxCellInGrid(rowIndex: 0);
@@ -153,7 +152,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.CreatedTime;
// Create a create time field
@@ -171,7 +170,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.LastEditedTime;
// Create a last time field
@@ -189,7 +188,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.DateTime;
await tester.createField(fieldType, fieldType.name);
@@ -216,13 +215,13 @@ void main() {
await tester.dismissCellEditor();
await tester.assertDateCellInGrid(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y').format(today),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
await tester.findDateEditor(findsOneWidget);
// Toggle include time
final now = DateTime.now();
@@ -230,8 +229,9 @@ void main() {
await tester.dismissCellEditor();
await tester.assertDateCellInGrid(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y HH:mm').format(now),
);
@@ -239,12 +239,14 @@ void main() {
await tester.findDateEditor(findsOneWidget);
// Change date format
await tester.tapChangeDateTimeFormatButton();
await tester.changeDateFormat();
await tester.dismissCellEditor();
await tester.assertDateCellInGrid(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('dd/MM/y HH:mm').format(now),
);
@@ -252,12 +254,14 @@ void main() {
await tester.findDateEditor(findsOneWidget);
// Change time format
await tester.tapChangeDateTimeFormatButton();
await tester.changeTimeFormat();
await tester.dismissCellEditor();
await tester.assertDateCellInGrid(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('dd/MM/y hh:mm a').format(now),
);
@@ -267,8 +271,9 @@ void main() {
// Clear the date and time
await tester.clearDate();
await tester.assertDateCellInGrid(
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: '',
);
@@ -282,7 +287,7 @@ void main() {
const fieldType = FieldType.SingleSelect;
// When create a grid, it will create a single select field by default
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Tap the cell to invoke the selection option editor
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -358,7 +363,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.MultiSelect;
await tester.createField(fieldType, fieldType.name);
@@ -441,7 +446,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Checklist;
await tester.createField(fieldType, fieldType.name);
@@ -1,6 +1,6 @@
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -15,7 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Grid);
// create a field
@@ -27,29 +27,29 @@ void main() {
// hide the field
await tester.tapGridFieldWithName('New field 1');
await tester.tapHidePropertyButton();
await tester.noFieldWithName('New field 1');
tester.noFieldWithName('New field 1');
// go back to inline database view, expect field to be shown
await tester.tapTabBarLinkedViewByViewName('Untitled');
await tester.findFieldWithName('New field 1');
tester.findFieldWithName('New field 1');
// go back to linked database view, expect field to be hidden
await tester.tapTabBarLinkedViewByViewName('Grid');
await tester.noFieldWithName('New field 1');
tester.noFieldWithName('New field 1');
// use the settings button to show the field
await tester.tapDatabaseSettingButton();
await tester.tapViewPropertiesButton();
await tester.tapViewTogglePropertyVisibilityButtonByName('New field 1');
await tester.dismissFieldEditor();
await tester.findFieldWithName('New field 1');
tester.findFieldWithName('New field 1');
// open first row in popup then hide the field
await tester.openFirstRowDetailPage();
await tester.tapGridFieldWithNameInRowDetailPage('New field 1');
await tester.tapHidePropertyButtonInFieldEditor();
await tester.dismissRowDetailPage();
await tester.noFieldWithName('New field 1');
tester.noFieldWithName('New field 1');
});
});
}
@@ -1,10 +1,12 @@
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/select_option.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/type_option/select/select_option.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:intl/intl.dart';
import '../util/database_test_op.dart';
import '../util/util.dart';
@@ -17,11 +19,11 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Name');
await tester.tapEditPropertyButton();
await tester.tapEditFieldButton();
await tester.renameField('hello world');
await tester.dismissFieldEditor();
@@ -34,15 +36,10 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditPropertyButton();
await tester.tapTypeOptionButton();
await tester.selectFieldType(FieldType.Checkbox);
await tester.dismissFieldEditor();
await tester.changeFieldTypeOfFieldWithName('Type', FieldType.Checkbox);
await tester.assertFieldTypeWithFieldName(
'Type',
@@ -56,13 +53,13 @@ void main() {
await tester.tapGoButton();
// create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checklist, 'checklist');
// check the field is created successfully
await tester.findFieldWithName('checklist');
tester.findFieldWithName('checklist');
await tester.pumpAndSettle();
});
@@ -70,7 +67,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checkbox, 'New field 1');
@@ -82,7 +79,7 @@ void main() {
// confirm delete
await tester.tapDialogOkButton();
await tester.noFieldWithName('New field 1');
tester.noFieldWithName('New field 1');
await tester.pumpAndSettle();
});
@@ -90,7 +87,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.scrollToRight(find.byType(GridPage));
@@ -102,7 +99,7 @@ void main() {
await tester.tapGridFieldWithName('New field 1');
await tester.tapDuplicatePropertyButton();
await tester.findFieldWithName('New field 1 (copy)');
tester.findFieldWithName('New field 1 (copy)');
await tester.pumpAndSettle();
});
@@ -110,7 +107,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
@@ -118,13 +115,13 @@ void main() {
await tester.tapGridFieldWithName('Type');
await tester.tapInsertFieldButton(left: false, name: 'Right');
await tester.dismissFieldEditor();
await tester.findFieldWithName('Right');
tester.findFieldWithName('Right');
// insert new field to the right
await tester.tapGridFieldWithName('Type');
await tester.tapInsertFieldButton(left: true, name: "Left");
await tester.dismissFieldEditor();
await tester.findFieldWithName('Left');
tester.findFieldWithName('Left');
await tester.pumpAndSettle();
});
@@ -133,13 +130,13 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
// Open the type option menu
await tester.tapTypeOptionButton();
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Checklist);
@@ -153,7 +150,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
for (final fieldType in [
FieldType.Checklist,
@@ -170,7 +167,7 @@ void main() {
await tester.renameField(fieldType.name);
// Open the type option menu
await tester.tapTypeOptionButton();
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
await tester.dismissFieldEditor();
@@ -181,17 +178,95 @@ void main() {
}
});
testWidgets('field types with empty type option editor', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
for (final fieldType in [
FieldType.RichText,
FieldType.Checkbox,
FieldType.Checklist,
FieldType.URL,
]) {
// create the field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField(fieldType.i18n);
// change field type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
await tester.dismissFieldEditor();
// open the field editor
await tester.tapGridFieldWithName(fieldType.i18n);
await tester.tapEditFieldButton();
// check type option editor is empty
tester.expectEmptyTypeOptionEditor();
await tester.dismissFieldEditor();
}
});
testWidgets('number field type option', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
// create a number field
await tester.tapNewPropertyButton();
await tester.renameField("Number");
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Number);
await tester.dismissFieldEditor();
// enter some data into the first number cell
await tester.editCell(
rowIndex: 0,
fieldType: FieldType.Number,
input: '123',
);
// edit the next cell to force the previous cell at row 0 to lose focus
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.Number,
input: '0.2',
);
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.Number,
content: '123',
);
// open editor and change number format
await tester.tapGridFieldWithName('Number');
await tester.tapEditFieldButton();
await tester.changeNumberFieldFormat();
await tester.dismissFieldEditor();
// assert number format has been changed
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.Number,
content: '\$123',
);
});
testWidgets('add option', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Grid,
);
// Invoke the field editor
// invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditPropertyButton();
await tester.tapEditFieldButton();
// tap 'add option' button
await tester.tapAddSelectOptionButton();
@@ -203,10 +278,115 @@ void main() {
await tester.enterText(inputField, text);
await tester.pumpAndSettle();
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle(const Duration(seconds: 1));
await tester.pumpAndSettle(const Duration(milliseconds: 500));
// check the result
tester.expectToSeeText(text);
});
testWidgets('date time field type options', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
// create a date field
await tester.tapNewPropertyButton();
await tester.renameField(FieldType.DateTime.i18n);
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.DateTime);
await tester.dismissFieldEditor();
// edit the first date cell
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.toggleIncludeTime();
final now = DateTime.now();
await tester.selectDay(content: now.day);
await tester.dismissCellEditor();
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y HH:mm').format(now),
);
// open editor and change date & time format
await tester.tapGridFieldWithName(FieldType.DateTime.i18n);
await tester.tapEditFieldButton();
await tester.changeDateFormat();
await tester.changeTimeFormat();
await tester.dismissFieldEditor();
// assert date format has been changed
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('dd/MM/y hh:mm a').format(now),
);
});
testWidgets('last modified and created at field type options',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
final created = DateTime.now();
// create a created at field
await tester.tapNewPropertyButton();
await tester.renameField(FieldType.CreatedTime.i18n);
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.CreatedTime);
await tester.dismissFieldEditor();
// create a last modified field
await tester.tapNewPropertyButton();
await tester.renameField(FieldType.LastEditedTime.i18n);
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.LastEditedTime);
await tester.dismissFieldEditor();
final modified = DateTime.now();
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.CreatedTime,
content: DateFormat('MMM dd, y HH:mm').format(created),
);
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.LastEditedTime,
content: DateFormat('MMM dd, y HH:mm').format(modified),
);
// open field editor and change date & time format
await tester.tapGridFieldWithName(FieldType.LastEditedTime.i18n);
await tester.tapEditFieldButton();
await tester.changeDateFormat();
await tester.changeTimeFormat();
await tester.dismissFieldEditor();
// open field editor and change date & time format
await tester.tapGridFieldWithName(FieldType.CreatedTime.i18n);
await tester.tapEditFieldButton();
await tester.changeDateFormat();
await tester.changeTimeFormat();
await tester.dismissFieldEditor();
// assert format has been changed
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.CreatedTime,
content: DateFormat('dd/MM/y hh:mm a').format(created),
);
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.LastEditedTime,
content: DateFormat('dd/MM/y hh:mm a').format(modified),
);
});
});
}
@@ -1,5 +1,5 @@
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/text.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checkbox.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/text.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -9,7 +9,7 @@ import '../util/database_test_op.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('database filter', () {
group('grid filter:', () {
testWidgets('add text filter', (tester) async {
await tester.openV020database();
@@ -0,0 +1,206 @@
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_item.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/database_test_op.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('reminder in database', () {
testWidgets('add date field and add reminder', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to date type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.DateTime);
await tester.dismissFieldEditor();
// Open date picker
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Select date
final isToday = await tester.selectLastDateInPicker();
// Select "On day of event" reminder
await tester.selectReminderOption(ReminderOption.onDayOfEvent);
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
// Dismiss the cell/date editor
await tester.dismissCellEditor();
// Open date picker again
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
// Dismiss the cell/date editor
await tester.dismissCellEditor();
int tabIndex = 1;
final now = DateTime.now();
if (isToday && now.hour >= 9) {
tabIndex = 0;
}
// Open "Upcoming" in Notification hub
await tester.openNotificationHub(tabIndex: tabIndex);
// Expect 1 notification
tester.expectNotificationItems(1);
});
testWidgets('navigate from reminder to open row', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to date type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.DateTime);
await tester.dismissFieldEditor();
// Open date picker
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Select date
final isToday = await tester.selectLastDateInPicker();
// Select "On day of event"-reminder
await tester.selectReminderOption(ReminderOption.onDayOfEvent);
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
// Dismiss the cell/date editor
await tester.dismissCellEditor();
// Open date picker again
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
// Dismiss the cell/date editor
await tester.dismissCellEditor();
// Create and Navigate to a new document
await tester.createNewPageWithNameUnderParent();
await tester.pumpAndSettle();
int tabIndex = 1;
final now = DateTime.now();
if (isToday && now.hour >= 9) {
tabIndex = 0;
}
// Open correct tab in Notification hub
await tester.openNotificationHub(tabIndex: tabIndex);
// Expect 1 notification
tester.expectNotificationItems(1);
// Tap on the notification
await tester.tap(find.byType(NotificationItem));
await tester.pumpAndSettle();
// Expect to see Row Editor Dialog
tester.expectToSeeRowDetailsPageDialog();
});
testWidgets(
'toggle include time sets reminder option correctly',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Grid,
);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to date type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.DateTime);
await tester.dismissFieldEditor();
// Open date picker
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Select date
await tester.selectLastDateInPicker();
// Select "On day of event"-reminder
await tester.selectReminderOption(ReminderOption.onDayOfEvent);
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
// Dismiss the cell/date editor
await tester.dismissCellEditor();
// Open date picker again
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
// Toggle include time on
await tester.toggleIncludeTime();
// Expect "At time of event" to be displayed
tester.expectSelectedReminder(ReminderOption.atTimeOfEvent);
// Dismiss the cell/date editor
await tester.dismissCellEditor();
// Open date picker again
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.findDateEditor(findsOneWidget);
// Expect "At time of event" to be displayed
tester.expectSelectedReminder(ReminderOption.atTimeOfEvent);
// Select "One hour before"-reminder
await tester.selectReminderOption(ReminderOption.oneHourBefore);
// Expect "One hour before" to be displayed
tester.expectSelectedReminder(ReminderOption.oneHourBefore);
// Toggle include time off
await tester.toggleIncludeTime();
// Expect "On day of event" to be displayed
tester.expectSelectedReminder(ReminderOption.onDayOfEvent);
},
);
});
}
@@ -1,6 +1,6 @@
import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
@@ -14,27 +14,30 @@ import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('grid', () {
testWidgets('row details page opens', (tester) async {
group('grid row detail page:', () {
testWidgets('opens', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
// Make sure that the row page is opened
tester.assertRowDetailPageOpened();
// Each row detail page should have a document
await tester.assertDocumentExistInRowDetailPage();
});
testWidgets('insert emoji in the row detail page', (tester) async {
testWidgets('add emoji', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -48,12 +51,12 @@ void main() {
await tester.tapButton(find.byType(EmojiButton));
});
testWidgets('update emoji in the row detail page', (tester) async {
testWidgets('update emoji', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -75,12 +78,12 @@ void main() {
expect(emojiText, findsNWidgets(2));
});
testWidgets('remove emoji in the row detail page', (tester) async {
testWidgets('remove emoji', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -96,12 +99,12 @@ void main() {
expect(emojiText, findsNothing);
});
testWidgets('create list of fields in row detail page', (tester) async {
testWidgets('create list of fields', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -120,7 +123,7 @@ void main() {
await tester.renameField(fieldType.name);
// Open the type option menu
await tester.tapTypeOptionButton();
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
@@ -135,7 +138,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -168,7 +171,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -211,27 +214,13 @@ void main() {
tester.assertToggleShowHiddenFieldsVisibility(false);
});
testWidgets('check document exists in row detail page', (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();
// Each row detail page should have a document
await tester.assertDocumentExistInRowDetailPage();
});
testWidgets('update the contents of the document and re-open it',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -271,7 +260,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -305,12 +294,12 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('delete row in row detail page', (tester) async {
testWidgets('delete row', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -322,12 +311,12 @@ void main() {
await tester.assertNumberOfRowsInGridPage(2);
});
testWidgets('duplicate row in row detail page', (tester) async {
testWidgets('duplicate row', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -1,4 +1,4 @@
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -13,7 +13,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateRowButtonInGrid();
// The initial number of rows is 3
@@ -25,7 +25,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
@@ -41,7 +41,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
// Open the row menu and then click the delete
@@ -59,7 +59,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.assertRowCountInGridPage(3);
await tester.pumpAndSettle();
@@ -1,5 +1,5 @@
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// open setting
await tester.tapDatabaseSettingButton();
@@ -31,7 +31,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// open setting
await tester.tapDatabaseSettingButton();
@@ -16,7 +16,7 @@ void main() {
// check the text cell
final textCells = <String>['A', 'B', 'C', 'D', 'E', '', '', '', '', ''];
for (final (index, content) in textCells.indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
@@ -57,7 +57,7 @@ void main() {
'',
];
for (final (index, content) in numberCells.indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
@@ -74,7 +74,7 @@ void main() {
'',
];
for (final (index, content) in urlCells.indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.URL,
content: content,
@@ -135,7 +135,7 @@ void main() {
null,
];
for (final (index, percent) in checklistCells.indexed) {
await tester.assertChecklistCellInGrid(
tester.assertChecklistCellInGrid(
rowIndex: index,
percent: percent,
);
@@ -155,8 +155,9 @@ void main() {
'',
];
for (final (index, content) in dateCells.indexed) {
await tester.assertDateCellInGrid(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.DateTime,
content: content,
);
}
@@ -28,7 +28,7 @@ void main() {
'',
];
for (final (index, content) in textCells.indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
@@ -51,7 +51,7 @@ void main() {
'',
'',
].indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
@@ -75,7 +75,7 @@ void main() {
'',
'',
].indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
@@ -86,7 +86,7 @@ void main() {
testWidgets('add checkbox sort', (tester) async {
await tester.openV020database();
// create a filter
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
@@ -136,7 +136,7 @@ void main() {
testWidgets('add number sort', (tester) async {
await tester.openV020database();
// create a filter
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
@@ -153,7 +153,7 @@ void main() {
'12',
'',
].indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
@@ -176,7 +176,7 @@ void main() {
'-2',
'',
].indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
@@ -188,7 +188,7 @@ void main() {
testWidgets('add checkbox and number sort', (tester) async {
await tester.openV020database();
// create a filter
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
@@ -255,7 +255,7 @@ void main() {
'2',
'',
].indexed) {
await tester.assertCellContent(
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
@@ -264,5 +264,111 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('reorder sort', (tester) async {
await tester.openV020database();
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
// open the sort menu and sort checkbox by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('Done');
await tester.tapSortByDescending();
// add another sort, this time by number descending
await tester.tapSortMenuInSettingBar();
await tester.tapCreateSortByFieldTypeInSortMenu(
FieldType.Number,
'number',
);
await tester.tapSortButtonByName('number');
await tester.tapSortByDescending();
// check checkbox cell order
for (final (index, content) in <bool>[
true,
true,
true,
true,
true,
false,
false,
false,
false,
false,
].indexed) {
await tester.assertCheckboxCell(
rowIndex: index,
isSelected: content,
);
}
// check number cell order
for (final (index, content) in <String>[
'1',
'0.2',
'0.1',
'-1',
'-2',
'12',
'11',
'10',
'2',
'',
].indexed) {
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
);
}
// reorder sort
await tester.tapSortMenuInSettingBar();
await tester.reorderSort(
(FieldType.Number, 'number'),
(FieldType.Checkbox, 'Done'),
);
// check checkbox cell order
for (final (index, content) in <bool>[
false,
false,
false,
false,
true,
true,
true,
true,
true,
false,
].indexed) {
await tester.assertCheckboxCell(
rowIndex: index,
isSelected: content,
);
}
// check the number cell order
for (final (index, content) in <String>[
'12',
'11',
'10',
'2',
'1',
'0.2',
'0.1',
'-1',
'-2',
'',
].indexed) {
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
);
}
});
});
}
@@ -1,5 +1,5 @@
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Board);
@@ -35,7 +35,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Board);
@@ -60,7 +60,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Board);
@@ -1,8 +1,11 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.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() {
@@ -42,5 +45,51 @@ void main() {
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_left_s);
expect(first.attributes[blockComponentAlign], 'left');
});
testWidgets('edit alignment using shortcut', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// click the first line of the readme
await tester.editor.tapLineOfEditorAt(0);
await tester.pumpAndSettle();
final editorState = tester.editor.getCurrentEditorState();
final first = editorState.getNodeAtPath([0])!;
// expect to see text aligned to the right
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.control,
LogicalKeyboardKey.shift,
LogicalKeyboardKey.keyR,
],
tester: tester,
);
expect(first.attributes[blockComponentAlign], rightAlignmentKey);
// expect to see text aligned to the center
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.control,
LogicalKeyboardKey.shift,
LogicalKeyboardKey.keyE,
],
tester: tester,
);
expect(first.attributes[blockComponentAlign], centerAlignmentKey);
// expect to see text aligned to the left
await FlowyTestKeyboard.simulateKeyDownEvent(
[
LogicalKeyboardKey.control,
LogicalKeyboardKey.shift,
LogicalKeyboardKey.keyL,
],
tester: tester,
);
expect(first.attributes[blockComponentAlign], leftAlignmentKey);
});
});
}
@@ -18,7 +18,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
// mock the clipboard
const lines = 3;
@@ -3,6 +3,7 @@ import 'dart:io';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -276,6 +277,22 @@ void main() {
},
);
});
testWidgets(
'auto convert url to link preview block',
(widgetTester) async {
const url = 'https://appflowy.io';
await widgetTester.pasteContent(
plainText: url,
(editorState) {
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, LinkPreviewBlockKeys.type);
expect(node.attributes[LinkPreviewBlockKeys.url], url);
},
);
},
);
}
extension on WidgetTester {
@@ -290,7 +307,7 @@ extension on WidgetTester {
await tapGoButton();
// create a new document
await createNewPageWithName();
await createNewPageWithNameUnderParent();
await beforeTest?.call(editor.getCurrentEditorState());
@@ -17,7 +17,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
// expect to see a new document
tester.expectToSeePageName(
@@ -35,7 +35,7 @@ void main() {
// delete the readme page
await tester.hoverOnPageName(
gettingStarted,
onHover: () async => await tester.tapDeletePageButton(),
onHover: () async => tester.tapDeletePageButton(),
);
// the banner should show up and the readme page should be gone
@@ -59,7 +59,7 @@ void main() {
// delete the readme page
await tester.hoverOnPageName(
gettingStarted,
onHover: () async => await tester.tapDeletePageButton(),
onHover: () async => tester.tapDeletePageButton(),
);
// the banner should show up and the readme page should be gone
@@ -1,9 +1,9 @@
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:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -30,7 +30,7 @@ void main() {
// Select result
final optionFinder = find.descendant(
of: find.byType(LinkToPageMenu),
of: find.byType(InlineActionsHandler),
matching: find.text(name),
);
@@ -86,9 +86,8 @@ void main() {
Future<String> createDocumentToReference(WidgetTester tester) async {
final name = 'document_${uuid()}';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: ViewLayoutPB.Document,
openAfterCreated: false,
);
@@ -32,7 +32,7 @@ void main() {
await tester.tapAt(Offset.zero);
await tester.tapAt(Offset.zero);
await tester.createNewPageWithName(name: 'test');
await tester.createNewPageWithNameUnderParent(name: 'test');
await tester.openPage(gettingStarted);
// check the status again
@@ -1,4 +1,3 @@
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';
@@ -10,7 +9,7 @@ void main() {
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.''',
'''no text direction items will be displayed in the default/LTR mode, and three text direction items will be displayed when toggle is enabled.''',
(tester) async {
// combine the two tests into one to avoid the time-consuming process of initializing the app
await tester.initializeAppFlowy();
@@ -29,10 +28,10 @@ void main() {
// 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',
'toolbar/text_direction_ltr',
'toolbar/text_direction_rtl',
];
// no text direction items in default/LTR mode
// no text direction items by default
var button = find.byWidgetPredicate(
(widget) =>
widget is SVGIconItemWidget &&
@@ -41,7 +40,7 @@ void main() {
expect(button, findsNothing);
// switch to the RTL mode
await tester.switchLayoutDirectionMode(LayoutDirection.rtlLayout);
await tester.toggleEnableRTLToolbarItems();
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.updateSelection(selection);
@@ -1,6 +1,6 @@
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:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
@@ -43,8 +43,6 @@ void main() {
await tester.editor.hoverOnCover();
await tester.editor.tapOnChangeCover();
await tester.editor.addNetworkImageCover(imageUrl);
await tester.editor.switchNetworkImageCover(imageUrl);
await tester.editor.dismissCoverPicker();
tester.expectToSeeDocumentCover(CoverType.file);
// Remove the cover
@@ -1,11 +1,11 @@
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/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
import 'package:appflowy/plugins/inline_actions/widgets/inline_actions_handler.dart';
import 'package:appflowy/plugins/database/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
@@ -40,7 +40,7 @@ void main() {
Position(path: [1]),
),
);
final gridTextCell = find.byType(GridTextCell).first;
final gridTextCell = find.byType(EditableTextCell).first;
await tester.tapButton(gridTextCell);
expect(tester.editor.getCurrentEditorState().selection, isNull);
@@ -84,7 +84,7 @@ void main() {
await createInlineDatabase(tester, ViewLayoutPB.Grid);
// validate the referenced grid is inserted
// validate the inline grid is created
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
@@ -100,7 +100,7 @@ void main() {
await createInlineDatabase(tester, ViewLayoutPB.Board);
// validate the referenced grid is inserted
// validate the inline board is created
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
@@ -116,7 +116,7 @@ void main() {
await createInlineDatabase(tester, ViewLayoutPB.Calendar);
// validate the referenced grid is inserted
// validate the inline calendar is created
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
@@ -136,16 +136,14 @@ Future<void> insertReferenceDatabase(
// create a new grid
final id = uuid();
final name = '${layout.name}_$id';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'insert_a_reference_${layout.name}',
layout: ViewLayoutPB.Document,
openAfterCreated: true,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -155,7 +153,7 @@ Future<void> insertReferenceDatabase(
layout.referencedMenuName,
);
final linkToPageMenu = find.byType(LinkToPageMenu);
final linkToPageMenu = find.byType(InlineActionsHandler);
expect(linkToPageMenu, findsOneWidget);
final referencedDatabase = find.descendant(
of: linkToPageMenu,
@@ -171,10 +169,8 @@ Future<void> createInlineDatabase(
) async {
// create a new document
final documentName = 'insert_a_inline_${layout.name}';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: documentName,
layout: ViewLayoutPB.Document,
openAfterCreated: true,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -1,13 +1,17 @@
import 'dart:io';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
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/resizeable_image.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:appflowy/startup/startup.dart';
import 'package:appflowy_editor/appflowy_editor.dart'
hide UploadImageMenu, ResizableImage;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@@ -31,9 +35,8 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -61,6 +64,7 @@ void main() {
paths: [imagePath],
);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
await tester.tapButtonWithName(
LocaleKeys.document_imageBlock_upload_placeholder.tr(),
);
@@ -79,9 +83,8 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -133,9 +136,8 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -1,6 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
@@ -20,9 +19,8 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'math equation',
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -66,9 +64,8 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'math equation',
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -1,5 +1,5 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -65,7 +65,7 @@ void main() {
const newName = 'RenameToNewPageName';
await tester.hoverOnPageName(
pageName,
onHover: () async => await tester.renamePage(newName),
onHover: () async => tester.renamePage(newName),
);
final finder = find.descendant(
of: find.byType(MentionPageBlock),
@@ -84,7 +84,7 @@ void main() {
await tester.hoverOnPageName(
pageName,
layout: ViewLayoutPB.Grid,
onHover: () async => await tester.tapDeletePageButton(),
onHover: () async => tester.tapDeletePageButton(),
);
final finder = find.descendant(
of: find.byType(MentionPageBlock),
@@ -105,16 +105,15 @@ Future<String> insertInlinePage(
// create a new grid
final id = uuid();
final name = '${layout.name}_$id';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'insert_a_inline_page_${layout.name}',
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -1,4 +1,3 @@
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -24,9 +23,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent();
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -1,12 +1,18 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/outline/outline_block_component.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
const String heading1 = "Heading 1";
const String heading2 = "Heading 2";
const String heading3 = "Heading 3";
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -15,9 +21,8 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'outline_test',
layout: ViewLayoutPB.Document,
);
await tester.editor.tapLineOfEditorAt(0);
@@ -32,16 +37,11 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'outline_test',
layout: ViewLayoutPB.Document,
);
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText('# Heading 1\n');
await tester.ime.insertText('## Heading 2\n');
await tester.ime.insertText('### Heading 3\n');
await insertHeadingComponent(tester);
/* Results in:
* # Heading 1
* ## Heading 2
@@ -54,7 +54,7 @@ void main() {
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text('Heading 1'),
matching: find.text(heading1),
),
findsOneWidget,
);
@@ -63,7 +63,7 @@ void main() {
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text('Heading 2'),
matching: find.text(heading2),
),
findsOneWidget,
);
@@ -72,7 +72,7 @@ void main() {
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text('Heading 3'),
matching: find.text(heading3),
),
findsOneWidget,
);
@@ -83,11 +83,86 @@ void main() {
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text('Heading 1Hello world'),
matching: find.text('${heading1}Hello world'),
),
findsOneWidget,
);
});
testWidgets("control the depth of outline block", (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(
name: 'outline_test',
);
await insertHeadingComponent(tester);
/* Results in:
* # Heading 1
* ## Heading 2
* ### Heading 3
*/
await tester.editor.tapLineOfEditorAt(3);
await insertOutlineInDocument(tester);
// expect to find only the `heading1` widget under the [OutlineBlockWidget]
await hoverAndClickDepthOptionAction(tester, [3], 1);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading2),
),
findsNothing,
);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading3),
),
findsNothing,
);
//////
/// expect to find only the 'heading1' and 'heading2' under the [OutlineBlockWidget]
await hoverAndClickDepthOptionAction(tester, [3], 2);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading3),
),
findsNothing,
);
//////
// expect to find all the headings under the [OutlineBlockWidget]
await hoverAndClickDepthOptionAction(tester, [3], 3);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading1),
),
findsOneWidget,
);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading2),
),
findsOneWidget,
);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading3),
),
findsOneWidget,
);
//////
});
});
}
@@ -100,3 +175,25 @@ Future<void> insertOutlineInDocument(WidgetTester tester) async {
);
await tester.pumpAndSettle();
}
Future<void> hoverAndClickDepthOptionAction(
WidgetTester tester,
List<int> path,
int level,
) async {
await tester.editor.hoverAndClickOptionMenuButton([3]);
await tester.tap(find.byType(AppFlowyPopover).hitTestable().last);
await tester.pumpAndSettle();
// Find a total of 4 HoverButtons under the [BlockOptionButton],
// in addition to 3 HoverButtons under the [DepthOptionAction] - (child of BlockOptionButton)
await tester.tap(find.byType(HoverButton).hitTestable().at(3 + level));
await tester.pumpAndSettle();
}
Future<void> insertHeadingComponent(WidgetTester tester) async {
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText('# $heading1\n');
await tester.ime.insertText('## $heading2\n');
await tester.ime.insertText('### $heading3\n');
}
@@ -1,7 +1,6 @@
import 'dart:io';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -40,9 +39,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent();
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -86,9 +83,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent();
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -125,9 +120,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent();
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -162,9 +155,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent();
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -176,11 +167,8 @@ void main() {
final toggleListIcon = find.byIcon(Icons.arrow_right);
await tester.tapButton(toggleListIcon);
await tester.editor.updateSelection(
Selection.collapsed(
Position(path: [0], offset: 0),
),
);
await tester.editor
.updateSelection(Selection.collapsed(Position(path: [0])));
await tester.ime.insertCharacter('\n');
final editorState = tester.editor.getCurrentEditorState();
@@ -196,9 +184,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent();
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -209,7 +195,7 @@ void main() {
await tester.editor.updateSelection(
Selection.collapsed(
Position(path: [0], offset: 0),
Position(path: [0]),
),
);
await tester.simulateKeyEvent(
@@ -1,6 +1,5 @@
import 'dart:io';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -18,10 +17,7 @@ void main() {
// create a new document called Sample
const pageName = 'Sample';
await tester.createNewPageWithName(
name: pageName,
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent(name: pageName);
// focus on the editor
await tester.editor.tapLineOfEditorAt(0);
@@ -75,10 +71,7 @@ void main() {
// create a new document called Sample
const pageName = 'Sample';
await tester.createNewPageWithName(
name: pageName,
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent(name: pageName);
// focus on the editor
await tester.editor.tapLineOfEditorAt(0);
@@ -104,7 +97,7 @@ void main() {
});
}
const _sample = r'''
const _sample = '''
# Heading 1
## Heading 2
### Heading 3
@@ -0,0 +1,41 @@
import 'dart:io';
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/editor/editor_component/service/editor.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();
// May be better to move this to an existing test but unsure what it fits with
group('Keyboard shortcuts related to emojis', () {
testWidgets('cmd/ctrl+alt+e shortcut opens the emoji picker',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final Finder editor = find.byType(AppFlowyEditor);
await tester.tap(editor);
await tester.pumpAndSettle();
expect(find.byType(EmojiSelectionMenu), findsNothing);
await FlowyTestKeyboard.simulateKeyDownEvent(
[
Platform.isMacOS
? LogicalKeyboardKey.meta
: LogicalKeyboardKey.control,
LogicalKeyboardKey.alt,
LogicalKeyboardKey.keyE,
],
tester: tester,
);
expect(find.byType(EmojiSelectionMenu), findsOneWidget);
});
});
}
@@ -28,8 +28,8 @@ void main() {
const service = TestWorkspaceService(TestWorkspace.emptyDocument);
group('Tests on a workspace with only an empty document', () {
setUpAll(() async => await service.setUpAll());
setUp(() async => await service.setUp());
setUpAll(() async => service.setUpAll());
setUp(() async => service.setUp());
testWidgets('/board shortcut creates a new board and view of the board',
(tester) async {
@@ -0,0 +1,107 @@
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/database_test_op.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Grid Calculations', () {
testWidgets('add calculation and update cell', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Change one Field to Number
await tester.changeFieldTypeOfFieldWithName('Type', FieldType.Number);
expect(find.text('Calculate'), findsOneWidget);
await tester.changeCalculateAtIndex(1, CalculationType.Sum);
// Enter values in cells
await tester.editCell(
rowIndex: 0,
fieldType: FieldType.Number,
input: '100',
);
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.Number,
input: '100',
);
// Dismiss edit cell
await tester.sendKeyDownEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('200'), findsOneWidget);
});
testWidgets('add calculations and remove row', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Change two Fields to Number
await tester.changeFieldTypeOfFieldWithName('Type', FieldType.Number);
await tester.changeFieldTypeOfFieldWithName('Done', FieldType.Number);
expect(find.text('Calculate'), findsNWidgets(2));
await tester.changeCalculateAtIndex(1, CalculationType.Sum);
await tester.changeCalculateAtIndex(2, CalculationType.Min);
// Enter values in cells
await tester.editCell(
rowIndex: 0,
fieldType: FieldType.Number,
input: '100',
);
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.Number,
input: '150',
);
await tester.editCell(
rowIndex: 0,
fieldType: FieldType.Number,
input: '50',
cellIndex: 1,
);
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.Number,
input: '100',
cellIndex: 1,
);
await tester.pumpAndSettle();
// Dismiss edit cell
await tester.sendKeyDownEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle();
expect(find.text('250'), findsOneWidget);
expect(find.text('50'), findsNWidgets(2));
// Delete 1st row
await tester.hoverOnFirstRowOfGrid();
await tester.tapRowMenuButtonInGrid();
await tester.tapDeleteOnRowMenu();
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('150'), findsNWidgets(2));
expect(find.text('100'), findsNWidgets(2));
});
});
}
@@ -19,7 +19,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@@ -71,7 +71,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle();
@@ -33,7 +33,7 @@ void main() {
File(path).writeAsStringSync(str);
}
// mock get files
await mockPickFilePaths(
mockPickFilePaths(
paths: testFileNames
.map((e) => p.join(context.applicationDataDirectory, e))
.toList(),
@@ -15,8 +15,8 @@ void main() {
const service = TestWorkspaceService(TestWorkspace.aiWorkSpace);
group('integration tests for open-ai smart menu', () {
setUpAll(() async => await service.setUpAll());
setUp(() async => await service.setUp());
setUpAll(() async => service.setUpAll());
setUp(() async => service.setUp());
testWidgets('testing selection on open-ai smart menu replace',
(tester) async {
@@ -59,7 +59,7 @@ void main() {
editorState.service.selectionService.updateSelection(
Selection(
start: Position(path: [1], offset: 0),
start: Position(path: [1]),
end: Position(path: [1], offset: 5),
),
);
@@ -80,8 +80,8 @@ void main() {
expect(
editorState.service.selectionService.currentSelection.value,
Selection(
start: Position(path: [2], offset: 0),
end: Position(path: [3], offset: 0),
start: Position(path: [2]),
end: Position(path: [3]),
),
);
});
@@ -99,7 +99,7 @@ Future<AppFlowyEditor> setUpOpenAITesting(WidgetTester tester) async {
final Finder editor = find.byType(AppFlowyEditor);
await tester.tap(editor);
await tester.pumpAndSettle();
return (tester.state(editor).widget as AppFlowyEditor);
return tester.state(editor).widget as AppFlowyEditor;
}
Future<void> mockOpenAIRepository() async {
@@ -1,20 +1,23 @@
import 'package:flutter/services.dart';
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/notifications/widgets/notification_item.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/expectation.dart';
import '../util/keyboard.dart';
void main() {
@@ -35,7 +38,7 @@ void main() {
await tester.pumpAndSettle();
// Trigger iline action menu and type 'remind tomorrow'
// Trigger inline action menu and type 'remind tomorrow'
final tomorrow = await _insertReminderTomorrow(tester);
Node node = tester.editor.getCurrentEditorState().getNodeAtPath([1])!;
@@ -43,7 +46,7 @@ void main() {
node.delta!.first.attributes![MentionBlockKeys.mention];
expect(node.type, 'paragraph');
expect(mentionAttr['type'], MentionType.reminder.name);
expect(mentionAttr['type'], MentionType.date.name);
expect(mentionAttr['date'], tomorrow.toIso8601String());
await tester.tap(
@@ -67,9 +70,57 @@ void main() {
_dateWithTime(dateTimeSettings.timeFormat, tomorrow, time);
expect(node.type, 'paragraph');
expect(mentionAttr['type'], MentionType.reminder.name);
expect(mentionAttr['type'], MentionType.date.name);
expect(mentionAttr['date'], tomorrowWithTime.toIso8601String());
});
testWidgets('Add reminder for tomorrow, and navigate to it',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.getCurrentEditorState().insertNewLine();
await tester.pumpAndSettle();
// Trigger inline action menu and type 'remind tomorrow'
final tomorrow = await _insertReminderTomorrow(tester);
final Node node =
tester.editor.getCurrentEditorState().getNodeAtPath([1])!;
final Map<String, dynamic> mentionAttr =
node.delta!.first.attributes![MentionBlockKeys.mention];
expect(node.type, 'paragraph');
expect(mentionAttr['type'], MentionType.date.name);
expect(mentionAttr['date'], tomorrow.toIso8601String());
// Create and Navigate to a new document
await tester.createNewPageWithNameUnderParent();
await tester.pumpAndSettle();
// Open "Upcoming" in Notification hub
await tester.openNotificationHub(tabIndex: 1);
// Expect 1 notification
tester.expectNotificationItems(1);
// Tap on the notification
await tester.tap(find.byType(NotificationItem));
await tester.pumpAndSettle();
// Expect node at path 1 to be the date/reminder
expect(
tester.editor
.getCurrentEditorState()
.getNodeAtPath([1])
?.delta
?.first
.attributes?[MentionBlockKeys.mention]['type'],
MentionType.date.name,
);
});
});
}
@@ -23,6 +23,7 @@ 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;
import 'emoji_shortcut_test.dart' as emoji_shortcut_test;
// import 'auth/supabase_auth_test.dart' as supabase_auth_test_runner;
/// The main task runner for all integration tests in AppFlowy.
@@ -69,6 +70,7 @@ Future<void> main() async {
// Others
hotkeys_test.main();
emoji_shortcut_test.main();
// Appearance integration test
appearance_test_runner.main();
@@ -1,13 +1,11 @@
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();
}
@@ -1,41 +0,0 @@
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/emoji.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.tapEmoji('😁');
await tester.pumpAndSettle();
final UserAvatar userAvatar =
tester.widget(userAvatarFinder) as UserAvatar;
expect(userAvatar.iconUrl, '😁');
});
});
}
@@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.language);
@@ -0,0 +1,51 @@
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy/workspace/presentation/widgets/rename_view_popover.dart';
import 'package:appflowy_editor/appflowy_editor.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/keyboard.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Rename current view item', () {
testWidgets('by F2 shortcut', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await FlowyTestKeyboard.simulateKeyDownEvent(
[LogicalKeyboardKey.f2],
tester: tester,
);
await tester.pumpAndSettle();
expect(find.byType(RenameViewPopover), findsOneWidget);
await tester.enterText(
find.descendant(
of: find.byType(RenameViewPopover),
matching: find.byType(FlowyTextField),
),
'hello',
);
await tester.pumpAndSettle();
// Dismiss rename popover
await tester.tap(find.byType(AppFlowyEditor));
await tester.pumpAndSettle();
expect(
find.descendant(
of: find.byType(SingleInnerViewItem),
matching: find.text('hello'),
),
findsOneWidget,
);
});
});
}
@@ -1,7 +1,6 @@
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/favorite_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -31,17 +30,11 @@ void main() {
].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) {
final parentName = i == 0 ? gettingStarted : names[i - 1];
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(
names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
parentLayout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(names[i], parentName: parentName);
}
await tester.favoriteViewByName(gettingStarted);
@@ -87,7 +80,6 @@ void main() {
await tester.favoriteViewByName(gettingStarted);
await tester.hoverOnPageName(
gettingStarted,
layout: ViewLayoutPB.Document,
onHover: () async {
await tester.renamePage(name);
await tester.pumpAndSettle();
@@ -113,10 +105,9 @@ void main() {
final names = [1, 2].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) {
final parentName = i == 0 ? gettingStarted : names[i - 1];
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(names[i], parentName: parentName);
}
@@ -136,7 +127,6 @@ void main() {
await tester.hoverOnPageName(
names[1],
layout: ViewLayoutPB.Document,
onHover: () async {
await tester.tapDeletePageButton();
await tester.pumpAndSettle();
@@ -150,7 +140,6 @@ void main() {
await tester.hoverOnPageName(
gettingStarted,
layout: ViewLayoutPB.Document,
onHover: () async {
await tester.tapDeletePageButton();
await tester.pumpAndSettle();
@@ -170,7 +159,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
await tester.favoriteViewByName(gettingStarted);
expect(
find.byWidgetPredicate(
@@ -190,11 +179,10 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
await tester.favoriteViewByName(gettingStarted);
await tester.hoverOnPageName(
gettingStarted,
layout: ViewLayoutPB.Document,
useLast: false,
onHover: () async {
await tester.tapPageOptionButton();
@@ -1,4 +1,4 @@
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -18,7 +18,7 @@ void main() {
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: value.name,
parentName: gettingStarted,
layout: value,
@@ -46,7 +46,7 @@ void main() {
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: value.name,
parentName: gettingStarted,
layout: value,
@@ -1,12 +1,12 @@
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/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -41,7 +41,7 @@ void main() {
for (final layout in ViewLayoutPB.values) {
// create a new page
final name = 'AppFlowy_$layout';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: layout,
);
@@ -79,10 +79,9 @@ void main() {
final names = [1, 2, 3, 4].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) {
final parentName = i == 0 ? gettingStarted : names[i - 1];
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(names[i], parentName: parentName);
}
@@ -144,14 +143,14 @@ void main() {
await tester.tapGoButton();
const document = 'document';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: document,
openAfterCreated: false,
);
tester.expectToSeePageName(document, layout: ViewLayoutPB.Document);
tester.expectToSeePageName(document);
const grid = 'grid';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: grid,
layout: ViewLayoutPB.Grid,
openAfterCreated: false,
@@ -187,10 +186,9 @@ void main() {
await tester.tapGoButton();
const grid = 'grid';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: grid,
layout: ViewLayoutPB.Grid,
openAfterCreated: true,
);
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
@@ -33,7 +33,7 @@ void main() {
);
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// switch to user B
{
@@ -51,7 +51,7 @@ void main() {
);
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// set user name for userB
await tester.openSettings();
@@ -71,7 +71,7 @@ void main() {
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
tester.expectToSeeUserName(userA);
}
@@ -88,7 +88,7 @@ void main() {
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
tester.expectToSeeUserName(userB);
}
});
@@ -99,7 +99,7 @@ void main() {
await tester.tapGoButton();
// home and readme document
tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// open settings and restore the location
await tester.openSettings();
@@ -2,7 +2,7 @@ import 'dart:io';
import 'package:appflowy/workspace/presentation/home/tabs/flowy_tab.dart';
import 'package:appflowy/workspace/presentation/home/tabs/tabs_manager.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -32,15 +32,9 @@ void main() {
findsNothing,
);
await tester.createNewPageWithName(
name: _documentName,
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent(name: _documentName);
await tester.createNewPageWithName(
name: _documentTwoName,
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithNameUnderParent(name: _documentTwoName);
/// Open second menu item in a new tab
await tester.openAppInNewTab(gettingStarted, ViewLayoutPB.Document);
@@ -1,16 +1,27 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.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';
import 'expectation.dart';
extension AppFlowyAuthTest on WidgetTester {
Future<void> tapGoogleLoginInButton() async {
await tapButton(find.byKey(const Key('signInWithGoogleButton')));
}
Future<void> logout() async {
await tapButton(find.byType(SettingLogoutButton));
expectToSeeText(LocaleKeys.button_ok.tr());
await tapButtonWithName(LocaleKeys.button_ok.tr());
}
Future<void> tapSignInAsGuest() async {
await tapButton(find.byType(SignInAnonymousButton));
}
@@ -11,11 +11,9 @@ import 'package:appflowy/user/application/auth/supabase_mock_auth_service.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:dartz/dartz.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
@@ -33,21 +31,24 @@ extension AppFlowyTestBase on WidgetTester {
Future<FlowyTestContext> initializeAppFlowy({
// use to append after the application data directory
String? pathExtension,
Size windowsSize = const Size(1600, 1200),
// use to specify the application data directory, if not specified, a temporary directory will be used.
String? dataDirectory,
Size windowSize = const Size(1600, 1200),
AuthenticatorType? cloudType,
String? userEmail,
String? email,
}) async {
binding.setSurfaceSize(windowsSize);
// view.physicalSize = windowsSize;
await binding.setSurfaceSize(windowSize);
// addTearDown(() => binding.setSurfaceSize(null));
mockHotKeyManagerHandlers();
final directory = await mockApplicationDataStorage(
pathExtension: pathExtension,
);
WidgetsFlutterBinding.ensureInitialized();
final applicationDataDirectory = dataDirectory ??
await mockApplicationDataStorage(
pathExtension: pathExtension,
);
await FlowyRunner.run(
FlowyApp(),
AppFlowyApplication(),
IntegrationMode.integrationTest,
rustEnvsBuilder: () {
final rustEnvs = <String, String>{};
@@ -57,10 +58,12 @@ extension AppFlowyTestBase on WidgetTester {
break;
case AuthenticatorType.supabase:
break;
case AuthenticatorType.appflowyCloud:
case AuthenticatorType.appflowyCloudSelfHost:
rustEnvs["GOTRUE_ADMIN_EMAIL"] = "admin@example.com";
rustEnvs["GOTRUE_ADMIN_PASSWORD"] = "password";
break;
default:
throw Exception("not supported");
}
}
return rustEnvs;
@@ -71,30 +74,33 @@ extension AppFlowyTestBase on WidgetTester {
if (cloudType != null) {
switch (cloudType) {
case AuthenticatorType.local:
await useLocal();
break;
case AuthenticatorType.supabase:
await useSupabaseCloud();
await useTestSupabaseCloud();
getIt.unregister<AuthService>();
getIt.registerFactory<AuthService>(
() => SupabaseMockAuthService(),
);
break;
case AuthenticatorType.appflowyCloud:
await useAppFlowyCloud();
case AuthenticatorType.appflowyCloudSelfHost:
await useTestSelfHostedAppFlowyCloud();
getIt.unregister<AuthService>();
getIt.registerFactory<AuthService>(
() => AppFlowyCloudMockAuthService(email: userEmail),
() => AppFlowyCloudMockAuthService(email: email),
);
break;
default:
throw Exception("not supported");
}
}
},
);
},
);
await waitUntilSignInPageShow();
return FlowyTestContext(
applicationDataDirectory: directory,
applicationDataDirectory: applicationDataDirectory,
);
}
@@ -109,27 +115,6 @@ extension AppFlowyTestBase on WidgetTester {
});
}
Future<String> mockApplicationDataStorage({
// use to append after the application data directory
String? pathExtension,
}) async {
final dir = await getTemporaryDirectory();
// Use a random uuid to avoid conflict.
String path = p.join(dir.path, 'appflowy_integration_test', uuid());
if (pathExtension != null && pathExtension.isNotEmpty) {
path = '$path/$pathExtension';
}
final directory = Directory(path);
if (!directory.existsSync()) {
await directory.create(recursive: true);
}
MockApplicationDataStorage.initialPath = directory.path;
return directory.path;
}
Future<void> waitUntilSignInPageShow() async {
if (isAuthEnabled) {
final finder = find.byType(SignInAnonymousButton);
@@ -142,16 +127,22 @@ extension AppFlowyTestBase on WidgetTester {
}
}
Future<void> waitForSeconds(int seconds) async {
await Future.delayed(Duration(seconds: seconds), () {});
}
Future<void> pumpUntilFound(
Finder finder, {
Duration timeout = const Duration(seconds: 10),
Duration pumpInterval =
const Duration(milliseconds: 50), // Interval between pumps
}) async {
bool timerDone = false;
final timer = Timer(timeout, () => timerDone = true);
while (timerDone != true) {
await pump();
while (!timerDone) {
await pump(pumpInterval); // Pump with an interval
if (any(finder)) {
timerDone = true;
break;
}
}
timer.cancel();
@@ -256,15 +247,38 @@ extension AppFlowyFinderTestBase on CommonFinders {
}
}
Future<void> useSupabaseCloud() async {
await setAuthenticatorType(AuthenticatorType.supabase);
await setSupbaseServer(
Some(TestEnv.supabaseUrl),
Some(TestEnv.supabaseAnonKey),
Future<void> useLocal() async {
await useLocalServer();
}
Future<void> useTestSupabaseCloud() async {
await useSupabaseCloud(
url: TestEnv.supabaseUrl,
anonKey: TestEnv.supabaseAnonKey,
);
}
Future<void> useAppFlowyCloud() async {
await setAuthenticatorType(AuthenticatorType.appflowyCloud);
// await setAppFlowyCloudUrl(Some(TestEnv.afCloudUrl));
Future<void> useTestSelfHostedAppFlowyCloud() async {
await useSelfHostedAppFlowyCloudWithURL(TestEnv.afCloudUrl);
}
Future<String> mockApplicationDataStorage({
// use to append after the application data directory
String? pathExtension,
}) async {
final dir = await getTemporaryDirectory();
// Use a random uuid to avoid conflict.
String path = p.join(dir.path, 'appflowy_integration_test', uuid());
if (pathExtension != null && pathExtension.isNotEmpty) {
path = '$path/$pathExtension';
}
final directory = Directory(path);
if (!directory.existsSync()) {
await directory.create(recursive: true);
}
MockApplicationDataStorage.initialPath = directory.path;
return directory.path;
}
@@ -14,10 +14,13 @@ import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_it
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/notifications/widgets/flowy_tab.dart';
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_button.dart';
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.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:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter/gestures.dart';
@@ -290,7 +293,7 @@ extension CommonOperations on WidgetTester {
await tapButton(markdownButton);
}
Future<void> createNewPageWithName({
Future<void> createNewPageWithNameUnderParent({
String? name,
ViewLayoutPB layout = ViewLayoutPB.Document,
String? parentName,
@@ -303,7 +306,7 @@ extension CommonOperations on WidgetTester {
KVKeys.showRenameDialogWhenCreatingNewFile,
(value) => bool.parse(value),
);
final showRenameDialog = settingsOrFailure.fold(() => false, (r) => r);
final showRenameDialog = settingsOrFailure ?? false;
if (showRenameDialog) {
await tapOKButton();
}
@@ -333,6 +336,13 @@ extension CommonOperations on WidgetTester {
}
}
Future<void> createNewPage({
ViewLayoutPB layout = ViewLayoutPB.Document,
bool openAfterCreated = true,
}) async {
await tapButton(find.byType(SidebarNewPageButton));
}
Future<void> simulateKeyEvent(
LogicalKeyboardKey key, {
bool isControlPressed = false,
@@ -387,7 +397,6 @@ extension CommonOperations on WidgetTester {
await hoverOnPageName(
name,
layout: layout,
useLast: true,
onHover: () async {
await tapFavoritePageButton();
await pumpAndSettle();
@@ -402,7 +411,6 @@ extension CommonOperations on WidgetTester {
await hoverOnPageName(
name,
layout: layout,
useLast: true,
onHover: () async {
await tapUnfavoritePageButton();
await pumpAndSettle();
@@ -486,6 +494,30 @@ extension CommonOperations on WidgetTester {
await tapEmoji(icon);
await pumpAndSettle();
}
Future<void> openNotificationHub({
int tabIndex = 0,
}) async {
final finder = find.descendant(
of: find.byType(NotificationButton),
matching: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.clock_alarm_s,
),
);
await tap(finder);
await pumpAndSettle();
if (tabIndex == 1) {
final tabFinder = find.descendant(
of: find.byType(NotificationTabBar),
matching: find.byType(FlowyTabItem).at(1),
);
await tap(tabFinder);
await pumpAndSettle();
}
}
}
extension ViewLayoutPBTest on ViewLayoutPB {
@@ -1,79 +1,96 @@
import 'dart:io';
import 'package:appflowy/plugins/database/application/calculations/calculation_type_ext.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculate_cell.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculation_type_item.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/type_option/number.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checkbox.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checklist.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/date.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/number.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/select_option.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/timestamp.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/url.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
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';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/option_list.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/text.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/create_filter_list.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/disclosure_button.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/filter_menu_item.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/footer/grid_footer.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_editor.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
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';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_editor.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_menu.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/database_layout_selector.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart';
import 'package:appflowy/plugins/database_view/tab_bar/desktop/tab_bar_add_button.dart';
import 'package:appflowy/plugins/database_view/tab_bar/desktop/tab_bar_header.dart';
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.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';
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_progress_bar.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart';
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/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_action.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/database_settings_list.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/setting_property_list.dart';
import 'package:appflowy/plugins/database/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/calendar/application/calendar_bloc.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_day.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_event_card.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_event_editor.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database/calendar/presentation/toolbar/calendar_layout_setting.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checkbox.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/select_option/option_list.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/text.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/create_filter_list.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/disclosure_button.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/filter_menu_item.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/footer/grid_footer.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/desktop_field_cell.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_editor.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_type_list.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/type_option/date/date_time_format.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/row/row.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/create_sort_list.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/order_panel.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/sort_editor.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/sort_menu.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/toolbar/filter_button.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/toolbar/sort_button.dart';
import 'package:appflowy/plugins/database/tab_bar/desktop/tab_bar_add_button.dart';
import 'package:appflowy/plugins/database/tab_bar/desktop/tab_bar_header.dart';
import 'package:appflowy/plugins/database/widgets/database_layout_ext.dart';
import 'package:appflowy/plugins/database/widgets/row/accessory/cell_accessory.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_progress_bar.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/date_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_text_field.dart';
import 'package:appflowy/plugins/database/widgets/row/row_action.dart';
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/database/widgets/row/row_document.dart';
import 'package:appflowy/plugins/database/widgets/row/row_property.dart';
import 'package:appflowy/plugins/database/widgets/setting/database_layout_selector.dart';
import 'package:appflowy/plugins/database/widgets/setting/database_setting_action.dart';
import 'package:appflowy/plugins/database/widgets/setting/database_settings_list.dart';
import 'package:appflowy/plugins/database/widgets/setting/setting_button.dart';
import 'package:appflowy/plugins/database/widgets/setting/setting_property_list.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/clear_date_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/date_type_option_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/end_time_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.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_backend/protobuf/flowy-folder/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';
import 'package:flowy_infra_ui/style_widget/text_input.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:table_calendar/table_calendar.dart';
// Non-exported member of the table_calendar library
import 'package:table_calendar/src/widgets/cell_content.dart';
import 'base.dart';
import 'common_operations.dart';
import 'expectation.dart';
@@ -107,7 +124,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
File(path).writeAsStringSync(str);
}
// mock get files
await mockPickFilePaths(
mockPickFilePaths(
paths: paths,
);
await tapDatabaseRawDataButton();
@@ -136,7 +153,6 @@ extension AppFlowyDatabaseTest on WidgetTester {
await pumpAndSettle();
}
///
Finder cellFinder(int rowIndex, FieldType fieldType, {int cellIndex = 0}) {
final findRow = find.byType(GridRow, skipOffstage: false);
final findCell = finderForFieldType(fieldType);
@@ -168,10 +184,14 @@ extension AppFlowyDatabaseTest on WidgetTester {
required bool isSelected,
}) async {
final cell = cellFinder(rowIndex, FieldType.Checkbox);
var finder = find.byType(CheckboxCellUncheck);
if (isSelected) {
finder = find.byType(CheckboxCellCheck);
}
final finder = isSelected
? find.byWidgetPredicate(
(widget) =>
widget is FlowySvg && widget.svg == FlowySvgs.check_filled_s,
)
: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.uncheck_s,
);
expect(
find.descendant(
@@ -188,30 +208,23 @@ extension AppFlowyDatabaseTest on WidgetTester {
}) async {
final cell = cellFinder(rowIndex, fieldType);
expect(cell, findsOneWidget);
await tapButton(cell, warnIfMissed: false);
await tapButton(cell);
}
/// The [fieldName] must be unique in the grid.
Future<void> assertCellContent({
void assertCellContent({
required int rowIndex,
required FieldType fieldType,
required String content,
int cellIndex = 0,
}) async {
}) {
final findCell = cellFinder(rowIndex, fieldType, cellIndex: cellIndex);
final findContent = find.descendant(
of: findCell,
matching: find.text(content),
skipOffstage: false,
);
final text = find.descendant(
of: find.byType(TextField),
matching: findContent,
skipOffstage: false,
);
expect(text, findsOneWidget);
expect(findContent, findsOneWidget);
}
Future<void> assertSingleSelectOption({
@@ -253,10 +266,10 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
/// null percent means no progress bar should be found
Future<void> assertChecklistCellInGrid({
void assertChecklistCellInGrid({
required int rowIndex,
required double? percent,
}) async {
}) {
final findCell = cellFinder(rowIndex, FieldType.Checklist);
if (percent == null) {
@@ -269,44 +282,14 @@ extension AppFlowyDatabaseTest on WidgetTester {
final finder = find.descendant(
of: findCell,
matching: find.byWidgetPredicate(
(widget) {
if (widget is ChecklistProgressBar) {
return widget.percent == percent;
}
return false;
},
(widget) =>
widget is ChecklistProgressBar && widget.percent == percent,
),
);
expect(finder, findsOneWidget);
}
}
Future<void> assertDateCellInGrid({
required int rowIndex,
required String content,
}) async {
final findRow = find.byType(GridRow, skipOffstage: false);
final findCell = find.descendant(
of: findRow.at(rowIndex),
matching: find.byType(GridDateCell),
skipOffstage: false,
);
final text = find.descendant(
of: findCell,
matching: find.byWidgetPredicate(
(widget) {
if (widget is FlowyText) {
return widget.text == content;
}
return false;
},
),
skipOffstage: false,
);
expect(text, findsOneWidget);
}
Future<void> selectDay({
required int content,
}) async {
@@ -341,6 +324,26 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(finder);
}
Future<void> selectReminderOption(ReminderOption option) async {
await tapButton(find.byType(ReminderSelector));
final finder = find.descendant(
of: find.byType(FlowyButton),
matching: find.textContaining(option.label),
);
await tapButton(finder);
}
Future<bool> selectLastDateInPicker() async {
final finder = find.byType(CellContent).last;
final w = widget(finder) as CellContent;
await tapButton(finder);
return w.isToday;
}
Future<void> toggleDateRange() async {
final findDateEditor = find.byType(EndTimeButton);
final findToggle = find.byType(Toggle);
@@ -351,15 +354,11 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(finder);
}
Future<void> changeDateFormat() async {
final findDateEditor = find.byType(DateCellEditor);
final findDateTimeOptionButton = find.byType(DateTypeOptionButton);
final finder = find.descendant(
of: findDateEditor,
matching: findDateTimeOptionButton,
);
await tapButton(finder);
Future<void> tapChangeDateTimeFormatButton() async {
await tapButton(find.byType(DateTypeOptionButton));
}
Future<void> changeDateFormat() async {
final findDateFormatButton = find.byType(DateFormatButton);
await tapButton(findDateFormatButton);
@@ -368,14 +367,6 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> changeTimeFormat() async {
final findDateEditor = find.byType(DateCellEditor);
final findDateTimeOptionButton = find.byType(DateTypeOptionButton);
final finder = find.descendant(
of: findDateEditor,
matching: findDateTimeOptionButton,
);
await tapButton(finder);
final findDateFormatButton = find.byType(TimeFormatButton);
await tapButton(findDateFormatButton);
@@ -489,7 +480,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
void assertChecklistEditorVisible({required bool visible}) {
final editor = find.byType(GridChecklistCellEditor);
final editor = find.byType(ChecklistCellEditor);
if (visible) {
expect(editor, findsOneWidget);
} else {
@@ -602,7 +593,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> editTitleInRowDetailPage(String title) async {
final titleField = find.byType(GridTextCell);
final titleField = find.byType(EditableTextCell);
await enterText(titleField, title);
await pumpAndSettle();
}
@@ -620,11 +611,11 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> openEmojiPicker() async {
await tapButton(find.byType(EmojiPickerButton));
await tapButton(find.byType(AddEmojiButton));
}
Future<void> tapDateCellInRowDetailPage() async {
final findDateCell = find.byType(GridDateCell);
final findDateCell = find.byType(EditableDateCell);
await tapButton(findDateCell);
}
@@ -715,7 +706,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
Future<void> scrollToRight(Finder find) async {
final size = getSize(find);
await drag(find, Offset(-size.width, 0));
await drag(find, Offset(-size.width, 0), warnIfMissed: false);
await pumpAndSettle(const Duration(milliseconds: 500));
}
@@ -732,8 +723,33 @@ extension AppFlowyDatabaseTest on WidgetTester {
await pumpAndSettle();
}
Future<void> changeFieldTypeOfFieldWithName(
String name,
FieldType type,
) async {
await tapGridFieldWithName(name);
await tapEditFieldButton();
await tapSwitchFieldTypeButton();
await selectFieldType(type);
await dismissFieldEditor();
}
Future<void> changeCalculateAtIndex(int index, CalculationType type) async {
await tap(find.byType(CalculateCell).at(index));
await pumpAndSettle();
await tap(
find.descendant(
of: find.byType(CalculationTypeItem),
matching: find.text(type.label),
),
);
await pumpAndSettle();
}
/// Should call [tapGridFieldWithName] first.
Future<void> tapEditPropertyButton() async {
Future<void> tapEditFieldButton() async {
await tapButtonWithName(LocaleKeys.grid_field_editProperty.tr());
await pumpAndSettle(const Duration(milliseconds: 200));
}
@@ -747,7 +763,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(field);
}
/// Should call [tapGridFieldWithName] first.
/// A SimpleDialog must be shown first, e.g. when deleting a field.
Future<void> tapDialogOkButton() async {
final field = find.byWidgetPredicate(
(widget) =>
@@ -815,7 +831,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(find.byType(RowDetailPageDuplicateButton));
}
Future<void> tapTypeOptionButton() async {
Future<void> tapSwitchFieldTypeButton() async {
await tapButton(find.byType(SwitchFieldButton));
}
@@ -823,18 +839,29 @@ extension AppFlowyDatabaseTest on WidgetTester {
await sendKeyEvent(LogicalKeyboardKey.escape);
}
/// Must call [tapTypeOptionButton] first.
/// Must call [tapSwitchFieldTypeButton] first.
Future<void> selectFieldType(FieldType fieldType) async {
final fieldTypeCell = find.byType(FieldTypeCell);
final fieldTypeButton = find.descendant(
of: fieldTypeCell,
matching: find.byWidgetPredicate(
(widget) => widget is FlowyText && widget.text == fieldType.title(),
(widget) => widget is FlowyText && widget.text == fieldType.i18n,
),
);
await tapButton(fieldTypeButton);
}
// Use in edit mode of FieldEditor
void expectEmptyTypeOptionEditor() {
expect(
find.descendant(
of: find.byType(FieldTypeOptionEditor),
matching: find.byType(TypeOptionSeparator),
),
findsNothing,
);
}
/// Each field has its own cell, so we can find the corresponding cell by
/// the field type after create a new field.
Future<void> findCellByFieldType(FieldType fieldType) async {
@@ -884,14 +911,14 @@ extension AppFlowyDatabaseTest on WidgetTester {
expect(widget.field.fieldType, fieldType);
}
Future<void> findFieldWithName(String name) async {
void findFieldWithName(String name) {
final field = find.byWidgetPredicate(
(widget) => widget is FieldCellButton && widget.field.name == name,
);
expect(field, findsOneWidget);
}
Future<void> noFieldWithName(String name) async {
void noFieldWithName(String name) {
final field = find.byWidgetPredicate(
(widget) => widget is FieldCellButton && widget.field.name == name,
);
@@ -956,7 +983,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await scrollToRight(find.byType(GridPage));
await tapNewPropertyButton();
await renameField(name);
await tapTypeOptionButton();
await tapSwitchFieldTypeButton();
await selectFieldType(fieldType);
await dismissFieldEditor();
}
@@ -1043,6 +1070,34 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(findSortItem);
}
/// Must call [tapSortMenuInSettingBar] first.
Future<void> reorderSort(
(FieldType, String) from,
(FieldType, String) to,
) async {
final fromSortItem = find.byWidgetPredicate(
(widget) =>
widget is DatabaseSortItem &&
widget.sortInfo.fieldInfo.fieldType == from.$1 &&
widget.sortInfo.fieldInfo.name == from.$2,
);
final toSortItem = find.byWidgetPredicate(
(widget) =>
widget is DatabaseSortItem &&
widget.sortInfo.fieldInfo.fieldType == to.$1 &&
widget.sortInfo.fieldInfo.name == to.$2,
);
final dragElement = find.descendant(
of: fromSortItem,
matching: find.byType(ReorderableDragStartListener),
);
await drag(
dragElement,
getCenter(toSortItem) - getCenter(fromSortItem),
);
await pumpAndSettle(const Duration(milliseconds: 200));
}
/// Must call [tapSortButtonByName] first.
Future<void> tapSortByDescending() async {
await tapButton(
@@ -1061,7 +1116,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
/// Must call [tapSortMenuInSettingBar] first.
Future<void> tapAllSortButton() async {
await tapButton(find.byType(DatabaseDeleteSortButton));
await tapButton(find.byType(DeleteAllSortsButton));
}
Future<void> scrollOptionFilterListByOffset(Offset offset) async {
@@ -1114,7 +1169,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
skipOffstage: false,
);
expect(findCell, findsOneWidget);
await tapButton(findCell, warnIfMissed: false);
await tapButton(findCell);
}
Future<void> tapCheckedButtonOnCheckboxFilter() async {
@@ -1384,7 +1439,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
Future<void> dragDropRescheduleCalendarEvent() async {
final findEventCard = find.byType(EventCard);
await drag(findEventCard.first, const Offset(0, 300));
await pumpAndSettle();
await pumpAndSettle(const Duration(microseconds: 300));
}
Future<void> openUnscheduledEventsPopup() async {
@@ -1563,7 +1618,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(okButton);
}
Future<void> assertCurrentDatabaseTagIs(DatabaseLayoutPB layout) async {
void assertCurrentDatabaseTagIs(DatabaseLayoutPB layout) {
switch (layout) {
case DatabaseLayoutPB.Board:
expect(find.byType(BoardPage), findsOneWidget);
@@ -1601,6 +1656,23 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButtonWithName(LocaleKeys.importPanel_database.tr());
}
// Use in edit mode of FieldEditor
Future<void> changeNumberFieldFormat() async {
final changeFormatButton = find.descendant(
of: find.byType(FieldTypeOptionEditor),
matching: find.text("Number"),
);
await tapButton(changeFormatButton);
await tapButton(
find.byWidgetPredicate(
(widget) =>
widget is NumberFormatCell && widget.format == NumberFormatPB.USD,
),
);
}
// Use in edit mode of FieldEditor
Future<void> tapAddSelectOptionButton() async {
await tapButtonWithName(LocaleKeys.grid_field_addSelectOption.tr());
}
@@ -1610,8 +1682,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
) async {
final field = find.byWidgetPredicate(
(widget) =>
widget is DesktopDatabasePropertyCell &&
widget.fieldInfo.name == fieldName,
widget is DatabasePropertyCell && widget.fieldInfo.name == fieldName,
);
final toggleVisibilityButton =
find.descendant(of: field, matching: find.byType(FlowyIconButton));
@@ -1635,24 +1706,45 @@ Finder finderForDatabaseLayoutType(DatabaseLayoutPB layout) {
Finder finderForFieldType(FieldType fieldType) {
switch (fieldType) {
case FieldType.Checkbox:
return find.byType(GridCheckboxCell, skipOffstage: false);
return find.byType(EditableCheckboxCell, skipOffstage: false);
case FieldType.DateTime:
return find.byType(GridDateCell, skipOffstage: false);
return find.byType(EditableDateCell, skipOffstage: false);
case FieldType.LastEditedTime:
return find.byWidgetPredicate(
(widget) =>
widget is EditableTimestampCell &&
widget.fieldType == FieldType.LastEditedTime,
skipOffstage: false,
);
case FieldType.CreatedTime:
return find.byType(GridTimestampCell, skipOffstage: false);
return find.byWidgetPredicate(
(widget) =>
widget is EditableTimestampCell &&
widget.fieldType == FieldType.CreatedTime,
skipOffstage: false,
);
case FieldType.SingleSelect:
return find.byType(GridSingleSelectCell, skipOffstage: false);
return find.byWidgetPredicate(
(widget) =>
widget is EditableSelectOptionCell &&
widget.fieldType == FieldType.SingleSelect,
skipOffstage: false,
);
case FieldType.MultiSelect:
return find.byType(GridMultiSelectCell, skipOffstage: false);
return find.byWidgetPredicate(
(widget) =>
widget is EditableSelectOptionCell &&
widget.fieldType == FieldType.MultiSelect,
skipOffstage: false,
);
case FieldType.Checklist:
return find.byType(GridChecklistCell, skipOffstage: false);
return find.byType(EditableChecklistCell, skipOffstage: false);
case FieldType.Number:
return find.byType(GridNumberCell, skipOffstage: false);
return find.byType(EditableNumberCell, skipOffstage: false);
case FieldType.RichText:
return find.byType(GridTextCell, skipOffstage: false);
return find.byType(EditableTextCell, skipOffstage: false);
case FieldType.URL:
return find.byType(GridURLCell, skipOffstage: false);
return find.byType(EditableURLCell, skipOffstage: false);
default:
throw Exception('Unknown field type: $fieldType');
}
@@ -0,0 +1,53 @@
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:archive/archive.dart';
Future<void> deleteDirectoriesWithSameBaseNameAsPrefix(
String path,
) async {
final dir = Directory(path);
final prefix = p.basename(dir.path);
final parentDir = dir.parent;
// Check if the directory exists
if (!await parentDir.exists()) {
// ignore: avoid_print
print('Directory does not exist');
return;
}
// List all entities in the directory
await for (final entity in parentDir.list()) {
// Check if the entity is a directory and starts with the specified prefix
if (entity is Directory && p.basename(entity.path).startsWith(prefix)) {
try {
await entity.delete(recursive: true);
} catch (e) {
// ignore: avoid_print
print('Failed to delete directory: ${entity.path}, Error: $e');
}
}
}
}
Future<void> unzipFile(File zipFile, Directory targetDirectory) async {
// Read the Zip file from disk.
final bytes = zipFile.readAsBytesSync();
// Decode the Zip file
final archive = ZipDecoder().decodeBytes(bytes);
// Extract the contents of the Zip archive to disk.
for (final file in archive) {
final filename = file.name;
if (file.isFile) {
final data = file.content as List<int>;
File(p.join(targetDirectory.path, filename))
..createSync(recursive: true)
..writeAsBytesSync(data);
} else {
Directory(p.join(targetDirectory.path, filename))
.createSync(recursive: true);
}
}
}
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:ui';
import 'package:appflowy/generated/locale_keys.g.dart';
@@ -5,10 +6,11 @@ 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/actions/block_action_option_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/image/embed_image_url_widget.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';
@@ -121,19 +123,25 @@ class EditorOperations {
}
Future<void> addNetworkImageCover(String imageUrl) async {
final findNewImageButton = find.byType(NewCustomCoverButton);
await tester.tapButton(findNewImageButton);
final embedLinkButton = find.findTextInFlowyText(
LocaleKeys.document_imageBlock_embedLink_label.tr(),
);
await tester.tapButton(embedLinkButton);
final imageUrlTextField = find.descendant(
of: find.byType(NetworkImageUrlInput),
of: find.byType(EmbedImageUrlWidget),
matching: find.byType(TextField),
);
await tester.enterText(imageUrlTextField, imageUrl);
await tester.tapButtonWithName(
LocaleKeys.document_plugins_cover_add.tr(),
);
await tester.tapButtonWithName(
LocaleKeys.document_plugins_cover_saveToGallery.tr(),
final textField = tester.widget<TextField>(imageUrlTextField);
textField.controller?.text = imageUrl;
await tester.pumpAndSettle();
await tester.tapButton(
find.descendant(
of: find.byType(EmbedImageUrlWidget),
matching: find.findTextInFlowyText(
LocaleKeys.document_imageBlock_embedLink_label.tr(),
),
),
);
}
@@ -196,9 +204,11 @@ class EditorOperations {
/// Update the editor's selection
Future<void> updateSelection(Selection selection) async {
final editorState = getCurrentEditorState();
editorState.updateSelectionWithReason(
selection,
reason: SelectionUpdateReason.uiEvent,
unawaited(
editorState.updateSelectionWithReason(
selection,
reason: SelectionUpdateReason.uiEvent,
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 200));
}
@@ -232,4 +242,25 @@ class EditorOperations {
},
);
}
/// hover and click on the option menu button beside the block component.
Future<void> hoverAndClickOptionMenuButton(Path path) async {
final optionMenuButton = find.byWidgetPredicate(
(widget) =>
widget is BlockComponentActionWrapper &&
widget.node.path.equals(path),
);
await tester.hoverOnWidget(
optionMenuButton,
onHover: () async {
await tester.tapButton(
find.byWidgetPredicate(
(widget) =>
widget is BlockOptionButton &&
widget.blockComponentContext.node.path.equals(path),
),
);
},
);
}
}
@@ -1,24 +1,40 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/document/presentation/banner.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/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/notifications/widgets/notification_item.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'util.dart';
// const String readme = 'Read me';
const String gettingStarted = 'Getting started';
extension Expectation on WidgetTester {
/// Expect to see the home page and with a default read me page.
void expectToSeeHomePage() {
expect(find.byType(HomeStack), findsOneWidget);
expect(find.textContaining(gettingStarted), findsWidgets);
Future<void> expectToSeeHomePageWithGetStartedPage() async {
final finder = find.byType(HomeStack);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
final docFinder = find.textContaining(gettingStarted);
await pumpUntilFound(docFinder);
}
Future<void> expectToSeeHomePage() async {
final finder = find.byType(HomeStack);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
}
/// Expect to see the page name on the home page.
@@ -202,7 +218,7 @@ extension Expectation on WidgetTester {
return find.descendant(
of: find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget is InnerViewItem &&
widget.view.name == parentName &&
widget.view.layout == parentLayout,
skipOffstage: false,
@@ -230,4 +246,29 @@ extension Expectation on WidgetTester {
);
expect(icon, findsOneWidget);
}
void expectSelectedReminder(ReminderOption option) {
final findSelectedText = find.descendant(
of: find.byType(ReminderSelector),
matching: find.text(option.label),
);
expect(findSelectedText, findsOneWidget);
}
void expectNotificationItems(int amount) {
final findItems = find.byType(NotificationItem);
expect(findItems, findsNWidgets(amount));
}
void expectToSeeRowDetailsPageDialog() {
expect(
find.descendant(
of: find.byType(RowDetailPage),
matching: find.byType(SimpleDialog),
),
findsOneWidget,
);
}
}
@@ -34,7 +34,6 @@ class IMESimulator {
selection: TextSelection.collapsed(
offset: value.selection.baseOffset + 1,
),
composing: TextRange.empty,
);
client.updateEditingValue(textEditingValue);
await tester.pumpAndSettle();
@@ -74,9 +74,7 @@ Future<String> mockSaveFilePath(
return path;
}
Future<List<String>> mockPickFilePaths({
required List<String> paths,
}) async {
List<String> mockPickFilePaths({required List<String> paths}) {
getIt.unregister<FilePickerService>();
getIt.registerFactory<FilePickerService>(
() => MockFilePicker(
@@ -1,11 +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/home/menu/sidebar/sidebar_setting.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/direction_setting.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';
@@ -13,7 +13,7 @@ import 'base.dart';
extension AppFlowySettings on WidgetTester {
/// Open settings page
Future<void> openSettings() async {
final settingsButton = find.byTooltip(LocaleKeys.settings_menu_open.tr());
final settingsButton = find.byType(UserSettingButton);
expect(settingsButton, findsOneWidget);
await tapButton(settingsButton);
final settingsDialog = find.byType(SettingsDialog);
@@ -75,31 +75,15 @@ extension AppFlowySettings on WidgetTester {
await pumpAndSettle();
}
// go to settings page and switch the layout direction
Future<void> switchLayoutDirectionMode(
LayoutDirection layoutDirection,
) async {
// go to settings page and toggle enable RTL toolbar items
Future<void> toggleEnableRTLToolbarItems() 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;
}
final switchButton =
find.byKey(EnableRTLToolbarItemsSetting.enableRTLSwitchKey);
expect(switchButton, findsOneWidget);
await tapButton(switchButton);
// tap anywhere to close the settings page
await tapAt(Offset.zero);
@@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>12.0</string>
</dict>
</plist>
+1 -1
View File
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+20 -31
View File
@@ -48,9 +48,6 @@ 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):
@@ -72,22 +69,20 @@ PODS:
- SDWebImage (5.14.2):
- SDWebImage/Core (= 5.14.2)
- SDWebImage/Core (5.14.2)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- Flutter
- sqflite (0.0.3):
- Flutter
- FMDB (>= 2.7.5)
- FlutterMacOS
- super_native_extensions (0.0.1):
- Flutter
- SwiftyGif (5.4.3)
- Toast (4.0.0)
- url_launcher_ios (0.0.1):
- Flutter
- webview_flutter_wkwebview (0.0.1):
- Flutter
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
@@ -106,18 +101,16 @@ DEPENDENCIES:
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- rich_clipboard_ios (from `.symlinks/plugins/rich_clipboard_ios/ios`)
- share_plus (from `.symlinks/plugins/share_plus/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`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- 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`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- FMDB
- ReachabilitySwift
- SDWebImage
- SwiftyGif
@@ -156,50 +149,46 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
rich_clipboard_ios:
:path: ".symlinks/plugins/rich_clipboard_ios/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
: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"
:path: ".symlinks/plugins/sqflite/darwin"
super_native_extensions:
:path: ".symlinks/plugins/super_native_extensions/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
webview_flutter_wkwebview:
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
SPEC CHECKSUMS:
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
integration_test: 13825b8a9334a850581300559b8839134b124670
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
rich_clipboard_ios: 7588abe18f881a6d0e9ec0b12e51cae2761e8942
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac
PODFILE CHECKSUM: d94f9be27d1db182e9bc77d10f065555d518f127
COCOAPODS: 1.12.1
COCOAPODS: 1.15.2
@@ -143,7 +143,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1430;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -330,7 +330,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -346,9 +346,11 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = VHB67HRSZG;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
@@ -359,6 +361,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@@ -416,7 +419,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -465,7 +468,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -482,9 +485,11 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = VHB67HRSZG;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
@@ -495,6 +500,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@@ -513,6 +519,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = VHB67HRSZG;
@@ -526,6 +534,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.appflowy.appflowy.flutter;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Loaded 100 of 2896 files, more files were not shown because too many files have changed in this diff. Show more