Compare commits

...
158 Commits
Author SHA1 Message Date
Nathan.fooo 055af03320 chore: check collab before saving collab to disk (#6261)
* chore: check collab before saving collab to disk
2024-09-10 07:56:13 +08:00
Annie 879d73a27a chore: update CHANGELOG.md incl v0.6.9 (#6256) 2024-09-09 21:55:52 +08:00
Annie 6721caf2fa chore: Update README.md (#6243)
change mobile screenshots layout
2024-09-09 21:02:25 +08:00
Mathias Mogensen 7bd876bf85 feat: file block on mobile (#6245)
* feat: file block on mobile

* chore: analyzer issues

* chore: cleanup after review
2024-09-09 19:47:33 +08:00
Lucas.Xu 2f3c9c11b1 feat: collect row page collabs (#6215)
* fix: invalid value when inserting image

* feat: collect row document collabs

* fix: code review

* fix: invalid value when inserting image

* chore: remove database_row_metas
2024-09-09 19:40:52 +08:00
Nathan.fooo 5d42d03e15 chore: bump collab (#6246)
* chore: bump collab

* chore: bump client api
2024-09-09 18:56:20 +08:00
Lucas.Xu 38d69c0b58 fix: android file permission issue (#6244)
* fix: invalid value when inserting image

* fix: upgrade share_plus version and use temp dir as android export log path

* fix: only noto emoji on Linux

* chore: upgrade android minSdkVersion to 29
2024-09-09 17:09:54 +08:00
Richard Shiue 7a0c6a829b fix: hover color in different color schemes (#6240) 2024-09-09 13:44:56 +08:00
Richard Shiue d1d485ee94 fix: incorrect colors for switch workspace button (#6228)
* fix: incorrect colors for switch workspace button

* chore: apply code style suggestions
2024-09-09 13:44:41 +08:00
Annie 1b15b8fa64 chore: update CHANGELOG.md (#6184) 2024-09-09 13:42:54 +08:00
Mathias MogensenandRichard Shiue 614f3ce81b feat: media launch review (#6198)
* fix: unexpected thrown exceptions~

* fix: wrap toggle rebuild

* fix: copywriting + checkbox group

* fix: only show item menu on hover

* feat: click to open image in viewer

* feat: improve row detail ux

* fix: add delete confirmation dialog

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2024-09-09 13:42:23 +08:00
Nathan.fooo 006ea02bfe chore: fix database rows filter and sort (#6241)
* chore: fix database rows filter and sort

* chore: fix ios build

* chore: fix task id

* chore: fmt

* chore: ios build
2024-09-09 12:54:44 +08:00
Kilu.He 3caf84b8a0 fix: modified some behavior of template (#6242) 2024-09-09 12:06:22 +08:00
zkkvandLucas.Xu a002cb7428 chore: update ru-RU translations (#6141)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-09 09:49:45 +08:00
rensawamo 96e39d0257 chore: update jp-JP translations (#6224)
* feat: pull upstream

* fix: revision

* chore: update jp-JP translations
2024-09-09 09:30:01 +08:00
Lucas.Xu 944da858a8 fix: redirect to login page after deleting account on Android (#6206) 2024-09-09 09:28:29 +08:00
CanonNi 53a2b7cb6e chore: update zh-CN translations (#6201)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦
2024-09-09 09:27:05 +08:00
Richard Shiue ec799afb7d fix: more checklist multiline issues (#6229)
* fix: more checklist multiline issues

* chore: add comment

* chore: apply code style improvments
2024-09-09 09:22:08 +08:00
Mathias Mogensen 06c356c7a1 fix: space button rebuild issue (#6235) 2024-09-08 21:58:00 +02:00
nathan dbe17aa4e8 chore: update logs 2024-09-08 23:38:24 +08:00
Nathan.fooo 187c5892ea fix: move group row (#6233)
* chore: fix group notification

* chore: clippy

* Revert "fix: newly-created group rows appear out of order (#6212)"

This reverts commit decc438b8a.

* chore: revamp function

* chore: update test

* chore: workaround to fix filter or sort don't show result after opening database

* chore: fix test
2024-09-08 22:21:34 +08:00
Annie c8be43134c chore: Update README.md (#6231)
two mobile images per row
2024-09-08 16:48:41 +08:00
Richard Shiue e615e7a304 fix: unhiding group throws exception (#6217) 2024-09-08 16:48:17 +08:00
Annie e3cd9a09f3 chore: Update README.md (#6230)
Part I: update product screenshots
2024-09-08 16:39:10 +08:00
Richard Shiue decc438b8a fix: newly-created group rows appear out of order (#6212)
* fix: newly-created group rows appear out of order

* test: fix tests

* fix: dont re-insert nor insert into no-status

* fix: clippy
2024-09-08 14:48:55 +08:00
Kilu.He a1793b53dd fix: open duplicate entrance and fixed some issues (#6216) 2024-09-07 13:35:51 +08:00
Mathias Mogensen 2b9b8c19a9 fix: flowy hover isselected check (#6223) 2024-09-07 01:39:49 +02:00
Richard Shiue 91173f707e fix: cannot drag newly-created board cards (#6207) 2024-09-07 00:20:13 +08:00
Kilu.He a1bc9246b1 fix: apple login on web (#6213) 2024-09-06 14:46:05 +08:00
Kilu.He 3e91be4960 fix: hide toast (#6210) 2024-09-06 12:28:49 +08:00
Kilu.He 9930efdc84 fix: toast issues (#6209) 2024-09-06 12:27:08 +08:00
Kilu.He 93ca6ac906 feat: support gallery block (#6205) 2024-09-06 11:49:50 +08:00
Lucas.Xu c400fdc01d fix: launch review 0.6.9 issues (#6203)
* chore: replace teamspaces with workspaces

* fix: set delete account button height to 32

* feat: use 'deletemyaccount' as confirmation text

* fix: remove input text after closing account deletion dialog

* feat: replace the existing error page with the new style

* fix: update photo library usage description

* chore: remove beta

* feat: add more acceptable confirm texts

* feat: optimize account deletion UX
2024-09-06 10:39:10 +08:00
Mathias Mogensen 4f592e80b6 fix: edit group title + rebuild improvement (#6156)
* fix: edit group title + rebuild improvement

* chore: fix clippy

* chore: fix clippy

* fix: stop widget replacement causing perf issues

* fix: after merge main

* chore: minor cleanup in view_editor

* fix: attempt to fix hover issue in tests
2024-09-05 12:48:44 +02:00
Nathan.fooo 7ea71fc6ae fix: open duplicated database (#6197)
* fix: open duplicated database

* chore: update logs
2024-09-05 17:35:24 +08:00
Lucas.Xu 8688183dae chore: update translation (#6196) 2024-09-05 15:28:34 +08:00
onxzyandLucas.Xu b5a17ee0bd chore: update fr-FR translations (#6148)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-05 14:07:51 +08:00
CanonNi 1ecb864db0 chore: update zh-CN translations (#6178) 2024-09-05 13:57:24 +08:00
SimonandLucas.Xu 7b8af686e0 chore: updat the Ukrainian translation (#5904)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-05 13:55:54 +08:00
Richard Shiue 1c6e709c82 fix: board ui bugs (#6194)
* fix: date reminder indicator on board/calendar cards

* fix: stop restricting max lines of card title to two lines

* fix: don't allow multiline row titles

* fix: oops
2024-09-05 13:55:37 +08:00
Richard ShiueandMathias Mogensen 0fd0483302 fix: various grid ui issues (#6182)
* fix: delete field confirmation dialog only closes top most popover

* fix: prioritize single-line checklist items

* chore: wrap text toggle persist

* test: update integration tests

* chore: delete conflicting outputs on freezed

* chore: slightly make field editor faster

* chore: use standard dialog componet

* chore: enable multiline checklist tasks on mobile

* chore: Update frontend/appflowy_flutter/lib/plugins/database/application/field/field_editor_bloc.dart

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

* chore: code cleanup

* fix: create field from row detail and add test

* chore: allow opening related database from editor

* test: integration test flake

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-09-05 13:54:50 +08:00
Kilu.He aa621289e9 feat: support publish outline (#6173) 2024-09-05 12:27:32 +08:00
Mathias Mogensen 009c2ed402 feat: media type option (#6090)
* feat: media type option

* feat: rename files + more media types

* feat: add basic style for cards on desktop

* test: add media

* chore: clippy

* feat: row detail ux improvement

* feat: show all media attachments as one count on card

* chore: localization

* fix: overlay issue + disable filter for option

* test: add base integration test

* test: add pumpAndSettle

* chore: update collab revision

* feat: mobile grid & board styling

* fix: clippy

* fix: grid reorder rows bug

* fix: style discrepancy

* chore: clippy

* chore: code cleanup
2024-09-05 06:03:58 +02:00
Lucas.Xu 08e2be367c feat: optimize error page in database row page and remove unused code (#6193) 2024-09-05 11:57:54 +08:00
Nathan.fooo 31567d451f chore: Observe database row event (#6190)
* chore: observe row

* chore: fix test
2024-09-04 23:21:05 +08:00
Lucas.Xu 8e34951477 feat: auto-fix table block data when duplicating it (#6185)
* fix: remove camera permission and update photo usage description

* feat: optimize the error block style in document

* feat: auto-fix table block when duplicating it
2024-09-04 17:11:50 +08:00
Lucas.Xu 589f5c1298 feat: exclude ARMv7 architecture for Android builds (#6187) 2024-09-04 16:55:49 +08:00
Lucas.Xu d1127a9bfa chore: update translations on iOS (#6186)
* chore: update mobile translations

* fix: folder context not found assertion

* fix: attempted to change a read-only map field

* feat: only replace the translation on iOS
2024-09-04 16:03:54 +08:00
Lucas.Xu 71bb182803 fix: remove camera permission and update photo usage description (#6181) 2024-09-04 14:26:32 +08:00
Richard Shiue 3161dddb25 chore(mobile): dismiss the keyboard when tap outside on login (#6183) 2024-09-04 14:04:39 +08:00
Lucas.Xu d9dc132e5b feat: enable apple sign in on desktop version (#6119) 2024-09-04 10:27:31 +08:00
Lucas.Xu 49ba1fd246 chore: podfile.lock should not be ignored (#6180) 2024-09-04 10:07:02 +08:00
Nathan.foooandLucas.Xu e9b2cbb317 chore: observe file upload state (#6172)
* chore: observe file upload state

* chore: observe file upload state

* chore: upgrade client api

* Update frontend/appflowy_flutter/lib/startup/tasks/file_storage_task.dart

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

* chore: fix tauri build

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-04 07:56:08 +08:00
Lucas.Xu 2bb33e1d2a fix: incorrect right-click menu position on Desktop (#6177) 2024-09-04 00:58:02 +02:00
Lucas.Xu b7db1e7dda fix: build error in release mode (#6175) 2024-09-03 18:10:02 +08:00
Lucas.Xu 9da71c3186 feat: support account deletion (#6103)
* feat: support account deletion

* chore: update translation

* feat: support account deletion on mobile

* fix: only display account deletion button in appflowy cloud mode

* chore: remove unused code

* chore: update checkbox style

* fix: integration test

* chore: update translations

* chore: update sentry version in podfile.lock

* chore: update version
2024-09-03 16:58:38 +08:00
Zack a6cce62b06 feat: added delete account functionality (#6167)
* feat: added delete account functionality

* chore: update client api
2024-09-03 15:19:28 +08:00
Richard Shiue f7c6b8792f chore(flutter): bump sentry version to fix compilation (#6170) 2024-09-03 15:17:41 +08:00
Lucas.Xu 735cddd64b chore: downgrade macOS version in iOS CI to avoid "no space left" error (#6168)
* chore: dump mobile ci disk space usage

* chore: downgrade macos ci version to avoid no space left error
2024-09-03 15:08:09 +08:00
Kilu.He 94c033bba8 fix: some duplicate issues (#6171) 2024-09-03 12:49:56 +08:00
Kilu.He 4b0368d552 fix: display duplicate entry (#5853)
* fix: some issue

* fix: add colors

* fix: do not allow people who are not appflowy
2024-09-03 11:50:28 +08:00
Lucas.Xu dda798752f chore: bump version 0.6.8 (#6164)
* chore: bump version 0.6.8

* chore: update translations
2024-09-02 16:42:25 +08:00
Ufal SalmanandLucas.Xu e561778526 chore: update ID-id translations (#6150)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-02 15:35:44 +08:00
FreezingKasandLucas.Xu ed2f2360fe chore: update FR-fr translations (#6155)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-02 15:35:08 +08:00
Nathan.fooo 08bf5db2de chore: auto update field title when creating a new field (#6159)
* chore: auto update field title when creating a new field

* chore: fix test
2024-09-02 13:54:21 +08:00
Lucas.Xu 080b7db605 chore: remove unused translation (#6158) 2024-09-02 10:46:51 +08:00
Nathan.fooo 1cc41c10c4 fix: local ai enable/disable (#6151)
* chore: local ai state

* chore: fix local ai state when switch workspace

* chore: fix test
2024-09-01 17:48:07 +08:00
Mohammad Zolfaghari 6ce77aea3e fix: wrap checklist item text (#6145) 2024-09-01 16:06:58 +08:00
Nathan.fooo 01d7d6e900 chore: show document icon or emoji (#6144)
* chore: show icon

* chore: rename

* chore: adjust UI

* chore: remove unused property

* chore: update test

* chore: fix test

* chore: fix test
2024-08-31 23:54:37 +08:00
Lucas.Xu d264f3dbde fix: android toast style (#6128) 2024-08-31 09:33:44 +08:00
Nathan.fooo 8139065113 fix: init database row init (#6127) 2024-08-30 22:12:20 +08:00
Aymane BoumaazaandLucas.Xu 3324e7837b chore: update ar-SA and fr-FR translations with Fink 🐦 (#6084)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 21:22:01 +08:00
vavenCVandLucas.Xu f20f8bcfbf chore: update Fr-fr translations (#6106)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 21:17:42 +08:00
MIckaelandLucas.Xu c20ed8c019 chore: update Pt-br translations (#6107)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 20:14:04 +08:00
YurminandLucas.Xu 0b658bff0b chore: update it-IT translations (#6058)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 20:13:33 +08:00
8319606cc0 chore: updated Arabic translation (#6111)
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 20:13:17 +08:00
Antonio Albert eefdf96b00 fix: typo in german translation (#6126) 2024-08-30 19:31:15 +08:00
KD-MM2 e85e092db8 chore: update translations for Vietnamese(vi-VN) (#6122)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦
2024-08-30 19:24:43 +08:00
Lucas.XuandMathias Mogensen 928da2a223 chore: update translations (#6124)
* chore: update translations

* fix: close popup menu when tapping navigation bar item

* chore: update toolbar divider color and popup menu background color

* chore: update translations and icon

* chore: update frontend/appflowy_flutter/lib/shared/popup_menu/appflowy_popup_menu.dart

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

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-08-30 19:19:41 +08:00
Mathias Mogensen 78c2e756d6 fix: lose focus when changing tabs (#6118) 2024-08-30 10:12:36 +02:00
Mathias Mogensen 47c2ae23ed fix: move title bar on top of tabs on Windows (#6116) 2024-08-30 10:12:26 +02:00
Mathias Mogensen 0fd0900b41 fix: add leading zeros to day & month in date format (#6114) 2024-08-30 10:12:16 +02:00
Lucas.Xu 61ad75502f feat: upgrade template button style (#6121) 2024-08-30 16:10:17 +08:00
Nathan.fooo 29858dda7a chore: update plan desc (#6120) 2024-08-30 15:35:57 +08:00
koukemo 34c441f3ad fix: add libnotify and rocksdb as docker dependencies (#6065) 2024-08-30 15:28:09 +08:00
Nathan.fooo c3114e5a39 chore: bump client api (#6113)
* chore: bump client api and collab
2024-08-30 14:31:05 +08:00
Nathan.fooo d89804f3e4 chore: bump client api (#6098) 2024-08-28 21:31:04 +08:00
Lucas.Xu 9209562648 fix: reset first page when switching space (#6097)
* fix: reset first page when switching space

* fix: primary field icon align issue in grid page
2024-08-28 21:25:57 +08:00
Lucas.Xu 9ee8cc6a7b feat: optimize sync error page (#6082) 2024-08-28 18:53:16 +08:00
Nathan.fooo 9a295daf99 chore: fix database filter (#6094)
* chore: fix database filter

* chore: fix test
2024-08-28 16:15:40 +08:00
Lucas.Xu 956d62fe82 fix: expand the icon to be the same size as the text in the heading block (#6093)
* fix: hidden board group padding

* fix: expand icon in heading style
2024-08-28 13:22:07 +08:00
Kilu.He 7541dff00e fix: some file block issues (#6085) 2024-08-28 10:30:08 +08:00
Nathan.fooo c4cdcbff73 chore: disable old import type (#6089) 2024-08-28 09:15:42 +08:00
Bartosz Sypytkowskiandnathan b77fdb8424 chore: update yrs dependencies (#6086)
* chore: update dependencies

* chore: catch results from apply update

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-08-27 20:53:00 +08:00
Nathan.fooo 083c0d0f0b chore: upgrade client api that fix initfine sync (#6083) 2024-08-27 19:59:52 +08:00
Kilu.He d25efba292 feat: support file block preview on web (#6081) 2024-08-27 15:01:23 +08:00
Nathan.fooo 40e627c303 chore: enable upload when switching workspace (#6080)
* chore: enable upload when switching workspace

* chore: update client api
2024-08-27 14:22:57 +08:00
Kilu.He e3a68d3ecb fix: change icons (#6076) 2024-08-27 10:59:31 +08:00
Lucas.Xu 1b185ba3cd feat: support sign in with Apple (#6049)
* feat: support sign in with Apple

* feat: support sign in with Apple

* feat: optimize sign in on desktop

* feat: expand third party sign in buttons on android

* fix: revert text color and font size in button
2024-08-27 10:49:31 +08:00
Lucas.Xu e5ad0f6d1d fix: table render error (#6074)
* fix: table render error

* fix: sidebar doesn't refresh if the pages are same

* chore: optimize empty placeholder align

* fix: debounce open workspace toast

* fix: editor color decoration error
2024-08-27 09:23:25 +08:00
Nathan.fooo 93bf1f79f6 chore: fix database row meta (#6078)
* chore: fix database row meta

* chore: update

* chore: update client api

* chore: clippy

* chore: update client api

* chore: update collab

* chore: update client api
2024-08-26 23:42:18 +08:00
Lucas.Xu f342f5ec7e feat: customize transition animation for popup menu (#6071)
* feat: customize transition animation for popup menu

* chore: add hint text for duplicate and favorite action

* fix: flutter analyze
2024-08-26 15:15:59 +08:00
Nathan.fooo 12cb9bde39 chore: replace cell content when import from csv (#6073) 2024-08-26 14:19:30 +08:00
Kilu.He b649950d62 fix: table issues (#6072) 2024-08-26 13:52:02 +08:00
Lucas.Xu 2ef74c229c fix: update settings menu color (#6039)
* chore: replace settings popup menu backgroundcolor

* fix: invite toast blocked by keyboard
2024-08-26 09:51:57 +08:00
Nathan.fooo 62f0307289 feat: async load database row, async filter, async sort (#6068)
* chore: display date when convert text to date

* chore: filter & sort

* chore: fix filter and sort

* chore: fix test

* chore: clippy

* chore: fix test
2024-08-26 09:46:16 +08:00
Kilu.He 242faee2f5 fix: document issues (#6069) 2024-08-25 22:06:34 +08:00
Kilu.He 7626cfd546 fix: database tabs (#6067) 2024-08-25 21:45:01 +08:00
Kilu.He 5b2df9e482 fix: calendar style issues (#6066) 2024-08-25 20:56:41 +08:00
Kilu.He 2a2dc903c1 fix: table cells order on publish (#6064) 2024-08-25 17:27:44 +08:00
Nathan.fooo d1ed45c312 fix: upload all imported csv rows (#6063)
* chore: upload imported csv rows

* chore: format number
2024-08-25 15:14:54 +08:00
Nathan.fooo a487aa74fd feat: support edit imported database (#6061)
* chore: change field type of imported csv

* fix: support load 10000 rows

* fix: clippy
2024-08-25 14:28:51 +08:00
Nathan.fooo d3b7c5fea5 chore: async load database row (#6051)
* chore: update

* chore: fix test

* chore: clippy

* chore: clippy
2024-08-24 00:40:57 +08:00
Kilu.He 3fa72106e9 fix: upload template (#6021)
* fix: upload template

* fix: scale thumb
2024-08-23 16:28:46 +08:00
Nathan.fooo 8ae67c5098 chore: upgrade collab verison (#6047) 2024-08-23 15:40:48 +08:00
Nathan.fooo a206d9aa8c chore: fix board row (#6046)
* chore: fix board row init

* chore: update client api version
2024-08-23 13:55:40 +08:00
Nathan.fooo 9e93483113 chore: Enable document undo redo (#6044)
* chore: update logs

* chore: enable document undo redo

* chore: clippy
2024-08-22 22:31:43 +08:00
Lucas.Xu 00690a1bb8 chore: add images from readme (#6041) 2024-08-22 17:51:44 +08:00
Nathan.fooo 86be92ba1b chore: upgrade collab version (#6038) 2024-08-22 16:28:29 +08:00
Khor Shu Heng 6305ab8c5d chore: bump version to 0.6.8 (#6037) 2024-08-22 12:33:13 +08:00
Lucas.Xu c371c6cd63 fix: ai writer generate button color (#6035)
* fix: ai writer generate button color

* fix: replace ai writer button with outlined rounded button
2024-08-22 11:38:50 +08:00
Lucas.Xu 190e3bedda chore: update member exceeded hint text (#6034)
* chore: update member exceeded hint text

* fix: disable ai writer widget on mobile
2024-08-22 11:14:01 +08:00
Francisco Di Marzo Borghi a78752d427 fix: removed Wayland Header (#5991)
* fix: sync AppImage recipe linux version with release

* fix: don't draw custom header on Wayland sessions

* chore(AppImage): reset `app_info.version`
2024-08-22 09:36:26 +08:00
Evililim b2b72d2130 chore: update French translations (#5973)
* chore: update translations with Fink 🐦

* Corrections demandée par Ninja i18n

* Chore: Correction for Ninja i18n
2024-08-22 09:34:06 +08:00
Lucas.Xu 104bf12ac7 feat: optimize settings on mobile (#6031)
* feat: optimize settings on mobile

* feat: open discord link when clicking help button

* fix: flutter analyze
2024-08-22 09:32:29 +08:00
Bartosz Sypytkowskiandnathan 0e844678fc chore: Remove last sync at (#6029)
* chore: update dependencies to stop using last sync at field

* chore: apply cargo fmt

* chore: fix dependencies

* chore: upgrade client api

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-08-22 08:42:32 +08:00
Nathan.fooo 23968d89fc chore: Upgrade collab version (#6028)
* chore: write collab to disk if it's not exist

* chore: write collab if it's not exit

* chore: fix test

* chore: upgrade appflowy collab

* chore: upgrade appflowy collab

* chore: update collab version

* chore: fix test
2024-08-22 07:45:51 +08:00
Nathan.fooo 0ce43ca5fa chore: write collab to disk if it's not exist (#6023)
* chore: write collab to disk if it's not exist

* chore: write collab if it's not exit

* chore: fix test
2024-08-21 14:04:53 +08:00
nathan b9a34f6fc2 chore: turn off verbose log 2024-08-20 21:45:14 +08:00
Nathan.fooo 93a110d37d chore: explicit using any int64 (#6020)
* chore: explicit using any int64

* chore: update commit id of appflowy collab
2024-08-20 21:38:29 +08:00
Nathan.fooo 70d6351a6c chore: calm clippy wanring when using non send with Arc (#6018) 2024-08-20 17:07:54 +08:00
Lucas.Xu 70e96c01b3 fix: ignore case sensitive of image name when dragging image to document (#6017) 2024-08-20 16:55:53 +08:00
Nathan.fooo 6a0650e6d5 chore: fix file upload test (#6016)
* chore: fix file upload test
2024-08-20 15:18:57 +08:00
Nathan.fooo 6d09c33782 chore: spawn task on local set (#6012)
* chore: spawn local

* chore: using multiple thread runtime

* chore: fix test
2024-08-20 14:16:24 +08:00
nathan faf1e98d15 chore: update appflowy collab 2024-08-19 22:09:31 +08:00
Nathan.fooo 58b17a939c chore: fix lib dispatch (#6008)
* chore: replace rc with arc

* chore: fix dispatch

* chore: fix test

* chore: fix dispatch

* chore: fix test

* chore: remove afconcurrent

* chore: fix runtime block_on runtime
2024-08-19 22:08:10 +08:00
Lucas.Xu 7113269802 chore: optimize row card page UI (#5995)
* chore: adjust buttons padding in row record page

* fix: disable more button in row page

* fix: upload image button ui on mobile

* fix: embed link button ui on mobile

* fix: add missing border for ai text field and ai translate field

* fix: delete AI can make mistakes on mobile

* chore: disable sentry

* fix: invite error toast

* fix: add member limit hint text in invite member screen

* feat: show toast after opening workspace on mobile

* chore: remove sentry

* chore: filter row page in recent views

* feat: support display field name as row page title

* chore: remove scroll bar on home page

* chore: remove legacy code

* chore: optimize mobile speed

* Revert "chore: remove sentry"

This reverts commit 73b45e2590.

* fix: reduce document page rebuild time

* chore: improve tooltip style
2024-08-19 11:06:34 +08:00
Lucas.Xu e460120a1c feat: add ai bubble button on mobile home page (#5992)
* chore: skip check list test if the task is not found

* feat: add ai bubble button in home page

* feat: only show the ai bubble button for the cloud user

* chore: add border color to ai bubble button

* Revert "chore: skip check list test if the task is not found"

This reverts commit 961f594a31.

* fix: only display ai bubble button on home page
2024-08-19 09:50:42 +08:00
Nathan.fooo d0ce65f711 chore: fix database filter (#6005)
* chore: fix filter
2024-08-19 09:47:37 +08:00
Nathan.fooo 5878379b2e chore: lazy load database row (#6001)
* chore: fix potential load database rows fail

* chore: fix layout padding
2024-08-18 18:44:32 +08:00
Bartosz Sypytkowskiandnathan fd5299a13d move to latest appflowy collab version (#5894)
* chore: move to latest appflowy collab version

* chore: filter mapping

* chore: remove mutex folder

* chore: cleanup borrow checker issues

* chore: fixed flowy user crate compilation errors

* chore: removed parking lot crate

* chore: adjusting non locking approach

* chore: remove with folder method

* chore: fix folder manager

* chore: fixed workspace database compilation errors

* chore: initialize database plugins

* chore: fix locks in flowy core

* chore: remove supabase

* chore: async traits

* chore: add mutexes in dart ffi

* chore: post rebase fixes

* chore: remove supabase dart code

* chore: fix deadlock

* chore: fix page_id is empty

* chore: use data source to init collab

* chore: fix user awareness test

* chore: fix database deadlock

* fix: initialize user awareness

* chore: fix open workspace test

* chore: fix import csv

* chore: fix update row meta deadlock

* chore: fix document size test

* fix: timestamp set/get type convert

* fix: calculation

* chore: revert Arc to Rc

* chore: attach plugin to database and database row

* chore: async get row

* chore: clippy

* chore: fix tauri build

* chore: clippy

* fix: duplicate view deadlock

* chore: fmt

* chore: tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-08-18 11:16:42 +08:00
Nathan.fooo c2d7c5360d chore: remove file size limit (#5974)
* chore: remove file size limit

* chore: flutter analyze
2024-08-17 21:51:36 +08:00
Lucas.Xu 9853fbfc10 chore: support monochrome icon on Android (#5989) 2024-08-17 11:05:06 +08:00
Lucas.Xu 44fb610269 fix: support pasting web image on mobile (#5987)
* fix: support pasting web image on mobile

* fix: permission check will deactive editor focus
2024-08-17 11:04:56 +08:00
Lucas.Xu e6bf6a5c7d feat: support inviting members on mobile (#5986)
* feat: support inviting members on mobile

* feat: support workspace member list on mobile

* feat: support leave workspace on mobile

* chore: adjust member list ui

* fix: flutter analyze
2024-08-17 11:04:43 +08:00
Lucas.Xu d3d929b68e fix: unable to insert todo list via slash menu (#5980)
* fix: unable to insert todo list via slash menu

* fix: unable to insert divider via slash menu

* chore: update editor version

* chore: update translations

* chore: decrease sentry sample rate to 0.1

* fix: integration test
2024-08-16 11:58:48 +08:00
Lucas.Xu f7a2d9e581 chore: add loading indicator when generating freezed file (#5978) 2024-08-15 20:12:25 +08:00
Lucas.Xu 6283649a6b feat: open the row page on mobile (#5975)
* chore: add dart dependency validator

* feat: open the row page on mobile

* Revert "chore: add dart dependency validator"

This reverts commit c81e5ef0ed.

* chore: update translations

* feat: preload row page to reduce open time

* chore: don't add orphan doc into recent records

* fix: bloc error

* fix: migrate the row page title to latest design

* chore: optimize database mobile UI
2024-08-15 20:12:09 +08:00
Lucas.Xu 88cc0caab7 feat: integrate Sentry Flutter and enable it if SENTRY_DSN is not empty (#5959)
* chore: add dart dependency validator

* feat: integrate sentry flutter

* chore: remove user info collection

* fix: flutter analyze

* fix: ios compile

* chore: add log
2024-08-15 10:00:27 +08:00
Nathan.fooo 7eb8ea347d fix: local ai toggle (#5968)
* chore: fix disable local ai

* chore: do not index file
2024-08-15 07:44:32 +08:00
Nathan.fooo 8935b7158c chore: remove workspac id in user profile (#5962)
* chore: remove workspac id in user profile

* chore: fix test

* chore: clippy

* chore: clippy

* chore: fix cloud test

* chore: fix checklist test
2024-08-14 19:44:15 +08:00
Nathan.fooo fa230907ca fix: refresh local ai state when opening workspace (#5961)
* chore: fix local ai state when open other workspace

* chore: fix duplicate message
2024-08-14 16:58:56 +08:00
Nathan.fooo 6d496b2088 chore: remove future result (#5960)
* chore: remove future result

* chore: fix test
2024-08-14 15:50:21 +08:00
Nathan.fooo 4b24b41dd4 chore: rm fut (#5958)
* chore: rm fut

* chore: clippy
2024-08-14 10:33:23 +08:00
Lucas.Xu b3a0119c18 feat: optimize date picker & mention block (#5954)
* chore: optimize rename button on mobile

* fix: mention block id empty error

* chore: optimize mention block style

* feat: add confirm button in date picker
2024-08-14 09:31:30 +08:00
Nathan.fooo 463c8c7ee4 feat: enable local set (#5955)
* chore: enable local set

* chore: fix test

* chore: clippy

* chore: fix tauri build

* chore: fix tauri build
2024-08-13 23:36:44 +08:00
Lucas.Xu e2359cf047 fix: row property align issue (#5950)
* fix: row property align issue

* fix: generate_freezed.sh path warning

* Revert "fix: generate_freezed.sh path warning"

This reverts commit 7c0a4a3177.

* fix: generate_freezed.sh path warning

* chore: improve chat page mobile UI
2024-08-13 20:01:32 +08:00
Lucas.Xu d23977ebb0 chore: optimize generation speed (#5930)
* chore: optimize language generation speed

* chore: optimize code generation speed

* chore: optimize freezed generation speed

* chore: optimzie appflowy_backend generation speed

* chore: optimize appflowy_result

* chore: optimzie flowy_infra generation speed

* chore: optimzie flowy_infra_ui generation speed

* chore: optimzie appflowy_flutter generation speed

* chore: optimize generate.sh

* chore: optimize the execution order

* chore: use exclude_packages instead of include_packages
2024-08-13 16:13:33 +08:00
928 changed files with 37368 additions and 14696 deletions

No files matched your search

+15 -3
View File
@@ -246,14 +246,26 @@ jobs:
- name: Run Docker-Compose
working-directory: AppFlowy-Cloud
env:
BACKEND_VERSION: 0.3.24-amd64
APPFLOWY_CLOUD_VERSION: 0.6.4-amd64
run: |
if [ "$(docker ps --filter name=appflowy-cloud -q)" == "" ]; then
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
if [ -z "$container_id" ]; then
echo "AppFlowy-Cloud container is not running. Pulling and starting the container..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
echo "Docker container 'appflowy-cloud' is already running."
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Pulling the correct version..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
echo "AppFlowy-Cloud is running with the correct version."
fi
fi
- name: Checkout source code
+5 -5
View File
@@ -21,7 +21,7 @@ on:
env:
FLUTTER_VERSION: "3.22.0"
RUST_TOOLCHAIN: "1.77.2"
RUST_TOOLCHAIN: "1.80.1"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -45,12 +45,12 @@ jobs:
- uses: futureware-tech/simulator-action@v3
id: simulator-action
with:
model: 'iPhone 15'
model: "iPhone 15"
shutdown_after_job: false
build-macos:
if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: macos-latest
runs-on: macos-13
steps:
- name: Checkout source code
@@ -79,7 +79,7 @@ jobs:
- uses: davidB/rust-cargo-make@v1
with:
version: "0.36.6"
version: "0.37.15"
- name: Install prerequisites
working-directory: frontend
@@ -99,7 +99,7 @@ jobs:
- uses: futureware-tech/simulator-action@v3
id: simulator-action
with:
model: 'iPhone 15'
model: "iPhone 15"
shutdown_after_job: false
# - name: Run AppFlowy on simulator
+42 -3
View File
@@ -43,6 +43,31 @@ jobs:
sed -i '' 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i '' 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Ensure AppFlowy-Cloud is Running with Correct Version
working-directory: AppFlowy-Cloud
env:
APPFLOWY_CLOUD_VERSION: 0.6.4-amd64
run: |
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
if [ -z "$container_id" ]; then
echo "AppFlowy-Cloud container is not running. Pulling and starting the container..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Pulling the correct version..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
echo "AppFlowy-Cloud is running with the correct version."
fi
fi
- name: Run rust-lib tests
working-directory: frontend/rust-lib
env:
@@ -104,15 +129,29 @@ jobs:
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Run Docker-Compose
- name: Ensure AppFlowy-Cloud is Running with Correct Version
working-directory: AppFlowy-Cloud
env:
APPFLOWY_CLOUD_VERSION: 0.6.4-amd64
run: |
if [ "$(docker ps --filter name=appflowy-cloud -q)" == "" ]; then
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
if [ -z "$container_id" ]; then
echo "AppFlowy-Cloud container is not running. Pulling and starting the container..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
echo "Docker container 'appflowy-cloud' is already running."
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Pulling the correct version..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
echo "AppFlowy-Cloud is running with the correct version."
fi
fi
- name: Run rust-lib tests
+26 -26
View File
@@ -20,34 +20,34 @@ concurrency:
cancel-in-progress: true
jobs:
tauri-build-self-hosted:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: install frontend dependencies
working-directory: frontend/appflowy_web_app
run: |
mkdir dist
pnpm install
cd src-tauri && cargo build
- name: test and lint
working-directory: frontend/appflowy_web_app
run: |
pnpm run lint:tauri
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tauriScript: pnpm tauri
projectPath: frontend/appflowy_web_app
args: "--debug"
# tauri-build-self-hosted:
# if: github.event.pull_request.head.repo.full_name == github.repository
# runs-on: self-hosted
#
# steps:
# - uses: actions/checkout@v4
# - name: install frontend dependencies
# working-directory: frontend/appflowy_web_app
# run: |
# mkdir dist
# pnpm install
# cd src-tauri && cargo build
#
# - name: test and lint
# working-directory: frontend/appflowy_web_app
# run: |
# pnpm run lint:tauri
#
# - uses: tauri-apps/tauri-action@v0
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# with:
# tauriScript: pnpm tauri
# projectPath: frontend/appflowy_web_app
# args: "--debug"
tauri-build-ubuntu:
if: github.event.pull_request.head.repo.full_name != github.repository
#if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-20.04
steps:
+35
View File
@@ -1,4 +1,39 @@
# Release Notes
## Version 0.6.9 - 09/09/2024
### New Features
- Added a new property type, 'Files & media'
- Supported Apple Sign-in
- Displayed the page icon next to the row name when the row page contains nested notes
- Enabled Delete Account in Settings
- Included a collapsible navigation menu in your published site
### Bug Fixes
- Fixed the space name color issue in the community themes
- Fixed database filters and sorting issues
- Fixed the issue of not being able to fully display the title on Kanban cards
- Fixed the inability to see the entire text of a checklist item when it's more than one line long
- Fixed hide/unhide buttons in the No Status group
- Fixed the inability to edit group names on Kanban boards
- Made error codes more user-friendly
- Added leading zeros to day and month in date format
## Version 0.6.8 - 22/08/2024
### New Features
- Enabled viewing data inside a database record on mobile.
- Added the ability to invite members to a workspace on mobile.
- Introduced Ask AI in the Home tab on mobile.
- Import CSV files with up to 1,000 rows.
- Convert properties from one type to another while preserving the data.
- Optimized the speed of opening documents and databases.
- Improved syncing performance across devices.
- Added support for a monochrome app icon on Android.
### Bug Fixes
- Removed the Wayland header from the AppImage build.
- Fixed the issue where pasting a web image on mobile failed.
- Corrected the Local AI state when switching between different workspaces.
- Fixed high CPU usage when opening large databases.
## Version 0.6.7 - 13/08/2024
### New Features
- Redesigned the icon picker design on Desktop.
+22 -8
View File
@@ -6,7 +6,7 @@
</h1>
<p align="center">
You are in charge of your data and customizations.
AppFlowy is the AI workspace where you achieve more without losing control of your data
</p>
<p align="center">
@@ -19,20 +19,34 @@ You are in charge of your data and customizations.
<p align="center">
<a href="https://www.appflowy.io"><b>Website</b></a> •
<a href="https://forum.appflowy.io/"><b>Forum</b></a> •
<a href="https://discord.gg/9Q2xaN37tV"><b>Discord</b></a> •
<a href="https://www.reddit.com/r/AppFlowy"><b>Reddit</b></a> •
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
</p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664610-fc209a97-815e-4716-af07-d94a859d1907.png" alt="AppFlowy Docs & Notes & Wikis" width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664628-5def2450-914a-4b2d-b907-92b7476b9863.png" alt="AppFlowy Databases for Tasks and Projects" width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664642-22e26c1b-5eae-4635-9aa6-b12ecf1c3c46.png" alt="AppFlowy Kanban Board for To-Dos" width="1000px" /></p>
<p align="center"><img src="https://github.com/AppFlowy-IO/AppFlowy/assets/12026239/6be93d2b-a5c5-48a9-b7cf-c599d5f5140c" alt="AppFlowy Calendars for Plan and Manage Content" width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664657-dc5291f3-67b0-4a43-a818-640e92735deb.png" alt="AppFlowy OpenAI GPT Writers" width="1000px" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/tasks.796c753e.png" alt="AppFlowy Kanban Board for To-dos" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/Grid.9e30484b.png" alt="AppFlowy Databases for Tasks and Projects" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/sites.a8d5b2b9.png" alt="AppFlowy Sites for Beautiful documentation" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/ai.e1460982.png" alt="AppFlowy AI" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/template.9ea13c3b.png" alt="AppFlowy Templates" /></p>
<br></br>
<p align="center" >
<img src="https://github.com/user-attachments/assets/5841c491-b564-4a26-b9b6-191def430911" alt="Work across devices" width="1040px" /></p>
<p align="center" >
<img src="https://github.com/user-attachments/assets/c2ba6bb8-746c-4743-9393-d008a669be95" alt="Work across devices" width="1040px" /></p>
<p align="center" >
<img src="https://github.com/user-attachments/assets/e83dd1a3-4975-4d0e-91a1-9eb6e0d248cd" alt="Work across devices" width="1040px" /></p>
## User Installation
- [Windows/Mac/Linux](https://docs.appflowy.io/docs/appflowy/install-appflowy/installation-methods/mac-windows-linux-packages)
- [Docker](https://docs.appflowy.io/docs/appflowy/install-appflowy/installation-methods/installing-with-docker)
- [Download AppFlowy Desktop (macOS, Windows, and Linux)](https://github.com/AppFlowy-IO/AppFlowy/releases)
- Other channels: [FlatHub](https://flathub.org/apps/io.appflowy.AppFlowy), [Snapcraft](https://snapcraft.io/appflowy), [Sourceforge](https://sourceforge.net/projects/appflowy/)
- Available on
- App Store: iPhone
- Play Store: Android 10 or above; ARMv7 is not supported
- [Self-hosting AppFlowy](https://docs.appflowy.io/docs/guides/appflowy/self-hosting-appflowy)
- [Source](https://docs.appflowy.io/docs/documentation/appflowy/from-source)
## Built With
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

+1 -1
View File
@@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
APPFLOWY_VERSION = "0.6.7"
APPFLOWY_VERSION = "0.6.9"
FLUTTER_DESKTOP_FEATURES = "dart"
PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0"
@@ -52,7 +52,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "io.appflowy.appflowy"
minSdkVersion 24
minSdkVersion 29
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@@ -87,6 +87,13 @@ android {
path "src/main/CMakeLists.txt"
}
}
// only support arm64-v8a
defaultConfig {
ndk {
abiFilters "arm64-v8a"
}
}
}
flutter {
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/black" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" />
<foreground
android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome
android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
Whitespace-only changes.
@@ -0,0 +1,12 @@
# dart_dependency_validator.yaml
allow_pins: true
include:
- "lib/**"
exclude:
- "packages/**"
ignore:
- analyzer
@@ -3,8 +3,6 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@@ -12,6 +10,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
@@ -19,6 +18,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:intl/intl.dart';
@@ -51,12 +51,12 @@ void main() {
// Scroll to sign-in
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
await tester.tapButton(find.byType(AccountSignInOutButton));
// sign up with Google
await tester.tapGoogleLoginInButton();
@@ -68,7 +68,7 @@ void main() {
// Scroll to sign-out
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
@@ -85,7 +85,7 @@ void main() {
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
final userNameInput =
tester.widget(find.byType(UserProfileSetting)) as UserProfileSetting;
tester.widget(find.byType(AccountUserProfile)) as AccountUserProfile;
expect(userNameInput.name, 'Me');
});
});
@@ -6,6 +6,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -41,11 +42,11 @@ void main() {
// Scroll to sign-out
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
await tester.tapButton(find.byType(AccountSignInOutButton));
tester.expectToSeeText(LocaleKeys.button_ok.tr());
await tester.tapButtonWithName(LocaleKeys.button_ok.tr());
@@ -67,11 +68,11 @@ void main() {
// Scroll to sign-in
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
await tester.tapButton(find.byType(AccountSignInOutButton));
tester.expectToSeeGoogleLoginButton();
});
@@ -1,93 +1,93 @@
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
// import 'package:appflowy/env/cloud_env.dart';
// import 'package:appflowy/workspace/application/settings/prelude.dart';
// import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
// import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart';
// import 'package:flutter_test/flutter_test.dart';
// import 'package:integration_test/integration_test.dart';
import '../shared/util.dart';
// import '../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// void main() {
// IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('supabase auth', () {
testWidgets('sign in with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
});
// group('supabase auth', () {
// testWidgets('sign in with supabase', (tester) async {
// await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
// await tester.tapGoogleLoginInButton();
// await tester.expectToSeeHomePageWithGetStartedPage();
// });
testWidgets('sign out with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
// testWidgets('sign out with supabase', (tester) async {
// await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
// await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
await tester.logout();
// // Open the setting page and sign out
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.account);
// await tester.logout();
// Go to the sign in page again
await tester.pumpAndSettle(const Duration(seconds: 1));
tester.expectToSeeGoogleLoginButton();
});
// // Go to the sign in page again
// await tester.pumpAndSettle(const Duration(seconds: 1));
// tester.expectToSeeGoogleLoginButton();
// });
testWidgets('sign in as anonymous', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapSignInAsGuest();
// testWidgets('sign in as anonymous', (tester) async {
// await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
// await tester.tapSignInAsGuest();
// should not see the sync setting page when sign in as anonymous
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
// // should not see the sync setting page when sign in as anonymous
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.account);
// Scroll to sign-out
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
// // Scroll to sign-out
// await tester.scrollUntilVisible(
// find.byType(SignInOutButton),
// 100,
// scrollable: find.findSettingsScrollable(),
// );
// await tester.tapButton(find.byType(SignInOutButton));
tester.expectToSeeGoogleLoginButton();
});
// tester.expectToSeeGoogleLoginButton();
// });
// testWidgets('enable encryption', (tester) async {
// await tester.initializeAppFlowy(cloudType: CloudType.supabase);
// await tester.tapGoogleLoginInButton();
// // testWidgets('enable encryption', (tester) async {
// // await tester.initializeAppFlowy(cloudType: CloudType.supabase);
// // await tester.tapGoogleLoginInButton();
// // Open the setting page and sign out
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.cloud);
// // // Open the setting page and sign out
// // await tester.openSettings();
// // await tester.openSettingsPage(SettingsPage.cloud);
// // the switch should be off by default
// tester.assertEnableEncryptSwitchValue(false);
// await tester.toggleEnableEncrypt();
// // // 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 should be on after toggling
// // tester.assertEnableEncryptSwitchValue(true);
// // the switch can not be toggled back to off
// await tester.toggleEnableEncrypt();
// 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(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
// testWidgets('enable sync', (tester) async {
// await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
// await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.cloud);
// // Open the setting page and sign out
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.cloud);
// the switch should be on by default
tester.assertSupabaseEnableSyncSwitchValue(true);
await tester.toggleEnableSync(SupabaseEnableSync);
// // the switch should be on by default
// tester.assertSupabaseEnableSyncSwitchValue(true);
// await tester.toggleEnableSync(SupabaseEnableSync);
// the switch should be off
tester.assertSupabaseEnableSyncSwitchValue(false);
// // the switch should be off
// tester.assertSupabaseEnableSyncSwitchValue(false);
// the switch should be on after toggling
await tester.toggleEnableSync(SupabaseEnableSync);
tester.assertSupabaseEnableSyncSwitchValue(true);
});
});
}
// // the switch should be on after toggling
// await tester.toggleEnableSync(SupabaseEnableSync);
// tester.assertSupabaseEnableSyncSwitchValue(true);
// });
// });
// }
@@ -2,8 +2,6 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@@ -11,6 +9,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account_user_profile.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
@@ -18,6 +17,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
@@ -47,31 +47,28 @@ void main() {
await tester.openSettingsPage(SettingsPage.account);
await tester.enterUserName(name);
await tester.tapEscButton();
// wait 2 seconds for the sync to finish
await tester.pumpAndSettle(const Duration(seconds: 6));
});
await tester.logout();
testWidgets('get user icon and name from server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
// Verify name
final profileSetting =
tester.widget(find.byType(UserProfileSetting)) as UserProfileSetting;
expect(profileSetting.name, name);
await tester.pumpAndSettle(const Duration(seconds: 2));
});
});
testWidgets('get user icon and name from server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
// Verify name
final profileSetting =
tester.widget(find.byType(AccountUserProfile)) as AccountUserProfile;
expect(profileSetting.name, name);
});
}
@@ -22,7 +22,7 @@ void main() {
const fieldName = "test change field";
await tester.createField(
FieldType.RichText,
fieldName,
name: fieldName,
layout: ViewLayoutPB.Board,
);
await tester.tapButton(card1);
@@ -1,3 +1,4 @@
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -41,7 +42,7 @@ void main() {
name: 'my grid',
layout: ViewLayoutPB.Grid,
);
await tester.createField(FieldType.RichText, 'description');
await tester.createField(FieldType.RichText, name: 'description');
await tester.editCell(
rowIndex: 0,
@@ -81,7 +82,7 @@ void main() {
const fieldType = FieldType.Number;
// Create a number field
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
await tester.editCell(
rowIndex: 0,
@@ -157,7 +158,7 @@ void main() {
const fieldType = FieldType.CreatedTime;
// Create a create time field
// The create time field is not editable
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -175,7 +176,7 @@ void main() {
const fieldType = FieldType.LastEditedTime;
// Create a last time field
// The last time field is not editable
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -191,7 +192,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.DateTime;
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
// Tap the cell to invoke the field editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -366,7 +367,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.MultiSelect;
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType, name: fieldType.i18n);
// Tap the cell to invoke the selection option editor
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -449,7 +450,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Checklist;
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
// assert that there is no progress bar in the grid
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
@@ -461,22 +462,22 @@ void main() {
tester.assertChecklistEditorVisible(visible: true);
// create a new task with enter
await tester.createNewChecklistTask(name: "task 0", enter: true);
await tester.createNewChecklistTask(name: "task 1", enter: true);
// assert that the task is displayed
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 0",
name: "task 1",
isChecked: false,
);
// update the task's name
await tester.renameChecklistTask(index: 0, name: "task 1");
await tester.renameChecklistTask(index: 0, name: "task 11");
// assert that the task's name is updated
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 1",
name: "task 11",
isChecked: false,
);
@@ -1,12 +1,13 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database/widgets/field/type_option_editor/select/select_option.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:intl/intl.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
@@ -56,11 +57,22 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checklist, 'checklist');
await tester.createField(FieldType.Checklist);
tester.findFieldWithName(FieldType.Checklist.i18n);
// check the field is created successfully
tester.findFieldWithName('checklist');
await tester.pumpAndSettle();
// editing field type during field creation should change title
await tester.createField(FieldType.MultiSelect);
tester.findFieldWithName(FieldType.MultiSelect.i18n);
// not if the user changes the title manually though
const name = "New field";
await tester.createField(FieldType.DateTime);
await tester.tapGridFieldWithName(FieldType.DateTime.i18n);
await tester.renameField(name);
await tester.tapEditFieldButton();
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.URL);
tester.findFieldWithName(name);
});
testWidgets('delete field', (tester) async {
@@ -70,14 +82,14 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checkbox, 'New field 1');
await tester.createField(FieldType.Checkbox, name: 'New field 1');
// Delete the field
await tester.tapGridFieldWithName('New field 1');
await tester.tapDeletePropertyButton();
// confirm delete
await tester.tapDialogOkButton();
await tester.tapButtonWithName(LocaleKeys.space_delete.tr());
tester.noFieldWithName('New field 1');
await tester.pumpAndSettle();
@@ -90,10 +102,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField('New field 1');
await tester.dismissFieldEditor();
await tester.createField(FieldType.RichText, name: 'New field 1');
// duplicate the field
await tester.tapGridFieldWithName('New field 1');
@@ -126,26 +135,6 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('create checklist field', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
// Open the type option menu
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Checklist);
// After update the field type, the cells should be updated
await tester.findCellByFieldType(FieldType.Checklist);
await tester.pumpAndSettle();
});
testWidgets('create list of fields', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -162,18 +151,10 @@ void main() {
FieldType.CreatedTime,
FieldType.Checkbox,
]) {
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField(fieldType.name);
// Open the type option menu
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
await tester.dismissFieldEditor();
await tester.createField(fieldType);
// After update the field type, the cells should be updated
await tester.findCellByFieldType(fieldType);
tester.findCellByFieldType(fieldType);
await tester.pumpAndSettle();
}
});
@@ -190,15 +171,7 @@ void main() {
FieldType.Checklist,
FieldType.URL,
]) {
// create the field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField(fieldType.i18n);
// change field type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
await tester.dismissFieldEditor();
await tester.createField(fieldType);
// open the field editor
await tester.tapGridFieldWithName(fieldType.i18n);
@@ -218,11 +191,7 @@ void main() {
await tester.scrollToRight(find.byType(GridPage));
// create a number field
await tester.tapNewPropertyButton();
await tester.renameField("Number");
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Number);
await tester.dismissFieldEditor();
await tester.createField(FieldType.Number);
// enter some data into the first number cell
await tester.editCell(
@@ -243,7 +212,7 @@ void main() {
);
// open editor and change number format
await tester.tapGridFieldWithName('Number');
await tester.tapGridFieldWithName(FieldType.Number.i18n);
await tester.tapEditFieldButton();
await tester.changeNumberFieldFormat();
await tester.dismissFieldEditor();
@@ -292,11 +261,7 @@ void main() {
await tester.scrollToRight(find.byType(GridPage));
// create a date field
await tester.tapNewPropertyButton();
await tester.renameField(FieldType.DateTime.i18n);
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.DateTime);
await tester.dismissFieldEditor();
await tester.createField(FieldType.DateTime);
// edit the first date cell
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
@@ -0,0 +1,96 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/media_cell_editor.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../../shared/database_test_op.dart';
import '../../shared/mock/mock_file_picker.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('media type option in database', () {
testWidgets('add media field and add files', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to media type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Media);
await tester.dismissFieldEditor();
// Open media cell editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.Media);
await tester.findMediaCellEditor(findsOneWidget);
// Prepare files for upload from local
final firstImage =
await rootBundle.load('assets/test/images/sample.jpeg');
final secondImage =
await rootBundle.load('assets/test/images/sample.gif');
final tempDirectory = await getTemporaryDirectory();
final firstImagePath = p.join(tempDirectory.path, 'sample.jpeg');
final firstFile = File(firstImagePath)
..writeAsBytesSync(firstImage.buffer.asUint8List());
final secondImagePath = p.join(tempDirectory.path, 'sample.gif');
final secondFile = File(secondImagePath)
..writeAsBytesSync(secondImage.buffer.asUint8List());
mockPickFilePaths(paths: [firstImagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect one file
expect(find.byType(RenderMedia), findsOneWidget);
// Mock second file
mockPickFilePaths(paths: [secondImagePath]);
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapButtonWithName(
LocaleKeys.document_plugins_file_fileUploadHint.tr(),
);
await tester.pumpAndSettle();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
// Remove the temp files
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
});
}
@@ -1,3 +1,6 @@
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/desktop_field_cell.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
@@ -121,15 +124,24 @@ void main() {
FieldType.Checkbox,
]) {
await tester.tapRowDetailPageCreatePropertyButton();
await tester.renameField(fieldType.name);
// Open the type option menu
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
final field = find.descendant(
of: find.byType(RowDetailPage),
matching: find.byWidgetPredicate(
(widget) =>
widget is FieldCellButton &&
widget.field.name == fieldType.i18n,
),
);
expect(field, findsOneWidget);
// After update the field type, the cells should be updated
await tester.findCellByFieldType(fieldType);
tester.findCellByFieldType(fieldType);
await tester.scrollRowDetailByOffset(const Offset(0, -50));
}
});
@@ -176,6 +176,7 @@ Future<void> createInlineDatabase(
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
layout.slashMenuName,
offset: 100,
);
await tester.pumpAndSettle();
@@ -1,7 +1,7 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
import 'package:appflowy/shared/flowy_error_page.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -92,7 +92,7 @@ void main() {
);
expect(finder, findsOneWidget);
await tester.tapButton(finder);
expect(find.byType(FlowyErrorPage), findsOneWidget);
expect(find.byType(AppFlowyErrorPage), findsOneWidget);
});
});
}
@@ -1,8 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -13,7 +12,7 @@ import 'util.dart';
extension AppFlowyAuthTest on WidgetTester {
Future<void> tapGoogleLoginInButton() async {
await tapButton(
find.byKey(const Key('signInWithGoogleButton')),
find.byKey(signInWithGoogleButtonKey),
);
}
@@ -21,12 +20,12 @@ extension AppFlowyAuthTest on WidgetTester {
Future<void> logout() async {
final scrollable = find.findSettingsScrollable();
await scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: scrollable,
);
await tapButton(find.byType(SignInOutButton));
await tapButton(find.byType(AccountSignInOutButton));
expectToSeeText(LocaleKeys.button_ok.tr());
await tapButtonWithName(LocaleKeys.button_ok.tr());
@@ -37,7 +36,7 @@ extension AppFlowyAuthTest on WidgetTester {
}
void expectToSeeGoogleLoginButton() {
expect(find.byKey(const Key('signInWithGoogleButton')), findsOneWidget);
expect(find.byKey(signInWithGoogleButtonKey), findsOneWidget);
}
void assertSwitchValue(Finder finder, bool value) {
@@ -52,26 +51,6 @@ extension AppFlowyAuthTest on WidgetTester {
assert(isSwitched == value);
}
void assertEnableEncryptSwitchValue(bool value) {
assertSwitchValue(
find.descendant(
of: find.byType(EnableEncrypt),
matching: find.byWidgetPredicate((widget) => widget is Switch),
),
value,
);
}
void assertSupabaseEnableSyncSwitchValue(bool value) {
assertSwitchValue(
find.descendant(
of: find.byType(SupabaseEnableSync),
matching: find.byWidgetPredicate((widget) => widget is Switch),
),
value,
);
}
void assertAppFlowyCloudEnableSyncSwitchValue(bool value) {
assertToggleValue(
find.descendant(
@@ -82,15 +61,6 @@ extension AppFlowyAuthTest on WidgetTester {
);
}
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(Type syncButton) async {
final finder = find.descendant(
of: find.byType(syncButton),
@@ -7,7 +7,6 @@ import 'package:appflowy/startup/entry_point.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/auth/supabase_mock_auth_service.dart';
import 'package:appflowy/user/presentation/presentation.dart';
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
@@ -55,8 +54,6 @@ extension AppFlowyTestBase on WidgetTester {
switch (cloudType) {
case AuthenticatorType.local:
break;
case AuthenticatorType.supabase:
break;
case AuthenticatorType.appflowyCloudSelfHost:
rustEnvs["GOTRUE_ADMIN_EMAIL"] = "admin@example.com";
rustEnvs["GOTRUE_ADMIN_PASSWORD"] = "password";
@@ -75,13 +72,6 @@ extension AppFlowyTestBase on WidgetTester {
case AuthenticatorType.local:
await useLocalServer();
break;
case AuthenticatorType.supabase:
await useTestSupabaseCloud();
getIt.unregister<AuthService>();
getIt.registerFactory<AuthService>(
() => SupabaseMockAuthService(),
);
break;
case AuthenticatorType.appflowyCloudSelfHost:
await useTestSelfHostedAppFlowyCloud();
getIt.unregister<AuthService>();
@@ -242,13 +232,6 @@ extension AppFlowyFinderTestBase on CommonFinders {
}
}
Future<void> useTestSupabaseCloud() async {
await useSupabaseCloud(
url: TestEnv.supabaseUrl,
anonKey: TestEnv.supabaseAnonKey,
);
}
Future<void> useTestSelfHostedAppFlowyCloud() async {
await useSelfHostedAppFlowyCloudWithURL(TestEnv.afCloudUrl);
}
@@ -1,5 +1,10 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
@@ -30,10 +35,6 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'emoji.dart';
@@ -41,6 +41,7 @@ import 'package:appflowy/plugins/database/tab_bar/desktop/tab_bar_header.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checkbox.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checklist.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/date.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/media.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/number.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/select_option.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
@@ -50,6 +51,7 @@ import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_edi
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_progress_bar.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/date_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/media_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_text_field.dart';
import 'package:appflowy/plugins/database/widgets/database_layout_ext.dart';
@@ -72,7 +74,6 @@ import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/clear_date_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/date_type_option_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
@@ -474,7 +475,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
await pumpAndSettle();
if (enter) {
await testTextInput.receiveAction(TextInputAction.done);
await pumpAndSettle();
await pumpAndSettle(const Duration(milliseconds: 500));
} else {
await tapButton(
find.descendant(
@@ -627,12 +628,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
(w) => w is FieldActionCell && w.action == FieldAction.delete,
);
await tapButton(deleteButton);
final confirmButton = find.descendant(
of: find.byType(NavigatorAlertDialog),
matching: find.byType(PrimaryTextButton),
);
await tapButton(confirmButton);
await tapButtonWithName(LocaleKeys.space_delete.tr());
}
Future<void> scrollRowDetailByOffset(Offset offset) async {
@@ -786,7 +782,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
/// Each field has its own cell, so we can find the corresponding cell by
/// the field type after create a new field.
Future<void> findCellByFieldType(FieldType fieldType) async {
void findCellByFieldType(FieldType fieldType) {
final finder = finderForFieldType(fieldType);
expect(finder, findsWidgets);
}
@@ -857,6 +853,11 @@ extension AppFlowyDatabaseTest on WidgetTester {
expect(finder, matcher);
}
Future<void> findMediaCellEditor(dynamic matcher) async {
final finder = find.byType(MediaCellEditor);
expect(finder, matcher);
}
Future<void> findSelectOptionEditor(dynamic matcher) async {
final finder = find.byType(SelectOptionCellEditor);
expect(finder, matcher);
@@ -887,18 +888,19 @@ extension AppFlowyDatabaseTest on WidgetTester {
}
Future<void> createField(
FieldType fieldType,
String name, {
FieldType fieldType, {
String? name,
ViewLayoutPB layout = ViewLayoutPB.Grid,
}) async {
if (layout == ViewLayoutPB.Grid) {
await scrollToRight(find.byType(GridPage));
}
await tapNewPropertyButton();
await renameField(name);
if (name != null) {
await renameField(name);
}
await tapSwitchFieldTypeButton();
await selectFieldType(fieldType);
await dismissFieldEditor();
}
Future<void> tapDatabaseSettingButton() async {
@@ -1580,6 +1582,8 @@ Finder finderForFieldType(FieldType fieldType) {
return find.byType(EditableTextCell, skipOffstage: false);
case FieldType.URL:
return find.byType(EditableURLCell, skipOffstage: false);
case FieldType.Media:
return find.byType(EditableMediaCell, skipOffstage: false);
default:
throw Exception('Unknown field type: $fieldType');
}
@@ -2,7 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account_user_profile.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_workspace_view.dart';
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
@@ -77,14 +77,14 @@ extension AppFlowySettings on WidgetTester {
Future<void> enterUserName(String name) async {
// Enable editing username
final editUsernameFinder = find.descendant(
of: find.byType(UserProfileSetting),
of: find.byType(AccountUserProfile),
matching: find.byFlowySvg(FlowySvgs.edit_s),
);
await tap(editUsernameFinder);
await tap(editUsernameFinder, warnIfMissed: false);
await pumpAndSettle();
final userNameFinder = find.descendant(
of: find.byType(UserProfileSetting),
of: find.byType(AccountUserProfile),
matching: find.byType(FlowyTextField),
);
await enterText(userNameFinder, name);
+17 -12
View File
@@ -48,8 +48,6 @@ PODS:
- fluttertoast (0.0.2):
- Flutter
- Toast
- image_gallery_saver (2.0.2):
- Flutter
- image_picker_ios (0.0.1):
- Flutter
- integration_test (0.0.1):
@@ -58,6 +56,8 @@ PODS:
- Flutter
- keyboard_height_plugin (0.0.1):
- Flutter
- open_filex (0.0.2):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
@@ -65,12 +65,15 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- printing (1.0.0):
- Flutter
- ReachabilitySwift (5.0.0)
- SDWebImage (5.14.2):
- SDWebImage/Core (= 5.14.2)
- SDWebImage/Core (5.14.2)
- Sentry/HybridSDK (8.35.1)
- sentry_flutter (8.8.0):
- Flutter
- FlutterMacOS
- Sentry/HybridSDK (= 8.35.1)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
@@ -95,15 +98,15 @@ DEPENDENCIES:
- flowy_infra_ui (from `.symlinks/plugins/flowy_infra_ui/ios`)
- Flutter (from `Flutter`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
- keyboard_height_plugin (from `.symlinks/plugins/keyboard_height_plugin/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- printing (from `.symlinks/plugins/printing/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
@@ -116,6 +119,7 @@ SPEC REPOS:
- DKPhotoGallery
- ReachabilitySwift
- SDWebImage
- Sentry
- SwiftyGif
- Toast
@@ -136,8 +140,6 @@ EXTERNAL SOURCES:
:path: Flutter
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
image_gallery_saver:
:path: ".symlinks/plugins/image_gallery_saver/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
integration_test:
@@ -146,14 +148,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/irondash_engine_context/ios"
keyboard_height_plugin:
:path: ".symlinks/plugins/keyboard_height_plugin/ios"
open_filex:
:path: ".symlinks/plugins/open_filex/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
printing:
:path: ".symlinks/plugins/printing/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
@@ -176,17 +180,18 @@ SPEC CHECKSUMS:
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1
sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
@@ -372,6 +372,7 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -383,6 +384,8 @@
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
@@ -511,6 +514,7 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -522,6 +526,8 @@
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -545,6 +551,7 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = AppFlowy;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -556,6 +563,8 @@
STRIP_STYLE = "non-global";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
+67 -69
View File
@@ -1,75 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>AppFlowy requires access to the camera.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>AppFlowy requires access to the photo library.</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true />
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
</array>
<key>FLTEnableImpeller</key>
<false />
<key>CFBundleName</key>
<string>AppFlowy</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string></string>
<key>CFBundleURLSchemes</key>
<array>
<string>appflowy-flutter</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true />
<key>UIApplicationSupportsIndirectInputEvents</key>
<true />
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false />
<key>NSAppTransportSecurity</key>
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
</array>
<key>CFBundleName</key>
<string>AppFlowy</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>CFBundleURLName</key>
<string></string>
<key>CFBundleURLSchemes</key>
<array>
<string>appflowy-flutter</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FLTEnableImpeller</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</plist>
<key>NSPhotoLibraryUsageDescription</key>
<string>AppFlowy needs access to your photos to let you add images to your documents</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UISupportsDocumentBrowser</key>
<true/>
</dict>
</plist>
@@ -4,5 +4,9 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>
@@ -1,15 +1,7 @@
import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/window_title_bar.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CocoaWindowChannel {
CocoaWindowChannel._();
@@ -38,11 +30,9 @@ class MoveWindowDetector extends StatefulWidget {
const MoveWindowDetector({
super.key,
this.child,
this.showTitleBar = false,
});
final Widget? child;
final bool showTitleBar;
@override
MoveWindowDetectorState createState() => MoveWindowDetectorState();
@@ -54,28 +44,10 @@ class MoveWindowDetectorState extends State<MoveWindowDetector> {
@override
Widget build(BuildContext context) {
if (!Platform.isMacOS && !Platform.isWindows) {
if (!Platform.isMacOS) {
return widget.child ?? const SizedBox.shrink();
}
if (Platform.isWindows) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.showTitleBar) ...[
WindowTitleBar(
leftChildren: [
_buildToggleMenuButton(context),
],
),
] else ...[
const SizedBox(height: 5),
],
widget.child ?? const SizedBox.shrink(),
],
);
}
return GestureDetector(
// https://stackoverflow.com/questions/52965799/flutter-gesturedetector-not-working-with-containers-in-stack
behavior: HitTestBehavior.translucent,
@@ -96,45 +68,4 @@ class MoveWindowDetectorState extends State<MoveWindowDetector> {
child: widget.child,
);
}
Widget _buildToggleMenuButton(BuildContext context) {
if (!context.read<HomeSettingBloc>().state.isMenuCollapsed) {
return const SizedBox.shrink();
}
final textSpan = TextSpan(
children: [
TextSpan(
text: '${LocaleKeys.sideBar_openSidebar.tr()}\n',
style: context.tooltipTextStyle(),
),
TextSpan(
text: Platform.isMacOS ? '⌘+.' : 'Ctrl+\\',
style: context
.tooltipTextStyle()
?.copyWith(color: Theme.of(context).hintColor),
),
],
);
return FlowyTooltip(
richMessage: textSpan,
child: Listener(
behavior: HitTestBehavior.translucent,
onPointerDown: (_) => context
.read<HomeSettingBloc>()
.add(const HomeSettingEvent.collapseMenu()),
child: FlowyHover(
child: Container(
width: 24,
padding: const EdgeInsets.all(4),
child: const RotatedBox(
quarterTurns: 2,
child: FlowySvg(FlowySvgs.hide_menu_s),
),
),
),
),
);
}
}
-30
View File
@@ -13,7 +13,6 @@ class AppFlowyConfiguration {
required this.device_id,
required this.platform,
required this.authenticator_type,
required this.supabase_config,
required this.appflowy_cloud_config,
required this.envs,
});
@@ -28,41 +27,12 @@ class AppFlowyConfiguration {
final String device_id;
final String platform;
final int authenticator_type;
final SupabaseConfiguration supabase_config;
final AppFlowyCloudConfiguration appflowy_cloud_config;
final Map<String, String> envs;
Map<String, dynamic> toJson() => _$AppFlowyConfigurationToJson(this);
}
@JsonSerializable()
class SupabaseConfiguration {
SupabaseConfiguration({
required this.url,
required this.anon_key,
});
factory SupabaseConfiguration.fromJson(Map<String, dynamic> json) =>
_$SupabaseConfigurationFromJson(json);
/// Indicates whether the sync feature is enabled.
final String url;
final String anon_key;
Map<String, dynamic> toJson() => _$SupabaseConfigurationToJson(this);
static SupabaseConfiguration defaultConfig() {
return SupabaseConfiguration(
url: '',
anon_key: '',
);
}
bool get isValid {
return url.isNotEmpty && anon_key.isNotEmpty;
}
}
@JsonSerializable()
class AppFlowyCloudConfiguration {
AppFlowyCloudConfiguration({
+1 -66
View File
@@ -21,9 +21,6 @@ Future<void> _setAuthenticatorType(AuthenticatorType ty) async {
case AuthenticatorType.local:
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, 0.toString());
break;
case AuthenticatorType.supabase:
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, 1.toString());
break;
case AuthenticatorType.appflowyCloud:
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, 2.toString());
break;
@@ -63,8 +60,6 @@ Future<AuthenticatorType> getAuthenticatorType() async {
switch (value ?? "0") {
case "0":
return AuthenticatorType.local;
case "1":
return AuthenticatorType.supabase;
case "2":
return AuthenticatorType.appflowyCloud;
case "3":
@@ -93,10 +88,6 @@ Future<AuthenticatorType> getAuthenticatorType() async {
/// Returns `false` otherwise.
bool get isAuthEnabled {
final env = getIt<AppFlowyCloudSharedEnv>();
if (env.authenticatorType == AuthenticatorType.supabase) {
return env.supabaseConfig.isValid;
}
if (env.authenticatorType.isAppFlowyCloudEnabled) {
return env.appflowyCloudConfig.isValid;
}
@@ -104,19 +95,6 @@ bool get isAuthEnabled {
return false;
}
/// Checks if Supabase is enabled.
///
/// This getter evaluates if Supabase should be enabled based on the
/// current integration mode and cloud type setting.
///
/// Returns:
/// A boolean value indicating whether Supabase is enabled. It returns `true`
/// if the application is in release or develop mode and the current cloud type
/// is `CloudType.supabase`. Otherwise, it returns `false`.
bool get isSupabaseEnabled {
return currentCloudType().isSupabaseEnabled;
}
/// Determines if AppFlowy Cloud is enabled.
bool get isAppFlowyCloudEnabled {
return currentCloudType().isAppFlowyCloudEnabled;
@@ -124,7 +102,6 @@ bool get isAppFlowyCloudEnabled {
enum AuthenticatorType {
local,
supabase,
appflowyCloud,
appflowyCloudSelfHost,
// The 'appflowyCloudDevelop' type is used for develop purposes only.
@@ -137,14 +114,10 @@ enum AuthenticatorType {
this == AuthenticatorType.appflowyCloudDevelop ||
this == AuthenticatorType.appflowyCloud;
bool get isSupabaseEnabled => this == AuthenticatorType.supabase;
int get value {
switch (this) {
case AuthenticatorType.local:
return 0;
case AuthenticatorType.supabase:
return 1;
case AuthenticatorType.appflowyCloud:
return 2;
case AuthenticatorType.appflowyCloudSelfHost:
@@ -158,8 +131,6 @@ enum AuthenticatorType {
switch (value) {
case 0:
return AuthenticatorType.local;
case 1:
return AuthenticatorType.supabase;
case 2:
return AuthenticatorType.appflowyCloud;
case 3:
@@ -197,25 +168,15 @@ Future<void> useLocalServer() async {
await _setAuthenticatorType(AuthenticatorType.local);
}
Future<void> useSupabaseCloud({
required String url,
required String anonKey,
}) async {
await _setAuthenticatorType(AuthenticatorType.supabase);
await setSupabaseServer(url, anonKey);
}
/// Use getIt<AppFlowyCloudSharedEnv>() to get the shared environment.
class AppFlowyCloudSharedEnv {
AppFlowyCloudSharedEnv({
required AuthenticatorType authenticatorType,
required this.appflowyCloudConfig,
required this.supabaseConfig,
}) : _authenticatorType = authenticatorType;
final AuthenticatorType _authenticatorType;
final AppFlowyCloudConfiguration appflowyCloudConfig;
final SupabaseConfiguration supabaseConfig;
AuthenticatorType get authenticatorType => _authenticatorType;
@@ -229,10 +190,6 @@ class AppFlowyCloudSharedEnv {
? await getAppFlowyCloudConfig(authenticatorType)
: AppFlowyCloudConfiguration.defaultConfig();
final supabaseCloudConfig = authenticatorType.isSupabaseEnabled
? await getSupabaseCloudConfig()
: SupabaseConfiguration.defaultConfig();
// In the backend, the value '2' represents the use of AppFlowy Cloud. However, in the frontend,
// we distinguish between [AuthenticatorType.appflowyCloudSelfHost] and [AuthenticatorType.appflowyCloud].
// When the cloud type is [AuthenticatorType.appflowyCloudSelfHost] in the frontend, it should be
@@ -244,7 +201,6 @@ class AppFlowyCloudSharedEnv {
return AppFlowyCloudSharedEnv(
authenticatorType: authenticatorType,
appflowyCloudConfig: appflowyCloudConfig,
supabaseConfig: supabaseCloudConfig,
);
} else {
// Using the cloud settings from the .env file.
@@ -257,7 +213,6 @@ class AppFlowyCloudSharedEnv {
return AppFlowyCloudSharedEnv(
authenticatorType: AuthenticatorType.fromValue(Env.authenticatorType),
appflowyCloudConfig: appflowyCloudConfig,
supabaseConfig: SupabaseConfiguration.defaultConfig(),
);
}
}
@@ -265,8 +220,7 @@ class AppFlowyCloudSharedEnv {
@override
String toString() {
return 'authenticator: $_authenticatorType\n'
'appflowy: ${appflowyCloudConfig.toJson()}\n'
'supabase: ${supabaseConfig.toJson()})\n';
'appflowy: ${appflowyCloudConfig.toJson()}\n';
}
}
@@ -354,22 +308,3 @@ Future<void> setSupabaseServer(
await getIt<KeyValueStorage>().set(KVKeys.kSupabaseAnonKey, anonKey);
}
}
Future<SupabaseConfiguration> getSupabaseCloudConfig() async {
final url = await _getSupabaseUrl();
final anonKey = await _getSupabaseAnonKey();
return SupabaseConfiguration(
url: url,
anon_key: anonKey,
);
}
Future<String> _getSupabaseUrl() async {
final result = await getIt<KeyValueStorage>().get(KVKeys.kSupabaseURL);
return result ?? '';
}
Future<String> _getSupabaseAnonKey() async {
final result = await getIt<KeyValueStorage>().get(KVKeys.kSupabaseAnonKey);
return result ?? '';
}
+7
View File
@@ -36,4 +36,11 @@ abstract class Env {
defaultValue: '',
)
static const String internalBuild = _Env.internalBuild;
@EnviedField(
obfuscate: false,
varName: 'SENTRY_DSN',
defaultValue: '',
)
static const String sentryDsn = _Env.sentryDsn;
}
@@ -2,27 +2,41 @@ import 'dart:async';
import 'dart:convert';
import 'package:appflowy/mobile/presentation/chat/mobile_chat_screen.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart';
import 'package:appflowy/mobile/presentation/database/mobile_calendar_screen.dart';
import 'package:appflowy/mobile/presentation/database/mobile_grid_screen.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
extension MobileRouter on BuildContext {
Future<void> pushView(ViewPB view, [Map<String, dynamic>? arguments]) async {
Future<void> pushView(
ViewPB view, {
Map<String, dynamic>? arguments,
bool addInRecent = true,
bool showMoreButton = true,
String? fixedTitle,
}) async {
// set the current view before pushing the new view
getIt<MenuSharedState>().latestOpenView = view;
unawaited(getIt<CachedRecentService>().updateRecentViews([view.id], true));
final queryParameters = view.queryParameters(arguments);
if (view.layout == ViewLayoutPB.Document) {
queryParameters[MobileDocumentScreen.viewShowMoreButton] =
showMoreButton.toString();
if (fixedTitle != null) {
queryParameters[MobileDocumentScreen.viewFixedTitle] = fixedTitle;
}
}
final uri = Uri(
path: view.routeName,
queryParameters: view.queryParameters(arguments),
queryParameters: queryParameters,
).toString();
await push(uri);
}
@@ -1,7 +1,5 @@
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/document_listener.dart';
import 'package:appflowy/plugins/document/application/document_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
@@ -113,7 +111,6 @@ class RecentViewBloc extends Bloc<RecentViewEvent, RecentViewState> {
);
}
final _service = DocumentService();
final ViewPB view;
final DocumentListener _documentListener;
final ViewListener _viewListener;
@@ -124,16 +121,6 @@ class RecentViewBloc extends Bloc<RecentViewEvent, RecentViewState> {
// for the version under 0.5.5
Future<(CoverType, String?)> getCoverV1() async {
final result = await _service.getDocument(documentId: view.id);
final document = result.fold((s) => s.toDocument(), (f) => null);
if (document != null) {
final coverType = CoverType.fromString(
document.root.attributes[DocumentHeaderBlockKeys.coverType],
);
final coverValue = document
.root.attributes[DocumentHeaderBlockKeys.coverDetails] as String?;
return (coverType, coverValue);
}
return (CoverType.none, null);
}
@@ -12,12 +12,12 @@ class UserProfileBloc extends Bloc<UserProfileEvent, UserProfileState> {
UserProfileBloc() : super(const _Initial()) {
on<UserProfileEvent>((event, emit) async {
await event.when(
started: () async => _initalize(emit),
started: () async => _initialize(emit),
);
});
}
Future<void> _initalize(Emitter<UserProfileState> emit) async {
Future<void> _initialize(Emitter<UserProfileState> emit) async {
emit(const UserProfileState.loading());
final workspaceOrFailure =
@@ -10,7 +10,7 @@ enum FlowyAppBarLeadingType {
Widget getWidget(VoidCallback? onTap) {
switch (this) {
case FlowyAppBarLeadingType.back:
return AppBarBackButton(onTap: onTap);
return AppBarImmersiveBackButton(onTap: onTap);
case FlowyAppBarLeadingType.close:
return AppBarCloseButton(onTap: onTap);
case FlowyAppBarLeadingType.cancel:
@@ -26,6 +26,31 @@ class AppBarBackButton extends StatelessWidget {
}
}
class AppBarImmersiveBackButton extends StatelessWidget {
const AppBarImmersiveBackButton({
super.key,
this.onTap,
});
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
return AppBarButton(
onTap: (_) => (onTap ?? () => Navigator.pop(context)).call(),
padding: const EdgeInsets.only(
left: 12.0,
top: 8.0,
bottom: 8.0,
right: 4.0,
),
child: const FlowySvg(
FlowySvgs.m_app_bar_back_s,
),
);
}
}
class AppBarCloseButton extends StatelessWidget {
const AppBarCloseButton({
super.key,
@@ -3,8 +3,8 @@ import 'package:appflowy/mobile/application/base/mobile_view_page_bloc.dart';
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart';
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
import 'package:appflowy/plugins/document/presentation/document_collaborators.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/plugin/plugin.dart';
@@ -27,6 +27,8 @@ class MobileViewPage extends StatefulWidget {
required this.viewLayout,
this.title,
this.arguments,
this.fixedTitle,
this.showMoreButton = true,
});
/// view id
@@ -34,6 +36,10 @@ class MobileViewPage extends StatefulWidget {
final ViewLayoutPB viewLayout;
final String? title;
final Map<String, dynamic>? arguments;
final bool showMoreButton;
// only used in row page
final String? fixedTitle;
@override
State<MobileViewPage> createState() => _MobileViewPageState();
@@ -164,6 +170,9 @@ class _MobileViewPageState extends State<MobileViewPage> {
return plugin.widgetBuilder.buildWidget(
shrinkWrap: false,
context: PluginContext(userProfile: state.userProfilePB),
data: {
MobileDocumentScreen.viewFixedTitle: widget.fixedTitle,
},
);
},
(error) {
@@ -216,13 +225,19 @@ class _MobileViewPageState extends State<MobileViewPage> {
]);
}
actions.addAll([
MobileViewPageMoreButton(
view: view,
isImmersiveMode: isImmersiveMode,
appBarOpacity: _appBarOpacity,
),
]);
if (widget.showMoreButton) {
actions.addAll([
MobileViewPageMoreButton(
view: view,
isImmersiveMode: isImmersiveMode,
appBarOpacity: _appBarOpacity,
),
]);
} else {
actions.addAll([
const HSpace(18.0),
]);
}
return actions;
}
@@ -232,19 +247,20 @@ class _MobileViewPageState extends State<MobileViewPage> {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null && icon.isNotEmpty)
ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 34.0),
child: EmojiText(
emoji: '$icon ',
fontSize: 22.0,
),
if (icon != null && icon.isNotEmpty) ...[
FlowyText.emoji(
icon,
fontSize: 15.0,
figmaLineHeight: 18.0,
),
const HSpace(4),
],
Expanded(
child: FlowyText.medium(
view?.name ?? widget.title ?? '',
widget.fixedTitle ?? view?.name ?? widget.title ?? '',
fontSize: 15.0,
overflow: TextOverflow.ellipsis,
figmaLineHeight: 18.0,
),
),
],
@@ -52,6 +52,7 @@ class _MobileBottomSheetRenameWidgetState
height: 42.0,
child: FlowyTextField(
controller: controller,
textStyle: Theme.of(context).textTheme.bodyMedium,
keyboardType: TextInputType.text,
onSubmitted: (text) => widget.onRename(text),
),
@@ -64,6 +64,10 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
case MobileViewItemBottomSheetBodyAction.duplicate:
Navigator.pop(context);
context.read<ViewBloc>().add(const ViewEvent.duplicate());
showToastNotification(
context,
message: LocaleKeys.button_duplicateSuccessfully.tr(),
);
break;
case MobileViewItemBottomSheetBodyAction.share:
// unimplemented
@@ -79,6 +83,12 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
context
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(widget.view));
showToastNotification(
context,
message: !widget.view.isFavorite
? LocaleKeys.button_favoriteSuccessfully.tr()
: LocaleKeys.button_unfavoriteSuccessfully.tr(),
);
break;
case MobileViewItemBottomSheetBodyAction.removeFromRecent:
_removeFromRecent(context);
@@ -116,12 +126,18 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
Future<void> _showConfirmDialog({required VoidCallback onDelete}) async {
await showFlowyCupertinoConfirmDialog(
title: LocaleKeys.sideBar_removePageFromRecent.tr(),
leftButton: FlowyText.regular(
leftButton: FlowyText(
LocaleKeys.button_cancel.tr(),
color: const Color(0xFF1456F0),
fontSize: 17.0,
figmaLineHeight: 24.0,
fontWeight: FontWeight.w500,
color: const Color(0xFF007AFF),
),
rightButton: FlowyText.medium(
rightButton: FlowyText(
LocaleKeys.button_delete.tr(),
fontSize: 17.0,
figmaLineHeight: 24.0,
fontWeight: FontWeight.w400,
color: const Color(0xFFFE0220),
),
onRightButtonPressed: (context) {
@@ -3,13 +3,13 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/board/board.dart';
import 'package:appflowy/mobile/presentation/database/board/widgets/group_card_header.dart';
import 'package:appflowy/mobile/presentation/database/card/card.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_type_extension.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_style_maps/mobile_board_card_cell_style.dart';
import 'package:appflowy/shared/flowy_error_page.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
@@ -69,10 +69,10 @@ class _MobileBoardPageState extends State<MobileBoardPage> {
loading: (_) => const Center(
child: CircularProgressIndicator.adaptive(),
),
error: (err) => FlowyMobileStateContainer.error(
emoji: '🛸',
title: LocaleKeys.board_mobile_failedToLoad.tr(),
errorMsg: err.toString(),
error: (err) => Center(
child: AppFlowyErrorPage(
error: err.error,
),
),
ready: (data) => const _BoardContent(),
orElse: () => const SizedBox.shrink(),
@@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/board/application/board_bloc.dart';
import 'package:appflowy/plugins/database/board/group_ext.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_skeleton/text_card_cell.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
@@ -11,7 +14,6 @@ import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
@@ -200,7 +202,7 @@ class MobileHiddenGroup extends StatelessWidget {
children: [
Expanded(
child: Text(
context.read<BoardBloc>().generateGroupNameFromGroup(group),
group.generateGroupName(databaseController),
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 2,
overflow: TextOverflow.ellipsis,
@@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar_actions.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/row_page_button.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
@@ -22,7 +25,6 @@ import 'package:appflowy_backend/protobuf/flowy-database2/row_entities.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:go_router/go_router.dart';
@@ -294,6 +296,7 @@ class MobileRowDetailPageContentState
RowCache get rowCache => widget.databaseController.rowCache;
FieldController get fieldController =>
widget.databaseController.fieldController;
ValueNotifier<String> primaryFieldId = ValueNotifier('');
@override
void initState() {
@@ -304,6 +307,8 @@ class MobileRowDetailPageContentState
viewId: viewId,
rowCache: rowCache,
);
rowController.initialize();
cellBuilder = EditableCellBuilder(
databaseController: widget.databaseController,
);
@@ -326,7 +331,13 @@ class MobileRowDetailPageContentState
fieldController: fieldController,
rowMeta: rowController.rowMeta,
)..add(const RowBannerEvent.initial()),
child: BlocBuilder<RowBannerBloc, RowBannerState>(
child: BlocConsumer<RowBannerBloc, RowBannerState>(
listener: (context, state) {
if (state.primaryField == null) {
return;
}
primaryFieldId.value = state.primaryField!.id;
},
builder: (context, state) {
if (state.primaryField == null) {
return const SizedBox.shrink();
@@ -366,6 +377,23 @@ class MobileRowDetailPageContentState
if (rowDetailState.numHiddenFields != 0) ...[
const ToggleHiddenFieldsVisibilityButton(),
],
const VSpace(8.0),
ValueListenableBuilder(
valueListenable: primaryFieldId,
builder: (context, primaryFieldId, child) {
if (primaryFieldId.isEmpty) {
return const SizedBox.shrink();
}
return OpenRowPageButton(
databaseController: widget.databaseController,
cellContext: CellContext(
rowId: rowController.rowId,
fieldId: primaryFieldId,
),
documentId: rowController.rowMeta.documentId,
);
},
),
MobileRowDetailCreateFieldButton(
viewId: viewId,
fieldController: fieldController,
@@ -22,7 +22,7 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
minHeight: GridSize.headerHeight,
maxHeight: GridSize.headerHeight,
),
child: TextButton.icon(
style: Theme.of(context).textButtonTheme.style?.copyWith(
@@ -37,7 +37,7 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
alignment: AlignmentDirectional.centerStart,
splashFactory: NoSplash.splashFactory,
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 14, horizontal: 6),
EdgeInsets.symmetric(horizontal: 6, vertical: 2),
),
),
label: FlowyText.medium(
@@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
@@ -6,7 +8,6 @@ import 'package:appflowy/plugins/database/grid/application/row/row_detail_bloc.d
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_builder.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MobileRowPropertyList extends StatelessWidget {
@@ -87,6 +88,7 @@ class _PropertyCellState extends State<_PropertyCell> {
fieldInfo.name,
overflow: TextOverflow.ellipsis,
fontSize: 14,
figmaLineHeight: 16.0,
color: Theme.of(context).hintColor,
),
),
@@ -0,0 +1,143 @@
import 'dart:async';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class OpenRowPageButton extends StatefulWidget {
const OpenRowPageButton({
super.key,
required this.documentId,
required this.databaseController,
required this.cellContext,
});
final String documentId;
final DatabaseController databaseController;
final CellContext cellContext;
@override
State<OpenRowPageButton> createState() => _OpenRowPageButtonState();
}
class _OpenRowPageButtonState extends State<OpenRowPageButton> {
late final cellBloc = TextCellBloc(
cellController: makeCellController(
widget.databaseController,
widget.cellContext,
).as(),
);
ViewPB? view;
@override
void initState() {
super.initState();
_preloadView(context, createDocumentIfMissed: true);
}
@override
Widget build(BuildContext context) {
return BlocBuilder<TextCellBloc, TextCellState>(
bloc: cellBloc,
builder: (context, state) {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
maxHeight: GridSize.buttonHeight,
),
child: TextButton.icon(
style: Theme.of(context).textButtonTheme.style?.copyWith(
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
overlayColor: WidgetStateProperty.all<Color>(
Theme.of(context).hoverColor,
),
alignment: AlignmentDirectional.centerStart,
splashFactory: NoSplash.splashFactory,
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(horizontal: 6),
),
),
label: FlowyText.medium(
LocaleKeys.grid_field_openRowDocument.tr(),
fontSize: 15,
),
icon: const Padding(
padding: EdgeInsets.all(4.0),
child: FlowySvg(
FlowySvgs.full_view_s,
size: Size.square(16.0),
),
),
onPressed: () {
final name = state.content;
_openRowPage(context, name);
},
),
);
},
);
}
Future<void> _openRowPage(BuildContext context, String fieldName) async {
Log.info('Open row page(${widget.documentId})');
if (view == null) {
showToastNotification(context, message: 'Failed to open row page');
// reload the view again
unawaited(_preloadView(context));
Log.error('Failed to open row page(${widget.documentId})');
return;
}
if (context.mounted) {
// the document in row is an orphan document, so we don't add it to recent
await context.pushView(
view!,
addInRecent: false,
showMoreButton: false,
fixedTitle: fieldName,
);
}
}
// preload view to reduce the time to open the view
Future<void> _preloadView(
BuildContext context, {
bool createDocumentIfMissed = false,
}) async {
Log.info('Preload row page(${widget.documentId})');
final result = await ViewBackendService.getView(widget.documentId);
view = result.fold((s) => s, (f) => null);
if (view == null && createDocumentIfMissed) {
// create view if not exists
Log.info('Create row page(${widget.documentId})');
final result = await ViewBackendService.createOrphanView(
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
viewId: widget.documentId,
layoutType: ViewLayoutPB.Document,
);
view = result.fold((s) => s, (f) => null);
}
}
}
@@ -1,9 +1,16 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy/plugins/database/widgets/card/card_bloc.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_builder.dart';
import 'package:appflowy/plugins/database/widgets/cell/card_cell_style_maps/mobile_board_card_cell_style.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
class MobileCardContent extends StatelessWidget {
const MobileCardContent({
@@ -21,19 +28,47 @@ class MobileCardContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
final attachmentCount = rowMeta.attachmentCount.toInt();
return Padding(
padding: styleConfiguration.cardPadding,
child: Column(
mainAxisSize: MainAxisSize.min,
children: cells.map(
(cellMeta) {
return cellBuilder.build(
cellContext: cellMeta.cellContext(),
styleMap: mobileBoardCardCellStyleMap(context),
hasNotes: !rowMeta.isDocumentEmpty,
);
},
).toList(),
children: [
...cells.map(
(cellMeta) {
return cellBuilder.build(
cellContext: cellMeta.cellContext(),
styleMap: mobileBoardCardCellStyleMap(context),
hasNotes: !rowMeta.isDocumentEmpty,
);
},
),
if (attachmentCount > 0) ...[
const VSpace(4),
Padding(
padding: const EdgeInsets.only(left: 8),
child: Row(
children: [
const FlowySvg(
FlowySvgs.media_s,
size: Size.square(12),
),
const HSpace(6),
Flexible(
child: FlowyText.regular(
LocaleKeys.grid_media_attachmentsHint
.tr(args: ['$attachmentCount']),
fontSize: 12,
color: AFThemeExtension.of(context).secondaryTextColor,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
],
],
),
);
}
@@ -1,12 +1,13 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
import 'package:appflowy/mobile/presentation/database/field/mobile_full_field_editor.dart';
import 'package:appflowy/plugins/database/domain/field_backend_service.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/domain/field_backend_service.dart';
import 'package:appflowy/plugins/database/domain/field_service.dart';
import 'package:appflowy/plugins/database/widgets/setting/field_visibility_extension.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class MobileEditPropertyScreen extends StatefulWidget {
@@ -49,7 +50,7 @@ class _MobileEditPropertyScreenState extends State<MobileEditPropertyScreen> {
return PopScope(
onPopInvoked: (didPop) {
if (didPop) {
if (!didPop) {
context.pop(_fieldOptionValues);
}
},
@@ -29,6 +29,7 @@ const mobileSupportedFieldTypes = [
FieldType.CreatedTime,
FieldType.Checkbox,
FieldType.Checklist,
FieldType.Media,
// FieldType.Time,
];
@@ -147,6 +147,8 @@ class FieldOptionValues {
timeFormat: timeFormat,
includeTime: includeTime,
).writeToBuffer();
case FieldType.Media:
return MediaTypeOptionPB().writeToBuffer();
default:
throw UnimplementedError();
}
@@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/database/card/card_detail/widgets/widgets.dart';
@@ -11,7 +13,6 @@ import 'package:appflowy/plugins/database/widgets/setting/field_visibility_exten
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
@@ -61,7 +62,8 @@ class _QuickEditFieldState extends State<QuickEditField> {
create: (_) => FieldEditorBloc(
viewId: widget.viewId,
fieldController: widget.fieldController,
field: widget.fieldInfo.field,
fieldInfo: widget.fieldInfo,
isNew: false,
),
child: BlocConsumer<FieldEditorBloc, FieldEditorState>(
listenWhen: (previous, current) =>
@@ -99,7 +101,7 @@ class _QuickEditFieldState extends State<QuickEditField> {
context.pop();
},
),
if (!widget.fieldInfo.isPrimary)
if (!widget.fieldInfo.isPrimary) ...[
FlowyOptionTile.text(
showTopBorder: false,
text: fieldVisibility.isVisibleState()
@@ -115,7 +117,6 @@ class _QuickEditFieldState extends State<QuickEditField> {
}
},
),
if (!widget.fieldInfo.isPrimary)
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.grid_field_insertLeft.tr(),
@@ -132,6 +133,7 @@ class _QuickEditFieldState extends State<QuickEditField> {
);
},
),
],
FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.grid_field_insertRight.tr(),
@@ -7,15 +7,21 @@ class MobileDocumentScreen extends StatelessWidget {
super.key,
required this.id,
this.title,
this.showMoreButton = true,
this.fixedTitle,
});
/// view id
final String id;
final String? title;
final bool showMoreButton;
final String? fixedTitle;
static const routeName = '/docs';
static const viewId = 'id';
static const viewTitle = 'title';
static const viewShowMoreButton = 'show_more_button';
static const viewFixedTitle = 'fixed_title';
@override
Widget build(BuildContext context) {
@@ -23,6 +29,8 @@ class MobileDocumentScreen extends StatelessWidget {
id: id,
title: title,
viewLayout: ViewLayoutPB.Document,
showMoreButton: showMoreButton,
fixedTitle: fixedTitle,
);
}
}
@@ -96,36 +96,34 @@ class _FavoriteViews extends StatelessWidget {
final borderColor = Theme.of(context).isLightMode
? const Color(0xFFE9E9EC)
: const Color(0x1AFFFFFF);
return Scrollbar(
child: ListView.separated(
key: const PageStorageKey('favorite_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final view = favoriteViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
return ListView.separated(
key: const PageStorageKey('favorite_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final view = favoriteViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
),
child: MobileViewPage(
key: ValueKey(view.item.id),
view: view.item,
timestamp: view.timestamp,
type: MobilePageCardType.favorite,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: favoriteViews.length,
),
),
child: MobileViewPage(
key: ValueKey(view.item.id),
view: view.item,
timestamp: view.timestamp,
type: MobilePageCardType.favorite,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: favoriteViews.length,
);
}
}
@@ -25,19 +25,17 @@ class _MobileHomeSpaceState extends State<MobileHomeSpace>
final workspaceId =
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return Scrollbar(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
top: HomeSpaceViewSizes.mVerticalPadding,
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
child: MobileFolders(
user: widget.userProfile,
workspaceId: workspaceId,
showFavorite: false,
),
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
top: HomeSpaceViewSizes.mVerticalPadding,
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
child: MobileFolders(
user: widget.userProfile,
workspaceId: workspaceId,
showFavorite: false,
),
),
);
@@ -1,20 +1,16 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/home/section_folder/mobile_home_section_folder.dart';
import 'package:appflowy/mobile/presentation/home/space/mobile_space.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:go_router/go_router.dart';
// Contains Public And Private Sections
class MobileFolders extends StatelessWidget {
@@ -35,6 +31,9 @@ class MobileFolders extends StatelessWidget {
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
listenWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId !=
current.currentWorkspace?.workspaceId,
listener: (context, state) {
context.read<SidebarSectionsBloc>().add(
SidebarSectionsEvent.initial(
@@ -46,6 +45,7 @@ class MobileFolders extends StatelessWidget {
SpaceEvent.reset(
user,
state.currentWorkspace?.workspaceId ?? workspaceId,
false,
),
);
},
@@ -70,13 +70,7 @@ class _MobileFolderState extends State<_MobileFolder> {
child: Column(
children: [
..._buildSpaceOrSection(context, state),
const VSpace(4.0),
const Padding(
padding: EdgeInsets.symmetric(
horizontal: HomeSpaceViewSizes.mHorizontalPadding,
),
child: _TrashButton(),
),
const VSpace(80.0),
],
),
);
@@ -119,28 +113,3 @@ class _MobileFolderState extends State<_MobileFolder> {
];
}
}
class _TrashButton extends StatelessWidget {
const _TrashButton();
@override
Widget build(BuildContext context) {
return SizedBox(
height: 52,
child: FlowyButton(
expand: true,
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2.0),
leftIcon: const FlowySvg(
FlowySvgs.m_delete_s,
),
leftIconSize: const Size.square(18),
iconPadding: 10.0,
text: FlowyText.regular(
LocaleKeys.trash_text.tr(),
fontSize: 16.0,
),
onTap: () => context.push(MobileHomeTrashPage.routeName),
),
);
}
}
@@ -1,8 +1,8 @@
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/home/mobile_home_page_header.dart';
import 'package:appflowy/mobile/presentation/home/tab/mobile_space_tab.dart';
import 'package:appflowy/mobile/presentation/home/tab/space_order_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
@@ -14,14 +14,19 @@ import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/presentation/home/errors/workspace_failed_screen.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:sentry/sentry.dart';
import 'package:toastification/toastification.dart';
class MobileHomeScreen extends StatelessWidget {
const MobileHomeScreen({super.key});
@@ -59,6 +64,14 @@ class MobileHomeScreen extends StatelessWidget {
return const WorkspaceFailedScreen();
}
Sentry.configureScope(
(scope) => scope.setUser(
SentryUser(
id: userProfile.id.toString(),
),
),
);
return Scaffold(
body: SafeArea(
bottom: false,
@@ -94,6 +107,8 @@ class MobileHomePage extends StatefulWidget {
}
class _MobileHomePageState extends State<MobileHomePage> {
Loading? loadingIndicator;
@override
void initState() {
super.initState();
@@ -125,75 +140,7 @@ class _MobileHomePageState extends State<MobileHomePage> {
value: getIt<ReminderBloc>()..add(const ReminderEvent.started()),
),
],
child: BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
buildWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId !=
current.currentWorkspace?.workspaceId,
listener: (context, state) {
getIt<CachedRecentService>().reset();
mCurrentWorkspace.value = state.currentWorkspace;
},
builder: (context, state) {
if (state.currentWorkspace == null) {
return const SizedBox.shrink();
}
final workspaceId = state.currentWorkspace!.workspaceId;
return Column(
children: [
// Header
Padding(
padding: EdgeInsets.only(
left: HomeSpaceViewSizes.mHorizontalPadding,
right: 8.0,
top: Platform.isAndroid ? 8.0 : 0.0,
),
child: MobileHomePageHeader(
userProfile: widget.userProfile,
),
),
Expanded(
child: MultiBlocProvider(
providers: [
BlocProvider(
create: (_) => SpaceOrderBloc()
..add(const SpaceOrderEvent.initial()),
),
BlocProvider(
create: (_) => SidebarSectionsBloc()
..add(
SidebarSectionsEvent.initial(
widget.userProfile,
workspaceId,
),
),
),
BlocProvider(
create: (_) =>
FavoriteBloc()..add(const FavoriteEvent.initial()),
),
BlocProvider(
create: (_) => SpaceBloc()
..add(
SpaceEvent.initial(
widget.userProfile,
workspaceId,
openFirstPage: false,
),
),
),
],
child: MobileSpaceTab(
userProfile: widget.userProfile,
),
),
),
],
);
},
),
child: _HomePage(userProfile: widget.userProfile),
);
}
@@ -205,3 +152,155 @@ class _MobileHomePageState extends State<MobileHomePage> {
await FolderEventSetLatestView(ViewIdPB(value: id)).send();
}
}
class _HomePage extends StatefulWidget {
const _HomePage({required this.userProfile});
final UserProfilePB userProfile;
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
Loading? loadingIndicator;
@override
Widget build(BuildContext context) {
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
buildWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId !=
current.currentWorkspace?.workspaceId,
listener: (context, state) {
getIt<CachedRecentService>().reset();
mCurrentWorkspace.value = state.currentWorkspace;
Debounce.debounce(
'workspace_action_result',
const Duration(milliseconds: 150),
() {
_showResultDialog(context, state);
},
);
},
builder: (context, state) {
if (state.currentWorkspace == null) {
return const SizedBox.shrink();
}
final workspaceId = state.currentWorkspace!.workspaceId;
return Column(
key: ValueKey('mobile_home_page_$workspaceId'),
children: [
// Header
Padding(
padding: const EdgeInsets.only(
left: HomeSpaceViewSizes.mHorizontalPadding,
right: 8.0,
),
child: MobileHomePageHeader(
userProfile: widget.userProfile,
),
),
Expanded(
child: MultiBlocProvider(
providers: [
BlocProvider(
create: (_) =>
SpaceOrderBloc()..add(const SpaceOrderEvent.initial()),
),
BlocProvider(
create: (_) => SidebarSectionsBloc()
..add(
SidebarSectionsEvent.initial(
widget.userProfile,
workspaceId,
),
),
),
BlocProvider(
create: (_) =>
FavoriteBloc()..add(const FavoriteEvent.initial()),
),
BlocProvider(
create: (_) => SpaceBloc()
..add(
SpaceEvent.initial(
widget.userProfile,
workspaceId,
openFirstPage: false,
),
),
),
],
child: MobileSpaceTab(
userProfile: widget.userProfile,
),
),
),
],
);
},
);
}
void _showResultDialog(BuildContext context, UserWorkspaceState state) {
final actionResult = state.actionResult;
if (actionResult == null) {
return;
}
Log.info('workspace action result: $actionResult');
final actionType = actionResult.actionType;
final result = actionResult.result;
final isLoading = actionResult.isLoading;
if (isLoading) {
loadingIndicator ??= Loading(context)..start();
return;
} else {
loadingIndicator?.stop();
loadingIndicator = null;
}
if (result == null) {
return;
}
result.onFailure((f) {
Log.error(
'[Workspace] Failed to perform ${actionType.toString()} action: $f',
);
});
final String? message;
ToastificationType toastType = ToastificationType.success;
switch (actionType) {
case UserWorkspaceActionType.open:
message = result.fold(
(s) {
toastType = ToastificationType.success;
return LocaleKeys.workspace_openSuccess.tr();
},
(e) {
toastType = ToastificationType.error;
return '${LocaleKeys.workspace_openFailed.tr()}: ${e.msg}';
},
);
break;
default:
message = null;
toastType = ToastificationType.error;
break;
}
if (message != null) {
showToastNotification(context, message: message, type: toastType);
}
}
}
@@ -1,8 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/gesture.dart';
import 'package:appflowy/mobile/presentation/base/animated_gesture.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/home/mobile_home_setting_page.dart';
import 'package:appflowy/mobile/presentation/home/workspaces/workspace_menu_bottom_sheet.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
@@ -18,6 +17,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'setting/settings_popup_menu.dart';
class MobileHomePageHeader extends StatelessWidget {
const MobileHomePageHeader({
super.key,
@@ -45,14 +46,8 @@ class MobileHomePageHeader extends StatelessWidget {
? _MobileWorkspace(userProfile: userProfile)
: _MobileUser(userProfile: userProfile),
),
GestureDetector(
onTap: () => context.push(
MobileHomeSettingPage.routeName,
),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: FlowySvg(FlowySvgs.m_notification_settings_s),
),
HomePageSettingsPopupMenu(
userProfile: userProfile,
),
const HSpace(8.0),
],
@@ -116,6 +111,7 @@ class _MobileWorkspace extends StatelessWidget {
return const SizedBox.shrink();
}
return AnimatedGestureDetector(
scaleFactor: 0.99,
alignment: Alignment.centerLeft,
onTapUp: () {
context.read<UserWorkspaceBloc>().add(
@@ -5,6 +5,7 @@ import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/mobile/presentation/setting/cloud/cloud_setting_group.dart';
import 'package:appflowy/mobile/presentation/setting/user_session_setting_group.dart';
import 'package:appflowy/mobile/presentation/setting/workspace/workspace_setting_group.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
@@ -79,14 +80,14 @@ class _MobileHomeSettingPageState extends State<MobileHomeSettingPage> {
PersonalInfoSettingGroup(
userProfile: userProfile,
),
// TODO: Enable and implement along with Push Notifications
// const NotificationsSettingGroup(),
const WorkspaceSettingGroup(),
const AppearanceSettingGroup(),
const LanguageSettingGroup(),
if (Env.enableCustomCloud) const CloudSettingGroup(),
const SupportSettingGroup(),
const AboutSettingGroup(),
UserSessionSettingGroup(
userProfile: userProfile,
showThirdPartyLogin: showThirdPartyLogin,
),
const VSpace(20),
@@ -64,11 +64,7 @@ class MobileHomeTrashPage extends StatelessWidget {
],
),
body: state.objects.isEmpty
? FlowyMobileStateContainer.info(
emoji: '🗑️',
title: LocaleKeys.trash_mobile_empty.tr(),
description: LocaleKeys.trash_mobile_emptyDescription.tr(),
)
? const _EmptyTrashBin()
: _DeletedFilesListView(state),
);
},
@@ -82,6 +78,41 @@ enum _TrashActionType {
deleteAll,
}
class _EmptyTrashBin extends StatelessWidget {
const _EmptyTrashBin();
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const FlowySvg(
FlowySvgs.m_empty_trash_xl,
size: Size.square(46),
),
const VSpace(16.0),
FlowyText.medium(
LocaleKeys.trash_mobile_empty.tr(),
fontSize: 18.0,
textAlign: TextAlign.center,
),
const VSpace(8.0),
FlowyText.regular(
LocaleKeys.trash_mobile_emptyDescription.tr(),
fontSize: 17.0,
maxLines: 10,
textAlign: TextAlign.center,
lineHeight: 1.3,
color: Theme.of(context).hintColor,
),
const VSpace(kBottomNavigationBarHeight + 36.0),
],
),
);
}
}
class _TrashActionAllButton extends StatelessWidget {
/// Switch between 'delete all' and 'restore all' feature
const _TrashActionAllButton({
@@ -68,36 +68,34 @@ class _RecentViews extends StatelessWidget {
? const Color(0xFFE9E9EC)
: const Color(0x1AFFFFFF);
return SlidableAutoCloseBehavior(
child: Scrollbar(
child: ListView.separated(
key: const PageStorageKey('recent_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final sectionView = recentViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
child: ListView.separated(
key: const PageStorageKey('recent_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final sectionView = recentViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
),
child: MobileViewPage(
key: ValueKey(sectionView.item.id),
view: sectionView.item,
timestamp: sectionView.timestamp,
type: MobilePageCardType.recent,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: recentViews.length,
),
),
child: MobileViewPage(
key: ValueKey(sectionView.item.id),
view: sectionView.item,
timestamp: sectionView.timestamp,
type: MobilePageCardType.recent,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: recentViews.length,
),
);
}
@@ -0,0 +1,154 @@
import 'package:appflowy/core/helpers/url_launcher.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/mobile/presentation/setting/workspace/invite_members_screen.dart';
import 'package:appflowy/shared/popup_menu/appflowy_popup_menu.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart'
hide PopupMenuButton, PopupMenuDivider, PopupMenuItem, PopupMenuEntry;
import 'package:go_router/go_router.dart';
enum _MobileSettingsPopupMenuItem {
settings,
members,
trash,
help,
}
class HomePageSettingsPopupMenu extends StatelessWidget {
const HomePageSettingsPopupMenu({
super.key,
required this.userProfile,
});
final UserProfilePB userProfile;
@override
Widget build(BuildContext context) {
return PopupMenuButton<_MobileSettingsPopupMenuItem>(
offset: const Offset(0, 36),
padding: EdgeInsets.zero,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12.0),
),
),
shadowColor: const Color(0x68000000),
elevation: 10,
color: context.popupMenuBackgroundColor,
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<_MobileSettingsPopupMenuItem>>[
_buildItem(
value: _MobileSettingsPopupMenuItem.settings,
svg: FlowySvgs.m_notification_settings_s,
text: LocaleKeys.settings_popupMenuItem_settings.tr(),
),
// only show the member items in cloud mode
if (userProfile.authenticator == AuthenticatorPB.AppFlowyCloud) ...[
const PopupMenuDivider(height: 0.5),
_buildItem(
value: _MobileSettingsPopupMenuItem.members,
svg: FlowySvgs.m_settings_member_s,
text: LocaleKeys.settings_popupMenuItem_members.tr(),
),
],
const PopupMenuDivider(height: 0.5),
_buildItem(
value: _MobileSettingsPopupMenuItem.trash,
svg: FlowySvgs.trash_s,
text: LocaleKeys.settings_popupMenuItem_trash.tr(),
),
const PopupMenuDivider(height: 0.5),
_buildItem(
value: _MobileSettingsPopupMenuItem.help,
svg: FlowySvgs.message_support_s,
text: LocaleKeys.settings_popupMenuItem_helpAndSupport.tr(),
),
],
onSelected: (_MobileSettingsPopupMenuItem value) {
switch (value) {
case _MobileSettingsPopupMenuItem.members:
_openMembersPage(context);
break;
case _MobileSettingsPopupMenuItem.trash:
_openTrashPage(context);
break;
case _MobileSettingsPopupMenuItem.settings:
_openSettingsPage(context);
break;
case _MobileSettingsPopupMenuItem.help:
_openHelpPage(context);
break;
}
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: FlowySvg(
FlowySvgs.m_settings_more_s,
),
),
);
}
PopupMenuItem<T> _buildItem<T>({
required T value,
required FlowySvgData svg,
required String text,
}) {
return PopupMenuItem<T>(
value: value,
padding: EdgeInsets.zero,
child: _PopupButton(
svg: svg,
text: text,
),
);
}
void _openMembersPage(BuildContext context) {
context.push(InviteMembersScreen.routeName);
}
void _openTrashPage(BuildContext context) {
context.push(MobileHomeTrashPage.routeName);
}
void _openHelpPage(BuildContext context) {
afLaunchUrlString('https://discord.com/invite/9Q2xaN37tV');
}
void _openSettingsPage(BuildContext context) {
context.push(MobileHomeSettingPage.routeName);
}
}
class _PopupButton extends StatelessWidget {
const _PopupButton({
required this.svg,
required this.text,
});
final FlowySvgData svg;
final String text;
@override
Widget build(BuildContext context) {
return Container(
height: 44,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
children: [
FlowySvg(svg, size: const Size.square(20)),
const HSpace(12),
FlowyText.regular(
text,
fontSize: 16,
),
],
),
);
}
}
@@ -6,7 +6,10 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
class EmptySpacePlaceholder extends StatelessWidget {
const EmptySpacePlaceholder({super.key, required this.type});
const EmptySpacePlaceholder({
super.key,
required this.type,
});
final MobilePageCardType type;
@@ -36,6 +39,7 @@ class EmptySpacePlaceholder extends StatelessWidget {
lineHeight: 1.3,
color: Theme.of(context).hintColor,
),
const VSpace(kBottomNavigationBarHeight + 36.0),
],
),
);
@@ -5,7 +5,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/mobile/application/recent/recent_view_bloc.dart';
import 'package:appflowy/mobile/presentation/base/gesture.dart';
import 'package:appflowy/mobile/presentation/base/animated_gesture.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/shared/appflowy_network_image.dart';
Loaded 100 of 928 files, more files were not shown because too many files have changed in this diff. Show more