Compare commits

..
184 Commits
Author SHA1 Message Date
Lucas.Xu daf9b48c73 chore: update CHANGELOG (#3433) 2023-09-18 14:39:25 +08:00
Lucas.Xu 0ea5b3c483 fix: rtl related issues 2023-09-18 14:33:51 +08:00
Nathan.fooo f3148640eb chore: update collab rev id (#3432) 2023-09-18 12:45:16 +08:00
Zackandnathan 1c84ee1d53 feat: integrate appflowy-cloud (#3359)
* feat: draft: code dependency

* chore: update ref

* feat: signup using client_api

* feat: support auto sign_in after sign_up if already confirmed(WIP)

* chore: update collab commit id

* chore: fix compile errors

* chore: user AFServer trait to provide optional service

* chore: refactor workspace

* chore: disable aws config

* chore: return ws connect

* chore: update collab rev

* chore: fmt and clippy

* chore: fix test

* chore: update chrono version

* chore: add script to update the collab crates commit id

* chore: update

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-09-17 17:14:34 +08:00
xfarrow cecd4f48ab Italian translation fix (#3395)
* Update it-IT.json
2023-09-15 15:43:05 +02:00
Richard Shiue 1e001640aa fix: cannot open popovers (#3410) 2023-09-15 19:01:22 +08:00
Lucas.Xu 3426e5b53e fix: launch review issues (#3413) 2023-09-15 17:51:29 +08:00
Yijing Huang 936b49a63f fix: alignment issue in login page (#3399) 2023-09-15 16:07:23 +08:00
Richard Shiue f6f80b48c9 fix: some UI issues (#3403) 2023-09-14 19:30:33 +08:00
Lucas.Xu 759cb27a43 chore: update version to 0.3.2 (#3404) 2023-09-14 19:23:39 +08:00
Lucas.Xu 26a2bffcd1 fix: some UI issues were present in version 0.3.1. (#3401) 2023-09-14 19:22:32 +08:00
Aman Negi fe55452c79 fix: restore banner theme issues (#3299) 2023-09-14 18:48:42 +08:00
Generic-Ripe 16adacac38 chore: update sv.json (#3386)
In this context board is tavla in Swedish.
Styrelse is board of directors.
2023-09-14 18:47:55 +08:00
Vincenzo De Petris d86531ac92 fix: add left padding to TabsManager widget (#3396) 2023-09-14 12:08:44 +02:00
Nathan.fooo 9231455f0d chore: update collab rev and fix compile (#3398) 2023-09-13 22:11:51 +08:00
Richard Shiue 0c6a1d4ae7 chore: revamp checklist ui (#3380)
* chore: revamp checklist editor  ui

* chore: checklist progress bar

* test: integration tests

* fix: flutter analyzer errors

* fix: checklist percentage complete
2023-09-13 20:44:04 +08:00
Richard Shiue 524efc2620 test: fi convert text to date cell test (#3377) 2023-09-13 19:12:40 +08:00
Richard Shiue 50a4f03931 chore: date editor ui polish (#3367) 2023-09-13 19:12:26 +08:00
Richard Shiue a4681a4042 fix: don't use timestamp fields to make calendar (#3366) 2023-09-13 19:11:46 +08:00
Richard Shiue 1ca130d7de feat: revamp row detail page UI (#3328)
* feat: revamp row detail page UI

* chore: some minor details and fix tests

* fix: fix tests

* chore: remove unused field

* chore: code cleanup

* test: add reordering fields in row page tests

* chore: remove duplicate and delete row events

* chore: timestamp cell ui adjustment

* chore: remove unused code

* test: fix new integration tests
2023-09-13 19:10:08 +08:00
Mathias Mogensen ef6f9a3175 fix: reorder rows on windows (#3279)
* fix: reorder rows on windows

Closes: #3208

* fix: unused import
2023-09-13 11:36:22 +08:00
Vincenzo De Petris aa25aa4474 fix: DateCardCellState date formatting (#3387)
* fix: DateCardCellState date formatting

* refactor: use string interpolation
2023-09-13 11:18:07 +08:00
c7af04b317 feat: support incremental updates for textblock's delta. (#3216)
* feat: support incremental to update textblock's delta

* fix: update test code

* fix: remove console

* fix: update test

* feat: integrate increamental delta in Flutter

* fix: delete quill editor

* fix: delete quill editor

* feat: add csharp in codeblock (#3371)

* chore: pt-PT & pt-BR translation updated  (#3353)

* chore: Ensure Cargo.lock Is Updated Alongside Changes to Cargo.toml (#3361)

* ci: add cargo check workflow

* ci: test cargo.toml

* fix: update test

* fix: code review

* fix: update cargo.toml and cargo.lock

* fix: code review

* fix: rust format

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: Mayur Mahajan <47064215+MayurSMahajan@users.noreply.github.com>
Co-authored-by: Carlos Silva <mtbf99@gmail.com>
2023-09-12 20:49:03 +08:00
Mohammad ZolfaghariandLucas.Xu 9565173baf feat: text and layout direction settings (#3247)
* feat: text and layout direction settings

Added ltr|rtl|auto direction button to appflowy toolbar.
Introduced layout and default direction settings.

* chore: formate code

* feat: added hint for direction settings

* fix: flutter analyze

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-09-12 19:11:13 +08:00
Lucas.Xu 5f4e3ecc76 fix: unable to paste texts contains section or font tag (#3379) 2023-09-12 15:53:39 +08:00
Lucas.Xu 043c68a333 fix: downgrade the folder path to io.appflowy.appflowy (#3344) 2023-09-12 14:31:05 +08:00
Yijing Huang f639d51c11 feat: auth pages improvement for mobile and desktop platform (#3217) 2023-09-12 10:32:26 +08:00
Lucas.Xu 71071b60b2 feat: improve performance of document page (#3357) 2023-09-12 10:29:41 +08:00
Kilu.He 608255fa0f chore: Ensure Cargo.lock Is Updated Alongside Changes to Cargo.toml (#3361)
* ci: add cargo check workflow

* ci: test cargo.toml
2023-09-11 18:59:35 +08:00
Carlos Silva f8b0a26acc chore: pt-PT & pt-BR translation updated (#3353) 2023-09-11 15:24:08 +08:00
Mayur Mahajan 133dab934b feat: add csharp in codeblock (#3371) 2023-09-11 15:02:57 +08:00
fangwufeng-v a81670c447 feat: new grid (#3167)
* feat: implement database database service by functions

* feat: define database data type

* feat: basic grid store and component

* feat: data communication mechanism and simple table ui. Can add new filed and update field name.

* feat: add grid text cell and grid checkbox cell

* feat: single select cell and multiselect cell

* refactor: fix code review problems

* feat: add new row

* feat: fix tsc error
2023-09-11 10:27:56 +08:00
Richard Shiue 35f84e42cc fix: one-frame glitch when deleting all sorts (#3330) 2023-09-10 15:50:49 +08:00
Yijing Huang 2f6df6a17d chore: remove default ImageFilter (#3349) 2023-09-08 10:09:16 +08:00
Richard Shiue 8bcc6384f2 refactor: different TypeOption between DateTime and LastModified/CreatedAt (#3356)
* fix: stringify date cell includes time if true

* refactor: LastModified and CreatedAt type option

* chore: frontend implementation

* chore: some adjustments and fix tests

* fix: integration tests

* chore: timestamp type option ui
2023-09-08 10:07:24 +08:00
Nathan.fooo a0fc4b86b0 chore: update collab libs rev (#3342) 2023-09-06 16:00:23 +08:00
Nathan.fooo 790580eea4 chore: update cargo build profile (#3332) 2023-09-05 09:31:23 +08:00
Lucas.Xu 3db9024a2d chore: release 0.3.1 (#3326)
* chore: update editor version

* fix: export name (with CJK) doesn't match the document name

* chore: bump version 0.3.1
2023-09-04 17:28:19 +08:00
Nathan.fooo a821740469 refactor: remove http server ref (#3327) 2023-09-04 15:50:38 +08:00
Lucas.Xu af0ae2e375 feat: enable heading in the table plugin (#3325) 2023-09-04 13:35:11 +08:00
Nils Jacobsen 7d6fa0b159 chore: update inlang.config.js and language files 2023-09-04 13:33:56 +08:00
Richard Shiueandnathan b73a34ed94 refactor: remove date cell persistence (#3095)
* refactor: remove date cell persistence

* refactor: use i64 rather than String in DateChangeset

* chore: code cleanup

* fix: tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-09-02 11:50:16 +08:00
Richard Shiue f3aaff77b9 chore: per-view field visibility UI (#3296)
* chore: default field settings if not exist

* chore: field settings listeners and services

* chore: don't need to updateFieldInfos

* feat: per-view field visibilty UI

* fix: remove unresolved imports
2023-09-02 00:42:46 +08:00
Vedant PandeyandRichard Shiue 9b7ff375b2 fix: trigger option selection on tap down (#2915)
* fix: trigger option selection on tap down

* chore: add TODO comment

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2023-09-01 22:58:21 +08:00
Richard Shiueandnathan 18498c0479 feat: field settings application domain (#3284)
* chore: default field settings if not exist

* chore: field settings listeners and services

* chore: don't need to updateFieldInfos

* chore: load default field settings if none found

* chore: update collab ref

* chore: fix remidner compile errors

* fix: fix tests

* chore: update tauri project setting

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-09-01 22:40:17 +08:00
Nathan.fooo c652c32575 feat File storage (#3306)
* refactor: file upload

* refactor: support upload plan

* test: add tests
2023-09-01 22:27:29 +08:00
Mohammad Zolfaghari df8642d446 feat: support table plugin (#3280) 2023-09-01 14:45:21 +08:00
Nathan.fooo abb6eff23d fix: disable sync if keys aren't provided (#3304) 2023-09-01 11:32:45 +08:00
Nathan.fooo 3b4f8e53a2 feat: storage file (#3303) 2023-08-31 16:40:40 +08:00
Nathan.fooo 4847b8b114 chore: enable discord and github login (#3293) 2023-08-31 15:45:01 +08:00
Lucas.Xu e8f124b97c feat: support editing name when creating page (#3297) 2023-08-30 22:16:12 +08:00
Lucas.Xu f73d59fb57 feat: support text align and block align (#3292)
* feat: support text align and block align

* test: add test
2023-08-30 17:21:32 +08:00
Nathan.fooo 897d7980f6 chore: remove jwt secret env variable (#3291) 2023-08-30 11:51:33 +08:00
Mayur MahajanandLucas.Xu b88aed887a fix: paste multiple lines in codeblock (#3151)
* fix: paste multiple lines in codeblock

* fix: works with non collapsed selection

* chore: localize code block

* test: multiline paste in codeblock

* chore: remove unused import

* fix: only hanlde code block paste command if all the selected nodes are code block

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-08-30 09:58:56 +08:00
Alex Wallen 4e863bc87f feat: add hover color to question bubble like mockup (#3222) 2023-08-29 21:03:58 +02:00
nathan 507554a596 chore: only show email if supabase is enabled 2023-08-29 09:52:41 +08:00
Nathan.fooo 0806436c19 chore: share database via csv (#3285)
* chore: share database via csv

* fix: flutter test
2023-08-28 23:20:56 +08:00
Nathan.fooo 1205f0ebf7 chore: enable edit user email (#3286) 2023-08-28 21:00:55 +08:00
Aryan Arora 26e56194ea fix: nightmode support for no recents text on the emoji menu (#3239) 2023-08-28 17:09:20 +08:00
Nathan.fooo 4e67282f2b feat: Data sync on signup (#3283)
* chore: sync all data

* chore: sync database row and document in the row

* chore: sync inline view id

* chore: sync row and document in row

* fix: tests

* fix: migrate document in row

* chore: retry when create collab fail

* fix: invalid secret cause rerun application

* chore: fix clippy warnnings
2023-08-28 13:28:24 +08:00
Lucas.Xu 41ec2d992e feat: improve CJK IME support (#3278) 2023-08-28 10:58:26 +08:00
Richard Shiue f0e4f3db61 chore: per-view field settings (#3199)
* chore: field-setting entities-events-notifications

* chore: update field settings

* chore: add tests

* chore: add docs

* chore: use an enum for field visibility

* chore: clippy warnings

* fix: deps fields

* chore: collab merge main

* chore: collab ref

* test: fix tests

* fix: tauri bump collab rev
2023-08-27 22:31:32 +08:00
Lucas.Xu 6634a0ecb3 chore: update supabase version and setup new deeplink for linux (#3272) 2023-08-25 18:06:23 +08:00
Lucas.Xu 255f30590f feat: add custom context menu items for copy, cut, and paste commands 2023-08-24 22:23:50 +08:00
Nathan.fooo 1ba7224088 docs: improve documentation (#3265) 2023-08-24 14:00:34 +08:00
Richard Shiue 4d7c0a7c67 chore: use vendored openssl 2023-08-23 14:55:36 +08:00
Lucas.Xu a0481e8020 chore: bump version 0.3.0 (#3252) 2023-08-23 10:43:18 +07:00
Lucas.Xu affd253e21 feat: support AppImage (#3248)
* feat: add build deb shell script

* feat: update release.yml

* chore: add flatpak readme

* feat: support appimage builder

* feat: support appimage builder

* Update release.yml
2023-08-23 08:46:11 +08:00
Alex Wallen 773b09c2f7 fix: create release regardless of run (#3256) 2023-08-22 11:00:01 -10:00
Nathan.fooo ea37128359 fix: reopen the application lost the theme (#3254) 2023-08-22 22:41:52 +08:00
Richard Shiue e9f31ea0f8 fix: arrow keys on field name text field (#3162) 2023-08-22 22:38:07 +08:00
Richard ShiueandMathias Mogensen 72363921b0 fix: use empty event title and add placeholder (#3234)
* fix: use empty event title and add placeholder

* chore: update frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_event_card.dart

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

* chore: remove unnecessary visible for testing

* chore: apply suggestions from code review

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

* fix: typo on suggested changes

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2023-08-22 22:30:41 +08:00
Nathan.fooo 7fa15615df chore: enable continue last session after logout (#3253) 2023-08-22 21:19:04 +08:00
Amir Lavasani ad596b3165 feat: add the Persian language translations (#3242) 2023-08-22 14:48:42 +07:00
Lucas.Xu 724fc895e1 feat: format the selected text to url if available (#3245) 2023-08-22 14:46:27 +07:00
Nathan.fooo 77637ff461 test: add supabase auth tests (#3250)
* test: add supabase auth tests

* chore: format before test

* chore: fix warnings

* ci: rust test

* chore: disable clicking get started button when logining through the google OAuth
2023-08-22 15:40:22 +08:00
Nathan.fooo 12d6cbd46a chore: optimize the UI if fail to open the workspace (#3246)
* chore: async load user profile

* chore: enable reset workspace

* chore: add confirm dialog
2023-08-22 00:19:15 +08:00
Lucas.Xu bd30e31f6c feat: improve copy paste plugins, and support in-app copy-paste (#3233) 2023-08-21 13:54:26 +08:00
Nathan.fooo 30155924a9 docs: documentation for encryption functions (#3243) 2023-08-20 15:38:52 +08:00
Nathan.fooo a1647bee78 feat: realtime user event (#3241)
* feat: update user profile after receiving realtime user event

* chore: logout if other deivce enable encyrption

* test: fix test

* chore: fix checkbox UI

* chore: fix tauri build

* chore: fix device id

* chore: fix duplicate run appflowy
2023-08-20 14:13:54 +08:00
Alex Wallen c5719be7ae fix: svg sizes (#3238)
* refactor: svg impl

* fix: icon sizes in appearance settings

* chore: change button icon

* fix: size of restore button

* chore: fix iconbutton api

* fix: analyzer issues
2023-08-19 09:53:10 +08:00
Nathan.fooo de01bf70cd fix: only encrypt if enable (#3236)
* fix: error page display issue

* fix: override document with empty data

* chore: add logs

* fix: encrypt errors

* fix: encrypt errors
2023-08-18 22:32:51 +08:00
Aryan Arora 23a34af30f chore: changed some german translations (#3203) 2023-08-18 16:22:22 +08:00
Alex Wallen 1cc78b87ab fix: some svgs do not have the correct color (#3221)
* fix: svg colors

* chore: rename variable name bc it doesn't make sense

* fix: google sign in button blend mode
2023-08-18 15:39:02 +08:00
Nathan.fooo c1bba7e48b fix: realtime event parser (#3231)
* chore: decrypt realtime event

* fix: realtime event parser
2023-08-18 15:13:34 +08:00
Lucas.Xu 78c33a4dd2 fix: macOS build error(Library not loaded) in debug mode (#3230) 2023-08-18 11:01:07 +08:00
Nathan.fooo 649b0a135a feat: encrypt collab update (#3215)
* feat: implement encrypt and decrypt

* feat: encrypt and decrypt

* feat: update user profile with encrypt

* chore: store encryption sign

* fix: login in setting menu

* chore: show encryption account name

* chore: fix test

* ci: fix warnings

* test: enable supabase test

* chore: fix test and rename column

* fix: update user profile after set the secret

* fix: encryption with wrong secret

* fix: don't save user data if the return value of did_sign_up is err

* chore: encrypt snapshot data

* chore: refactor snapshots interface

* ci: add tests

* chore: update collab rev
2023-08-17 23:46:39 +08:00
Alex Wallen 103f56922f fix: windows release build (#3168)
* refactor: build tool

* chore: update release.yml

* chore: skip creating release if already created
2023-08-17 21:03:29 +08:00
Yijing Huang 07cf7287d6 fix: color issues related to hover effect (#3206)
* fix: fix hover color on information and setting button

* chore: update the hover color of icon in SelectOptionTag

* chore: change hover color for add icon button

* chore: change the SelectOptionTag text color and _SelectOptionCell icon hover color

* fix: change hover color in tab close button #3172

* chore: add spacing in SelectOptionTag

* chore: remove the hover color on close tag icon

* chore: dart fix
2023-08-17 21:02:24 +08:00
Lucas.Xu 8a277b7380 chore: codesign macOS packages 2023-08-17 21:01:08 +08:00
Lucas.Xu 7f7fd4958f feat: support deeplink on Linux 2023-08-17 17:45:26 +08:00
Lucas.Xu de4f47b2a1 chore: migrate to the latest api 2023-08-17 17:43:05 +08:00
Lucas.Xu e226eaad45 feat: imporve the functionality of pasting from html 2023-08-17 17:43:05 +08:00
Alex Wallen a1f1559936 Reset theme buttons (#3137)
* feat: add translation for tooltip

* feat: add defaults for theme settings

* feat: refactor appearance view so that all theme settings can be reset

* chore: add keys for reset button

* chore: add tests for the reset button

* feat: register appearance test in runner

* chore: remove comment

* feat: add default file for appearance

* chore: move around files

* feat: make reset button respond to hover

* fix: incorrect use of resetTheme

* refactor: use maybeWhen

* fix: icon button style

* fix: rebase errors
2023-08-15 18:28:58 -10:00
Alex Wallen f994f50ef9 [fix] transparent svgs (#3213)
* fix: transparent emojis

* chore: enhance documentation
2023-08-15 12:14:22 -10:00
Yijing Huang 29431b3038 fix: replace svgWidget by FlowySv (#3212) 2023-08-15 18:15:09 +02:00
Mathias Mogensen ee14d31194 fix: overflow and alignment in sort editor (#3201)
* fix: overflow and alignment in sort editor

Closes: #3196 #3197

* fix: add and delete button on row
2023-08-15 16:28:55 +02:00
Alex Wallen 00ee4be723 [feat] improve svg widget api (#3205)
* feat: change api

* fix: api upgrade errors
2023-08-14 16:26:11 -07:00
243f80b6d5 [chore] svg improvements (#3145)
* chore: remove use of svgWidget()

* refactor: redundant code in svg

* feat: add generator to generate flowy_svgs.g.dart

* chore: reference new package in pubspec

* chore: remove svg widget from flowy_infra

* refactor: update usage in flowy_infra_ui

* refactor: usage in appflowy_flutter

* fix: error with script not running

* fix: error with script not running

* fix: use unix style file path

* feat: use generation script for flowy svgs

* feat: add task

* fix: add required missing semicolon

* fix: rebase errors

* feat: update generate build script

* fix: solve duplicate entries in the generated file

* fix: compilation errors

* fix: replace all spaces with an underscore

* feat: use FlowySvgs

* feat: reduce assets and simplify

* refactor: do not return empty svg widget

* fix: rebase errors

* fix: analyzer warnings

* chore: remove flowy_icons from tracking

* chore: fix generate flowy icons script linux

* chore: macos/linux script

* chore: add rsync

---------

Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
2023-08-14 10:34:01 -10:00
6fc8072459 feat: tauri grid changes and fixes (#2995)
* (feat) implement row drag and drop functionality

* (feat) implement grid row actions options ui

* (feat) add delete row function

* (feat) implemet grid filter and sort popup layout

* chore: move row methods to database controller

* (feat) integrate delete and duplicate row functions

* chore: add option on field popup

* chore: padding on edit row

* fix: change option color

* chore: stick to corner on resize

* fix: stick to corner

* chore: grid row popup changes

* chore: grid title

* chore: add field width

* chore: replace table layout with fixed column size

* chore: resize column WIP

* chore: save column width and draggable WIP

* chore: nav panel resize fix

* chore: database filter store

* chore: filter popups

* chore: filter value options

* chore: remove console

* chore: database filter refactor

* chore: prevent jitter and dont include used fields

* chore: checked field type

* chore: reset operator

* chore: filter icon

* chore: database sort popup

* chore: add icons into ref page

* chore: sort icon in column header

* chore: grid title fix

* chore: change text and border colors

* chore: grid rows dnd and optimise components

* chore: select option color change fix

* chore: filter service and controller

* chore: wire filter UI to service WIP

* chore: show only fields/cells with visiblity set to true

* fix: grid visible column exception

* chore: add update text filter backend

* chore: select option filter save modify get

* fix: filter reload and new filter

* fix: new filter order

* chore: sort backend service

* chore: database sort UI

* chore: field select popover component

* chore: operator select popover

* chore: select options popover

* chore: change text color

* chore: post merge

* chore: sort popover

* chore: bg body

* chore: grid row actions popover

* chore: dragging row change

* chore: new field column fix

* chore: field actions popover and field type popover

* chore: hide and delete field actions

* chore: duplicate field

* fix: pnpm lock file has error and button color update

* fix: tsc error

* chore: add field to left and right

---------

Co-authored-by: Mikias Tilahun Abebe <mikiastilahun@gmail.com>
Co-authored-by: qinluhe <qinluhe.twodog@gmail.com>
2023-08-14 17:06:27 +08:00
Nathan.fooo 27b1f00e17 feat: user awareness (#3185)
* refactor: separate functions

* feat: init user awareness object

* test: create reminder event test

* docs: add documentation
2023-08-14 12:57:59 +08:00
Mohammad Zolfaghariandnathan 2f8edf1fd1 feat: group by date (#2641)
* feat: group by date

* test: added more tests for group by date

* fix: print month in abbrev format

* chore: adapt group event changes

* style: remove comment

* fix: change date on changing group

* fix: dont count time in relative group

* fix: check beginning of month is within 30 days

* refactor: unify group id date format

---------

Co-authored-by: nathan <nathan@appflowy.io>
2023-08-14 11:37:35 +08:00
Lucas.Xu 9643315d5f Merge pull request #3183 from LucasXu0/fix_029_bugs
fix: some known bugs in v0.2.9
2023-08-13 18:22:36 +07:00
Lucas.Xu a1e2d97388 chore: update editor version 2023-08-13 18:15:59 +08:00
Lucas.Xu 9863000f4a feat: support DidUpdateChildViews callback 2023-08-13 17:32:52 +08:00
Lucas.Xu d0a343ee36 chore: remove the unused code 2023-08-13 17:14:58 +08:00
Lucas.Xu 7a6c829187 chore: enable macOS build on 10.14 2023-08-13 16:59:14 +08:00
Lucas.Xu a47e065f30 fix: windows release build failed 2023-08-13 16:58:28 +08:00
Lucas.Xu fc0ded4990 fix: universal build for macOS 2023-08-13 16:58:28 +08:00
Nathan.fooo 9063b40e06 feat: enable collaboration update synchronization between different devices (#3169)
* feat: bypass realtime event

* chore: use user device id

* chore: send realtime update

* chore: setup realtime recever

* chore: setup realtime recever

* chore: clippy

* chore: update collab rev

* chore: update realtime subscription

* chore: fix test

* chore: fmt

* test: fix flutter test
2023-08-12 17:36:31 +08:00
Lucas.Xu 764b4db166 chore: bump version 0.2.9 (#3144) 2023-08-10 21:18:31 +08:00
Lucas.Xu 7701533ed2 chore: remove the unused value in supabase_task (#3157) 2023-08-10 21:06:02 +08:00
ferreira-fp 29c89013f0 chore: update PT-BR translations (#3156) 2023-08-10 20:59:53 +08:00
Yijing Huang 1fad5aa804 feat: callout improvement (#3090) 2023-08-10 20:59:24 +08:00
Johan Sutrisno 675e23e971 fix: scroll to heading is too slow (#2952) (#3045) 2023-08-10 18:36:53 +08:00
Lucas.Xu c9ee82ec75 chore: update editor version to 1.2.3 (#3153) 2023-08-10 18:35:27 +08:00
Nathan.fooo 0c9935ccf2 fix: using freeze to refactor the FieldInfo class (#3152) 2023-08-10 15:46:16 +08:00
Lucas.Xu d28846bbaa chore: update German translations 2023-08-10 09:18:18 +07:00
Richard Shiue 58ecf62240 feat: selectOption sort + fix logic in edge cases (#3109) 2023-08-09 12:43:03 +08:00
Nathan.fooo a5eaf15548 refactor: login session (#3149) 2023-08-09 10:13:49 +08:00
fbiere 4589d86d81 inlang: update translations 2023-08-08 18:18:46 +02:00
Richard Shiue 9330df4ce1 fix: overlapped scrollbar in calendar (#3075)
* fix: height for calendar view in document

* fix: hide overlapped scrollbars

* chore: merge remote branch 'upstream/main' into fix-#2618
2023-08-08 16:58:04 +08:00
Richard Shiue 7cdd47757b chore: database tab bar ui improvements (#3093)
* chore: tab bar ui polish

* chore: toolbar buttons ui

* chore: minor padding radius and spacing adjustment

* fix: padding issues

* chore: add view button size and padding

* chore: the carelessness is real

* fix: dark mode colors

* fix: selected icon color
2023-08-08 16:57:25 +08:00
Alex Wallen 9d18e9de40 fix: use dart build script on Windows (#3141) 2023-08-08 16:08:34 +08:00
Lucas.Xu e2dd179001 Merge pull request #3140 from LucasXu0/url_protocol_in_windows_installer 2023-08-08 12:19:56 +07:00
Mathias Mogensen 35a47bfe5d feat: tabs shortcuts (#3112) 2023-08-08 13:09:17 +08:00
Lucas.Xu 9dc209bda7 fix: loading status widget on the signup page flickers. 2023-08-08 11:24:06 +08:00
Lucas.Xu 104851d330 chore: optimize the logout button 2023-08-08 10:58:14 +08:00
Lucas.Xu a1db5bff5c fix: user page inside setting overflow 2023-08-08 10:46:52 +08:00
Lucas.Xu 453346e69c fix: the minHeight of the personal header is too small 2023-08-08 10:32:08 +08:00
Kilu.He 923285bfcf feat: support mention a page (#3117) 2023-08-08 10:07:59 +08:00
Lucas.Xu 0de8b92db6 fix: deeplink doesn't work in windows exe installer 2023-08-08 10:06:29 +08:00
Nathan.fooo 125bcbc9db fix: rebuild application when setting the theme or font (#3139) 2023-08-08 09:08:24 +08:00
Nathan.fooo ef9596f4ab chore: enable single instance desktop application on windows (#3136) 2023-08-07 23:30:14 +08:00
Nathan.fooo 3c04b72932 fix: push to sign in screen when logout (#3127)
* fix: push to sign in screen when logout

* chore: show historical login users

* chore: open historical user

* chore: show historical user

* chore: reload app widget with unique key

* chore: add tooltip for user history
2023-08-07 22:24:04 +08:00
StarAtt a3bea472bf chore: update zh-TW translations (#3131) 2023-08-07 20:59:36 +08:00
Dan Zheng 5ac7b8e165 fix: automatically wrap the date, number or URL cells. 2023-08-07 17:58:24 +08:00
Lucas.Xu 95a938657b feat: support windows supabase deeplink callback (#3133) 2023-08-07 17:54:50 +08:00
Richard Shiue fbb1753350 fix: euro currency number format (#3115) 2023-08-07 17:49:03 +08:00
Lucas.Xu c6401da0b5 feat: support customizing the supabase auth path (#3130) 2023-08-07 14:31:20 +08:00
Lucas.Xu f724185f1c chore: Support CI build universal macOS package (#3124)
* fix: macos release build

* feat: support build arm64 macOS package on CI

* feat: support build arm64 macOS package on CI
2023-08-06 16:06:43 +08:00
Nathan.fooo 63a12a1d2b test: add subscription test (#3126) 2023-08-06 15:54:18 +08:00
Mihir 890f7573f3 fix: favorite selection and context menu doesn't work (#3114) 2023-08-06 12:31:47 +08:00
Nathan.fooo 6f159e741b refactor: remove shared instance KV (#3123)
* refactor: remove shared instance KV

* test: enable document test
2023-08-06 11:51:03 +08:00
Nathan.fooo 9a72f31d60 feat: show loading indicator when loading data from remote (#3120)
* chore: show circle indicator if fetch the data from remote

* chore: fix the lb warnings

* chore: create sdk-build for macOS
2023-08-05 15:02:05 +08:00
Mayur MahajanandMathias Mogensen ab7acbd5de chore: german translation for new property and shortcuts (#3116)
* chore: translation for new property nd shortcuts

* Update frontend/resources/translations/de-DE.json

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2023-08-04 20:46:09 +02:00
Lucas.Xu b7dfc85208 fix: macos release build (#3118) 2023-08-04 21:22:28 +08:00
Kilu.HeandLucas.Xu 16a01e11ed feat: support updating the view name and icon through document (#3099)
* feat: support updating the view name and icon through document

* fix: store expand pages

* fix: refactor text link

* fix: update cargo.toml

* fix: update test

* fix: update event map

* fix: move deal with icon codes to a single file

* fix: delete useless code from flutter

* fix: document banner

* fix: build error

* fix: update rust library

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-08-04 19:27:14 +08:00
Lucas.Xu 70914e6228 chore: support building universal macos package (#3110) 2023-08-03 20:02:44 +08:00
Lucas.Xu 45cbd70bf4 chore: bump version 0.2.8 (#3105) 2023-08-03 15:07:01 +08:00
Lucas.Xu fb9bc359b8 feat: disable moving page into the database (#3107) 2023-08-03 15:06:02 +08:00
Nathan.fooo 135d8a811e chore: fix historical user open issue (#3106) 2023-08-03 12:07:42 +08:00
Nathan.fooo 03518c951c ci: disable document test (#3104) 2023-08-03 10:33:25 +08:00
Nathan.fooo 03b8f2ccb2 feat: Get started doc migration (#3102)
* feat: migrate empty document

* chore: update collab rev

* chore: fmt
2023-08-03 09:14:52 +08:00
Lucas.Xu a40c639a96 fix: dispose the listener when the favorite bloc dispose (#3103) 2023-08-03 08:50:56 +08:00
Nathan.foooandMathias Mogensen ea0c4e96d2 feat: implement magic link login (#3086)
* feat: implement magic link login

* ci: create env file

* ci: generate flutter env files

* ci: disable inject env

* chore: update table name

* Update frontend/appflowy_flutter/lib/env/env.dart

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

* chore: fix compile

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2023-08-03 08:48:04 +08:00
Mihir a1143e24f3 feat: support favorites folder 2023-08-02 21:20:51 +08:00
Richard Shiue ff79635b2b fix: height for calendar view in document (#3073) 2023-08-02 18:07:44 +08:00
Lucas.Xu f0d2cf7da3 fix: insert reference page in nested page 2023-08-01 21:47:20 +08:00
Richard Shiue 5e2ed56f5b fix: move translation jsons to right folder (#3050) 2023-08-01 14:19:45 +08:00
Mayur Mahajan 70963a55f1 chore: add c/cpp/auto options in code langauges 2023-08-01 14:16:01 +08:00
Lucas.Xu 62be81395d fix: missing c++ library when building iOS (#3092) 2023-08-01 14:15:19 +08:00
Vedant Pandey 7c21f61d2e feat: add duplicate in context menu (#2921) 2023-08-01 11:19:48 +08:00
Lucas.Xu ad4c68a353 chore: update iOS flowy infra UI name (#3091) 2023-08-01 10:07:12 +08:00
Yijing Huang 355061d415 fix: fix theme color (#3089) 2023-07-31 23:01:24 +08:00
Yijing Huang 3039944c74 feat: welcome screen UI improvement (#3057) 2023-07-31 23:01:12 +08:00
Yijing Huang 338e342410 feat: lavender theme refactor 2023-07-31 20:22:56 +08:00
Aman Negi 8c544bc8c4 fix: improve readability in callout 2023-07-31 20:18:43 +08:00
Lucas.Xu 266209caeb feat: implement draggable folder (#3083) 2023-07-31 20:06:01 +08:00
Kilu.He eb77346e5a feat: support add cover and icon in tauri document (#3069)
* feat: support add cover and icon

* feat: emoji picker

* feat: emoji picker
2023-07-31 11:39:44 +08:00
dejvizelo f28c5d849c feat: clear date value (#2700)
* chore: Add _ClearDateFieldButton

* chore: Add new DateCellCalendarEvent to clear date

* chore: Add grid_field_clearDate translation token

* refactor: _ClearDateFieldButton -> _ClearDateButton

* fix: Fix dart(unused_element) in _ClearDateButton

* feat: Handle clearDate

* Revert "feat: Handle clearDate"

This reverts commit fd145ef8e9589f3b4aa1a16e5d72c15b6d0b53c4.

* feat: Handle clearDate

* feat: Add clear_flag field

* feat: check clear_flag to clear date

* chore: update exisitng tests

* fix: add mssing import

* refactor: remove check for timeFormatError

* fix: fix margin on _ClearDateButton

* refactor: _ClearDateButton -> ClearDateButton

* test: add clear date backend unit test

* test: add clear date integration test

* test: add clear date to edit time cell test

* chore: mark ClearDateButton visible for testing

* feat: close date editor popover on clear date

* style: make AppFlowyPopover taller

* fix: trim dateStr in _dateStrFromCellData

* fix: don't dismiss CellEditor after clearDate
2023-07-31 10:23:20 +08:00
Richard ShiueandLucas.Xu ea37f46f88 fix: date field created when reference a calendar (#2910)
* fix: date field created when reference a calendar

* fix: make everything one transaction

* chore: apply suggestions from Lucas

* chore: do the same for board

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2023-07-31 10:12:26 +08:00
Nathan.fooo e68d3f1c71 tests: add supabase tests (#3084) 2023-07-30 08:39:01 +08:00
Jannes Blobel 5741feb7cc Add Transaltion section README.md (#2751)
* Add Transaltion section README.md

AppFlowy has a lot of missing translations. 
I thought you could use your community for the missing translation.

* Fix typo and add backticks for readability in README.md

* Update README.md
2023-07-29 15:00:25 +08:00
Nathan.foooandFu Zi Xiang 2cd88594e8 feat: migrate user data to cloud (#3078)
* refactor: weak passed-in params in handler

* refactor: rename struct

* chore: update tables

* chore: update schema

* chore: add permission

* chore: update tables

* chore: support transaction mode

* chore: workspace database id

* chore: add user workspace

* feat: return list of workspaces

* chore: add user to workspace

* feat: separate database row table

* refactor: update schema

* chore: partition table

* chore: use transaction

* refactor: dir

* refactor: collab db ref

* fix: collab db lock

* chore: rename files

* chore: add tables descriptions

* chore: update readme

* docs: update documentation

* chore: rename crate

* chore: update ref

* chore: update tests

* chore: update tests

* refactor: crate deps

* chore: update crate ref

* chore: remove unused deps

* chore: remove unused deps

* chore: update collab crate refs

* chore: replace client with transaction in pooler

* refactor: return error type

* refactor: use anyhow error in deps

* feat: supabase postgrest user signin (wip)

* fix: Cargo.toml source git deps, changed Error to anyhow::Error

* fix: uuid serialization

* chore: fix conflict

* chore: extend the response

* feat: add implementation place holders

* feat: impl get_user_workspaces

* feat: impl get_user_profile

* test: create workspace

* fix: postgrest: field names and alias

* chore: implement folder restful api

* chore: implement collab storate with restful api

* feat: added placeholders for impl: update_user_profile, check_user

* feat: impl: update_user_profile

* feat: impl: check_user

* fix: use UidResponse, add more debug info for serde serialization error

* fix: get_user_profile: use Optional<UserProfileResponse>

* chore: imple init sync

* chore: support soft delete

* feat: postgresql: add migration test

* feat: postgresql migration test: added UID display and colored output

* feat: postgresql migration test: workspace role

* feat: postgresql migration test: create shared common utils

* feat: postgresql migration test: fixed shebang

* chore: add flush_collab_update pg function

* chore: implement datbaase and document restful api

* chore: migrate to use restful api

* chore: update table schema

* chore: fix tests

* chore: remove unused code

* chore: format code

* chore: remove unused env

* fix: tauri build

* fix: tauri build

---------

Co-authored-by: Fu Zi Xiang <speed2exe@live.com.sg>
2023-07-29 09:46:24 +08:00
Kilu.He a885170869 feat: support editor format text color and bg color (#3061) 2023-07-27 20:40:18 +08:00
Kilu.He 915ce02157 fix: implement the interface of move nested views (#3042)
* fix: implement the interface of move nested views

* fix: update rust ci ubuntu version

* fix: update rust ci version
2023-07-26 16:49:50 +08:00
Lucas.Xu 6e9a5a16a6 fix: windows relesae job (#3038) 2023-07-25 16:41:03 +08:00
Richard Shiue 13c72a31b7 fix: cursor for block options on Windows (#3052) 2023-07-25 16:40:25 +08:00
Richard Shiue 96410b2d32 fix: text overflow when editing a filter 2023-07-25 09:07:21 +07:00
Lucas.Xu d32c2082b6 feat: support building on iOS platform (#3033) 2023-07-21 15:53:57 +08:00
Richard Shiue c368d855c7 feat: enable sort by date + sort fix (#2953) 2023-07-21 15:51:20 +08:00
Mayur Mahajan b1378b4545 feat: customize command shortcuts (#2848) 2023-07-20 16:11:00 +08:00
Kilu.He 5ab64f8835 feat: support views drag and drop (#3004) 2023-07-19 17:59:32 +08:00
1439 changed files with 59542 additions and 27186 deletions

No files matched your search

+1
View File
@@ -134,6 +134,7 @@ jobs:
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 20
attempt_delay: 10000
+1
View File
@@ -136,5 +136,6 @@ jobs:
fail_ci_if_error: true
verbose: true
os: ${{ matrix.os }}
token: ${{ secrets.CODECOV_TOKEN }}
attempt_limit: 20
attempt_delay: 10000
+137 -29
View File
@@ -82,9 +82,12 @@ jobs:
- name: Build Windows app
working-directory: frontend
# the cargo make script has to be run separately because of file locking issues
run: |
flutter config --enable-windows-desktop
dart ./scripts/flutter_release_build/build_flowy.dart exclude-directives . ${{ github.ref_name }}
cargo make --env APP_VERSION=${{ github.ref_name }} --profile production-windows-x86 appflowy
dart ./scripts/flutter_release_build/build_flowy.dart include-directives . ${{ github.ref_name }}
- name: Archive Asset
uses: vimtor/action-zip@v1
@@ -124,7 +127,7 @@ jobs:
asset_name: ${{ env.WINDOWS_INSTALLER_NAME }}.exe
asset_content_type: application/octet-stream
build-for-macOS:
build-for-macOS-x86_64:
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
runs-on: ${{ matrix.job.os }}
needs: create-release
@@ -172,7 +175,17 @@ jobs:
working-directory: frontend
run: |
flutter config --enable-macos-desktop
dart ./scripts/flutter_release_build/build_flowy.dart . ${{ github.ref_name }}
dart ./scripts/flutter_release_build/build_flowy.dart run . ${{ github.ref_name }}
- name: Codesign AppFlowy
run: |
echo ${{ secrets.MACOS_CERTIFICATE }} | base64 --decode > certificate.p12
security create-keychain -p action build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p action build.keychain
security import certificate.p12 -k build.keychain -P ${{ secrets.MACOS_CERTIFICATE_PWD }} -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k action build.keychain
/usr/bin/codesign --force --options runtime --deep --sign "${{ secrets.MACOS_CODESIGN_ID }}" "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app" -v
- name: Create macOS dmg
run: |
@@ -188,6 +201,10 @@ jobs:
"${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \
"${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app"
- name: Notarize AppFlowy
run: |
xcrun notarytool submit ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} -v -f "json" --wait
- name: Archive Asset
working-directory: ${{ env.MACOS_APP_RELEASE_PATH }}
run: zip --symlinks -qr ${{ env.MACOS_X86_ZIP_NAME }} AppFlowy.app
@@ -212,6 +229,110 @@ jobs:
asset_name: ${{ env.MACOS_DMG_NAME }}.dmg
asset_content_type: application/octet-stream
build-for-macOS-universal:
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
runs-on: ${{ matrix.job.os }}
needs: create-release
env:
MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/macos/Release
MACOS_AARCH64_ZIP_NAME: AppFlowy_${{ github.ref_name }}_macos-universal.zip
MACOS_DMG_NAME: AppFlowy_${{ github.ref_name }}_macos-universal
strategy:
fail-fast: false
matrix:
job:
- {
targets: "aarch64-apple-darwin,x86_64-apple-darwin",
os: macos-11,
extra-build-args: "",
}
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Install flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
targets: ${{ matrix.job.targets }}
components: rustfmt
- uses: Swatinem/rust-cache@v2
with:
prefix-key: appflowy-lib-cache
key: ${{ matrix.job.os }}-${{ matrix.job.target }}
- name: Install prerequisites
working-directory: frontend
run: |
cargo install --force cargo-make
cargo install --force duckscript_cli
- name: Build AppFlowy
working-directory: frontend
run: |
flutter config --enable-macos-desktop
sh scripts/flutter_release_build/build_universal_package_for_macos.sh
- name: Codesign AppFlowy
run: |
echo ${{ secrets.MACOS_CERTIFICATE }} | base64 --decode > certificate.p12
security create-keychain -p action build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p action build.keychain
security import certificate.p12 -k build.keychain -P ${{ secrets.MACOS_CERTIFICATE_PWD }} -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k action build.keychain
/usr/bin/codesign --force --options runtime --deep --sign "${{ secrets.MACOS_CODESIGN_ID }}" "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app" -v
- name: Create macOS dmg
run: |
brew install create-dmg
create-dmg \
--volname ${{ env.MACOS_DMG_NAME }} \
--hide-extension "AppFlowy.app" \
--background frontend/scripts/dmg_assets/AppFlowyInstallerBackground.jpg \
--window-size 600 450 \
--icon-size 94 \
--icon "AppFlowy.app" 141 249 \
--app-drop-link 458 249 \
"${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \
"${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app"
- name: Notarize AppFlowy
run: |
xcrun notarytool submit ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} -v -f "json" --wait
- name: Archive Asset
working-directory: ${{ env.MACOS_APP_RELEASE_PATH }}
run: zip --symlinks -qr ${{ env.MACOS_AARCH64_ZIP_NAME }} AppFlowy.app
- name: Upload Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_AARCH64_ZIP_NAME }}
asset_name: ${{ env.MACOS_AARCH64_ZIP_NAME }}
asset_content_type: application/octet-stream
- name: Upload DMG Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg
asset_name: ${{ env.MACOS_DMG_NAME }}.dmg
asset_content_type: application/octet-stream
build-for-linux:
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
runs-on: ${{ matrix.job.os }}
@@ -273,42 +394,23 @@ jobs:
if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }}
working-directory: frontend
run: |
sudo apt-get install -qy binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
sudo apt-get install -qy binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libgtk-3-0
- name: Build AppFlowy
working-directory: frontend
run: |
flutter config --enable-linux-desktop
dart ./scripts/flutter_release_build/build_flowy.dart . ${{ github.ref_name }}
dart ./scripts/flutter_release_build/build_flowy.dart run . ${{ github.ref_name }}
- name: Archive Assert
- name: Archive Asset
working-directory: ${{ env.LINUX_APP_RELEASE_PATH }}
run: tar -czf ${{ env.LINUX_ZIP_NAME }} *
- name: Configuring Linux Package
- name: Build Linux package (.deb)
working-directory: frontend
run: |
mkdir -p ../${{ env.LINUX_APP_RELEASE_PATH }}/package/opt
mkdir -p ../${{ env.LINUX_APP_RELEASE_PATH }}/package/usr/share/applications
cp -r ./scripts/linux_installer ../${{ env.LINUX_APP_RELEASE_PATH }}/package/DEBIAN
cd ../${{ env.LINUX_APP_RELEASE_PATH }}/package/DEBIAN
grep -rl "\[CHANGE_THIS\]" ./control | xargs sed -i "s/\[CHANGE_THIS\]/${{ github.ref_name }}/"
chmod 0755 {postinst,postrm}
- name: Build Linux package
working-directory: ${{ env.LINUX_APP_RELEASE_PATH }}
run: |
mv AppFlowy package/opt/
cd package
# Update Exec & icon path in desktop entry
grep -rl "\[CHANGE_THIS\]" ./opt/AppFlowy/appflowy.desktop.temp | xargs sed -i "s/\[CHANGE_THIS\]/\/opt/"
# Add desktop entry in package
mv ./opt/AppFlowy/appflowy.desktop.temp ./usr/share/applications/appflowy.desktop
# Build
cd ../ && dpkg-deb --build --root-owner-group -Z xz package ${{ env.LINUX_PACKAGE_NAME }}
sh scripts/linux_distribution/deb/build_deb.sh appflowy_flutter/product/${{ github.ref_name }}/linux/Release ${{ github.ref_name }} ${{ env.LINUX_PACKAGE_NAME }}
- name: Upload Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
@@ -320,7 +422,7 @@ jobs:
asset_name: ${{ env.LINUX_ZIP_NAME }}
asset_content_type: application/octet-stream
- name: Upload Asset Install Package
- name: Upload Debian package
id: upload-release-asset-install-package
uses: actions/upload-release-asset@v1
env:
@@ -360,7 +462,13 @@ jobs:
notify-discord:
runs-on: ubuntu-latest
needs: [build-for-linux, build-for-windows, build-for-macOS]
needs:
[
build-for-linux,
build-for-windows,
build-for-macOS-x86_64,
build-for-macOS-universal,
]
steps:
- name: Notify Discord
run: |
+18 -27
View File
@@ -22,10 +22,10 @@ on:
env:
CARGO_TERM_COLOR: always
RUST_TOOLCHAIN: "1.70"
FLUTTER_VERSION: "3.10.1"
jobs:
test-on-ubuntu:
environment: SUPABASE_CI
runs-on: ubuntu-latest
steps:
- name: Checkout source code
@@ -40,14 +40,6 @@ jobs:
components: rustfmt, clippy
profile: minimal
- name: Install flutter
id: flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install prerequisites
working-directory: frontend
run: |
@@ -58,12 +50,23 @@ jobs:
with:
prefix-key: 'ubuntu-latest'
workspaces: |
frontend/rust-lib
frontend/rust-lib
- name: Build FlowySDK
working-directory: frontend
- name: Create .env file in flowy-server
working-directory: frontend/rust-lib/flowy-server
run: |
cargo make --profile development-linux-x86_64 appflowy-core-dev
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: Create .env file in flowy-test
working-directory: frontend/rust-lib/flowy-test
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: Run rust-lib tests
working-directory: frontend/rust-lib
@@ -74,17 +77,5 @@ jobs:
working-directory: frontend/rust-lib/
- name: clippy rust-lib
run: cargo clippy --features="rev-sqlite"
working-directory: frontend/rust-lib
- name: rustfmt shared-lib
run: cargo fmt --all -- --check
working-directory: shared-lib
- name: clippy shared-lib
run: cargo clippy -- -D warnings
working-directory: shared-lib
- name: Run shared-lib tests
working-directory: shared-lib
run: RUST_LOG=info cargo test --no-default-features
run: cargo clippy --all
working-directory: frontend/rust-lib
+30 -9
View File
@@ -32,6 +32,26 @@ jobs:
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_tauri/src-tauri
- name: Cache Node.js dependencies
uses: actions/cache@v2
with:
path: ~/.npm
key: npm-${{ runner.os }}
- name: Cache node_modules
uses: actions/cache@v2
with:
path: frontend/appflowy_tauri/node_modules
key: node-modules-${{ runner.os }}
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
@@ -40,13 +60,6 @@ jobs:
override: true
profile: minimal
- uses: Swatinem/rust-cache@v2
with:
prefix-key: 'ubuntu-latest-tauri'
workspaces: |
frontend/rust-lib
frontend/appflowy_tauri/src-tauri
- name: install dependencies (windows only)
if: matrix.platform == 'windows-latest'
working-directory: frontend
@@ -75,15 +88,23 @@ jobs:
cargo make appflowy-tauri-deps-tools
npm install -g pnpm@${{ env.PNPM_VERSION }}
- name: build
- name: Build
working-directory: frontend/appflowy_tauri
run: |
mkdir dist
pnpm install
cargo make --cwd .. tauri_build
pnpm test
pnpm test:errors
- name: Check for uncommitted changes
run: |
diff_files=$(git status --porcelain)
if [ -n "$diff_files" ]; then
echo "There are uncommitted changes in the working tree. Please commit them before pushing."
exit 1
fi
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+6
View File
@@ -37,3 +37,9 @@ pubspec.lock
.fvm/
**/AppFlowy-Collab/
# ignore the deb filegit
frontend/package
frontend/*.deb
**/Cargo.toml.bak
+82 -2
View File
@@ -1,11 +1,91 @@
# Release Notes
## Version 0.3.2 - 09/18/2023
### New Features
- Improve the performance of the editor, now it is much faster when editing a large document.
- Support for reordering the rows of the database on Windows.
- Revamp the row detail page of the database.
- Revamp the checklist cell editor of the database.
### Bug fixes
- Some UI issues
## Version 0.3.1 - 09/04/2023
### New Features
- Improve CJK (Chinese, Japanese, Korean) input method support.
- Share a database in CSV format.
- Support for aligning the block component with the toolbar.
- Support for editing name when creating a new page.
- Support for inserting a table in the document page.
- Database views allow for independent field visibility toggling.
### Bug fixes
- Paste multiple lines in code block.
- Some UI issues
## Version 0.3.0 - 08/22/2023
### New Features
- Improve paste features:
- Paste HTML content from website.
- Paste image from clipboard.
- Support Group by Date in Kanban Board.
- Notarize the macOS package, which is now verified by Apple.
- Add Persian language translations.
### Bug fixes
- Some UI issues
## Version 0.2.9 - 08/08/2023
### New Features
- Improve tab and shortcut, click with alt/option to open a page in new tab.
- Improve database tab bar UI.
### Bug fixes
- Add button and more action button of the favorite section doesn't work.
- Fix euro currency number format.
- Some UI issues
## Version 0.2.8 - 08/03/2023
### New Features
- Nestable personal folder that supports drag and drop
- Support for favorite folders.
- Support for sorting by date in Grid view.
- Add a duplicate button in the Board context menu.
### Bug fixes
- Improve readability in Callout
- Some UI issues
## Version 0.2.7 - 07/18/2023
### New Features
- Dynamic load themes
- Inline math equation
<img width="1147" src="https://github.com/AppFlowy-IO/AppFlowy/assets/11863087/ac464740-c685-4a85-ae99-1074c1c607e5">
- Open page in new tab
- Create toggle lists to keep things tidy in your pages
- Alt/Option + click to add a text block above
### Bug fixes
- Pasting into a Grid property crashed on Windows
- Double-click a link to open
## Version 0.2.6 - 07/11/2023
+8
View File
@@ -68,6 +68,14 @@ Contributions make the open-source community a fantastic place to learn, inspire
If your Pull Request is accepted as it fixes a bug, adds functionality, or makes AppFlowy's codebase significantly easier to use or understand, **Congratulations!** If your administrative and managerial work behind the scenes sustains the community, **Congratulations!** You are now an official contributor to AppFlowy. Get in touch with us ([link](https://tally.so/r/mKP5z3)) to receive the very special Contributor T-shirt!
Proudly wear your T-shirt and show it to us by tagging [@appflowy](https://twitter.com/appflowy) on Twitter.
## Translations 🌎🗺
[![translation badge](https://inlang.com/badge?url=github.com/AppFlowy-IO/AppFlowy)](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy?ref=badge)
To add translations, you can manually edit the JSON translation files in `/frontend/appflowy_flutter/assets/translations`, use the [inlang online editor](https://inlang.com/editor/github.com/AppFlowy-IO/AppFlowy), or run `npx inlang machine translate` to add missing translations.
## Join the community to build AppFlowy together
<a href="https://github.com/AppFlowy-IO/AppFlowy/graphs/contributors">
+22 -45
View File
@@ -43,47 +43,34 @@
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-iOS: Clean + Rebuild All",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"preLaunchTask": "AF: Clean + Rebuild All (iOS)",
"env": {
"RUST_LOG": "trace"
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-iOS-Simulator: Clean + Rebuild All",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"preLaunchTask": "AF: Clean + Rebuild All (iOS Simulator)",
"env": {
"RUST_LOG": "trace"
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
"name": "AF-desktop: Debug Rust",
"request": "attach",
"type": "lldb",
"pid": "${command:pickMyProcess}"
},
// {
// "name": "AF-desktop: profile mode",
// "request": "launch",
// "program": "./lib/main.dart",
// "type": "dart",
// "flutterMode": "profile",
// "cwd": "${workspaceRoot}/appflowy_flutter"
// },
{
// This task builds the Rust and Dart code of AppFlowy for android.
"name": "AF-android: Build All",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"preLaunchTask": "AF: build_mobile_sdk",
"env": {
"RUST_LOG": "info"
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
// This task builds will:
// - call the clean task,
// - rebuild all the generated Files (including freeze and language files)
// - rebuild the the Rust and Dart code of AppFlowy.
"name": "AF-android: Clean + Rebuild All",
"request": "launch",
"program": "./lib/main.dart",
"type": "dart",
"preLaunchTask": "AF: Clean + Rebuild All (Android)",
"env": {
"RUST_LOG": "info"
},
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{
// https://tauri.app/v1/guides/debugging/vs-code
"type": "lldb",
@@ -99,15 +86,5 @@
"preLaunchTask": "AF: Tauri UI Dev",
"cwd": "${workspaceRoot}/appflowy_tauri/"
},
// {
// "type": "lldb",
// "request": "launch",
// "name": "AF-tauri: Production Debug",
// "cargo": {
// "args": ["build", "--release", "--manifest-path=./appflowy_tauri/src-tauri/Cargo.toml"]
// },
// "preLaunchTask": "AF: Tauri UI Build",
// "cwd": "${workspaceRoot}/appflowy_tauri/"
// },
]
}
+66 -22
View File
@@ -20,7 +20,8 @@
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files"
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
],
"presentation": {
"reveal": "always",
@@ -28,17 +29,18 @@
}
},
{
"label": "AF: Clean + Rebuild All (Android)",
"label": "AF: Clean + Rebuild All (iOS)",
"type": "shell",
"dependsOrder": "sequence",
"dependsOn": [
"AF: Dart Clean",
"AF: Flutter Clean",
"AF: Build Appflowy Core_for_android",
"AF: Build Appflowy Core For iOS",
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files"
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
],
"presentation": {
"reveal": "always",
@@ -46,9 +48,37 @@
}
},
{
"label": "AF: Build Appflowy Core_for_android",
"label": "AF: Clean + Rebuild All (iOS Simulator)",
"type": "shell",
"command": "cargo make --profile development-android appflowy-core-dev-android",
"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"
],
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "AF: Build Appflowy Core For iOS",
"type": "shell",
"command": "cargo make --profile development-ios-arm64 appflowy-core-dev-ios",
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Build Appflowy Core For iOS Simulator",
"type": "shell",
"command": "cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios",
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
@@ -80,7 +110,8 @@
"AF: Flutter Pub Get",
"AF: Flutter Package Get",
"AF: Generate Language Files",
"AF: Generate Freezed Files"
"AF: Generate Freezed Files",
"AF: Generate Svg Files"
],
"group": {
"kind": "build",
@@ -134,7 +165,7 @@
]
}
}
},
}
},
{
"label": "AF: Generate Language Files",
@@ -157,6 +188,27 @@
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Generate Svg Files",
"type": "shell",
"command": "sh ./scripts/code_generation/flowy_icons/generate_flowy_icons.sh",
"windows": {
"options": {
"shell": {
"executable": "cmd.exe",
"args": [
"/d",
"/c",
".\\scripts\\code_generation\\flowy_icons\\generate_flowy_icons.cmd"
]
}
}
},
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
}
},
{
"label": "AF: Flutter Clean",
"type": "shell",
@@ -170,10 +222,7 @@
"label": "AF: flutter build aar",
"type": "flutter",
"command": "flutter",
"args": [
"build",
"aar"
],
"args": ["build", "aar"],
"group": "build",
"problemMatcher": [],
"detail": "appflowy_flutter"
@@ -183,9 +232,7 @@
"type": "shell",
"isBackground": true,
"command": "yarn",
"args": [
"dev"
],
"args": ["dev"],
"options": {
"cwd": "${workspaceFolder}/appflowy_tauri"
}
@@ -218,10 +265,7 @@
"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}"
}
@@ -235,12 +279,12 @@
}
},
{
"label": "AF: Generate Env",
"label": "AF: Generate Env File",
"type": "shell",
"command": "dart run build_runner clean && dart run build_runner build --delete-conflicting-outputs ",
"options": {
"cwd": "${workspaceFolder}/appflowy_flutter"
}
},
}
]
}
}
+38 -7
View File
@@ -2,6 +2,7 @@
extend = [
{ path = "scripts/makefile/desktop.toml" },
{ path = "scripts/makefile/mobile.toml" },
{ path = "scripts/makefile/protobuf.toml" },
{ path = "scripts/makefile/tests.toml" },
{ path = "scripts/makefile/docker.toml" },
@@ -19,11 +20,12 @@ run_task = { name = ["restore-crate-type"] }
[env]
RUST_LOG = "info"
CARGO_PROFILE = "dev"
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.2.7"
CURRENT_APP_VERSION = "0.3.2"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite"
PRODUCT_NAME = "AppFlowy"
# CRATE_TYPE: https://doc.rust-lang.org/reference/linkage.html
@@ -59,6 +61,7 @@ BUILD_FLAG = "debug"
FLUTTER_OUTPUT_DIR = "Debug"
PRODUCT_EXT = "app"
BUILD_ARCHS = "arm64"
BUILD_ACTIVE_ARCHS_ONLY = true
CRATE_TYPE = "staticlib"
[env.development-mac-x86_64]
@@ -69,9 +72,11 @@ BUILD_FLAG = "debug"
FLUTTER_OUTPUT_DIR = "Debug"
PRODUCT_EXT = "app"
BUILD_ARCHS = "x86_64"
BUILD_ACTIVE_ARCHS_ONLY = true
CRATE_TYPE = "staticlib"
[env.production-mac-arm64]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "macos"
RUST_COMPILE_TARGET = "aarch64-apple-darwin"
@@ -79,9 +84,11 @@ FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "app"
APP_ENVIRONMENT = "production"
BUILD_ARCHS = "arm64"
BUILD_ACTIVE_ARCHS_ONLY = false
CRATE_TYPE = "staticlib"
[env.production-mac-x86_64]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "macos"
RUST_COMPILE_TARGET = "x86_64-apple-darwin"
@@ -89,8 +96,18 @@ FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "app"
APP_ENVIRONMENT = "production"
BUILD_ARCHS = "x86_64"
BUILD_ACTIVE_ARCHS_ONLY = false
CRATE_TYPE = "staticlib"
[env.production-mac-universal]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "macos"
FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "app"
BUILD_ACTIVE_ARCHS_ONLY = false
APP_ENVIRONMENT = "production"
[env.development-windows-x86]
TARGET_OS = "windows"
RUST_COMPILE_TARGET = "x86_64-pc-windows-msvc"
@@ -101,6 +118,7 @@ CRATE_TYPE = "cdylib"
LIB_EXT = "dll"
[env.production-windows-x86]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "windows"
RUST_COMPILE_TARGET = "x86_64-pc-windows-msvc"
@@ -120,6 +138,7 @@ LIB_EXT = "so"
LINUX_ARCH = "x64"
[env.production-linux-x86_64]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "linux"
RUST_COMPILE_TARGET = "x86_64-unknown-linux-gnu"
@@ -140,6 +159,7 @@ LINUX_ARCH = "arm64"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[env.production-linux-aarch64]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "linux"
RUST_COMPILE_TARGET = "aarch64-unknown-linux-gnu"
@@ -150,6 +170,22 @@ LINUX_ARCH = "arm64"
APP_ENVIRONMENT = "production"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[env.development-ios-arm64-sim]
BUILD_FLAG = "debug"
TARGET_OS = "ios"
FLUTTER_OUTPUT_DIR = "Debug"
RUST_COMPILE_TARGET = "aarch64-apple-ios-sim"
BUILD_ARCHS = "arm64"
CRATE_TYPE = "staticlib"
[env.development-ios-arm64]
BUILD_FLAG = "debug"
TARGET_OS = "ios"
FLUTTER_OUTPUT_DIR = "Debug"
RUST_COMPILE_TARGET = "aarch64-apple-ios"
BUILD_ARCHS = "arm64"
CRATE_TYPE = "staticlib"
[tasks.echo_env]
script = ['''
echo "-------- Env Parameters --------"
@@ -165,12 +201,6 @@ script = ['''
''']
script_runner = "@shell"
[env.production-ios]
BUILD_FLAG = "release"
TARGET_OS = "ios"
FLUTTER_OUTPUT_DIR = "Release"
PRODUCT_EXT = "ipa"
[env.development-android]
BUILD_FLAG = "debug"
TARGET_OS = "android"
@@ -179,6 +209,7 @@ FLUTTER_OUTPUT_DIR = "Debug"
FLUTTER_DESKTOP_FEATURES = "dart,rev-sqlite,openssl_vendored"
[env.production-android]
CARGO_PROFILE = "release"
BUILD_FLAG = "release"
TARGET_OS = "android"
CRATE_TYPE = "cdylib"
+1
View File
@@ -77,3 +77,4 @@ coverage/
**/failures/*.png
assets/translations/
assets/flowy_icons/*
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

@@ -1,10 +0,0 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_10_2941)">
<path d="M17.9706 5.70199L17.9706 5.702L17.9712 5.70405L20.4218 13.6624C20.4393 13.7435 20.4508 13.8258 20.4561 13.9086V19.3106C20.4561 19.7769 20.078 20.1549 19.6117 20.1548H3.40062C2.93431 20.1549 2.55625 19.7769 2.55625 19.3106V13.9086C2.56155 13.8257 2.57301 13.7433 2.59054 13.6622L4.97263 5.70366C5.26597 4.72587 6.16595 4.05625 7.1868 4.05625L15.8285 4.05625C16.8329 4.05625 17.7119 4.7315 17.9706 5.70199ZM4.55716 12.99L4.53544 13.0624H4.61104H8.80431C9.02825 13.0624 9.24302 13.1514 9.40137 13.3097C9.55971 13.4681 9.64867 13.6828 9.64867 13.9068V14.8074V14.8636H9.70492H13.3074H13.3636V14.8074V13.9068C13.3636 13.6828 13.4526 13.4681 13.6109 13.3097C13.7693 13.1514 13.9841 13.0624 14.208 13.0624H18.4013H18.4769L18.4551 12.99L16.5342 6.5868C16.3843 6.08715 15.9244 5.74498 15.4028 5.74498H7.60955C7.0879 5.74498 6.62802 6.08715 6.47812 6.5868L4.55716 12.99ZM15.1086 14.7511H15.0524V14.8074V15.708C15.0524 15.8189 15.0305 15.9287 14.9881 16.0311C14.9457 16.1336 14.8835 16.2267 14.8051 16.3051C14.7267 16.3835 14.6336 16.4457 14.5311 16.4881C14.4287 16.5305 14.3189 16.5524 14.208 16.5524H8.80431C8.69343 16.5524 8.58363 16.5305 8.48118 16.4881C8.37874 16.4457 8.28566 16.3835 8.20725 16.3051C8.12885 16.2267 8.06665 16.1336 8.02422 16.0311C7.98178 15.9287 7.95994 15.8189 7.95994 15.708V14.8074V14.7511H7.90369H4.52623C4.3709 14.7511 4.24498 14.8771 4.24498 15.0324V18.1849C4.24498 18.3402 4.3709 18.4661 4.52623 18.4661H18.4861C18.6414 18.4661 18.7673 18.3402 18.7673 18.1849V15.0324C18.7673 14.8771 18.6414 14.7511 18.4861 14.7511H15.1086ZM8.80435 10.2481C8.58041 10.2481 8.36564 10.1591 8.20729 10.0007C8.04895 9.8424 7.95999 9.62763 7.95999 9.40369C7.95999 9.17975 8.04895 8.96498 8.20729 8.80663C8.36564 8.64829 8.58041 8.55933 8.80435 8.55933H14.208C14.432 8.55933 14.6468 8.64829 14.8051 8.80663C14.9635 8.96498 15.0524 9.17975 15.0524 9.40369C15.0524 9.62763 14.9635 9.8424 14.8051 10.0007C14.6468 10.1591 14.432 10.2481 14.208 10.2481H8.80435Z" fill="#333333" stroke="white" stroke-width="0.1125"/>
</g>
<defs>
<clipPath id="clip0_10_2941">
<rect width="18" height="16.2111" fill="white" transform="translate(2.5 4)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1,5 +0,0 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 14.0039C11.3137 14.0039 14 11.3176 14 8.00391C14 4.6902 11.3137 2.00391 8 2.00391C4.68629 2.00391 2 4.6902 2 8.00391C2 11.3176 4.68629 14.0039 8 14.0039Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="7.5" y="7.00391" width="1" height="4" rx="0.5" fill="#333333"/>
<rect x="7.5" y="5.00391" width="1" height="1" rx="0.5" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 482 B

@@ -1,3 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.7" d="M14.1579 9L14.6673 8.57546C14.5413 8.42426 14.3547 8.33684 14.1579 8.33684V9ZM16 11.2105L15.4905 11.6351C15.6165 11.7863 15.8032 11.8737 16 11.8737V11.2105ZM9.66316 12.6843C9.66316 12.318 9.36625 12.0211 9 12.0211C8.63375 12.0211 8.33684 12.318 8.33684 12.6843H9.66316ZM8.33684 17.1053C8.33684 17.4716 8.63375 17.7685 9 17.7685C9.36625 17.7685 9.66316 17.4716 9.66316 17.1053H8.33684ZM23.6632 12.6843C23.6632 12.318 23.3663 12.0211 23 12.0211C22.6337 12.0211 22.3368 12.318 22.3368 12.6843H23.6632ZM22.3368 17.1053C22.3368 17.4716 22.6337 17.7685 23 17.7685C23.3663 17.7685 23.6632 17.4716 23.6632 17.1053H22.3368ZM9.66316 9.73684C9.66316 9.69614 9.69614 9.66316 9.73684 9.66316V8.33684C8.96364 8.33684 8.33684 8.96364 8.33684 9.73684H9.66316ZM9.73684 9.66316H14.1579V8.33684H9.73684V9.66316ZM13.6484 9.42454L15.4905 11.6351L16.5094 10.786L14.6673 8.57546L13.6484 9.42454ZM16 11.8737H22.2631V10.5474H16V11.8737ZM22.2631 11.8737C22.3038 11.8737 22.3368 11.9067 22.3368 11.9474H23.6631C23.6631 11.1742 23.0363 10.5474 22.2631 10.5474V11.8737ZM22.3368 11.9474V21.5263H23.6631V11.9474H22.3368ZM22.3368 21.5263C22.3368 21.567 22.3038 21.6 22.2631 21.6V22.9263C23.0363 22.9263 23.6631 22.2995 23.6631 21.5263H22.3368ZM22.2631 21.6H9.73684V22.9263H22.2631V21.6ZM9.73684 21.6C9.69614 21.6 9.66316 21.567 9.66316 21.5263H8.33684C8.33684 22.2995 8.96365 22.9263 9.73684 22.9263V21.6ZM9.66316 21.5263V9.73684H8.33684V21.5263H9.66316ZM22.9999 14.2317H9V15.558H22.9999V14.2317ZM8.33684 12.6843V17.1053H9.66316V12.6843H8.33684ZM22.3368 12.6843V17.1053H23.6632V12.6843H22.3368Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

@@ -1,4 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.7874 10.1975C22.48 10.8859 23.0235 11.6885 23.4041 12.5811C23.7967 13.5077 24 14.4863 24 15.499C24 16.5117 23.7987 17.4943 23.4061 18.4189C23.0256 19.3115 22.482 20.1141 21.7894 20.8025C21.0968 21.491 20.2895 22.0314 19.3915 22.4096C18.4614 22.8019 17.4729 23 16.4541 23C15.4354 23 14.4469 22.7999 13.5167 22.4096C12.6188 22.0314 11.8114 21.491 11.1189 20.8025C10.8833 20.5684 10.8833 20.1881 11.1189 19.954C11.3544 19.7198 11.7369 19.7198 11.9725 19.954C13.1684 21.1448 14.7589 21.7992 16.4521 21.7992C18.1453 21.7992 19.7338 21.1428 20.9317 19.954C22.1296 18.7652 22.792 17.1801 22.792 15.499C22.792 13.8179 22.1316 12.2368 20.9357 11.046C19.7398 9.85524 18.1493 9.2008 16.4561 9.2008C15.6971 9.2008 14.9562 9.33089 14.2516 9.59106C13.5711 9.84323 12.9429 10.2055 12.3852 10.6718C11.6041 11.3242 10.996 12.1508 10.6075 13.0734L11.2618 12.7231C11.5557 12.565 11.9222 12.6751 12.0792 12.9673C12.2383 13.2595 12.1275 13.6237 11.8336 13.7799L9.92094 14.8005C9.92094 14.8025 9.91892 14.8025 9.91892 14.8025C9.82832 14.8506 9.72967 14.8746 9.63303 14.8746C9.44378 14.8746 9.26258 14.7885 9.14581 14.6304C9.14455 14.6267 9.14249 14.6237 9.14064 14.621C9.13954 14.6194 9.13851 14.6179 9.13776 14.6164C9.13575 14.6124 9.13323 14.6089 9.13071 14.6054C9.1282 14.6019 9.12568 14.5984 9.12367 14.5944C9.11561 14.5824 9.10756 14.5704 9.10152 14.5584L8.07272 12.6551C7.91367 12.3629 8.0244 11.9987 8.31834 11.8426C8.61228 11.6845 8.97871 11.7945 9.13575 12.0867L9.45989 12.6871C9.91892 11.5584 10.6558 10.5457 11.6061 9.75317C12.2705 9.1988 13.0174 8.76451 13.8288 8.46631C14.6663 8.1561 15.5501 8 16.4521 8C17.4708 8 18.4594 8.20013 19.3895 8.59039C20.2875 8.96865 21.0948 9.50901 21.7874 10.1975ZM15.52 12.1206C15.52 11.7884 15.7898 11.5202 16.124 11.5202C16.4582 11.5202 16.728 11.7884 16.728 12.1206V15.2747H19.8244C20.1587 15.2747 20.4284 15.5429 20.4284 15.8751C20.4284 16.2073 20.1587 16.4755 19.8244 16.4755H16.1481C15.8441 16.4755 15.5925 16.2514 15.5502 15.9612C15.5301 15.9031 15.52 15.8411 15.52 15.7751V12.1206Z" fill="#333333" fill-opacity="0.7"/>
<path d="M23.4041 12.5811L23.4435 12.5643L23.4435 12.5642L23.4041 12.5811ZM21.7874 10.1975L21.7572 10.2279L21.7874 10.1975ZM23.4061 18.4189L23.4455 18.4358L23.4455 18.4357L23.4061 18.4189ZM19.3915 22.4096L19.3749 22.3701L19.3749 22.3701L19.3915 22.4096ZM13.5167 22.4096L13.5001 22.4491L13.5001 22.4491L13.5167 22.4096ZM11.1189 20.8025L11.1491 20.7721L11.1189 20.8025ZM11.1189 19.954L11.1491 19.9844L11.1189 19.954ZM11.9725 19.954L12.0027 19.9236L12.0027 19.9236L11.9725 19.954ZM20.9317 19.954L20.9619 19.9844L20.9317 19.954ZM20.9357 11.046L20.9055 11.0764L20.9357 11.046ZM14.2516 9.59106L14.2367 9.55086L14.2367 9.55087L14.2516 9.59106ZM12.3852 10.6718L12.4127 10.7047L12.4127 10.7047L12.3852 10.6718ZM10.6075 13.0734L10.568 13.0567L10.521 13.1683L10.6277 13.1112L10.6075 13.0734ZM11.2618 12.7231L11.282 12.7609L11.2821 12.7609L11.2618 12.7231ZM12.0792 12.9673L12.0415 12.9876L12.0416 12.9878L12.0792 12.9673ZM11.8336 13.7799L11.8135 13.742L11.8134 13.742L11.8336 13.7799ZM9.92094 14.8005L9.90076 14.7627L9.87808 14.7748V14.8005H9.92094ZM9.91892 14.8025L9.9189 14.7597L9.90825 14.7597L9.89885 14.7647L9.91892 14.8025ZM9.14581 14.6304L9.10311 14.6447L9.11134 14.6559L9.14581 14.6304ZM9.14064 14.621L9.10537 14.6453L9.10537 14.6453L9.14064 14.621ZM9.13776 14.6164L9.17605 14.5972L9.17604 14.5972L9.13776 14.6164ZM9.13071 14.6054L9.09591 14.6304L9.09591 14.6304L9.13071 14.6054ZM9.12367 14.5944L9.16225 14.575L9.15926 14.5705L9.12367 14.5944ZM9.10152 14.5584L9.13982 14.5391L9.13922 14.538L9.10152 14.5584ZM8.07272 12.6551L8.11042 12.6347L8.11036 12.6346L8.07272 12.6551ZM8.31834 11.8426L8.33844 11.8804L8.33864 11.8803L8.31834 11.8426ZM9.13575 12.0867L9.09799 12.107L9.09803 12.1071L9.13575 12.0867ZM9.45989 12.6871L9.42218 12.7075L9.46535 12.7875L9.49959 12.7033L9.45989 12.6871ZM11.6061 9.75317L11.6335 9.78608L11.6335 9.78608L11.6061 9.75317ZM13.8288 8.46631L13.8436 8.50654L13.8437 8.5065L13.8288 8.46631ZM19.3895 8.59039L19.4062 8.5509L19.4061 8.55087L19.3895 8.59039ZM16.728 15.2747H16.6851V15.3176H16.728V15.2747ZM15.5502 15.9612L15.5934 15.9549L15.5907 15.9471L15.5502 15.9612ZM23.4435 12.5642C23.0608 11.6666 22.5141 10.8594 21.8176 10.1671L21.7572 10.2279C22.4458 10.9124 22.9863 11.7104 23.3646 12.5979L23.4435 12.5642ZM24.0429 15.499C24.0429 14.4805 23.8383 13.4961 23.4435 12.5643L23.3646 12.5978C23.755 13.5192 23.9571 14.4922 23.9571 15.499H24.0429ZM23.4455 18.4357C23.8404 17.5058 24.0429 16.5174 24.0429 15.499H23.9571C23.9571 16.5059 23.757 17.4829 23.3666 18.4022L23.4455 18.4357ZM21.8196 20.8329C22.5161 20.1406 23.0628 19.3334 23.4455 18.4358L23.3667 18.4021C22.9883 19.2896 22.4478 20.0876 21.7592 20.7721L21.8196 20.8329ZM19.4082 22.4491C20.3112 22.0687 21.1231 21.5253 21.8196 20.8329L21.7592 20.7721C21.0705 21.4567 20.2678 21.994 19.3749 22.3701L19.4082 22.4491ZM16.4541 23.0429C17.4785 23.0429 18.4727 22.8436 19.4082 22.4491L19.3749 22.3701C18.4501 22.7601 17.4672 22.9571 16.4541 22.9571V23.0429ZM13.5001 22.4491C14.4355 22.8416 15.4297 23.0429 16.4541 23.0429V22.9571C15.4411 22.9571 14.4582 22.7581 13.5333 22.3701L13.5001 22.4491ZM11.0886 20.8329C11.7851 21.5253 12.5971 22.0687 13.5001 22.4491L13.5333 22.3701C12.6405 21.994 11.8377 21.4567 11.1491 20.7721L11.0886 20.8329ZM11.0886 19.9236C10.8362 20.1745 10.8362 20.582 11.0886 20.8329L11.1491 20.7721C10.9304 20.5547 10.9304 20.2018 11.1491 19.9844L11.0886 19.9236ZM12.0027 19.9236C11.7504 19.6728 11.3409 19.6728 11.0886 19.9236L11.1491 19.9844C11.3679 19.7668 11.7234 19.7668 11.9423 19.9844L12.0027 19.9236ZM16.4521 21.7563C14.7702 21.7563 13.1906 21.1064 12.0027 19.9236L11.9423 19.9843C13.1462 21.1832 14.7476 21.8421 16.4521 21.8421V21.7563ZM20.9015 19.9235C19.7116 21.1044 18.134 21.7563 16.4521 21.7563V21.8421C18.1566 21.8421 19.756 21.1811 20.9619 19.9844L20.9015 19.9235ZM22.7492 15.499C22.7492 17.1686 22.0914 18.7428 20.9015 19.9235L20.9619 19.9844C22.1679 18.7876 22.8349 17.1916 22.8349 15.499H22.7492ZM20.9055 11.0764C22.0934 12.2592 22.7492 13.8294 22.7492 15.499H22.8349C22.8349 13.8064 22.1699 12.2144 20.966 11.0157L20.9055 11.0764ZM16.4561 9.24366C18.1381 9.24366 19.7177 9.89365 20.9055 11.0764L20.966 11.0157C19.762 9.81683 18.1606 9.15794 16.4561 9.15794V9.24366ZM14.2664 9.63127C14.9662 9.37289 15.7021 9.24366 16.4561 9.24366V9.15794C15.6922 9.15794 14.9462 9.28889 14.2367 9.55086L14.2664 9.63127ZM12.4127 10.7047C12.9666 10.2415 13.5905 9.88174 14.2665 9.63125L14.2367 9.55087C13.5517 9.80472 12.9192 10.1694 12.3577 10.6389L12.4127 10.7047ZM10.647 13.09C11.0329 12.1737 11.6368 11.3527 12.4127 10.7047L12.3578 10.6389C11.5713 11.2957 10.9592 12.1278 10.568 13.0567L10.647 13.09ZM11.2416 12.6854L10.5872 13.0356L10.6277 13.1112L11.282 12.7609L11.2416 12.6854ZM12.117 12.947C11.9487 12.6339 11.5562 12.5161 11.2415 12.6854L11.2821 12.7609C11.5553 12.614 11.8957 12.7164 12.0415 12.9876L12.117 12.947ZM11.8537 13.8177C12.1685 13.6505 12.2874 13.2601 12.1168 12.9468L12.0416 12.9878C12.1891 13.2589 12.0865 13.597 11.8135 13.742L11.8537 13.8177ZM9.94111 14.8383L11.8538 13.8177L11.8134 13.74Line truncated
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Calendar / Calendar_Days">
<path id="Vector" d="M8 4H7.2002C6.08009 4 5.51962 4 5.0918 4.21799C4.71547 4.40973 4.40973 4.71547 4.21799 5.0918C4 5.51962 4 6.08009 4 7.2002V8M8 4H16M8 4V2M16 4H16.8002C17.9203 4 18.4796 4 18.9074 4.21799C19.2837 4.40973 19.5905 4.71547 19.7822 5.0918C20 5.5192 20 6.07899 20 7.19691V8M16 4V2M4 8V16.8002C4 17.9203 4 18.4801 4.21799 18.9079C4.40973 19.2842 4.71547 19.5905 5.0918 19.7822C5.5192 20 6.07899 20 7.19691 20H16.8031C17.921 20 18.48 20 18.9074 19.7822C19.2837 19.5905 19.5905 19.2842 19.7822 18.9079C20 18.4805 20 17.9215 20 16.8036V8M4 8H20M16 16H16.002L16.002 16.002L16 16.002V16ZM12 16H12.002L12.002 16.002L12 16.002V16ZM8 16H8.002L8.00195 16.002L8 16.002V16ZM16.002 12V12.002L16 12.002V12H16.002ZM12 12H12.002L12.002 12.002L12 12.002V12ZM8 12H8.002L8.00195 12.002L8 12.002V12Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,6 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 4.40039H4.11111H13" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.77799 4.4V3.2C5.77799 2.88174 5.89506 2.57652 6.10343 2.35147C6.31181 2.12643 6.59442 2 6.88911 2H9.11133C9.40601 2 9.68863 2.12643 9.897 2.35147C10.1054 2.57652 10.2224 2.88174 10.2224 3.2V4.4M11.8891 4.4V12.8C11.8891 13.1183 11.772 13.4235 11.5637 13.6485C11.3553 13.8736 11.0727 14 10.778 14H5.22244C4.92775 14 4.64514 13.8736 4.43676 13.6485C4.22839 13.4235 4.11133 13.1183 4.11133 12.8V4.4H11.8891Z" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.88867 7.40039V11.0004" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.11133 7.40039V11.0004" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 886 B

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.974 6.33301H7.35865C6.7922 6.33301 6.33301 6.7922 6.33301 7.35865V11.974C6.33301 12.5405 6.7922 12.9997 7.35865 12.9997H11.974C12.5405 12.9997 12.9997 12.5405 12.9997 11.974V7.35865C12.9997 6.7922 12.5405 6.33301 11.974 6.33301Z" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.53846 9.66667H4.02564C3.75362 9.66667 3.49275 9.55861 3.3004 9.36626C3.10806 9.17392 3 8.91304 3 8.64103V4.02564C3 3.75362 3.10806 3.49275 3.3004 3.3004C3.49275 3.10806 3.75362 3 4.02564 3H8.64103C8.91304 3 9.17392 3.10806 9.36626 3.3004C9.55861 3.49275 9.66667 3.75362 9.66667 4.02564V4.53846" stroke="#BBC3CD" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 785 B

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(12.941176%,12.941176%,12.941176%);fill-opacity:1;" d="M 8 1.332031 C 11.683594 1.332031 14.667969 4.316406 14.667969 8 C 14.667969 11.683594 11.683594 14.667969 8 14.667969 C 4.316406 14.667969 1.332031 11.683594 1.332031 8 C 1.332031 4.316406 4.316406 1.332031 8 1.332031 Z M 8 2.332031 C 4.871094 2.332031 2.332031 4.871094 2.332031 8 C 2.332031 11.128906 4.871094 13.667969 8 13.667969 C 11.128906 13.667969 13.667969 11.128906 13.667969 8 C 13.667969 4.871094 11.128906 2.332031 8 2.332031 Z M 5.640625 9.855469 C 6.207031 10.574219 7.066406 11 8 11 C 8.929688 11 9.789062 10.574219 10.355469 9.859375 C 10.527344 9.640625 10.84375 9.605469 11.058594 9.777344 C 11.277344 9.949219 11.3125 10.261719 11.140625 10.476562 C 10.386719 11.433594 9.238281 12 8 12 C 6.757812 12 5.609375 11.429688 4.855469 10.476562 C 4.683594 10.257812 4.722656 9.945312 4.9375 9.773438 C 5.15625 9.601562 5.46875 9.640625 5.640625 9.855469 Z M 6 5.835938 C 6.460938 5.835938 6.832031 6.207031 6.832031 6.667969 C 6.832031 7.125 6.460938 7.5 6 7.5 C 5.539062 7.5 5.167969 7.125 5.167969 6.667969 C 5.167969 6.207031 5.539062 5.835938 6 5.835938 Z M 10 5.835938 C 10.460938 5.835938 10.832031 6.207031 10.832031 6.667969 C 10.832031 7.125 10.460938 7.5 10 7.5 C 9.539062 7.5 9.167969 7.125 9.167969 6.667969 C 9.167969 6.207031 9.539062 5.835938 10 5.835938 Z M 10 5.835938 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(12.941176%,12.941176%,12.941176%);fill-opacity:1;" d="M 11.667969 8 C 13.691406 8 15.332031 9.640625 15.332031 11.667969 C 15.332031 13.691406 13.691406 15.332031 11.667969 15.332031 C 9.640625 15.332031 8 13.691406 8 11.667969 C 8 9.640625 9.640625 8 11.667969 8 Z M 8 1.332031 C 11.683594 1.332031 14.667969 4.316406 14.667969 8 C 14.667969 8.175781 14.660156 8.351562 14.648438 8.523438 C 14.355469 8.246094 14.023438 8.007812 13.664062 7.820312 C 13.570312 4.773438 11.070312 2.332031 8 2.332031 C 4.871094 2.332031 2.332031 4.871094 2.332031 8 C 2.332031 11.070312 4.773438 13.570312 7.820312 13.664062 C 8.007812 14.027344 8.246094 14.355469 8.523438 14.648438 C 8.351562 14.660156 8.175781 14.667969 8 14.667969 C 4.316406 14.667969 1.332031 11.683594 1.332031 8 C 1.332031 4.316406 4.316406 1.332031 8 1.332031 Z M 11.667969 9.332031 L 11.605469 9.339844 C 11.46875 9.363281 11.363281 9.46875 11.339844 9.605469 L 11.332031 9.667969 L 11.332031 11.332031 L 9.664062 11.332031 L 9.605469 11.339844 C 9.46875 11.363281 9.363281 11.46875 9.335938 11.605469 L 9.332031 11.667969 L 9.335938 11.726562 C 9.363281 11.863281 9.46875 11.96875 9.605469 11.996094 L 9.664062 12 L 11.332031 12 L 11.335938 13.667969 L 11.339844 13.730469 C 11.363281 13.863281 11.472656 13.972656 11.609375 13.996094 L 11.667969 14.003906 L 11.726562 13.996094 C 11.863281 13.972656 11.96875 13.863281 11.996094 13.730469 L 12 13.667969 L 12 12 L 13.667969 12 L 13.730469 11.996094 C 13.867188 11.96875 13.972656 11.863281 13.996094 11.726562 L 14.003906 11.667969 L 13.996094 11.605469 C 13.972656 11.46875 13.867188 11.363281 13.730469 11.339844 L 13.667969 11.332031 L 12 11.332031 L 12 9.667969 L 11.996094 9.605469 C 11.96875 9.46875 11.863281 9.363281 11.726562 9.339844 Z M 5.640625 9.855469 C 6.082031 10.414062 6.703125 10.796875 7.394531 10.941406 C 7.355469 11.175781 7.332031 11.417969 7.332031 11.667969 C 7.332031 11.761719 7.335938 11.855469 7.34375 11.945312 C 6.359375 11.785156 5.472656 11.261719 4.855469 10.476562 C 4.683594 10.257812 4.722656 9.945312 4.9375 9.773438 C 5.15625 9.601562 5.46875 9.640625 5.640625 9.855469 Z M 6 5.835938 C 6.460938 5.835938 6.832031 6.207031 6.832031 6.667969 C 6.832031 7.125 6.460938 7.5 6 7.5 C 5.539062 7.5 5.167969 7.125 5.167969 6.667969 C 5.167969 6.207031 5.539062 5.835938 6 5.835938 Z M 10 5.835938 C 10.460938 5.835938 10.832031 6.207031 10.832031 6.667969 C 10.832031 7.125 10.460938 7.5 10 7.5 C 9.539062 7.5 9.167969 7.125 9.167969 6.667969 C 9.167969 6.207031 9.539062 5.835938 10 5.835938 Z M 10 5.835938 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 8.91521C7.21574 9.22582 7.49099 9.48283 7.80707 9.66881C8.12315 9.85479 8.47268 9.96538 8.83194 9.99309C9.1912 10.0208 9.5518 9.96497 9.88926 9.8294C10.2267 9.69383 10.5332 9.48169 10.7878 9.20736L12.2949 7.58431C12.7525 7.07413 13.0056 6.39083 12.9999 5.68156C12.9942 4.9723 12.73 4.29384 12.2643 3.7923C11.7986 3.29075 11.1686 3.00627 10.51 3.0001C9.85142 2.99394 9.21693 3.26659 8.7432 3.75935L7.87913 4.68448" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 7.08479C8.78426 6.77418 8.50901 6.51717 8.19293 6.33119C7.87685 6.14521 7.52732 6.03462 7.16806 6.00691C6.8088 5.9792 6.4482 6.03503 6.11074 6.1706C5.77327 6.30617 5.46683 6.51831 5.21218 6.79264L3.7051 8.41569C3.24755 8.92587 2.99437 9.60918 3.00009 10.3184C3.00582 11.0277 3.26998 11.7062 3.73569 12.2077C4.2014 12.7092 4.8314 12.9937 5.48999 12.9999C6.14858 13.0061 6.78307 12.7334 7.2568 12.2407L8.11584 11.3155" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1 +0,0 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" style="width: 16px; height: 16px; display: block; fill: inherit; flex-shrink: 0; backface-visibility: hidden;" width="30" height="30" ><path d="M6.04883 27.3232C7.24219 27.3232 7.86426 26.4854 8.20703 25.3936L13.9834 6.79492H27.5039C28.2275 6.79492 28.7227 6.35059 28.7227 5.65234C28.7227 4.97949 28.2275 4.53516 27.5039 4.53516H13.958C12.6631 4.53516 12.0791 5.01758 11.7363 6.13477L6.18848 24.3525H5.97266L3.58594 15.9355C3.38281 15.2373 3.00195 14.9072 2.40527 14.9072C1.73242 14.9072 1.2373 15.3896 1.2373 16.0117C1.2373 16.2656 1.30078 16.4941 1.35156 16.6846L4.04297 25.5332C4.36035 26.5615 4.93164 27.3232 6.04883 27.3232ZM16.3955 24.7334C16.8652 24.7334 17.1064 24.5684 17.4619 24.0732L20.4707 19.8203H20.5215L23.5049 24.0732C23.873 24.5684 24.1143 24.7334 24.5713 24.7334C25.2061 24.7334 25.6758 24.3018 25.6758 23.7051C25.6758 23.4258 25.6123 23.1973 25.4219 22.9561L21.9307 18.208L25.4473 13.4346C25.6377 13.168 25.7139 12.9395 25.7139 12.6855C25.7139 12.127 25.2568 11.6953 24.6475 11.6953C24.2031 11.6953 23.9365 11.8477 23.6064 12.3174L20.7246 16.5957H20.6611L17.6904 12.3047C17.373 11.8477 17.0938 11.6953 16.624 11.6953C16.0146 11.6953 15.5068 12.165 15.5068 12.7363C15.5068 13.0537 15.583 13.2568 15.8115 13.5488L19.1504 18.1445L15.6084 23.0322C15.418 23.2861 15.3672 23.4639 15.3672 23.7559C15.3672 24.3018 15.8115 24.7334 16.3955 24.7334Z" fill="#2F3030"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,8 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="9" y="3" width="2" height="2" rx="0.5" fill="#333333"/>
<rect x="5" y="3" width="2" height="2" rx="0.5" fill="#333333"/>
<rect x="9" y="7" width="2" height="2" rx="0.5" fill="#333333"/>
<rect x="5" y="7" width="2" height="2" rx="0.5" fill="#333333"/>
<rect x="9" y="11" width="2" height="2" rx="0.5" fill="#333333"/>
<rect x="5" y="11" width="2" height="2" rx="0.5" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 2.5V6C9 6.55228 9.44772 7 10 7H12" stroke="#333333"/>
<path d="M3.5 3.5C3.5 2.94771 3.94772 2.5 4.5 2.5H8H8.5C9.12951 2.5 9.72229 2.79639 10.1 3.3L12.1 5.96667C12.3596 6.31286 12.5 6.73393 12.5 7.16667V8V12.5C12.5 13.0523 12.0523 13.5 11.5 13.5H4.5C3.94772 13.5 3.5 13.0523 3.5 12.5V3.5Z" stroke="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 423 B

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.5 15V6.9C3.5 6.05992 3.5 5.63988 3.66349 5.31901C3.8073 5.03677 4.03677 4.8073 4.31901 4.66349C4.63988 4.5 5.05992 4.5 5.9 4.5H8.47237C8.84808 4.5 9.03594 4.5 9.20646 4.55179C9.35741 4.59763 9.49785 4.6728 9.61972 4.77298C9.75739 4.88614 9.86159 5.04245 10.07 5.35507L10.93 6.64533C11.1384 6.95795 11.2426 7.11426 11.3803 7.22742C11.5022 7.3276 11.6426 7.40277 11.7935 7.44861C11.9641 7.5004 12.1519 7.5004 12.5276 7.5004H16.5004C16.965 7.5004 17.1973 7.5004 17.3879 7.55143C17.9058 7.69008 18.3103 8.09459 18.449 8.61248C18.5 8.80308 18.5 9.03539 18.5 9.5V9.5M10.5 13.5H16.5" stroke="#222222" stroke-linecap="round"/>
<path d="M4.5 18.5L16.7701 18.5004C17.3922 18.5004 17.7032 18.5004 17.9679 18.3963C18.2016 18.3044 18.4084 18.1553 18.5695 17.9626C18.752 17.7445 18.8503 17.4494 19.047 16.8593L20.4471 12.6592C20.8026 11.5927 20.9803 11.0595 20.8737 10.635C20.7804 10.2635 20.5485 9.94171 20.2255 9.7357C19.8566 9.50035 19.2945 9.50033 18.1703 9.5003L10.2299 9.50005C9.60784 9.50003 9.29681 9.50002 9.03216 9.60411C8.79846 9.69601 8.59157 9.84513 8.43047 10.0378C8.24804 10.2559 8.14968 10.551 7.95298 11.1411L5.7649 17.7057C5.60671 18.1803 5.16255 18.5004 4.66227 18.5004V18.5004C4.02037 18.5004 3.5 17.98 3.5 17.3381V14.5" stroke="#222222"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,3 +0,0 @@
<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 5.2L2.84615 7L9 1" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 198 B

@@ -1,6 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 13H3V10" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 3H13V6" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 13L7 9" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 3L9 7" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 449 B

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.9083 10.9011C10.4173 11.2751 9.83813 11.4814 9.09532 11.4814C7.93705 11.4814 6.82914 10.8367 6.45144 9.2765H10.027V8.50287H6.32554C6.31295 8.34814 6.31295 8.19341 6.31295 8.02579C6.31295 7.84527 6.32554 7.67765 6.33813 7.51003H10.027V6.73639H6.45144C6.81655 5.25358 7.82374 4.50573 9.09532 4.50573C9.72482 4.50573 10.304 4.69914 10.8201 5.06017L11.4371 4.24785C10.7194 3.73209 9.91367 3.5 9.09532 3.5C7.10612 3.5 5.72122 4.69914 5.31835 6.73639H4.5V7.51003H5.21763C5.20504 7.67765 5.20504 7.84527 5.20504 8.02579C5.20504 8.19341 5.20504 8.34814 5.21763 8.50287H4.5V9.2765H5.31835C5.7464 11.5716 7.40827 12.5 9.09532 12.5C10.0773 12.5 10.8705 12.1777 11.5 11.7264L10.9083 10.9011Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 814 B

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.201 6.4H3.001V12H2.081V7.384L0.953 7.704L0.729 6.92L2.201 6.4ZM3.91156 12V11.1L6.35156 8.61C6.9449 8.01667 7.24156 7.50333 7.24156 7.07C7.24156 6.73 7.13823 6.46667 6.93156 6.28C6.73156 6.08667 6.4749 5.99 6.16156 5.99C5.5749 5.99 5.14156 6.28 4.86156 6.86L3.89156 6.29C4.11156 5.82333 4.42156 5.47 4.82156 5.23C5.22156 4.99 5.6649 4.87 6.15156 4.87C6.7649 4.87 7.29156 5.06333 7.73156 5.45C8.17156 5.83667 8.39156 6.36333 8.39156 7.03C8.39156 7.74333 7.9949 8.50333 7.20156 9.31L5.62156 10.89H8.52156V12H3.91156ZM12.9025 7.032C13.5105 7.176 14.0025 7.46 14.3785 7.884C14.7625 8.3 14.9545 8.824 14.9545 9.456C14.9545 10.296 14.6705 10.956 14.1025 11.436C13.5345 11.916 12.8385 12.156 12.0145 12.156C11.3745 12.156 10.7985 12.008 10.2865 11.712C9.78253 11.416 9.41853 10.984 9.19453 10.416L10.3705 9.732C10.6185 10.452 11.1665 10.812 12.0145 10.812C12.4945 10.812 12.8745 10.692 13.1545 10.452C13.4345 10.204 13.5745 9.872 13.5745 9.456C13.5745 9.04 13.4345 8.712 13.1545 8.472C12.8745 8.232 12.4945 8.112 12.0145 8.112H11.7025L11.1505 7.284L12.9625 4.896H9.44653V3.6H14.6065V4.776L12.9025 7.032Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.716 9.828C10.716 8.292 9.6 7.896 8.124 7.416C7.128 7.092 6.396 6.828 6.396 6.072C6.396 5.376 6.984 4.968 7.824 4.968C8.412 4.968 9.216 5.22 9.84 5.676L10.44 4.944C9.9 4.512 9.096 4.176 8.352 4.056V2.508H7.572V4.008C6.12 4.092 5.304 4.98 5.304 6.132C5.304 7.56 6.516 7.98 7.824 8.388C8.928 8.748 9.612 9.036 9.612 9.9C9.612 10.644 8.964 11.088 8.076 11.088C7.308 11.088 6.444 10.752 5.772 10.092L5.136 10.836C5.844 11.532 6.684 11.904 7.572 12.012V13.476H8.352V12.024C9.84 11.928 10.716 11.052 10.716 9.828Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 641 B

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2301 4.25586H10.0181L8.02613 7.93986H8.00213L5.99813 4.25586H4.78613L7.06613 8.23986H5.43413V8.95986H7.47413L7.48613 8.98386V9.82386H5.43413V10.5319H7.48613V12.4999H8.53013V10.5319H10.4981V9.82386H8.53013V8.98386L8.54213 8.95986H10.4981V8.23986H8.95013L11.2301 4.25586Z" fill="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 404 B

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.12265 11.5847C5.92255 12.1165 6.88538 12.5 8.00024 12.5C10.4842 12.5 12.2135 10.596 13.0675 9.39083C13.6624 8.55146 13.6624 7.44854 13.0675 6.60917C12.7341 6.13867 12.2673 5.56168 11.6743 5.03305L10.9661 5.74127C11.4908 6.20089 11.9225 6.72296 12.2516 7.18736C12.601 7.68035 12.601 8.31965 12.2516 8.81264C11.4276 9.97552 9.9599 11.5 8.00024 11.5C7.19618 11.5 6.47495 11.2434 5.84702 10.8603L5.12265 11.5847ZM5.03441 10.2587L4.32618 10.967C3.73316 10.4383 3.26636 9.86133 2.93294 9.39083C2.33811 8.55146 2.33811 7.44854 2.93294 6.60917C3.78701 5.40397 5.51627 3.5 8.00024 3.5C9.1151 3.5 10.0779 3.88354 10.8778 4.4153L10.1535 5.13966C9.52554 4.75665 8.80431 4.5 8.00024 4.5C6.04059 4.5 4.57293 6.02448 3.74884 7.18736C3.39948 7.68035 3.39948 8.31965 3.74884 8.81264C4.07794 9.27704 4.50968 9.79911 5.03441 10.2587ZM6.99269 9.71466C7.28548 9.8954 7.62952 10 8.00036 10C9.09422 10 9.95491 9.08996 9.95491 8C9.95491 7.64165 9.86187 7.30275 9.69811 7.00924L8.93118 7.77618C8.94668 7.84779 8.95491 7.92265 8.95491 8C8.95491 8.5669 8.51315 9 8.00036 9C7.91225 9 7.82623 8.98721 7.7442 8.96316L6.99269 9.71466ZM7.06951 8.22363L6.30253 8.99061C6.13882 8.69713 6.04582 8.35829 6.04582 8C6.04582 6.91005 6.9065 6 8.00036 6C8.37114 6 8.71513 6.10456 9.00789 6.28525L8.25635 7.03679C8.17436 7.01277 8.08841 7 8.00036 7C7.48757 7 7.04582 7.4331 7.04582 8C7.04582 8.07728 7.05403 8.15208 7.06951 8.22363Z" fill="#333333"/>
<path d="M11.667 3.33398L3.33366 11.6673" stroke="#333333" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="-0.02 0 122.88 122.88" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="enable-background:new 0 0 122.84 122.88" xml:space="preserve">
<g>
<path d="M81.54,4.71c0-2.62,2.58-4.71,5.77-4.71c3.2,0,5.77,2.13,5.77,4.71V25.4c0,2.62-2.58,4.71-5.77,4.71 c-3.2,0-5.77-2.13-5.77-4.71V4.71L81.54,4.71z M20.4,89.87l7.55-0.47c0.16,1.22,0.5,2.16,1,2.79c0.82,1.04,1.99,1.56,3.51,1.56 c1.13,0,2.01-0.26,2.62-0.8C35.69,92.41,36,91.8,36,91.1c0-0.66-0.29-1.26-0.87-1.79c-0.58-0.53-1.93-1.02-4.06-1.49 c-3.49-0.78-5.96-1.82-7.45-3.12c-1.5-1.29-2.25-2.95-2.25-4.96c0-1.32,0.38-2.56,1.15-3.74c0.77-1.18,1.92-2.1,3.46-2.77 c1.54-0.67,3.65-1.01,6.32-1.01c3.29,0,5.79,0.61,7.52,1.84c1.72,1.22,2.75,3.17,3.08,5.84l-7.47,0.44 c-0.2-1.17-0.62-2.02-1.25-2.55c-0.64-0.53-1.52-0.8-2.64-0.8c-0.92,0-1.62,0.2-2.09,0.59c-0.47,0.39-0.7,0.87-0.7,1.43 c0,0.41,0.19,0.77,0.57,1.1c0.37,0.34,1.25,0.65,2.65,0.95c3.47,0.75,5.96,1.51,7.46,2.28c1.5,0.77,2.6,1.71,3.28,2.85 c0.68,1.13,1.02,2.4,1.02,3.81c0,1.65-0.46,3.17-1.37,4.56c-0.92,1.39-2.19,2.45-3.83,3.17c-1.64,0.72-3.7,1.08-6.19,1.08 c-4.37,0-7.4-0.84-9.09-2.53C21.58,94.6,20.62,92.46,20.4,89.87L20.4,89.87z M64.53,72.65h7.94v15.33c0,1.52-0.24,2.95-0.71,4.3 c-0.47,1.35-1.22,2.53-2.23,3.55c-1.01,1.01-2.07,1.72-3.18,2.13c-1.54,0.57-3.4,0.86-5.56,0.86c-1.25,0-2.62-0.09-4.1-0.26 c-1.48-0.17-2.72-0.52-3.71-1.04c-0.99-0.52-1.9-1.26-2.72-2.22c-0.83-0.96-1.39-1.95-1.69-2.96c-0.49-1.64-0.74-3.08-0.74-4.35 V72.65h7.94v15.69c0,1.4,0.39,2.5,1.16,3.28c0.78,0.79,1.86,1.19,3.23,1.19c1.36,0,2.43-0.39,3.21-1.17 c0.77-0.77,1.16-1.87,1.16-3.3V72.65L64.53,72.65z M77.85,72.65h7.42l9.65,14.21V72.65h7.51v25.73h-7.51l-9.59-14.13v14.13h-7.47 V72.65L77.85,72.65z M29.53,4.71c0-2.62,2.58-4.71,5.77-4.71c3.2,0,5.77,2.13,5.77,4.71V25.4c0,2.62-2.58,4.71-5.77,4.71 c-3.2,0-5.77-2.13-5.77-4.71V4.71L29.53,4.71z M7.56,44.09h107.62V22.66c0-0.8-0.31-1.55-0.84-2.04c-0.53-0.53-1.24-0.84-2.04-0.84 h-9.31c-1.78,0-3.2-2.63-3.2-4.41c0-1.78,1.42-3.2,3.2-3.2h10.53c2.58,0,4.88,1.07,6.57,2.75c1.69,1.69,2.75,4.04,2.75,6.57v92.06 c0,2.58-1.07,4.88-2.75,6.57c-1.69,1.69-4.04,2.75-6.57,2.75H9.33c-2.58,0-4.88-1.07-6.57-2.75C1.07,118.44,0,116.08,0,113.55 V21.49c0-2.58,1.07-4.88,2.75-6.57c1.69-1.69,4.04-2.75,6.57-2.75h11.28c1.78,0,3.2,1.42,3.2,3.2s-1.42,4.41-3.2,4.41H10.54 c-0.8,0-1.55,0.31-2.09,0.84c-0.53,0.53-0.84,1.24-0.84,2.09v21.43L7.56,44.09L7.56,44.09z M115.19,52.9H7.56v59.4 c0,0.8,0.31,1.55,0.84,2.09c0.53,0.53,1.24,0.84,2.09,0.84h101.76c0.8,0,1.55-0.31,2.09-0.84c0.53-0.53,0.84-1.24,0.84-2.09V52.9 L115.19,52.9z M50.36,19.73c-1.78,0-3.2-2.63-3.2-4.41c0-1.78,1.42-3.2,3.2-3.2h21.49c1.78,0,3.2,1.42,3.2,3.2 c0,1.78-1.42,4.41-3.2,4.41H50.36L50.36,19.73z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 6C3 3.79086 4.79086 2 7 2H17C19.2091 2 21 3.79086 21 6C21 8.20914 19.2091 10 17 10H7C4.79086 10 3 8.20914 3 6Z" stroke="#000000" stroke-width="2"/>
<path d="M3 16C3 14.8954 3.89543 14 5 14H8C9.10457 14 10 14.8954 10 16V19C10 20.1046 9.10457 21 8 21H5C3.89543 21 3 20.1046 3 19V16Z" stroke="#000000" stroke-width="2"/>
<path d="M14 17.5C14 15.567 15.567 14 17.5 14C19.433 14 21 15.567 21 17.5C21 19.433 19.433 21 17.5 21C15.567 21 14 19.433 14 17.5Z" stroke="#000000" stroke-width="2"/>
</svg>

Before

Width:  |  Height:  |  Size: 725 B

@@ -1,7 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 2H13C13.5523 2 14 2.44772 14 3V6" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 2H3C2.44772 2 2 2.44772 2 3V6" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 14H3C2.44772 14 2 13.5523 2 13V10" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 14H13C13.5523 14 14 13.5523 14 13V10" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="6" y="6" width="4" height="4" rx="1" stroke="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 620 B

@@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5221 3.21932C11.4366 2.6913 12.5634 2.6913 13.4779 3.21932L18.8653 6.32972C19.7799 6.85774 20.3433 7.83356 20.3433 8.88959V15.1104C20.3433 16.1664 19.7799 17.1423 18.8653 17.6703L13.4779 20.7807C12.5634 21.3087 11.4366 21.3087 10.5221 20.7807L5.13468 17.6703C4.22012 17.1423 3.65673 16.1664 3.65673 15.1104V8.88959C3.65673 7.83356 4.22012 6.85774 5.13467 6.32972L10.5221 3.21932Z" stroke="#333333" stroke-width="1.5"/>
<circle cx="12" cy="12" r="3.75" stroke="#333333" stroke-width="1.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 606 B

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="3" width="4" height="10" rx="1" stroke="#333333"/>
<rect x="9.5" y="7" width="4" height="6" rx="1" stroke="#333333"/>
</svg>

Before

Width:  |  Height:  |  Size: 238 B

@@ -1,17 +0,0 @@
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg808"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs812" />
<path
id="path930"
style="fill:#00bcf0;fill-opacity:1"
transform="rotate(-90)"
d="M 0,7.9238281 A 8,8 0 0 0 -8.0585938,0 8,8 0 0 0 -16,8.0390625 8,8 0 0 0 -7.9804688,16 8,8 0 0 0 0,8 Z M -4,8 c 0,0.2769988 -0.2230012,0.5 -0.5,0.5 h -3 v 3 c 0,0.277 -0.2230012,0.5 -0.5,0.5 -0.2769988,0 -0.5,-0.223 -0.5,-0.5 v -3 h -3 C -11.777,8.5 -12,8.2769988 -12,8 c 0,-0.2769988 0.223,-0.5 0.5,-0.5 h 3 v -3 C -8.5,4.2230012 -8.2769988,4 -8,4 c 0.2769988,0 0.5,0.2230012 0.5,0.5 v 3 h 3 C -4.2230012,7.5 -4,7.7230012 -4,8 Z" />
</svg>

Before

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

@@ -1,5 +1,6 @@
import 'package:appflowy/workspace/application/appearance_defaults.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/settings_appearance.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -41,5 +42,47 @@ void main() {
expect(find.textContaining('Abel'), findsOneWidget);
});
testWidgets('reset the font family', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
final dropDown = find.byKey(ThemeFontFamilySetting.popoverKey);
await tester.tap(dropDown);
await tester.pumpAndSettle();
final textField = find.byKey(ThemeFontFamilySetting.textFieldKey);
await tester.tap(textField);
await tester.pumpAndSettle();
await tester.enterText(textField, 'Abel');
await tester.pumpAndSettle();
final fontFamilyButton = find.byKey(const Key('Abel'));
expect(fontFamilyButton, findsOneWidget);
await tester.tap(fontFamilyButton);
await tester.pumpAndSettle();
// just switch the page and verify that the font family was set after that
await tester.openSettingsPage(SettingsPage.files);
await tester.openSettingsPage(SettingsPage.appearance);
final resetButton = find.byKey(ThemeFontFamilySetting.resetButtonkey);
await tester.tap(resetButton);
await tester.pumpAndSettle();
// just switch the page and verify that the font family was set after that
await tester.openSettingsPage(SettingsPage.files);
await tester.openSettingsPage(SettingsPage.appearance);
expect(find.textContaining(DefaultAppearanceSettings.kDefaultFontFamily),
findsOneWidget,
);
});
});
}
@@ -0,0 +1,85 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('auth', () {
testWidgets('sign in with supabase', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoogleLoginInButton();
tester.expectToSeeHomePage();
});
testWidgets('sign out with supabase', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.tapButton(find.byType(SettingLogoutButton));
tester.expectToSeeText(LocaleKeys.button_OK.tr());
await tester.tapButtonWithName(LocaleKeys.button_OK.tr());
// Go to the sign in page again
await tester.pumpAndSettle(const Duration(seconds: 1));
tester.expectToSeeGoogleLoginButton();
});
testWidgets('sign in as annoymous', (tester) async {
await tester.initializeAppFlowy();
await tester.tapSignInAsGuest();
// should not see the sync setting page when sign in as annoymous
await tester.openSettings();
await tester.expectNoSettingsPage(SettingsPage.syncSetting);
});
testWidgets('enable encryption', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.syncSetting);
// the switch should be off by default
tester.assertEnableEncryptSwitchValue(false);
await tester.toggleEnableEncrypt();
// the switch should be on after toggling
tester.assertEnableEncryptSwitchValue(true);
// the switch can not be toggled back to off
await tester.toggleEnableEncrypt();
tester.assertEnableEncryptSwitchValue(true);
});
testWidgets('enable sync', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.syncSetting);
// the switch should be on by default
tester.assertEnableSyncSwitchValue(true);
await tester.toggleEnableSync();
// the switch should be off
tester.assertEnableSyncSwitchValue(false);
// the switch should be on after toggling
await tester.toggleEnableSync();
tester.assertEnableSyncSwitchValue(true);
});
});
}
@@ -0,0 +1,50 @@
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:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board row test', () {
testWidgets('delete item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.findTextInFlowyText(name);
await tester.hoverOnWidget(
card1,
onHover: () async {
final moreOption = find.byType(CardMoreOption);
await tester.tapButton(moreOption);
},
);
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
expect(find.findTextInFlowyText(name), findsNothing);
});
testWidgets('duplicate item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.findTextInFlowyText(name);
await tester.hoverOnWidget(
card1,
onHover: () async {
final moreOption = find.byType(CardMoreOption);
await tester.tapButton(moreOption);
},
);
await tester.tapButtonWithName(LocaleKeys.button_duplicate.tr());
expect(find.textContaining(name, findRichText: true), findsNWidgets(2));
});
});
}
@@ -0,0 +1,10 @@
import 'package:integration_test/integration_test.dart';
import 'board_row_test.dart' as board_row_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Board integration tests
board_row_test.main();
}
@@ -9,13 +9,12 @@ import 'util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('calendar database view', () {
group('calendar', () {
testWidgets('update calendar layout', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateCalendarButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
// open setting
await tester.tapDatabaseSettingButton();
@@ -36,7 +35,11 @@ void main() {
await tester.tapGoButton();
// Create calendar view
await tester.createNewPageWithName(ViewLayoutPB.Calendar, 'calendar');
const name = 'calendar';
await tester.createNewPageWithName(
name: name,
layout: ViewLayoutPB.Calendar,
);
// Open setting
await tester.tapDatabaseSettingButton();
@@ -47,9 +50,9 @@ void main() {
await tester.tapFirstDayOfWeekStartFromMonday();
// Open the other page and open the new calendar page again
await tester.openPage(readme);
await tester.openPage(gettingStarted);
await tester.pumpAndSettle(const Duration(milliseconds: 300));
await tester.openPage('calendar');
await tester.openPage(name, layout: ViewLayoutPB.Calendar);
// Open setting again and check the start from Monday is selected
await tester.tapDatabaseSettingButton();
@@ -65,8 +68,7 @@ void main() {
await tester.tapGoButton();
// Create the calendar view
await tester.tapAddButton();
await tester.tapCreateCalendarButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
// Scroll until today's date cell is visible
await tester.scrollToToday();
@@ -114,6 +116,7 @@ void main() {
tester.assertRowDetailPageOpened();
// Duplicate the event
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDuplicateRowButton();
await tester.dismissRowDetailPage();
@@ -123,6 +126,7 @@ void main() {
// Delete an event
await tester.openCalendarEvent(index: 1);
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDeleteRowButton();
// Check that there is 1 event
@@ -135,8 +139,7 @@ void main() {
await tester.tapGoButton();
// Create the calendar view
await tester.tapAddButton();
await tester.tapCreateCalendarButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
// Create a new event on the first of this month
final today = DateTime.now();
@@ -154,6 +157,7 @@ void main() {
// Delete the event
await tester.openCalendarEvent(index: 0, date: sameDayNextWeek);
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDeleteRowButton();
// Create a new event in today's calendar cell
@@ -15,8 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.editCell(
rowIndex: 0,
@@ -38,7 +37,10 @@ void main() {
testWidgets('edit multiple text cells', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(ViewLayoutPB.Grid, 'my grid');
await tester.createNewPageWithName(
name: 'my grid',
layout: ViewLayoutPB.Grid,
);
await tester.createField(FieldType.RichText, 'description');
await tester.editCell(
@@ -75,8 +77,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Number;
@@ -134,8 +135,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.assertCheckboxCell(rowIndex: 0, isSelected: false);
await tester.tapCheckboxCellInGrid(rowIndex: 0);
@@ -153,8 +153,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.CreatedTime;
// Create a create time field
@@ -172,8 +171,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.LastEditedTime;
// Create a last time field
@@ -191,8 +189,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.DateTime;
await tester.createField(fieldType, fieldType.name);
@@ -221,7 +218,6 @@ void main() {
await tester.assertDateCellInGrid(
rowIndex: 0,
fieldType: fieldType,
content: DateFormat('MMM dd, y').format(today),
);
@@ -236,7 +232,6 @@ void main() {
await tester.assertDateCellInGrid(
rowIndex: 0,
fieldType: fieldType,
content: DateFormat('MMM dd, y HH:mm').format(now),
);
@@ -250,7 +245,6 @@ void main() {
await tester.assertDateCellInGrid(
rowIndex: 0,
fieldType: fieldType,
content: DateFormat('dd/MM/y HH:mm').format(now),
);
@@ -264,10 +258,20 @@ void main() {
await tester.assertDateCellInGrid(
rowIndex: 0,
fieldType: fieldType,
content: DateFormat('dd/MM/y hh:mm a').format(now),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
await tester.findDateEditor(findsOneWidget);
// Clear the date and time
await tester.clearDate();
await tester.assertDateCellInGrid(
rowIndex: 0,
content: '',
);
await tester.pumpAndSettle();
});
@@ -276,9 +280,9 @@ void main() {
await tester.tapGoButton();
const fieldType = FieldType.SingleSelect;
await tester.tapAddButton();
// When create a grid, it will create a single select field by default
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Tap the cell to invoke the selection option editor
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -354,8 +358,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.MultiSelect;
await tester.createField(fieldType, fieldType.name);
@@ -434,4 +437,116 @@ void main() {
await tester.pumpAndSettle();
});
});
testWidgets('edit checklist cell', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Checklist;
await tester.createField(fieldType, fieldType.name);
// assert that there is no progress bar in the grid
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
// tap on the first checklist cell
await tester.tapChecklistCellInGrid(rowIndex: 0);
// assert that the checklist editor is shown
tester.assertChecklistEditorVisible(visible: true);
// assert that new task editor is shown
tester.assertNewCheckListTaskEditorVisible(visible: true);
// create a new task with enter
await tester.createNewChecklistTask(name: "task 0", enter: true);
// assert that the task is displayed
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 0",
isChecked: false,
);
// update the task's name
await tester.renameChecklistTask(index: 0, name: "task 1");
// assert that the task's name is updated
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 1",
isChecked: false,
);
// dismiss new task editor
await tester.dismissCellEditor();
tester.assertNewCheckListTaskEditorVisible(visible: false);
// dismiss checklist cell editor
await tester.dismissCellEditor();
// assert that progress bar is shown in grid at 0%
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 0);
// start editing the first checklist cell again, click on new task button
await tester.tapChecklistCellInGrid(rowIndex: 0);
tester.assertNewCheckListTaskEditorVisible(visible: false);
await tester.tapChecklistNewTaskButton();
tester.assertNewCheckListTaskEditorVisible(visible: true);
// create another task with the create button
await tester.createNewChecklistTask(name: "task 2", button: true);
// assert that the task was inserted
tester.assertChecklistTaskInEditor(
index: 1,
name: "task 2",
isChecked: false,
);
// mark it as complete
await tester.checkChecklistTask(index: 1);
// assert that the task was checked in the editor
tester.assertChecklistTaskInEditor(
index: 1,
name: "task 2",
isChecked: true,
);
// dismiss checklist editor
await tester.dismissCellEditor();
await tester.dismissCellEditor();
// assert that progressbar is shown in grid at 50%
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 0.5);
// re-open the cell editor
await tester.tapChecklistCellInGrid(rowIndex: 0);
// hover over first task and delete it
await tester.deleteChecklistTask(index: 0);
// dismiss cell editor
await tester.dismissCellEditor();
// assert that progressbar is shown in grid at 100%
tester.assertChecklistCellInGrid(rowIndex: 0, percent: 1);
// re-open the cell edior
await tester.tapChecklistCellInGrid(rowIndex: 0);
// delete the remaining task
await tester.deleteChecklistTask(index: 0);
// assert that the new task editor is shown
tester.assertNewCheckListTaskEditorVisible(visible: true);
// dismiss the cell editor
await tester.dismissCellEditor();
// check that the progress bar is not viisble
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
});
}
@@ -0,0 +1,55 @@
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pbenum.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('database field settings', () {
testWidgets('field visibility', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.grid);
// create a field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField('New field 1');
await tester.dismissFieldEditor();
// hide the field
await tester.tapGridFieldWithName('New field 1');
await tester.tapHidePropertyButton();
await 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');
// go back to linked database view, expect field to be hidden
await tester.tapTabBarLinkedViewByViewName('grid');
await 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');
// 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');
});
});
}
@@ -17,8 +17,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Name');
@@ -35,8 +34,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
@@ -58,8 +56,7 @@ void main() {
await tester.tapGoButton();
// create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checklist, 'checklist');
@@ -73,8 +70,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checkbox, 'New field 1');
@@ -94,8 +90,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// create a field
await tester.scrollToRight(find.byType(GridPage));
@@ -111,33 +106,11 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('hide field', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
// create a field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField('New field 1');
await tester.dismissFieldEditor();
// Delete the field
await tester.tapGridFieldWithName('New field 1');
await tester.tapHidePropertyButton();
await tester.noFieldWithName('New field 1');
await tester.pumpAndSettle();
});
testWidgets('create checklist field ', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
@@ -157,8 +130,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
for (final fieldType in [
FieldType.Checklist,
@@ -190,7 +162,9 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(ViewLayoutPB.Grid);
await tester.createNewPageWithName(
layout: ViewLayoutPB.Grid,
);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
@@ -9,7 +9,7 @@ import 'util/database_test_op.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('grid', () {
group('database filter', () {
testWidgets('add text filter', (tester) async {
await tester.openV020database();
@@ -1,5 +1,6 @@
import 'package:appflowy/plugins/database_view/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_editor/appflowy_editor.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
@@ -19,8 +20,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -34,8 +34,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -55,8 +54,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -85,8 +83,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -108,8 +105,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -139,13 +135,45 @@ void main() {
}
});
testWidgets('check document is exist in row detail page', (tester) async {
testWidgets('change order of fields and cells', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
// Assert that the first field in the row details page is the select
// option tyoe
tester.assertFirstFieldInRowDetailByType(FieldType.SingleSelect);
// Reorder first field in list
final gesture = await tester.hoverOnFieldInRowDetail(index: 0);
await tester.pumpAndSettle();
await tester.reorderFieldInRowDetail(offset: 30);
// Orders changed, now the checkbox is first
tester.assertFirstFieldInRowDetailByType(FieldType.Checkbox);
await gesture.removePointer();
await tester.pumpAndSettle();
// Reorder second field in list
await tester.hoverOnFieldInRowDetail(index: 1);
await tester.pumpAndSettle();
await tester.reorderFieldInRowDetail(offset: -30);
// First field is now back to select option
tester.assertFirstFieldInRowDetailByType(FieldType.SingleSelect);
});
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();
@@ -154,14 +182,13 @@ void main() {
await tester.assertDocumentExistInRowDetailPage();
});
testWidgets('update the content of the document and re-open it',
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.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -201,8 +228,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@@ -241,12 +267,12 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDeleteRowButton();
await tester.tapEscButton();
@@ -258,12 +284,12 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
await tester.tapRowDetailPageRowActionButton();
await tester.tapRowDetailPageDuplicateRowButton();
await tester.tapEscButton();
@@ -1,3 +1,4 @@
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -12,8 +13,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.tapCreateRowButtonInGrid();
// The initial number of rows is 3
@@ -25,8 +25,8 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
await tester.tapCreateRowButtonInRowMenuOfGrid();
@@ -41,8 +41,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
// Open the row menu and then click the delete
@@ -60,8 +59,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.assertRowCountInGridPage(3);
await tester.pumpAndSettle();
@@ -1,4 +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:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -13,8 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// open setting
await tester.tapDatabaseSettingButton();
@@ -31,8 +31,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// open setting
await tester.tapDatabaseSettingButton();
@@ -122,17 +122,17 @@ void main() {
}
// check the checklist cell
final List<double> checklistCells = [
0.6,
0.3,
final List<double?> checklistCells = [
0.67,
0.33,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
null,
null,
null,
null,
null,
null,
null,
];
for (final (index, percent) in checklistCells.indexed) {
await tester.assertChecklistCellInGrid(
@@ -157,7 +157,6 @@ void main() {
for (final (index, content) in dateCells.indexed) {
await tester.assertDateCellInGrid(
rowIndex: index,
fieldType: FieldType.DateTime,
content: content,
);
}
@@ -10,22 +10,22 @@ void main() {
group('grid', () {
testWidgets('add text sort', (tester) async {
await tester.openV020database();
// create a filter
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.RichText, 'Name');
// check the text cell order
final textCells = <String>[
'',
'',
'',
'',
'',
'A',
'B',
'C',
'D',
'E',
'',
'',
'',
'',
'',
];
for (final (index, content) in textCells.indexed) {
await tester.assertCellContent(
@@ -142,7 +142,6 @@ void main() {
// check the number cell order
for (final (index, content) in <String>[
'',
'-2',
'-1',
'0.1',
@@ -152,6 +151,7 @@ void main() {
'10',
'11',
'12',
'',
].indexed) {
await tester.assertCellContent(
rowIndex: index,
@@ -186,53 +186,74 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('add number and text sort', (tester) async {
testWidgets('add checkbox and number sort', (tester) async {
await tester.openV020database();
// create a filter
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
// open the sort menu and select number order by descending
// open the sort menu and sort checkbox by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('number');
await tester.tapSortButtonByName('Done');
await tester.tapSortByDescending();
for (final (index, content) in <String>[
'12',
'11',
'10',
'2',
'1',
'0.2',
'0.1',
'-1',
'-2',
'',
for (final (index, content) in <bool>[
true,
true,
true,
true,
true,
false,
false,
false,
false,
false,
].indexed) {
await tester.assertCellContent(
await tester.assertCheckboxCell(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
isSelected: content,
);
}
// add another sort, this time by number descending
await tester.tapSortMenuInSettingBar();
await tester.tapCreateSortByFieldTypeInSortMenu(
FieldType.RichText,
'Name',
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',
'',
'-1',
'-2',
'0.1',
'0.2',
'1',
].indexed) {
await tester.assertCellContent(
rowIndex: index,
@@ -241,26 +262,6 @@ void main() {
);
}
// check text cell order
for (final (index, content) in <String>[
'',
'',
'',
'',
'',
'A',
'B',
'C',
'D',
'E',
].indexed) {
await tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
);
}
await tester.pumpAndSettle();
});
});
@@ -15,8 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.board);
@@ -37,8 +36,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.board);
@@ -63,8 +61,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.tapAddButton();
await tester.tapCreateGridButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(AddButtonAction.board);
@@ -0,0 +1,46 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('document alignment', () {
testWidgets('edit alignment in toolbar', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
final selection = Selection.single(
path: [0],
startOffset: 0,
endOffset: 1,
);
// click the first line of the readme
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.updateSelection(selection);
await tester.pumpAndSettle();
// click the align center
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_left_s);
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_center_s);
// expect to see the align center
final editorState = tester.editor.getCurrentEditorState();
final first = editorState.getNodeAtPath([0])!;
expect(first.attributes[blockComponentAlign], 'center');
// click the align right
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_center_s);
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_right_s);
expect(first.attributes[blockComponentAlign], 'right');
// click the align left
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_right_s);
await tester.tapButtonWithFlowySvgData(FlowySvgs.toolbar_align_left_s);
expect(first.attributes[blockComponentAlign], 'left');
});
});
}
@@ -0,0 +1,60 @@
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('paste in codeblock', () {
testWidgets('paste multiple lines in codeblock', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName();
// mock the clipboard
const lines = 3;
final text = List.generate(lines, (index) => 'line $index').join('\n');
AppFlowyClipboard.mockSetData(
AppFlowyClipboardData(
text: text,
),
);
await insertCodeBlockInDocument(tester);
// paste the text
await tester.simulateKeyEvent(
LogicalKeyboardKey.keyV,
isControlPressed: Platform.isLinux || Platform.isWindows,
isMetaPressed: Platform.isMacOS,
);
await tester.pumpAndSettle();
final editorState = tester.editor.getCurrentEditorState();
expect(editorState.document.root.children.length, 1);
expect(
editorState.getNodeAtPath([0])!.delta!.toPlainText(),
text,
);
});
});
}
/// Inserts an codeBlock in the document
Future<void> insertCodeBlockInDocument(WidgetTester tester) async {
// open the actions menu and insert the codeBlock
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_selectionMenu_codeBlock.tr(),
);
await tester.pumpAndSettle();
}
@@ -0,0 +1,316 @@
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:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('copy and paste in document', () {
testWidgets('paste multiple lines at the first line', (tester) async {
// mock the clipboard
const lines = 3;
await tester.pasteContent(
plainText: List.generate(lines, (index) => 'line $index').join('\n'),
(editorState) {
expect(editorState.document.root.children.length, 3);
for (var i = 0; i < lines; i++) {
expect(
editorState.getNodeAtPath([i])!.delta!.toPlainText(),
'line $i',
);
}
},
);
});
// ## **User Installation**
// - [Windows/Mac/Linux](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages)
// - [Docker](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker)
// - [Source](https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source)
testWidgets('paste content from html, sample 1', (tester) async {
await tester.pasteContent(
html:
'''<meta charset='utf-8'><h2><strong>User Installation</strong></h2>
<ul>
<li><a href="https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages">Windows/Mac/Linux</a></li>
<li><a href="https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker">Docker</a></li>
<li><a href="https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source">Source</a></li>
</ul>''',
(editorState) {
expect(editorState.document.root.children.length, 4);
final node1 = editorState.getNodeAtPath([0])!;
final node2 = editorState.getNodeAtPath([1])!;
final node3 = editorState.getNodeAtPath([2])!;
final node4 = editorState.getNodeAtPath([3])!;
expect(node1.delta!.toJson(), [
{
"insert": "User Installation",
"attributes": {"bold": true},
}
]);
expect(node2.delta!.toJson(), [
{
"insert": "Windows/Mac/Linux",
"attributes": {
"href":
"https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/mac-windows-linux-packages",
},
}
]);
expect(
node3.delta!.toJson(),
[
{
"insert": "Docker",
"attributes": {
"href":
"https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/installing-with-docker",
},
}
],
);
expect(
node4.delta!.toJson(),
[
{
"insert": "Source",
"attributes": {
"href":
"https://appflowy.gitbook.io/docs/essential-documentation/install-appflowy/installation-methods/from-source",
},
}
],
);
},
);
});
testWidgets('paste code from VSCode', (tester) async {
await tester.pasteContent(
html:
'''<meta charset='utf-8'><div style="color: #bbbbbb;background-color: #262335;font-family: Consolas, 'JetBrains Mono', monospace, 'cascadia code', Menlo, Monaco, 'Courier New', monospace;font-weight: normal;font-size: 14px;line-height: 21px;white-space: pre;"><div><span style="color: #fede5d;">void</span><span style="color: #ff7edb;"> </span><span style="color: #36f9f6;">main</span><span style="color: #ff7edb;">() {</span></div><div><span style="color: #ff7edb;"> </span><span style="color: #36f9f6;">runApp</span><span style="color: #ff7edb;">(</span><span style="color: #fede5d;">const</span><span style="color: #ff7edb;"> </span><span style="color: #fe4450;">MyApp</span><span style="color: #ff7edb;">());</span></div><div><span style="color: #ff7edb;">}</span></div></div>''',
(editorState) {
expect(editorState.document.root.children.length, 3);
final node1 = editorState.getNodeAtPath([0])!;
final node2 = editorState.getNodeAtPath([1])!;
final node3 = editorState.getNodeAtPath([2])!;
expect(node1.type, ParagraphBlockKeys.type);
expect(node2.type, ParagraphBlockKeys.type);
expect(node3.type, ParagraphBlockKeys.type);
expect(node1.delta!.toJson(), [
{
"insert": "void",
"attributes": {"font_color": "0xfffede5d"},
},
{
"insert": " ",
"attributes": {"font_color": "0xffff7edb"},
},
{
"insert": "main",
"attributes": {"font_color": "0xff36f9f6"},
},
{
"insert": "() {",
"attributes": {"font_color": "0xffff7edb"},
}
]);
expect(node2.delta!.toJson(), [
{
"insert": " ",
"attributes": {"font_color": "0xffff7edb"},
},
{
"insert": "runApp",
"attributes": {"font_color": "0xff36f9f6"},
},
{
"insert": "(",
"attributes": {"font_color": "0xffff7edb"},
},
{
"insert": "const",
"attributes": {"font_color": "0xfffede5d"},
},
{
"insert": " ",
"attributes": {"font_color": "0xffff7edb"},
},
{
"insert": "MyApp",
"attributes": {"font_color": "0xfffe4450"},
},
{
"insert": "());",
"attributes": {"font_color": "0xffff7edb"},
}
]);
expect(node3.delta!.toJson(), [
{
"insert": "}",
"attributes": {"font_color": "0xffff7edb"},
}
]);
});
});
});
testWidgets('paste image(png) from memory', (tester) async {
final image = await rootBundle.load('assets/test/images/sample.png');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(image: ('png', bytes), (editorState) {
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotNull);
});
});
testWidgets('paste image(jpeg) from memory', (tester) async {
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(image: ('jpeg', bytes), (editorState) {
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotNull);
});
});
testWidgets('paste image(gif) from memory', (tester) async {
// It's not supported yet.
// final image = await rootBundle.load('assets/test/images/sample.gif');
// final bytes = image.buffer.asUint8List();
// await tester.pasteContent(image: ('gif', bytes), (editorState) {
// expect(editorState.document.root.children.length, 2);
// final node = editorState.getNodeAtPath([0])!;
// expect(node.type, ImageBlockKeys.type);
// expect(node.attributes[ImageBlockKeys.url], isNotNull);
// });
});
testWidgets(
'format the selected text to href when pasting url if available',
(tester) async {
const text = 'appflowy';
const url = 'https://appflowy.io';
await tester.pasteContent(
plainText: url,
beforeTest: (editorState) async {
await tester.ime.insertText(text);
await tester.editor.updateSelection(
Selection.single(
path: [0],
startOffset: 0,
endOffset: text.length,
),
);
},
(editorState) {
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ParagraphBlockKeys.type);
expect(node.delta!.toJson(), [
{
'insert': text,
'attributes': {'href': url}
}
]);
},
);
},
);
// https://github.com/AppFlowy-IO/AppFlowy/issues/3263
testWidgets(
'paste the image from clipboard when html and image are both available',
(tester) async {
const html =
'''<meta charset='utf-8'><img src="https://user-images.githubusercontent.com/9403740/262918875-603f4adb-58dd-49b5-8201-341d354935fd.png" alt="image"/>''';
final image = await rootBundle.load('assets/test/images/sample.png');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(
html: html,
image: ('png', bytes),
(editorState) {
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(
node.attributes[ImageBlockKeys.url],
'https://user-images.githubusercontent.com/9403740/262918875-603f4adb-58dd-49b5-8201-341d354935fd.png',
);
},
);
},
);
testWidgets('paste the html content contains section', (tester) async {
const html =
'''<meta charset='utf-8'><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;">AppFlowy</strong></span></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;">Hello World</strong></span></section>''';
await tester.pasteContent(
html: html,
(editorState) {
expect(editorState.document.root.children.length, 2);
final node1 = editorState.getNodeAtPath([0])!;
final node2 = editorState.getNodeAtPath([1])!;
expect(node1.type, ParagraphBlockKeys.type);
expect(node2.type, ParagraphBlockKeys.type);
},
);
});
testWidgets('paste the html from google translation', (tester) async {
const html =
'''<meta charset='utf-8'><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;">new force</font></font></strong></span></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;">Assessment focus: potential motivations, empathy</font></font></strong></span></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><br style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;"></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-Line truncated
await tester.pasteContent(
html: html,
(editorState) {
expect(editorState.document.root.children.length, 8);
},
);
});
}
extension on WidgetTester {
Future<void> pasteContent(
void Function(EditorState editorState) test, {
Future<void> Function(EditorState editorState)? beforeTest,
String? plainText,
String? html,
(String, Uint8List?)? image,
}) async {
await initializeAppFlowy();
await tapGoButton();
// create a new document
await createNewPageWithName();
await beforeTest?.call(editor.getCurrentEditorState());
// mock the clipboard
await getIt<ClipboardService>().setData(
ClipboardServiceData(
plainText: plainText,
html: html,
image: image,
),
);
// paste the text
await simulateKeyEvent(
LogicalKeyboardKey.keyV,
isControlPressed: Platform.isLinux || Platform.isWindows,
isMetaPressed: Platform.isMacOS,
);
await pumpAndSettle();
test(editor.getCurrentEditorState());
}
}
@@ -17,9 +17,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.tapAddButton();
await tester.tapCreateDocumentButton();
await tester.pumpAndSettle();
await tester.createNewPageWithName();
// expect to see a new document
tester.expectToSeePageName(
@@ -35,19 +33,21 @@ void main() {
await tester.tapGoButton();
// delete the readme page
await tester.hoverOnPageName(readme);
await tester.tapDeletePageButton();
await tester.hoverOnPageName(
gettingStarted,
onHover: () async => await tester.tapDeletePageButton(),
);
// the banner should show up and the readme page should be gone
tester.expectToSeeDocumentBanner();
tester.expectNotToSeePageName(readme);
tester.expectNotToSeePageName(gettingStarted);
// restore the readme page
await tester.tapRestoreButton();
// the banner should be gone and the readme page should be back
tester.expectNotToSeeDocumentBanner();
tester.expectToSeePageName(readme);
tester.expectToSeePageName(gettingStarted);
});
testWidgets('delete the readme page and delete it permanently',
@@ -57,19 +57,21 @@ void main() {
await tester.tapGoButton();
// delete the readme page
await tester.hoverOnPageName(readme);
await tester.tapDeletePageButton();
await tester.hoverOnPageName(
gettingStarted,
onHover: () async => await tester.tapDeletePageButton(),
);
// the banner should show up and the readme page should be gone
tester.expectToSeeDocumentBanner();
tester.expectNotToSeePageName(readme);
tester.expectNotToSeePageName(gettingStarted);
// delete the page permanently
await tester.tapDeletePermanentlyButton();
// the banner should be gone and the readme page should be gone
tester.expectNotToSeeDocumentBanner();
tester.expectNotToSeePageName(readme);
tester.expectNotToSeePageName(gettingStarted);
});
});
}
@@ -1,5 +1,8 @@
import 'package:integration_test/integration_test.dart';
import 'document_alignment_test.dart' as document_alignment_test;
import 'document_codeblock_paste_test.dart' as document_codeblock_paste_test;
import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
import 'document_create_and_delete_test.dart'
as document_create_and_delete_test;
import 'document_with_cover_image_test.dart' as document_with_cover_image_test;
@@ -7,9 +10,9 @@ import 'document_with_database_test.dart' as document_with_database_test;
import 'document_with_inline_math_equation_test.dart'
as document_with_inline_math_equation_test;
import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
import 'document_with_outline_block_test.dart' as document_with_outline_block;
import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
import 'edit_document_test.dart' as document_edit_test;
import 'document_with_outline_block_test.dart' as document_with_outline_block;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -23,4 +26,7 @@ void startTesting() {
document_with_cover_image_test.main();
document_with_outline_block.main();
document_with_toggle_list_test.main();
document_copy_and_paste_test.main();
document_codeblock_paste_test.main();
document_alignment_test.main();
}
@@ -1,9 +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/document/presentation/editor_plugins/base/link_to_page_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -61,6 +64,54 @@ void main() {
findsOneWidget,
);
});
testWidgets('create a grid inside a document', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await createInlineDatabase(tester, ViewLayoutPB.Grid);
// validate the referenced grid is inserted
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.byType(GridPage),
),
findsOneWidget,
);
});
testWidgets('create a board inside a document', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await createInlineDatabase(tester, ViewLayoutPB.Board);
// validate the referenced grid is inserted
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.byType(BoardPage),
),
findsOneWidget,
);
});
testWidgets('create a calendar inside a document', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await createInlineDatabase(tester, ViewLayoutPB.Calendar);
// validate the referenced grid is inserted
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.byType(CalendarPage),
),
findsOneWidget,
);
});
});
}
@@ -73,13 +124,15 @@ Future<void> insertReferenceDatabase(
final id = uuid();
final name = '${layout.name}_$id';
await tester.createNewPageWithName(
layout,
name,
name: name,
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
'insert_a_reference_${layout.name}',
name: 'insert_a_reference_${layout.name}',
layout: ViewLayoutPB.Document,
openAfterCreated: true,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -98,3 +151,38 @@ Future<void> insertReferenceDatabase(
expect(referencedDatabase, findsOneWidget);
await tester.tapButton(referencedDatabase);
}
Future<void> createInlineDatabase(
WidgetTester tester,
ViewLayoutPB layout,
) async {
// create a new document
final documentName = 'insert_a_inline_${layout.name}';
await tester.createNewPageWithName(
name: documentName,
layout: ViewLayoutPB.Document,
openAfterCreated: true,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
// insert a referenced view
await tester.editor.showSlashMenu();
final name = switch (layout) {
ViewLayoutPB.Grid => LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
ViewLayoutPB.Board =>
LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
ViewLayoutPB.Calendar =>
LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr(),
_ => '',
};
await tester.editor.tapSlashMenuItemWithName(
name,
);
await tester.pumpAndSettle();
final childViews = tester
.widget<SingleInnerViewItem>(tester.findPageName(documentName))
.view
.childViews;
expect(childViews.length, 1);
}
@@ -21,8 +21,8 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
name: LocaleKeys.document_plugins_createInlineMathEquation.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -67,8 +67,8 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
name: LocaleKeys.document_plugins_createInlineMathEquation.tr(),
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -62,9 +62,11 @@ void main() {
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Document);
// rename
await tester.hoverOnPageName(pageName);
const newName = 'RenameToNewPageName';
await tester.renamePage(newName);
await tester.hoverOnPageName(
pageName,
onHover: () async => await tester.renamePage(newName),
);
final finder = find.descendant(
of: find.byType(MentionPageBlock),
matching: find.findTextInFlowyText(newName),
@@ -79,8 +81,11 @@ void main() {
final pageName = await insertingInlinePage(tester, ViewLayoutPB.Grid);
// rename
await tester.hoverOnPageName(pageName);
await tester.tapDeletePageButton();
await tester.hoverOnPageName(
pageName,
layout: ViewLayoutPB.Grid,
onHover: () async => await tester.tapDeletePageButton(),
);
final finder = find.descendant(
of: find.byType(MentionPageBlock),
matching: find.findTextInFlowyText(pageName),
@@ -101,13 +106,14 @@ Future<String> insertingInlinePage(
final id = uuid();
final name = '${layout.name}_$id';
await tester.createNewPageWithName(
layout,
name,
name: name,
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
'insert_a_inline_page_${layout.name}',
name: 'insert_a_inline_page_${layout.name}',
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
await tester.editor.tapLineOfEditorAt(0);
@@ -25,7 +25,7 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -16,8 +16,8 @@ void main() {
await tester.tapGoButton();
await tester.createNewPageWithName(
ViewLayoutPB.Document,
'outline_test',
name: 'outline_test',
layout: ViewLayoutPB.Document,
);
await tester.editor.tapLineOfEditorAt(0);
@@ -33,8 +33,8 @@ void main() {
await tester.tapGoButton();
await tester.createNewPageWithName(
ViewLayoutPB.Document,
'outline_test',
name: 'outline_test',
layout: ViewLayoutPB.Document,
);
await tester.editor.tapLineOfEditorAt(0);
@@ -32,7 +32,7 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -78,7 +78,7 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -93,9 +93,8 @@ void main() {
// Press the enter key
await tester.editor.updateSelection(
Selection.collapse(
[0],
'Hello '.length,
Selection.collapsed(
Position(path: [0], offset: 'Hello '.length),
),
);
await tester.ime.insertCharacter('\n');
@@ -118,7 +117,7 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -129,9 +128,8 @@ void main() {
// Press the enter key
await tester.editor.updateSelection(
Selection.collapse(
[0],
'Hello '.length,
Selection.collapsed(
Position(path: [0], offset: 'Hello '.length),
),
);
await tester.ime.insertCharacter('\n');
@@ -156,7 +154,7 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -170,9 +168,8 @@ void main() {
await tester.tapButton(toggleListIcon);
await tester.editor.updateSelection(
Selection.collapse(
[0],
0,
Selection.collapsed(
Position(path: [0], offset: 0),
),
);
await tester.ime.insertCharacter('\n');
@@ -191,7 +188,7 @@ void main() {
// create a new document
await tester.createNewPageWithName(
ViewLayoutPB.Document,
layout: ViewLayoutPB.Document,
);
// tap the first line of the document
@@ -202,9 +199,8 @@ void main() {
expectToggleListOpened();
await tester.editor.updateSelection(
Selection.collapse(
[0],
0,
Selection.collapsed(
Position(path: [0], offset: 0),
),
);
await tester.simulateKeyEvent(
@@ -18,7 +18,10 @@ void main() {
// create a new document called Sample
const pageName = 'Sample';
await tester.createNewPageWithName(ViewLayoutPB.Document, pageName);
await tester.createNewPageWithName(
name: pageName,
layout: ViewLayoutPB.Document,
);
// focus on the editor
await tester.editor.tapLineOfEditorAt(0);
@@ -56,7 +59,7 @@ void main() {
);
// switch to other page and switch back
await tester.openPage(readme);
await tester.openPage(gettingStarted);
await tester.openPage(pageName);
// the numbered list should be kept
@@ -72,7 +75,10 @@ void main() {
// create a new document called Sample
const pageName = 'Sample';
await tester.createNewPageWithName(ViewLayoutPB.Document, pageName);
await tester.createNewPageWithName(
name: pageName,
layout: ViewLayoutPB.Document,
);
// focus on the editor
await tester.editor.tapLineOfEditorAt(0);
@@ -85,7 +91,7 @@ void main() {
}
// switch to other page and switch back
await tester.openPage(readme);
await tester.openPage(gettingStarted);
await tester.openPage(pageName);
// this screenshots are different on different platform, so comment it out temporarily.
@@ -1,7 +1,7 @@
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
@@ -75,7 +75,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.byType(HomeMenu), findsOneWidget);
expect(find.byType(HomeSideBar), findsOneWidget);
await FlowyTestKeyboard.simulateKeyDownEvent(
[
@@ -89,7 +89,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.byType(HomeMenu), findsNothing);
expect(find.byType(HomeSideBar), findsNothing);
});
});
}
@@ -16,10 +16,10 @@ void main() {
final context = await tester.initializeAppFlowy();
await tester.tapGoButton();
// expect to see a readme page
tester.expectToSeePageName(readme);
// expect to see a getting started page
tester.expectToSeePageName(gettingStarted);
await tester.tapAddButton();
await tester.tapAddViewButton();
await tester.tapImportButton();
final testFileNames = ['test1.md', 'test2.md'];
@@ -1,8 +1,10 @@
import 'package:appflowy/env/env.dart';
import 'package:integration_test/integration_test.dart';
import 'database_calendar_test.dart' as database_calendar_test;
import 'database_cell_test.dart' as database_cell_test;
import 'database_field_test.dart' as database_field_test;
import 'database_field_settings_test.dart' as database_field_settings_test;
import 'database_filter_test.dart' as database_filter_test;
import 'database_row_page_test.dart' as database_row_page_test;
import 'database_row_test.dart' as database_row_test;
@@ -14,6 +16,12 @@ import 'document/document_test_runner.dart' as document_test_runner;
import 'import_files_test.dart' as import_files_test;
import 'share_markdown_test.dart' as share_markdown_test;
import 'switch_folder_test.dart' as switch_folder_test;
import 'sidebar/sidebar_test_runner.dart' as sidebar_test_runner;
import 'board/board_test_runner.dart' as board_test_runner;
import 'tabs_test.dart' as tabs_test;
import 'hotkeys_test.dart' as hotkeys_test;
import 'appearance_settings_test.dart' as appearance_test_runner;
import 'auth/auth_test.dart' as auth_test_runner;
/// The main task runner for all integration tests in AppFlowy.
///
@@ -31,9 +39,16 @@ void main() {
// Document integration tests
document_test_runner.startTesting();
// Sidebar integration tests
sidebar_test_runner.startTesting();
// Board integration test
board_test_runner.startTesting();
// Database integration tests
database_cell_test.main();
database_field_test.main();
database_field_settings_test.main();
database_share_test.main();
database_row_page_test.main();
database_row_test.main();
@@ -43,6 +58,19 @@ void main() {
database_view_test.main();
database_calendar_test.main();
// Tabs
tabs_test.main();
// Others
hotkeys_test.main();
// Appearance integration test
appearance_test_runner.main();
if (isSupabaseEnabled) {
auth_test_runner.main();
}
// board_test.main();
// empty_document_test.main();
// smart_menu_test.main();
@@ -16,7 +16,7 @@ void main() {
await tester.tapGoButton();
// expect to see a readme page
tester.expectToSeePageName(readme);
tester.expectToSeePageName(gettingStarted);
// mock the file picker
final path = await mockSaveFilePath(
@@ -42,12 +42,16 @@ void main() {
final context = await tester.initializeAppFlowy();
await tester.tapGoButton();
// expect to see a readme page
tester.expectToSeePageName(readme);
// expect to see a getting started page
tester.expectToSeePageName(gettingStarted);
// rename the document
await tester.hoverOnPageName(readme);
await tester.renamePage('example');
await tester.hoverOnPageName(
gettingStarted,
onHover: () async {
await tester.renamePage('example');
},
);
final shareButton = find.byType(ShareActionList);
final shareButtonState =
@@ -90,6 +94,13 @@ const expectedMarkdown = r'''
1. Keyboard shortcuts [guide](https://appflowy.gitbook.io/docs/essential-documentation/shortcuts)
1. Markdown [reference](https://appflowy.gitbook.io/docs/essential-documentation/markdown)
1. Type `/code` to insert a code block
```rust
// This is the main function.
fn main() {
// Print text to the console.
println!("Hello World!");
}
```
## Have a question❓
> Click `?` at the bottom right for help and support.
@@ -0,0 +1,48 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sidebar expand test', () {
bool isExpanded({required FolderCategoryType type}) {
if (type == FolderCategoryType.personal) {
return find
.descendant(
of: find.byType(PersonalFolder),
matching: find.byType(ViewItem),
)
.evaluate()
.isNotEmpty;
}
return false;
}
testWidgets('first time the personal folder is expanded', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// first time is expanded
expect(isExpanded(type: FolderCategoryType.personal), true);
// collapse the personal folder
await tester.tapButton(
find.byTooltip(LocaleKeys.sideBar_clickToHidePersonal.tr()),
);
expect(isExpanded(type: FolderCategoryType.personal), false);
// expand the personal folder
await tester.tapButton(
find.byTooltip(LocaleKeys.sideBar_clickToHidePersonal.tr()),
);
expect(isExpanded(type: FolderCategoryType.personal), true);
});
});
}
@@ -0,0 +1,222 @@
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';
import 'package:integration_test/integration_test.dart';
import '../util/base.dart';
import '../util/common_operations.dart';
import '../util/expectation.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Favorites', () {
testWidgets(
'Toggle favorites for views creates / removes the favorite header along with favorite views',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// no favorite folder
expect(find.byType(FavoriteFolder), findsNothing);
// create the nested views
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(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(
names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
parentLayout: ViewLayoutPB.Document,
);
}
await tester.favoriteViewByName(gettingStarted);
expect(
tester.findFavoritePageName(gettingStarted),
findsOneWidget,
);
await tester.favoriteViewByName(names[1]);
expect(
tester.findFavoritePageName(names[1]),
findsNWidgets(2),
);
await tester.unfavoriteViewByName(gettingStarted);
expect(
tester.findFavoritePageName(gettingStarted),
findsNothing,
);
expect(
tester.findFavoritePageName(
names[1],
),
findsOneWidget,
);
await tester.unfavoriteViewByName(names[1]);
expect(
tester.findFavoritePageName(
names[1],
),
findsNothing,
);
});
testWidgets(
'renaming a favorite view updates name under favorite header',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
const name = 'test';
await tester.favoriteViewByName(gettingStarted);
await tester.hoverOnPageName(
gettingStarted,
layout: ViewLayoutPB.Document,
onHover: () async {
await tester.renamePage(name);
await tester.pumpAndSettle();
},
);
expect(
tester.findPageName(name),
findsNWidgets(2),
);
expect(
tester.findFavoritePageName(name),
findsNothing,
);
},
);
testWidgets(
'deleting first level favorite view removes its instance from favorite header, deleting root level views leads to removal of all favorites that are its children',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
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(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(names[i], parentName: parentName);
}
await tester.favoriteViewByName(gettingStarted);
await tester.favoriteViewByName(names[0]);
await tester.favoriteViewByName(names[1]);
expect(
find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
),
findsNWidgets(6),
);
await tester.hoverOnPageName(
names[1],
layout: ViewLayoutPB.Document,
onHover: () async {
await tester.tapDeletePageButton();
await tester.pumpAndSettle();
},
);
expect(
find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
),
findsNWidgets(3),
);
await tester.hoverOnPageName(
gettingStarted,
layout: ViewLayoutPB.Document,
onHover: () async {
await tester.tapDeletePageButton();
await tester.pumpAndSettle();
},
);
expect(
find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite,
),
findsNothing,
);
},
);
testWidgets(
'view selection is synced between favorites and personal folder',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName();
await tester.favoriteViewByName(gettingStarted);
expect(
find.byWidgetPredicate(
(widget) =>
widget is FlowyHover &&
widget.isSelected != null &&
widget.isSelected!(),
),
findsNWidgets(2),
);
},
);
testWidgets(
'context menu opens up for favorites',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName();
await tester.favoriteViewByName(gettingStarted);
await tester.hoverOnPageName(
gettingStarted,
layout: ViewLayoutPB.Document,
useLast: false,
onHover: () async {
await tester.tapPageOptionButton();
await tester.pumpAndSettle();
expect(
find.byType(PopoverContainer),
findsOneWidget,
);
},
);
await tester.pumpAndSettle();
},
);
});
}
@@ -0,0 +1,207 @@
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/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_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sidebar test', () {
testWidgets('create a new page', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
// create a new page
await tester.tapNewPageButton();
// expect to see a new document
tester.expectToSeePageName(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
);
// and with one paragraph block
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
});
testWidgets('create a new document, grid, board and calendar',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
for (final layout in ViewLayoutPB.values) {
// create a new page
final name = 'AppFlowy_$layout';
await tester.createNewPageWithName(
name: name,
layout: layout,
);
// expect to see a new page
tester.expectToSeePageName(
name,
layout: layout,
);
switch (layout) {
case ViewLayoutPB.Document:
// and with one paragraph block
expect(find.byType(TextBlockComponentWidget), findsOneWidget);
break;
case ViewLayoutPB.Grid:
expect(find.byType(GridPage), findsOneWidget);
break;
case ViewLayoutPB.Board:
expect(find.byType(BoardPage), findsOneWidget);
break;
case ViewLayoutPB.Calendar:
expect(find.byType(CalendarPage), findsOneWidget);
break;
}
await tester.openPage(gettingStarted);
}
});
testWidgets('create some nested pages, and move them', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
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(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
);
tester.expectToSeePageName(names[i], parentName: parentName);
}
// move the document_3 to the getting started page
await tester.movePageToOtherPage(
name: names[3],
parentName: gettingStarted,
layout: ViewLayoutPB.Document,
parentLayout: ViewLayoutPB.Document,
);
final fromId = tester
.widget<SingleInnerViewItem>(tester.findPageName(names[3]))
.view
.parentViewId;
final toId = tester
.widget<SingleInnerViewItem>(tester.findPageName(gettingStarted))
.view
.id;
expect(fromId, toId);
// move the document_2 before document_1
await tester.movePageToOtherPage(
name: names[2],
parentName: gettingStarted,
layout: ViewLayoutPB.Document,
parentLayout: ViewLayoutPB.Document,
position: DraggableHoverPosition.bottom,
);
final childViews = tester
.widget<SingleInnerViewItem>(tester.findPageName(gettingStarted))
.view
.childViews;
expect(
childViews[0].id,
tester
.widget<SingleInnerViewItem>(tester.findPageName(names[2]))
.view
.id,
);
expect(
childViews[1].id,
tester
.widget<SingleInnerViewItem>(tester.findPageName(names[0]))
.view
.id,
);
expect(
childViews[2].id,
tester
.widget<SingleInnerViewItem>(tester.findPageName(names[3]))
.view
.id,
);
});
testWidgets('unable to move a document into a database', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
const document = 'document';
await tester.createNewPageWithName(
name: document,
openAfterCreated: false,
);
tester.expectToSeePageName(document, layout: ViewLayoutPB.Document);
const grid = 'grid';
await tester.createNewPageWithName(
name: grid,
layout: ViewLayoutPB.Grid,
openAfterCreated: false,
);
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
// move the document to the grid page
await tester.movePageToOtherPage(
name: document,
parentName: grid,
layout: ViewLayoutPB.Document,
parentLayout: ViewLayoutPB.Grid,
);
// it should not be moved
final childViews = tester
.widget<SingleInnerViewItem>(tester.findPageName(gettingStarted))
.view
.childViews;
expect(
childViews[0].name,
document,
);
expect(
childViews[1].name,
grid,
);
});
testWidgets('unable to create a new database inside the existing one',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
const grid = 'grid';
await tester.createNewPageWithName(
name: grid,
layout: ViewLayoutPB.Grid,
openAfterCreated: true,
);
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
await tester.hoverOnPageName(
grid,
layout: ViewLayoutPB.Grid,
onHover: () async {
expect(find.byType(ViewAddButton), findsNothing);
expect(find.byType(ViewMoreActionButton), findsOneWidget);
},
);
});
});
}
@@ -0,0 +1,14 @@
import 'package:integration_test/integration_test.dart';
import 'sidebar_test.dart' as sidebar_test;
import 'sidebar_expand_test.dart' as sidebar_expanded_test;
import 'sidebar_favorites_test.dart' as sidebar_favorite_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// Sidebar integration tests
sidebar_test.main();
sidebar_expanded_test.main();
sidebar_favorite_test.main();
}
@@ -1,23 +1,26 @@
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:flutter/material.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/expectation.dart';
import 'util/keyboard.dart';
const _readmeName = 'Read me';
const _documentName = 'Document';
const _calendarName = 'Calendar';
const _documentName = 'First Doc';
const _documentTwoName = 'Second Doc';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Tabs', () {
testWidgets('Open AppFlowy and open/navigate multiple tabs',
(tester) async {
testWidgets('Open AppFlowy and open/navigate/close tabs', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
@@ -29,25 +32,21 @@ void main() {
findsNothing,
);
await tester.createNewPageWithName(ViewLayoutPB.Calendar, _calendarName);
await tester.createNewPageWithName(ViewLayoutPB.Document, _documentName);
await tester.createNewPageWithName(
name: _documentName,
layout: ViewLayoutPB.Document,
);
// Navigate current view to "Read me" document again
await tester.tapButtonWithName(_readmeName);
await tester.createNewPageWithName(
name: _documentTwoName,
layout: ViewLayoutPB.Document,
);
/// Open second menu item in a new tab
await tester.openAppInNewTab(_calendarName);
await tester.openAppInNewTab(gettingStarted, ViewLayoutPB.Document);
/// Open third menu item in a new tab
await tester.openAppInNewTab(_documentName);
expect(
find.descendant(
of: find.byType(TabsManager),
matching: find.byType(TabBar),
),
findsOneWidget,
);
await tester.openAppInNewTab(_documentName, ViewLayoutPB.Document);
expect(
find.descendant(
@@ -57,13 +56,32 @@ void main() {
findsNWidgets(3),
);
/// Navigate to the first tab
/// Navigate to the second tab
await tester.tap(
find.descendant(
of: find.byType(FlowyTab),
matching: find.text(_readmeName),
matching: find.text(gettingStarted),
),
);
/// Close tab by shortcut
await FlowyTestKeyboard.simulateKeyDownEvent(
[
Platform.isMacOS
? LogicalKeyboardKey.meta
: LogicalKeyboardKey.control,
LogicalKeyboardKey.keyW,
],
tester: tester,
);
expect(
find.descendant(
of: find.byType(TabBar),
matching: find.byType(FlowyTab),
),
findsNWidgets(2),
);
});
});
}
@@ -0,0 +1,64 @@
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/sync_setting_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'base.dart';
extension AppFlowyAuthTest on WidgetTester {
Future<void> tapGoogleLoginInButton() async {
await tapButton(find.byKey(const Key('signInWithGoogleButton')));
}
Future<void> tapSignInAsGuest() async {
await tapButton(find.byType(SignInAnonymousButton));
}
void expectToSeeGoogleLoginButton() {
expect(find.byKey(const Key('signInWithGoogleButton')), findsOneWidget);
}
void assertSwitchValue(Finder finder, bool value) {
final Switch switchWidget = widget(finder);
final isSwitched = switchWidget.value;
assert(isSwitched == value);
}
void assertEnableEncryptSwitchValue(bool value) {
assertSwitchValue(
find.descendant(
of: find.byType(EnableEncrypt),
matching: find.byWidgetPredicate((widget) => widget is Switch),
),
value,
);
}
void assertEnableSyncSwitchValue(bool value) {
assertSwitchValue(
find.descendant(
of: find.byType(EnableSync),
matching: find.byWidgetPredicate((widget) => widget is Switch),
),
value,
);
}
Future<void> toggleEnableEncrypt() async {
final finder = find.descendant(
of: find.byType(EnableEncrypt),
matching: find.byWidgetPredicate((widget) => widget is Switch),
);
await tapButton(finder);
}
Future<void> toggleEnableSync() async {
final finder = find.descendant(
of: find.byType(EnableSync),
matching: find.byWidgetPredicate((widget) => widget is Switch),
);
await tapButton(finder);
}
}
@@ -1,7 +1,9 @@
import 'dart:async';
import 'dart:io';
import 'package:appflowy/startup/entry_point.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/presentation.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -9,8 +11,8 @@ 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_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
class FlowyTestContext {
FlowyTestContext({
@@ -39,8 +41,8 @@ extension AppFlowyTestBase on WidgetTester {
IntegrationMode.integrationTest,
);
await wait(3000);
await pumpAndSettle(const Duration(seconds: 2));
await waitUntilSignInPageShow();
return FlowyTestContext(
applicationDataDirectory: directory,
);
@@ -78,6 +80,27 @@ extension AppFlowyTestBase on WidgetTester {
return directory.path;
}
Future<void> waitUntilSignInPageShow() async {
final finder = find.byType(GoButton);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
}
Future<void> pumpUntilFound(
Finder finder, {
Duration timeout = const Duration(seconds: 10),
}) async {
bool timerDone = false;
final timer = Timer(timeout, () => timerDone = true);
while (timerDone != true) {
await pump();
if (any(finder)) {
timerDone = true;
}
}
timer.cancel();
}
Future<void> tapButton(
Finder finder, {
int? pointer,
@@ -91,7 +114,6 @@ extension AppFlowyTestBase on WidgetTester {
warnIfMissed: warnIfMissed,
);
await pumpAndSettle(Duration(milliseconds: milliseconds));
return;
}
Future<void> tapButtonWithName(
@@ -1,15 +1,21 @@
import 'dart:ui';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
import 'package:appflowy/user/presentation/skip_log_in_screen.dart';
import 'package:appflowy/workspace/presentation/home/menu/app/header/add_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/app/section/item.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/screens/screens.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/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';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -24,35 +30,48 @@ extension CommonOperations on WidgetTester {
}
/// Tap the + button on the home page.
Future<void> tapAddButton() async {
final addButton = find.byType(AddButton);
await tapButton(addButton);
Future<void> tapAddViewButton({
String name = gettingStarted,
}) async {
await hoverOnPageName(
name,
onHover: () async {
final addButton = find.byType(ViewAddButton);
await tapButton(addButton);
},
);
}
/// Tap the 'New Page' Button on the sidebar.
Future<void> tapNewPageButton() async {
final newPageButton = find.byType(SidebarNewPageButton);
await tapButton(newPageButton);
}
/// Tap the create document button.
///
/// Must call [tapAddButton] first.
/// Must call [tapAddViewButton] first.
Future<void> tapCreateDocumentButton() async {
await tapButtonWithName(LocaleKeys.document_menuName.tr());
}
/// Tap the create grid button.
///
/// Must call [tapAddButton] first.
/// Must call [tapAddViewButton] first.
Future<void> tapCreateGridButton() async {
await tapButtonWithName(LocaleKeys.grid_menuName.tr());
}
/// Tap the create grid button.
///
/// Must call [tapAddButton] first.
/// Must call [tapAddViewButton] first.
Future<void> tapCreateCalendarButton() async {
await tapButtonWithName(LocaleKeys.calendar_menuName.tr());
}
/// Tap the import button.
///
/// Must call [tapAddButton] first.
/// Must call [tapAddViewButton] first.
Future<void> tapImportButton() async {
await tapButtonWithName(LocaleKeys.moreAction_import.tr());
}
@@ -116,6 +135,7 @@ extension CommonOperations on WidgetTester {
Finder finder, {
Offset? offset,
Future<void> Function()? onHover,
bool removePointer = true,
}) async {
try {
final gesture = await createGesture(kind: PointerDeviceKind.mouse);
@@ -133,19 +153,30 @@ extension CommonOperations on WidgetTester {
/// Hover on the page name.
Future<void> hoverOnPageName(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
Future<void> Function()? onHover,
bool useLast = true,
}) async {
final pageNames = findPageName(name, layout: layout);
if (useLast) {
await hoverOnWidget(findPageName(name).last, onHover: onHover);
await hoverOnWidget(
pageNames.last,
onHover: onHover,
);
} else {
await hoverOnWidget(findPageName(name).first, onHover: onHover);
await hoverOnWidget(
pageNames.first,
onHover: onHover,
);
}
}
/// open the page with given name.
Future<void> openPage(String name) async {
final finder = findPageName(name);
Future<void> openPage(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
}) async {
final finder = findPageName(name, layout: layout);
expect(finder, findsOneWidget);
await tapButton(finder);
}
@@ -154,20 +185,38 @@ extension CommonOperations on WidgetTester {
///
/// Must call [hoverOnPageName] first.
Future<void> tapPageOptionButton() async {
final optionButton = find.byType(ViewDisclosureButton);
final optionButton = find.byType(ViewMoreActionButton);
await tapButton(optionButton);
}
/// Tap the delete page button.
Future<void> tapDeletePageButton() async {
await tapPageOptionButton();
await tapButtonWithName(ViewDisclosureAction.delete.name);
await tapButtonWithName(ViewMoreActionType.delete.name);
}
/// Tap the rename page button.
Future<void> tapRenamePageButton() async {
await tapPageOptionButton();
await tapButtonWithName(ViewDisclosureAction.rename.name);
await tapButtonWithName(ViewMoreActionType.rename.name);
}
/// Tap the favorite page button
Future<void> tapFavoritePageButton() async {
await tapPageOptionButton();
await tapButtonWithName(ViewMoreActionType.favorite.name);
}
/// Tap the unfavorite page button
Future<void> tapUnfavoritePageButton() async {
await tapPageOptionButton();
await tapButtonWithName(ViewMoreActionType.unFavorite.name);
}
/// Tap the Open in a new tab button
Future<void> tapOpenInTabButton() async {
await tapPageOptionButton();
await tapButtonWithName(ViewMoreActionType.openInNewTab.name);
}
/// Rename the page.
@@ -224,19 +273,30 @@ extension CommonOperations on WidgetTester {
await tapButton(markdownButton);
}
Future<void> createNewPageWithName(
ViewLayoutPB layout, [
Future<void> createNewPageWithName({
String? name,
]) async {
ViewLayoutPB layout = ViewLayoutPB.Document,
String? parentName,
bool openAfterCreated = true,
}) async {
// create a new page
await tapAddButton();
await tapAddViewButton(name: parentName ?? gettingStarted);
await tapButtonWithName(layout.menuName);
final settingsOrFailure = await getIt<KeyValueStorage>().getWithFormat(
KVKeys.showRenameDialogWhenCreatingNewFile,
(value) => bool.parse(value),
);
final showRenameDialog = settingsOrFailure.fold((l) => false, (r) => r);
if (showRenameDialog) {
await tapOKButton();
}
await pumpAndSettle();
// hover on it and change it's name
if (name != null) {
await hoverOnPageName(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout: layout,
onHover: () async {
await renamePage(name);
await pumpAndSettle();
@@ -244,6 +304,16 @@ extension CommonOperations on WidgetTester {
);
await pumpAndSettle();
}
// open the page after created
if (openAfterCreated) {
await openPage(
// if the name is null, use the default name
name ?? LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout: layout,
);
await pumpAndSettle();
}
}
Future<void> simulateKeyEvent(
@@ -282,13 +352,82 @@ extension CommonOperations on WidgetTester {
await pumpAndSettle();
}
Future<void> openAppInNewTab(String name) async {
await hoverOnPageName(name);
await tap(find.byType(ViewDisclosureButton));
Future<void> openAppInNewTab(String name, ViewLayoutPB layout) async {
await hoverOnPageName(
name,
onHover: () async {
await tapOpenInTabButton();
await pumpAndSettle();
},
);
await pumpAndSettle();
await tap(find.text(LocaleKeys.disclosureAction_openNewTab.tr()));
}
Future<void> favoriteViewByName(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
}) async {
await hoverOnPageName(
name,
layout: layout,
useLast: true,
onHover: () async {
await tapFavoritePageButton();
await pumpAndSettle();
},
);
}
Future<void> unfavoriteViewByName(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
}) async {
await hoverOnPageName(
name,
layout: layout,
useLast: true,
onHover: () async {
await tapUnfavoritePageButton();
await pumpAndSettle();
},
);
}
Future<void> movePageToOtherPage({
required String name,
required String parentName,
required ViewLayoutPB layout,
required ViewLayoutPB parentLayout,
DraggableHoverPosition position = DraggableHoverPosition.center,
}) async {
final from = findPageName(name, layout: layout);
final to = findPageName(parentName, layout: parentLayout);
final gesture = await startGesture(getCenter(from));
Offset offset = Offset.zero;
switch (position) {
case DraggableHoverPosition.center:
offset = getCenter(to);
break;
case DraggableHoverPosition.top:
offset = getTopLeft(to);
break;
case DraggableHoverPosition.bottom:
offset = getBottomLeft(to);
break;
default:
}
await gesture.moveTo(offset, timeStamp: const Duration(milliseconds: 400));
await gesture.up();
await pumpAndSettle();
}
// tap the button with [FlowySvgData]
Future<void> tapButtonWithFlowySvgData(FlowySvgData svg) async {
final button = find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg.path == svg.path,
);
await tapButton(button);
}
}
extension ViewLayoutPBTest on ViewLayoutPB {
@@ -1,11 +1,14 @@
import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database_view/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_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';
@@ -14,31 +17,46 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/
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_cell_action_sheet.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/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/header/type_option/date.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/grid_layout.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart';
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.dart';
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_header.dart';
import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
import 'package:appflowy/plugins/database_view/widgets/field/grid_property.dart';
import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_cell_editor.dart';
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/cells/checklist_cell/checklist_progress_bar.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/timestamp_cell/timestamp_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart';
import 'package:appflowy/plugins/database_view/widgets/row/row_property.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/database_setting.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
import 'package:appflowy/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:calendar_view/calendar_view.dart';
@@ -50,25 +68,12 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.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/row/row.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/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/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:path/path.dart' as p;
import 'package:table_calendar/table_calendar.dart';
import 'base.dart';
import 'common_operations.dart';
import 'expectation.dart';
import 'package:path/path.dart' as p;
import 'mock/mock_file_picker.dart';
extension AppFlowyDatabaseTest on WidgetTester {
@@ -77,9 +82,9 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapGoButton();
// expect to see a readme page
expectToSeePageName(readme);
expectToSeePageName(gettingStarted);
await tapAddButton();
await tapAddViewButton();
await tapImportButton();
final testFileNames = ['v020.afdb'];
@@ -103,7 +108,8 @@ extension AppFlowyDatabaseTest on WidgetTester {
paths: paths,
);
await tapDatabaseRawDataButton();
await openPage('v020');
await pumpAndSettle();
await openPage('v020', layout: ViewLayoutPB.Grid);
}
Future<void> hoverOnFirstRowOfGrid() async {
@@ -239,36 +245,43 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
}
/// null percent means no progress bar should be found
Future<void> assertChecklistCellInGrid({
required int rowIndex,
required double percent,
required double? percent,
}) async {
final findCell = cellFinder(rowIndex, FieldType.Checklist);
final finder = find.descendant(
of: findCell,
matching: find.byWidgetPredicate(
(widget) {
if (widget is ChecklistProgressBar) {
return widget.percent == percent;
}
return false;
},
),
);
expect(finder, findsOneWidget);
if (percent == null) {
final finder = find.descendant(
of: findCell,
matching: find.byType(ChecklistProgressBar),
);
expect(finder, findsNothing);
} else {
final finder = find.descendant(
of: findCell,
matching: find.byWidgetPredicate(
(widget) {
if (widget is ChecklistProgressBar) {
return widget.percent == percent;
}
return false;
},
),
);
expect(finder, findsOneWidget);
}
}
Future<void> assertDateCellInGrid({
required int rowIndex,
required FieldType fieldType,
required String content,
}) async {
final findRow = find.byType(GridRow, skipOffstage: false);
final findCell = find.descendant(
of: findRow.at(rowIndex),
matching: find.byWidgetPredicate(
(widget) => widget is GridDateCell && widget.fieldType == fieldType,
),
matching: find.byType(GridDateCell),
skipOffstage: false,
);
@@ -358,6 +371,16 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(findNewDateFormat);
}
Future<void> clearDate() async {
final findDateEditor = find.byType(DateCellEditor);
final findClearButton = find.byType(ClearDateButton);
final finder = find.descendant(
of: findDateEditor,
matching: findClearButton,
);
await tapButton(finder);
}
Future<void> tapSelectOptionCellInGrid({
required int rowIndex,
required FieldType fieldType,
@@ -439,6 +462,119 @@ extension AppFlowyDatabaseTest on WidgetTester {
expect(cell, matcher);
}
Future<void> tapChecklistCellInGrid({required int rowIndex}) async {
final findRow = find.byType(GridRow);
final findCell = finderForFieldType(FieldType.Checklist);
final cell = find.descendant(
of: findRow.at(rowIndex),
matching: findCell,
);
await tapButton(cell);
}
void assertChecklistEditorVisible({required bool visible}) {
final editor = find.byType(GridChecklistCellEditor);
if (visible) {
expect(editor, findsOneWidget);
} else {
expect(editor, findsNothing);
}
}
void assertNewCheckListTaskEditorVisible({required bool visible}) {
final editor = find.byType(NewTaskItem);
if (visible) {
expect(editor, findsOneWidget);
} else {
expect(editor, findsNothing);
}
}
Future<void> createNewChecklistTask({
required String name,
enter = false,
button = false,
}) async {
assert(!(enter && button));
final textField = find.descendant(
of: find.byType(NewTaskItem),
matching: find.byType(TextField),
);
await enterText(textField, name);
await pumpAndSettle(const Duration(milliseconds: 300));
if (enter) {
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle(const Duration(milliseconds: 300));
} else {
await tapButton(
find.descendant(
of: find.byType(NewTaskItem),
matching: find.byType(FlowyTextButton),
),
);
}
}
void assertChecklistTaskInEditor({
required int index,
required String name,
required bool isChecked,
}) {
final task = find.byType(ChecklistItem).at(index);
final widget = this.widget<ChecklistItem>(task);
assert(
widget.option.data.name == name && widget.option.isSelected == isChecked,
);
}
Future<void> renameChecklistTask({
required int index,
required String name,
}) async {
final textField = find
.descendant(
of: find.byType(ChecklistItem),
matching: find.byType(TextField),
)
.at(index);
await enterText(textField, name);
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle(const Duration(milliseconds: 300));
}
Future<void> tapChecklistNewTaskButton() async {
await tapButton(find.byType(ChecklistNewTaskButton));
}
Future<void> checkChecklistTask({required int index}) async {
final button = find.descendant(
of: find.byType(ChecklistItem).at(index),
matching: find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.uncheck_s,
),
);
await tapButton(button);
}
Future<void> deleteChecklistTask({required int index}) async {
final task = find.byType(ChecklistItem).at(index);
await startGesture(getCenter(task), kind: PointerDeviceKind.mouse);
await pumpAndSettle();
final button = find.byWidgetPredicate(
(widget) => widget is FlowySvg && widget.svg == FlowySvgs.delete_s,
);
await tapButton(button);
}
Future<void> openFirstRowDetailPage() async {
await hoverOnFirstRowOfGrid();
@@ -475,7 +611,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
expect(banner, findsOneWidget);
await startGesture(
getTopLeft(banner),
getCenter(banner),
kind: PointerDeviceKind.mouse,
);
@@ -492,6 +628,18 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(findDateCell);
}
Future<void> tapGridFieldWithNameInRowDetailPage(String name) async {
final fields = find.byWidgetPredicate(
(widget) => widget is FieldCellButton && widget.field.name == name,
);
final field = find.descendant(
of: find.byType(RowDetailPage),
matching: fields,
);
await tapButton(field);
await pumpAndSettle();
}
Future<void> duplicateRowInRowDetailPage() async {
final duplicateButton = find.byType(RowDetailPageDuplicateButton);
await tapButton(duplicateButton);
@@ -502,6 +650,31 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(deleteButton);
}
Future<TestGesture> hoverOnFieldInRowDetail({required int index}) async {
final fieldButtons = find.byType(FieldCellButton);
final button = find
.descendant(of: find.byType(RowDetailPage), matching: fieldButtons)
.at(index);
return startGesture(
getCenter(button),
kind: PointerDeviceKind.mouse,
);
}
Future<void> reorderFieldInRowDetail({required double offset}) async {
final thumb = find
.byWidgetPredicate(
(widget) => widget is ReorderableDragStartListener && widget.enabled,
)
.first;
await drag(
thumb,
Offset(0, offset),
kind: PointerDeviceKind.mouse,
);
await pumpAndSettle();
}
Future<void> scrollGridByOffset(Offset offset) async {
await drag(find.byType(GridPage), offset);
await pumpAndSettle();
@@ -574,6 +747,15 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(field);
}
Future<void> tapHidePropertyButtonInFieldEditor() async {
final button = find.byType(HideFieldButton);
await tapButton(button);
}
Future<void> tapRowDetailPageRowActionButton() async {
await tapButton(find.byType(RowActionButton));
}
Future<void> tapRowDetailPageCreatePropertyButton() async {
await tapButton(find.byType(CreateRowFieldButton));
}
@@ -643,6 +825,18 @@ extension AppFlowyDatabaseTest on WidgetTester {
expect(field, findsOneWidget);
}
void assertFirstFieldInRowDetailByType(FieldType fieldType) {
final firstField = find
.descendant(
of: find.byType(RowDetailPage),
matching: find.byType(FieldCellButton),
)
.first;
final widget = this.widget<FieldCellButton>(firstField);
expect(widget.field.fieldType, fieldType);
}
Future<void> findFieldWithName(String name) async {
final field = find.byWidgetPredicate(
(widget) => widget is FieldCellButton && widget.field.name == name,
@@ -914,6 +1108,23 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(button);
}
/// Should call [tapDatabaseSettingButton] first.
Future<void> tapViewPropertiesButton() async {
final findSettingItem = find.byType(DatabaseSettingItem);
final findLayoutButton = find.byWidgetPredicate(
(widget) =>
widget is FlowyText &&
widget.text == DatabaseSettingAction.showProperties.title(),
);
final button = find.descendant(
of: findSettingItem,
matching: findLayoutButton,
);
await tapButton(button);
}
/// Should call [tapDatabaseSettingButton] first.
Future<void> tapDatabaseLayoutButton() async {
final findSettingItem = find.byType(DatabaseSettingItem);
@@ -1100,6 +1311,11 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButton(findCreateButton);
}
Future<void> tapTabBarLinkedViewByViewName(String name) async {
final viewButton = findTabBarLinkViewByViewName(name);
await tapButton(viewButton);
}
Finder findTabBarLinkViewByViewLayout(ViewLayoutPB layout) {
return find.byWidgetPredicate(
(widget) => widget is TabBarItemButton && widget.view.layout == layout,
@@ -1201,6 +1417,18 @@ extension AppFlowyDatabaseTest on WidgetTester {
Future<void> tapAddSelectOptionButton() async {
await tapButtonWithName(LocaleKeys.grid_field_addSelectOption.tr());
}
Future<void> tapViewTogglePropertyVisibilityButtonByName(
String fieldName,
) async {
final field = find.byWidgetPredicate(
(widget) =>
widget is GridPropertyCell && widget.fieldInfo.name == fieldName,
);
final toggleVisibilityButton =
find.descendant(of: field, matching: find.byType(FlowyIconButton));
await tapButton(toggleVisibilityButton);
}
}
Finder finderForDatabaseLayoutType(DatabaseLayoutPB layout) {
@@ -1224,7 +1452,7 @@ Finder finderForFieldType(FieldType fieldType) {
return find.byType(GridDateCell, skipOffstage: false);
case FieldType.LastEditedTime:
case FieldType.CreatedTime:
return find.byType(GridDateCell, skipOffstage: false);
return find.byType(GridTimestampCell, skipOffstage: false);
case FieldType.SingleSelect:
return find.byType(GridSingleSelectCell, skipOffstage: false);
case FieldType.MultiSelect:
@@ -87,7 +87,7 @@ class EditorOperations {
Future<void> switchSolidColorBackground() async {
final findPurpleButton = find.byWidgetPredicate(
(widget) => widget is ColorItem && widget.option.colorHex == "ffe8e0ff",
(widget) => widget is ColorItem && widget.option.name == 'Purple',
);
await tester.tapButton(findPurpleButton);
}
@@ -2,30 +2,53 @@ import 'package:appflowy/generated/locale_keys.g.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/app/section/item.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_test/flutter_test.dart';
const String readme = 'Read me';
// const String 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(readme), findsWidgets);
expect(find.textContaining(gettingStarted), findsWidgets);
}
/// Expect to see the page name on the home page.
void expectToSeePageName(String name) {
final pageName = findPageName(name);
void expectToSeePageName(
String name, {
String? parentName,
ViewLayoutPB layout = ViewLayoutPB.Document,
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
}) {
final pageName = findPageName(
name,
layout: layout,
parentName: parentName,
parentLayout: parentLayout,
);
expect(pageName, findsOneWidget);
}
/// Expect not to see the page name on the home page.
void expectNotToSeePageName(String name) {
final pageName = findPageName(name);
void expectNotToSeePageName(
String name, {
String? parentName,
ViewLayoutPB layout = ViewLayoutPB.Document,
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
}) {
final pageName = findPageName(
name,
layout: layout,
parentName: parentName,
parentLayout: parentLayout,
);
expect(pageName, findsNothing);
}
@@ -125,11 +148,49 @@ extension Expectation on WidgetTester {
expect(textWidget, findsOneWidget);
}
/// Find the page name on the home page.
Finder findPageName(String name) {
/// Find if the page is favorite
Finder findFavoritePageName(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
String? parentName,
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
}) {
return find.byWidgetPredicate(
(widget) => widget is ViewSectionItem && widget.view.name == name,
(widget) =>
widget is ViewItem &&
widget.view.isFavorite &&
widget.categoryType == FolderCategoryType.favorite &&
widget.view.name == name &&
widget.view.layout == layout,
skipOffstage: false,
);
}
Finder findPageName(
String name, {
ViewLayoutPB layout = ViewLayoutPB.Document,
String? parentName,
ViewLayoutPB parentLayout = ViewLayoutPB.Document,
}) {
if (parentName == null) {
return find.byWidgetPredicate(
(widget) =>
widget is SingleInnerViewItem &&
widget.view.name == name &&
widget.view.layout == layout,
skipOffstage: false,
);
}
return find.descendant(
of: find.byWidgetPredicate(
(widget) =>
widget is ViewItem &&
widget.view.name == parentName &&
widget.view.layout == parentLayout,
skipOffstage: false,
),
matching: findPageName(name, layout: layout),
);
}
}
@@ -77,13 +77,6 @@ Future<String> mockSaveFilePath(
Future<List<String>> mockPickFilePaths({
required List<String> paths,
}) async {
// late final Directory dir;
// if (customPath != null) {
// dir = Directory(customPath);
// } else {
// dir = await TestFolder.testLocation(applicationDataPath, name);
// }
// final paths = fileNames.map((e) => p.join(dir.path, e)).toList();
getIt.unregister<FilePickerService>();
getIt.registerFactory<FilePickerService>(
() => MockFilePicker(
@@ -29,6 +29,14 @@ extension AppFlowySettings on WidgetTester {
return;
}
Future<void> expectNoSettingsPage(SettingsPage page) async {
final button = find.byWidgetPredicate(
(widget) => widget is SettingsMenuElement && widget.page == page,
);
expect(button, findsNothing);
return;
}
/// Restore the AppFlowy data storage location
Future<void> restoreLocation() async {
final button =
@@ -6,3 +6,4 @@ export 'expectation.dart';
export 'editor_test_operations.dart';
export 'mock/mock_url_launcher.dart';
export 'ime.dart';
export 'auth_operation.dart';
@@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<string>11.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, '9.0'
# platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+146 -52
View File
@@ -1,81 +1,175 @@
PODS:
- flowy_editor (0.0.1):
- Flutter
- flowy_infra_ui (0.0.1):
- app_links (0.0.1):
- Flutter
- appflowy_backend (0.0.1):
- Flutter
- connectivity_plus (0.0.1):
- Flutter
- ReachabilitySwift
- device_info_plus (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- flowy_infra_ui (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_inappwebview (0.0.1):
- fluttertoast (0.0.2):
- Flutter
- flutter_inappwebview/Core (= 0.0.1)
- OrderedSet (~> 5.0)
- flutter_inappwebview/Core (0.0.1):
- Toast
- integration_test (0.0.1):
- Flutter
- OrderedSet (~> 5.0)
- flutter_keyboard_visibility (0.0.1):
- irondash_engine_context (0.0.1):
- Flutter
- image_picker (0.0.1):
- package_info_plus (0.4.5):
- Flutter
- OrderedSet (5.0.0)
- path_provider (0.0.1):
- path_provider_foundation (0.0.1):
- Flutter
- url_launcher (0.0.1):
- FlutterMacOS
- ReachabilitySwift (5.0.0)
- rich_clipboard_ios (0.0.1):
- Flutter
- video_player (0.0.1):
- SDWebImage (5.14.2):
- SDWebImage/Core (= 5.14.2)
- SDWebImage/Core (5.14.2)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- Flutter
- 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:
- flowy_editor (from `.symlinks/plugins/flowy_editor/ios`)
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
- app_links (from `.symlinks/plugins/app_links/ios`)
- appflowy_backend (from `.symlinks/plugins/appflowy_backend/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
- Flutter (from `Flutter`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- rich_clipboard_ios (from `.symlinks/plugins/rich_clipboard_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- 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:
- OrderedSet
- DKImagePickerController
- DKPhotoGallery
- ReachabilitySwift
- SDWebImage
- SwiftyGif
- Toast
EXTERNAL SOURCES:
flowy_editor:
:path: ".symlinks/plugins/flowy_editor/ios"
flowy_infra_ui:
:path: ".symlinks/plugins/flowy_infra_ui/ios"
app_links:
:path: ".symlinks/plugins/app_links/ios"
appflowy_backend:
:path: ".symlinks/plugins/appflowy_backend/ios"
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
flowy_infra_ui:
:path: ".symlinks/plugins/flowy_infra_ui/ios"
Flutter:
:path: Flutter
flutter_inappwebview:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
video_player:
:path: ".symlinks/plugins/video_player/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
irondash_engine_context:
:path: ".symlinks/plugins/irondash_engine_context/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
rich_clipboard_ios:
:path: ".symlinks/plugins/rich_clipboard_ios/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sign_in_with_apple:
:path: ".symlinks/plugins/sign_in_with_apple/ios"
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:
flowy_editor: bf8d58894ddb03453bd4d8521c57267ad638b837
flowy_infra_ui: 146c88346fd55d2ee6a41ae35059a5bf095cfbb3
appflowy_backend: c416222c639e678828776789bf0c1a1d0d59df3c
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
video_player: ecd305f42e9044793efd34846e1ce64c31ea6fcb
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
integration_test: 13825b8a9334a850581300559b8839134b124670
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
rich_clipboard_ios: 7588abe18f881a6d0e9ec0b12e51cae2761e8942
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
super_native_extensions: 49e897b6039bb784226e7354e502a3c68e1659b5
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
COCOAPODS: 1.10.1
COCOAPODS: 1.11.3
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -217,10 +217,12 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
@@ -231,6 +233,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -340,7 +343,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -414,7 +417,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -463,7 +466,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -16,6 +16,17 @@
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string></string>
<key>CFBundleURLSchemes</key>
<array>
<string>appflowy-flutter</string>
</array>
</dict>
</array>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -47,5 +58,7 @@
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
@@ -7,6 +7,10 @@ import 'package:shared_preferences/shared_preferences.dart';
abstract class KeyValueStorage {
Future<void> set(String key, String value);
Future<Either<FlowyError, String>> get(String key);
Future<Either<FlowyError, T>> getWithFormat<T>(
String key,
T Function(String value) formatter,
);
Future<void> remove(String key);
Future<void> clear();
}
@@ -26,6 +30,18 @@ class DartKeyValue implements KeyValueStorage {
return Left(FlowyError());
}
@override
Future<Either<FlowyError, T>> getWithFormat<T>(
String key,
T Function(String value) formatter,
) async {
final value = await get(key);
return value.fold(
(l) => left(l),
(r) => right(formatter(r)),
);
}
@override
Future<void> remove(String key) async {
await _initSharedPreferencesIfNeeded();
@@ -71,6 +87,18 @@ class RustKeyValue implements KeyValueStorage {
return response.swap().map((r) => r.value);
}
@override
Future<Either<FlowyError, T>> getWithFormat<T>(
String key,
T Function(String value) formatter,
) async {
final value = await get(key);
return value.fold(
(l) => left(l),
(r) => right(formatter(r)),
);
}
@override
Future<void> remove(String key) async {
await ConfigEventRemoveKeyValue(
@@ -29,4 +29,24 @@ class KVKeys {
'kDocumentAppearanceFontSize';
static const String kDocumentAppearanceFontFamily =
'kDocumentAppearanceFontFamily';
static const String kDocumentAppearanceDefaultTextDirection =
'kDocumentAppearanceDefaultTextDirection';
/// The key for saving the expanded views
///
/// The value is a json string with the following format:
/// {'viewId': true, 'viewId2': false}
static const String expandedViews = 'expandedViews';
/// The key for saving the expanded folder
///
/// The value is a json string with the following format:
/// {'SidebarFolderCategoryType.value': true}
static const String expandedFolders = 'expandedFolders';
/// The key for saving if showing the rename dialog when creating a new file
///
/// The value is a boolean string.
static const String showRenameDialogWhenCreatingNewFile =
'showRenameDialogWhenCreatingNewFile';
}
@@ -1,9 +1,9 @@
import 'dart:async';
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-net/network_state.pb.dart';
import 'package:flutter/services.dart';
class NetworkListener {
@@ -46,12 +46,12 @@ class NetworkListener {
return NetworkTypePB.VPN;
case ConnectivityResult.none:
case ConnectivityResult.other:
return NetworkTypePB.Unknown;
return NetworkTypePB.NetworkUnknown;
}
}();
Log.info("Network type: $networkType");
final state = NetworkStatePB.create()..ty = networkType;
NetworkEventUpdateNetworkType(state).send().then((result) {
UserEventUpdateNetworkState(state).send().then((result) {
result.fold(
(l) {},
(e) => Log.error(e),
@@ -8,4 +8,12 @@ extension RawKeyboardExtension on RawKeyboard {
LogicalKeyboardKey.altRight,
].contains(key),
);
bool get isControlPressed => keysPressed.any(
(key) => [
LogicalKeyboardKey.control,
LogicalKeyboardKey.controlLeft,
LogicalKeyboardKey.controlRight,
].contains(key),
);
}
+9 -56
View File
@@ -1,4 +1,5 @@
// lib/env/env.dart
import 'package:appflowy/startup/startup.dart';
import 'package:envied/envied.dart';
part 'env.g.dart';
@@ -28,61 +29,13 @@ abstract class Env {
defaultValue: '',
)
static final String supabaseAnonKey = _Env.supabaseAnonKey;
@EnviedField(
obfuscate: true,
varName: 'SUPABASE_KEY',
defaultValue: '',
)
static final String supabaseKey = _Env.supabaseKey;
@EnviedField(
obfuscate: true,
varName: 'SUPABASE_JWT_SECRET',
defaultValue: '',
)
static final String supabaseJwtSecret = _Env.supabaseJwtSecret;
@EnviedField(
obfuscate: true,
varName: 'SUPABASE_DB',
defaultValue: '',
)
static final String supabaseDb = _Env.supabaseDb;
@EnviedField(
obfuscate: true,
varName: 'SUPABASE_DB_USER',
defaultValue: '',
)
static final String supabaseDbUser = _Env.supabaseDbUser;
@EnviedField(
obfuscate: true,
varName: 'SUPABASE_DB_PASSWORD',
defaultValue: '',
)
static final String supabaseDbPassword = _Env.supabaseDbPassword;
@EnviedField(
obfuscate: true,
varName: 'SUPABASE_DB_PORT',
defaultValue: '5432',
)
static final String supabaseDbPort = _Env.supabaseDbPort;
@EnviedField(
obfuscate: true,
varName: 'ENABLE_SUPABASE_SYNC',
defaultValue: true,
)
static final bool enableSupabaseSync = _Env.enableSupabaseSync;
}
bool get isSupabaseEnable => false;
// Env.supabaseUrl.isNotEmpty &&
// Env.supabaseAnonKey.isNotEmpty &&
// Env.supabaseKey.isNotEmpty &&
// Env.supabaseJwtSecret.isNotEmpty &&
// Env.supabaseDb.isNotEmpty &&
// Env.supabaseDbUser.isNotEmpty &&
// Env.supabaseDbPassword.isNotEmpty &&
// Env.supabaseDbPort.isNotEmpty;
bool get isSupabaseEnabled {
// Only enable supabase in release and develop mode.
if (integrationMode().isRelease || integrationMode().isDevelop) {
return Env.supabaseUrl.isNotEmpty && Env.supabaseAnonKey.isNotEmpty;
} else {
return false;
}
}
+1 -6
View File
@@ -1,13 +1,8 @@
import 'package:appflowy/startup/entry_point.dart';
import 'package:flutter/material.dart';
import 'startup/startup.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlowyRunner.run(
FlowyApp(),
integrationEnv(),
);
await runAppFlowy();
}
Loaded 100 of 1439 files, more files were not shown because too many files have changed in this diff. Show more