Compare commits

...

134 Commits

Author SHA1 Message Date
Krille-chan b4fcb5b0d9 chore: Use correct versions of adaptive_dialog 2023-07-14 08:02:47 +00:00
Krille 1911004d05
refactor: Update dependencies 2023-07-13 19:46:16 +09:00
Raatty 5d67564445
Added translation using Weblate (Greek) 2023-07-09 09:42:27 +02:00
Krille be04c5a46e
design: Adjust open url dialog design a little bit 2023-07-07 12:10:07 +09:00
Farooq Karimi Zadeh bd7a4c9dfb
Translated using Weblate (Persian)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/fa/
2023-07-06 10:52:33 +02:00
Krille 10ee57722e
chore: Enable webrtc for linux again 2023-06-30 19:15:45 +09:00
Malin Errenst ff5f7ab50e Merge branch 'malin/group-notification-channels' into 'main'
feat: Added grouping to message notification channels

See merge request famedly/fluffychat!1134
2023-06-30 07:55:24 +00:00
Krille 277885a61e
chore: Streamline background gradients 2023-06-29 16:56:15 +09:00
Malin Errenst 6633ebc376
feat: Added grouping to message notification channels 2023-06-29 09:36:08 +02:00
Krille-chan b2d9986cd3 Merge branch 'braid/cute-events' into 'main'
fix: overflow in cute events

See merge request famedly/fluffychat!1132
2023-06-29 07:13:55 +00:00
Krille-chan a0b9bb277f Merge branch 'braid/url-launch-copy' into 'main'
feat: add button to copy url in open dialog

See merge request famedly/fluffychat!1133
2023-06-29 07:13:30 +00:00
TheOneWithTheBraid d381705cdd
feat: add button to copy url in open dialog
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-06-27 14:09:00 +02:00
Aminda Suomalainen 3820d4264a
Translated using Weblate (Finnish)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/fi/
2023-06-26 14:50:25 +02:00
Milo Ivir cf4e2d3fad
Translated using Weblate (Croatian)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/hr/
2023-06-26 14:50:24 +02:00
josé m 002dc87577
Translated using Weblate (Galician)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/
2023-06-22 07:51:05 +02:00
The one with the braid 922e7ad0ff fix: overflow in cute events
Signed-off-by: The one with the braid <the-one@with-the-braid.cf>
2023-06-21 16:08:20 +02:00
Oğuz Ersen 5d7be8a672
Translated using Weblate (Turkish)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/tr/
2023-06-20 19:50:49 +02:00
Krille-chan 431b357cfa Merge branch 'braid/allow-aarch64-failure' into 'main'
fix: allow aarch64 upload failure

See merge request famedly/fluffychat!1131
2023-06-19 10:35:58 +00:00
TheOneWithTheBraid 2938acf152 fix: allow aarch64 upload failure
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-06-19 12:27:07 +02:00
Krille 4127f70e4d
build: Change wakelock hotfix 2023-06-19 10:48:10 +02:00
xabirequejo c07221cc12
Translated using Weblate (Basque)
Currently translated at 97.6% (536 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/eu/
2023-06-17 20:51:13 +02:00
Rex_sa 33b2f95e3f
Translated using Weblate (Arabic)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ar/
2023-06-16 11:52:28 +02:00
Ihor Hordiichuk 2a5cd9b218
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/uk/
2023-06-15 10:51:43 +02:00
Linerly a15fed034d
Translated using Weblate (Indonesian)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/id/
2023-06-13 14:47:59 +02:00
Riley b9641ac021
Translated using Weblate (Romanian)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ro/
2023-06-13 14:47:59 +02:00
josé m 2145bd8846
Translated using Weblate (Galician)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/
2023-06-13 14:47:58 +02:00
Priit Jõerüüt 672b97b310
Translated using Weblate (Estonian)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/et/
2023-06-13 14:47:58 +02:00
Umoya NgoLwesihlanu 974da6ec90
Translated using Weblate (Arabic)
Currently translated at 100.0% (549 of 549 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ar/
2023-06-13 14:47:57 +02:00
Krille f19bbcd010
refactor: More reliable request history/future timeline mechanism 2023-06-13 08:41:49 +02:00
Krille a1468c92c8 Merge branch 'braid/allow-windows-failure' into 'main'
fix: allow windows upload job failure

See merge request famedly/fluffychat!1129
2023-06-12 05:19:41 +00:00
TheOneWithTheBraid 6dd125a087 fix: allow windows upload job failure
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-06-11 19:46:11 +02:00
Krille 842ecc4235
feat: New simplified login process with more prominent SSO and nicer layout 2023-06-11 18:04:31 +02:00
Krille db66793d28
docs: Update mastodon link 2023-06-11 10:56:23 +02:00
Krille 324da027e9
builds: Bump version 2023-06-10 08:19:17 +02:00
DarkCoder15 f2f45e53a8
Translated using Weblate (Russian)
Currently translated at 99.2% (542 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ru/
2023-06-07 16:55:20 +02:00
Krille cacab45fe3
chore: Follow up scrolldownbutton style 2023-06-04 11:14:06 +02:00
Krille 908d428220
design: Replace anime images with neutral cupertino icons 2023-06-03 18:27:26 +02:00
Krille 8a6d726b8c Merge branch 'braid/emoji-placeholder' into 'main'
fix: custom emote placeholder

See merge request famedly/fluffychat!1127
2023-06-03 16:05:59 +00:00
Krille 40275d3d14
fix: Scroll up and scroll down buttons in chat list 2023-06-03 17:59:48 +02:00
Krille 5039f1ba3b
refactor: Use AnimatedSize for FAB 2023-06-03 17:49:13 +02:00
Krille 299aac134d
feat: Display progress value for initial sync 2023-06-03 17:28:32 +02:00
TheOneWithTheBraid 044171c002 fix: custom emote placeholder
- place emote loading spinner in the position as the emote itself
- add key to preview in order to ensure proper states aligned

Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-06-02 18:39:47 +02:00
Krille ec9155d8f0
chore: Update dependencies 2023-06-02 09:49:32 +02:00
Krille 221fe3edcc
builds: Update flutter table html 2023-06-01 13:01:58 +02:00
Krille e166f17cae
refactor: Update flutter_html 2023-06-01 11:03:40 +02:00
Krille 640fe0d476
builds: Update flutter_html 2023-06-01 11:00:14 +02:00
Krille 3942de3222
fix: User pills 2023-05-31 15:52:51 +02:00
Krille b00111381a
feat: Allow ruby tags in html 2023-05-31 13:05:06 +02:00
Krille 715dca561f
fix: Remove wrong rendered linebreak in html 2023-05-31 10:19:13 +02:00
Krille 44d7f61788
fix: Try to reload timeline on IOException 2023-05-31 09:22:50 +02:00
Krille 518739e29f
builds: Remove workaround for building linux arm64 2023-05-31 08:03:23 +02:00
Krille 06e6e9c5b1
chore: Follow up linkify inside html 2023-05-30 13:39:36 +02:00
Krille 17cfff153b Merge branch 'braid/macos' into 'main'
feat: update macOS build files

See merge request famedly/fluffychat!1121
2023-05-30 05:51:48 +00:00
Krille 9f224b9839 Merge branch 'braid/ci-fixes' into 'main'
fix: broken CI artifact uploads

See merge request famedly/fluffychat!1125
2023-05-30 05:51:28 +00:00
TheOneWithTheBraid 56e1bb6bfd fix: broken CI artifact uploads
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-29 19:19:28 +02:00
lauren n. liberda 6529ce0d0f
Translated using Weblate (Polish)
Currently translated at 99.2% (542 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/pl/
2023-05-28 11:48:20 +02:00
Rex_sa 81c7f7decd
Translated using Weblate (Arabic)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ar/
2023-05-27 10:48:20 +02:00
Krille 85868cc0bd
chore: Follow up linkify in html message 2023-05-26 09:11:04 +02:00
Milo Ivir 1d0c842bad
Translated using Weblate (Croatian)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/hr/
2023-05-24 22:48:59 +02:00
Krille 02bcc98037
chore: Disable linux webrtc 2023-05-24 21:02:13 +02:00
Krille 1a1c166ab0
chore: Enhance room pills 2023-05-24 08:23:06 +02:00
Krille 692d6042c5
chore: Ask for storage persistence 2023-05-23 15:21:38 +02:00
Krille fa2ed930eb Revert "chore: Upgrade to Flutter 3.10.1"
This reverts commit d300cdb58f
2023-05-23 13:02:28 +00:00
Krille 9785b0023c Revert "refactor: Update dependencies"
This reverts commit 2bb0dce7a1
2023-05-23 13:02:15 +00:00
Malin Errenst 313c94a4f1 Merge branch 'malin/flutter-3-10-1' into 'main'
chore: Upgrade to Flutter 3.10.1

See merge request famedly/fluffychat!1122
2023-05-23 07:44:51 +00:00
Krille 2bb0dce7a1
refactor: Update dependencies 2023-05-23 08:40:56 +02:00
Krille b1785d4b8a
builds: Update file_picker to 5.3.0 2023-05-23 08:34:24 +02:00
Krille 3f15fa365f
chore: Follow up missing cache key 2023-05-23 08:32:27 +02:00
Krille a56ebb245e
chore: do not humanize links 2023-05-23 08:22:34 +02:00
Malin Errenst d300cdb58f
chore: Upgrade to Flutter 3.10.1 2023-05-22 21:33:14 +02:00
Krille d88a1cd2d6
chore: Follow up img tag 2023-05-22 17:05:54 +02:00
Krille 3070b38d2e
chore: Follow up update matrix sdk 2023-05-22 16:30:04 +02:00
Krille 38db3b35aa
chore: Follow up html messages mxc images 2023-05-22 16:26:43 +02:00
Linerly c4447adf8c
Translated using Weblate (Indonesian)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/id/
2023-05-21 16:49:01 +02:00
Riley 0b91d3cecc
Translated using Weblate (Romanian)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ro/
2023-05-21 16:49:01 +02:00
Eric 3b3d20f250
Translated using Weblate (Chinese (Simplified))
Currently translated at 97.6% (533 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/zh_Hans/
2023-05-21 16:48:59 +02:00
Ihor Hordiichuk 0376e7f4b8
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/uk/
2023-05-21 16:48:59 +02:00
josé m 77f43fbde0
Translated using Weblate (Galician)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/
2023-05-21 16:48:59 +02:00
Priit Jõerüüt e203508c42
Translated using Weblate (Estonian)
Currently translated at 100.0% (546 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/et/
2023-05-21 16:48:58 +02:00
José Muñoz 8b6745763a
Translated using Weblate (Spanish)
Currently translated at 77.1% (421 of 546 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/es/
2023-05-21 16:48:58 +02:00
Krille 8c4b2ade88
fix: Do not unnecessary request all members in public rooms 2023-05-20 08:21:33 +02:00
TheOneWithTheBraid 4e5f2ff05f fix: path of libolm
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-19 18:38:32 +02:00
TheOneWithTheBraid fd1b62fc8d chore: update macOS icons and add build script
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-19 18:11:19 +02:00
Krille f53d17eab7
chore: Readd support for html tables 2023-05-19 17:30:25 +02:00
TheOneWithTheBraid c3b3f762eb feat: set display information correctly
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-19 14:11:27 +02:00
TheOneWithTheBraid d288603c07 feat: clean up macOS build metadata
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-19 14:03:18 +02:00
TheOneWithTheBraid e61682ef46 feat: update macOS build information for macOS Ventura
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-19 13:46:50 +02:00
TheOneWithTheBraid 3b228bb58b feat: update macOS build files
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-05-19 13:24:08 +02:00
Krille b62c41ce57
chore: Follow up html styling 2023-05-19 08:14:48 +02:00
Krille a4397e9cec
builds: Do not allow failure for linux x86 2023-05-18 11:02:32 +02:00
Krille 981d69706c
builds: Do not use verbose mode on building linux 2023-05-18 11:01:59 +02:00
Krille 0a4683d8a6
chore: Update flutter webrtc 2023-05-18 10:48:27 +02:00
Krille 43f6284ada
chore: Allow failure in build linux for now 2023-05-17 15:21:01 +02:00
Krille 8cf6297560
chore: Disable img for now in html messages 2023-05-17 15:20:40 +02:00
Krille 1f42d7dff0
chore: Add missing blockquote style 2023-05-17 13:25:39 +02:00
Krille abbf18e1dc Merge branch 'krille/reimplement-flutter-matrix-html' into 'main'
refactor: Reimplement flutter matrix html locally

See merge request famedly/fluffychat!1119
2023-05-17 10:55:34 +00:00
Krille 102f3bba8e
refactor: Reimplement flutter matrix html locally 2023-05-17 12:26:59 +02:00
Krille 8faba7bdf2
chore: Remove macos_ui dependency 2023-05-16 19:21:37 +02:00
Krille d41d21f8e1
chore: Remove webrtc override 2023-05-16 19:12:20 +02:00
Krille 298cd6245c Merge branch 'fail-on-curl-failures-during-build' into 'main'
change release curl calls to use --fail-with-body

Closes #1193

See merge request famedly/fluffychat!1110
2023-05-16 17:03:16 +00:00
Tim Flink 8bd88c4845 chore: change release curl calls to use --fail-with-body 2023-05-16 17:03:15 +00:00
Krille e3bf76d8e2 Merge branch 'braid/update-fonts' into 'main'
chore: Update Roboto and Noto Emoji

See merge request famedly/fluffychat!1107
2023-05-16 16:56:09 +00:00
The one with the Braid 3445d5be21 refactor: Update Roboto and Noto Emoji 2023-05-16 16:56:09 +00:00
Krille a838ba3000 Merge branch 'filenametolong' into 'main'
filename is too long and over the widget

See merge request famedly/fluffychat!1103
2023-05-16 16:55:19 +00:00
Skying 15b655413d fix: Too long file name cause a render overflow 2023-05-16 16:55:19 +00:00
Krille 2418c61498
chore: Follow up clean up 2023-05-16 18:51:01 +02:00
Krille dfacbf9e32 Merge branch 'group-notif' into 'main'
Add Group Notifications

Closes #1175

See merge request famedly/fluffychat!1116
2023-05-16 16:50:20 +00:00
fbievan 85f5b69d6e feat: Add toggle to mute notifications from chat groups 2023-05-16 16:50:20 +00:00
Krille 08797da53d
feat: Implement new error reporting tool when critical features break like playing audio or video messages or opening a chat 2023-05-16 18:45:39 +02:00
Krille d3bd2c3a08
builds: Change minsdkversion of Android from 16 to 19 2023-05-16 10:44:25 +02:00
Krille 1086c0e5cd Merge branch 'malin/improve-date-localization' into 'main'
Improve date localization

See merge request famedly/fluffychat!1118
2023-05-16 08:37:46 +00:00
Malin Errenst 60df0761a5
chore: Clean unused translations 2023-05-16 10:25:52 +02:00
Malin Errenst 650d878649
refactor: Use DateTime for weekday localization 2023-05-16 10:25:52 +02:00
Krille 06f399c76d
chore: Update dep ref 2023-05-16 09:35:27 +02:00
Krille 7c5b60474f
chore: Follow up update flutter matrix html 2023-05-16 09:12:13 +02:00
Krille d81f92f2e2
builds: Linux with flutter 3.10 2023-05-15 19:14:03 +02:00
Krille 1a8038e51d
chore: Minor code clean up 2023-05-15 18:55:27 +02:00
Krille 54a6ce8391 Merge branch 'dart3' into 'main'
migrate to dart 3.0/flutter 3.10

Closes #1203

See merge request famedly/fluffychat!1114
2023-05-15 16:52:03 +00:00
lauren n. liberda b1c38d766f builds: migrate to dart 3.0/flutter 3.10 2023-05-15 16:52:03 +00:00
Krille f44e24aec1 Merge branch 'vrouter-context' into 'main'
fix "Unhandled Exception: VRouter.of(context) was called with a context which...

Closes #1163

See merge request famedly/fluffychat!1117
2023-05-15 16:37:51 +00:00
Lauren N. Liberda 325dcf901a
fix "Unhandled Exception: VRouter.of(context) was called with a context which does not contain a VRouter."
fixes #1163
2023-05-14 19:17:47 +02:00
Krille 77e1da8318
chore: Disable webrtc on linux again 2023-05-11 18:15:47 +02:00
Krille b0a58d8524
perf: Use valuenotifier to not rebuild chatlist 2023-05-10 13:01:35 +02:00
Krille 623c3bfc2e
fix: Scroll down button 2023-05-09 15:14:35 +02:00
Krille 5cd6cf79a2
build: Remove dependency overwrite for ffi 2023-05-09 14:51:25 +02:00
Krille e1d54fa992
build: Update dependencies 2023-05-09 14:47:05 +02:00
Krille b1c481c4d1
fix: Broken arb file 2023-05-09 13:37:51 +02:00
Krille 64821e4ec5 Merge branch 'main' into 'main'
fix: Quick account switching

Closes #1186

See merge request famedly/fluffychat!1111
2023-05-08 13:26:59 +00:00
Krille 88585fb192
fix: Scrolldown button 2023-05-08 15:25:36 +02:00
JHansen 25f5d5f4fd Fix read reciepts 2023-05-08 12:02:15 +00:00
JHansen d0d33ce2c8 Fix Quick account switching 2023-05-08 04:56:40 +00:00
Mæve Rey 32d8791fe9
Added translation using Weblate (Toki Pona) 2023-05-07 16:23:08 +02:00
Linerly e76f42a706
Translated using Weblate (Indonesian)
Currently translated at 100.0% (559 of 559 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/id/
2023-05-07 15:48:59 +02:00
josé m 32f4e471cf
Translated using Weblate (Galician)
Currently translated at 100.0% (559 of 559 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/
2023-05-06 05:50:56 +02:00
158 changed files with 36050 additions and 35434 deletions

View File

@ -1,5 +1,5 @@
variables:
FLUTTER_VERSION: 3.7.11
FLUTTER_VERSION: 3.10.0
image: ghcr.io/cirruslabs/flutter:${FLUTTER_VERSION}
@ -19,7 +19,7 @@ code_analyze:
script:
- flutter pub get
- dart run import_sorter:main --no-comments --exit-if-changed
- flutter format lib/ test/ --set-exit-if-changed
- dart format lib/ test/ --set-exit-if-changed
- flutter analyze
- git apply ./scripts/enable-android-google-services.patch
- flutter pub get
@ -31,7 +31,7 @@ code_analyze:
widget_test:
stage: test
script: [ flutter test ]
script: [flutter test]
# the basic integration test configuration testing FLOSS builds on Synapse
.integration_test:
@ -84,7 +84,6 @@ widget_test:
- docker
- famedly
# integration tests for Linux builds
### disabled because of Linux headless issues
.integration_test_linux:
@ -98,7 +97,7 @@ widget_test:
- apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libsecret-1-dev libjsoncpp-dev
- flutter pub get
- flutter test integration_test -d linux --dart-define=HOMESERVER=$HOMESERVER --dart-define=USER1_NAME=$USER1_NAME --dart-define=USER2_NAME=$USER2_NAME --dart-define=USER1_PW=$USER1_PW --dart-define=USER2_PW=$USER2_PW || ( sleep 10 && exit 1 )
after_script: [ ]
after_script: []
artifacts:
# extending the default tests to test the Google-flavored builds
@ -144,7 +143,7 @@ release_mode_launches:
build_web:
stage: build
before_script:
[ sudo apt update && sudo apt install curl -y, ./scripts/prepare-web.sh ]
[sudo apt update && sudo apt install curl -y, ./scripts/prepare-web.sh]
script:
- flutter build web --release --verbose --source-maps
artifacts:
@ -195,7 +194,7 @@ build_windows:
build_android_debug:
stage: build
script: [ flutter build apk --debug ]
script: [flutter build apk --debug]
artifacts:
when: on_success
paths:
@ -212,7 +211,7 @@ build_android_apk:
before_script:
- git apply ./scripts/enable-android-google-services.patch
- ./scripts/prepare-android-release.sh
script: [ flutter build apk --release ]
script: [flutter build apk --release]
artifacts:
when: on_success
paths:
@ -229,7 +228,7 @@ deploy_playstore_internal:
before_script:
- git apply ./scripts/enable-android-google-services.patch
- ./scripts/prepare-android-release.sh
script: [ ./scripts/release-playstore-beta.sh ]
script: [./scripts/release-playstore-beta.sh]
artifacts:
when: on_success
paths:
@ -284,11 +283,11 @@ pages:
build_linux_x86:
stage: build
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/flutter-linux/stable
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/flutter-linux/stable:${FLUTTER_VERSION}
before_script:
- sudo apt-get update
- sudo apt-get install curl clang cmake ninja-build pkg-config libgtk-3-dev libblkid-dev liblzma-dev libjsoncpp-dev cmake-data libsecret-1-dev libsecret-1-0 librhash0 -y
script: [ flutter build linux --release -v ]
script: [flutter build linux --release]
tags:
- docker
- famedly
@ -300,18 +299,9 @@ build_linux_x86:
build_linux_arm64:
stage: build
before_script:
# Workaround from https://github.com/flutter/flutter/issues/116703#issuecomment-1403956612
- rm -rf workaround116703
- mkdir workaround116703
- cd workaround116703
- curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz
- tar -xvf flutter_linux_${FLUTTER_VERSION}-stable.tar.xz flutter/bin/cache/artifacts/engine/linux-x64/shader_lib
- mkdir -p /opt/flutter/bin/cache/artifacts/engine/linux-arm64
- cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib /opt/flutter/bin/cache/artifacts/engine/linux-arm64
- rm -rf flutter flutter_linux_${FLUTTER_VERSION}-stable.tar.xz
- cd ..
script: [ flutter build linux --release -v ]
tags: [ docker_arm64 ]
- flutter upgrade $FLUTTER_VERSION --force
script: [flutter build linux --release]
tags: [docker_arm64]
only:
- main
- tags
@ -323,7 +313,7 @@ build_linux_arm64:
update_dependencies:
stage: build
needs: [ ]
needs: []
only:
- schedules
variables:
@ -360,29 +350,29 @@ upload_android:
extends: .release
script:
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file build/android/app-release.apk ${PACKAGE_REGISTRY_URL}/fluffychat.apk
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file build/app/outputs/apk/release/app-release.apk ${PACKAGE_REGISTRY_URL}/fluffychat.apk
upload_web:
extends: .release
script:
# workaround bug of Flutter engine
- tar czf package.tar.gz --ignore-failed-read -C build/web/ .
- tar czf package.tar.gz -C build/web/ .
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-web.tar.gz
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-web.tar.gz
upload_linux_x86:
extends: .release
script:
- tar czf package.tar.gz -C build/linux/x64/release/bundle/ .
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-x86.tar.gz
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-x86.tar.gz
upload_linux_arm64:
extends: .release
script:
- tar czf package.tar.gz -C build/linux/arm64/release/bundle/ .
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-arm64.tar.gz
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-arm64.tar.gz
allow_failure: true
upload_windows:
extends: .release
@ -392,15 +382,16 @@ upload_windows:
- mv build/windows/runner/Release/fluffychat.msix fluffychat.msix
- cd build/windows/runner/Release; zip -r ../../../../package.zip . ; cd -
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.zip ${PACKAGE_REGISTRY_URL}/fluffychat-windows.zip
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file fluffychat.msix ${PACKAGE_REGISTRY_URL}/fluffychat-windows.msix
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.zip ${PACKAGE_REGISTRY_URL}/fluffychat-windows.zip
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file fluffychat.msix ${PACKAGE_REGISTRY_URL}/fluffychat-windows.msix
allow_failure: true
deploy_playstore:
stage: deploy
before_script:
- git apply ./scripts/enable-android-google-services.patch
- ./scripts/prepare-android-release.sh
script: [ ./scripts/release-playstore.sh ]
script: [./scripts/release-playstore.sh]
resource_group: playstore_release
only:
- tags

View File

@ -4,7 +4,7 @@
# This file should be version controlled.
version:
revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
channel: stable
project_type: app
@ -13,26 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
- platform: android
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
- platform: ios
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
- platform: linux
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
- platform: macos
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
- platform: web
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
- platform: windows
create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849
create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
# User provided section

View File

@ -1,3 +1,67 @@
## v1.12.0
- Added translation using Weblate (Toki Pona) (Mæve Rey)
- Translated using Weblate (Arabic) (Rex_sa)
- Translated using Weblate (Chinese (Simplified)) (Eric)
- Translated using Weblate (Croatian) (Milo Ivir)
- Translated using Weblate (Estonian) (Priit Jõerüüt)
- Translated using Weblate (Galician) (josé m)
- Translated using Weblate (Indonesian) (Linerly)
- Translated using Weblate (Polish) (lauren n. liberda)
- Translated using Weblate (Romanian) (Riley)
- Translated using Weblate (Russian) (DarkCoder15)
- Translated using Weblate (Spanish) (José Muñoz)
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
- build: Remove dependency overwrite for ffi (Krille)
- build: Update dependencies (Krille)
- builds: Change minsdkversion of Android from 16 to 19 (Krille)
- builds: Do not allow failure for linux x86 (Krille)
- builds: Do not use verbose mode on building linux (Krille)
- builds: Linux with flutter 3.10 (Krille)
- builds: Remove workaround for building linux arm64 (Krille)
- builds: Update file_picker to 5.3.0 (Krille)
- builds: Update flutter table html (Krille)
- builds: Update flutter_html (Krille)
- builds: migrate to dart 3.0/flutter 3.10 (lauren n. liberda)
- chore: Add missing blockquote style (Krille)
- chore: Allow failure in build linux for now (Krille)
- chore: Ask for storage persistence (Krille)
- chore: Clean unused translations (Malin Errenst)
- chore: Enhance room pills (Krille)
- chore: Minor code clean up (Krille)
- chore: Update flutter webrtc (Krille)
- chore: Upgrade to Flutter 3.10.1 (Malin Errenst)
- chore: change release curl calls to use --fail-with-body (Tim Flink)
- chore: update macOS icons and add build script (TheOneWithTheBraid)
- design: Replace anime images with neutral cupertino icons (Krille)
- feat: Add toggle to mute notifications from chat groups (fbievan)
- feat: Allow ruby tags in html (Krille)
- feat: Display progress value for initial sync (Krille)
- feat: Implement new error reporting tool when critical features break like playing audio or video messages or opening a chat (Krille)
- feat: clean up macOS build metadata (TheOneWithTheBraid)
- feat: set display information correctly (TheOneWithTheBraid)
- feat: update macOS build files (TheOneWithTheBraid)
- feat: update macOS build information for macOS Ventura (TheOneWithTheBraid)
- fix "Unhandled Exception: VRouter.of(context) was called with a context which does not contain a VRouter." (Lauren N. Liberda)
- fix: Broken arb file (Krille)
- fix: Do not unnecessary request all members in public rooms (Krille)
- fix: Remove wrong rendered linebreak in html (Krille)
- fix: Scroll down button (Krille)
- fix: Scroll up and scroll down buttons in chat list (Krille)
- fix: Scrolldown button (Krille)
- fix: Too long file name cause a render overflow (Skying)
- fix: Try to reload timeline on IOException (Krille)
- fix: User pills (Krille)
- fix: broken CI artifact uploads (TheOneWithTheBraid)
- fix: custom emote placeholder (TheOneWithTheBraid)
- fix: path of libolm (TheOneWithTheBraid)
- fix: Quick account switching (JHansen)
- fix: read reciepts (JHansen)
- perf: Use valuenotifier to not rebuild chatlist (Krille)
- refactor: Reimplement flutter matrix html locally (Krille)
- refactor: Update Roboto and Noto Emoji (The one with the Braid)
- refactor: Use AnimatedSize for FAB (Krille)
- refactor: Use DateTime for weekday localization (Malin Errenst)
## v1.11.2
- Translated using Weblate (Croatian) (Milo Ivir)
- Translated using Weblate (Dutch) (Jelv)

View File

@ -44,7 +44,7 @@ android {
defaultConfig {
applicationId "chat.fluffy.fluffychat"
minSdkVersion 16
minSdkVersion 19
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

View File

@ -27,6 +27,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
{}
{}

View File

@ -71,11 +71,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Sala arxivada",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Accés dels usuaris convidats",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -400,11 +395,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Signatura creuada activada",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Actiu actualment",
"@currentlyActive": {
"type": "text",
@ -602,11 +592,6 @@
"type": "text",
"placeholders": {}
},
"friday": "divendres",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Des de la unió",
"@fromJoining": {
"type": "text",
@ -772,11 +757,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Les claus estan desades a la memòria cau",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} ha expulsat a {targetName}",
"@kicked": {
"type": "text",
@ -906,11 +886,6 @@
"type": "text",
"placeholders": {}
},
"monday": "dilluns",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Silencia el xat",
"@muteChat": {
"type": "text",
@ -1201,11 +1176,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "dissabte",
"@saturday": {
"type": "text",
"placeholders": {}
},
"security": "Seguretat",
"@security": {
"type": "text",
@ -1394,11 +1364,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "diumenge",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "Sistema",
"@systemTheme": {
"type": "text",
@ -1414,16 +1379,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Aquesta sala ha estat arxivada.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "dijous",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1445,11 +1400,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "dimarts",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "No disponible",
"@unavailable": {
"type": "text",
@ -1610,11 +1560,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "dimecres",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Us hem enviat un missatge de correu electrònic",
"@weSentYouAnEmail": {
"type": "text",
@ -1801,8 +1746,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "El vostre id. dusuari:",
"@yourUserId": {},
"enableEncryption": "Activa el xifratge",
"@enableEncryption": {
"type": "text",
@ -2065,11 +2008,6 @@
"supportedVersions": {}
}
},
"discover": "Descobreix",
"@discover": {
"type": "text",
"placeholders": {}
},
"editChatPermissions": "Edita els permisos del xat",
"@editChatPermissions": {
"type": "text",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
assets/l10n/intl_el.arb Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -134,11 +134,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Archived Room",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Are guest users allowed to join",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -388,8 +383,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "Your user ID:",
"@yourUserId": {},
"yourChatBackupHasBeenSetUp": "Your chat backup has been set up.",
"@yourChatBackupHasBeenSetUp": {},
"chatBackup": "Chat backup",
@ -633,11 +626,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Cross-signing on",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Currently active",
"@currentlyActive": {
"type": "text",
@ -723,6 +711,11 @@
"type": "text",
"placeholders": {}
},
"allRooms": "All Group Chats",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"discover": "Discover",
"@discover": {
"type": "text",
@ -896,11 +889,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Friday",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "From joining",
"@fromJoining": {
"type": "text",
@ -1091,11 +1079,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Keys are cached",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} kicked {targetName}",
"@kicked": {
"type": "text",
@ -1160,8 +1143,6 @@
"@dehydrate": {},
"dehydrateWarning": "This action cannot be undone. Ensure you safely store the backup file.",
"@dehydrateWarning": {},
"dehydrateShare": "This is your private FluffyChat export. Ensure you don't lose it and keep it private.",
"@dehydrateShare": {},
"dehydrateTor": "TOR Users: Export session",
"@dehydrateTor": {},
"dehydrateTorLong": "For TOR users, it is recommended to export the session before closing the window.",
@ -1236,17 +1217,11 @@
"type": "text",
"placeholders": {}
},
"noSearchResult": "No matching search results.",
"moderator": "Moderator",
"@moderator": {
"type": "text",
"placeholders": {}
},
"monday": "Monday",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Mute chat",
"@muteChat": {
"type": "text",
@ -1312,8 +1287,6 @@
},
"shareYourInviteLink": "Share your invite link",
"@shareYourInviteLink": {},
"typeInInviteLinkManually": "Type in invite link manually...",
"@typeInInviteLinkManually": {},
"scanQrCode": "Scan QR code",
"@scanQrCode": {},
"none": "None",
@ -1671,11 +1644,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Saturday",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Save file",
"@saveFile": {
"type": "text",
@ -1929,11 +1897,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Sunday",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Synchronizing… Please wait.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1954,16 +1917,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "This room has been archived.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Thursday",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -2000,11 +1953,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Tuesday",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Unavailable",
"@unavailable": {
"type": "text",
@ -2177,11 +2125,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Wednesday",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "We sent you an email",
"@weSentYouAnEmail": {
"type": "text",
@ -2436,8 +2379,6 @@
"@stories": {},
"users": "Users",
"@users": {},
"enableAutoBackups": "Enable auto backups",
"@enableAutoBackups": {},
"unlockOldMessages": "Unlock old messages",
"@unlockOldMessages": {},
"storeInSecureStorageDescription": "Store the recovery key in the secure storage of this device.",
@ -2530,5 +2471,10 @@
"jumpToLastReadMessage": "Jump to last read message",
"readUpToHere": "Read up to here",
"jump": "Jump",
"openLinkInBrowser": "Open link in browser"
"openLinkInBrowser": "Open link in browser",
"reportErrorDescription": "Oh no. Something went wrong. Please try again later. If you want, you can report the bug to the developers.",
"report": "report",
"signInWithPassword": "Sign in with password",
"continueWith": "Continue with:",
"pleaseTryAgainLaterOrChooseDifferentServer": "Please try again later or choose a different server."
}

View File

@ -81,11 +81,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Arĥivita ĉambro",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Ĉu gastoj rajtas aliĝi",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -533,11 +528,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Delegaj subskriboj estas ŝaltitaj",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Nun aktiva",
"@currentlyActive": {
"type": "text",
@ -623,11 +613,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Trovi",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Prezenta nomo ŝanĝiĝis",
"@displaynameHasBeenChanged": {
"type": "text",
@ -794,11 +779,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Vendredo",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Ekde aliĝo",
"@fromJoining": {
"type": "text",
@ -989,11 +969,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Ŝlosiloj estas kaŝmemoritaj",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} forpelis uzanton {targetName}",
"@kicked": {
"type": "text",
@ -1118,11 +1093,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Lundo",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Silentigi babilon",
"@muteChat": {
"type": "text",
@ -1503,11 +1473,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sabato",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Konservi dosieron",
"@saveFile": {
"type": "text",
@ -1742,11 +1707,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Dimanĉo",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Spegulante… Bonvolu atendi.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1767,16 +1727,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Ĉi tiu ĉambro arĥiviĝis.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Ĵaŭdo",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1813,11 +1763,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Mardo",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Nedisponeble",
"@unavailable": {
"type": "text",
@ -1988,11 +1933,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Merkredo",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Ni sendis retleteron al vi",
"@weSentYouAnEmail": {
"type": "text",

File diff suppressed because it is too large Load Diff

View File

@ -82,11 +82,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Arhiveeritud jututuba",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Kas külalised võivad liituda",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -544,11 +539,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Risttunnustamine on kasutusel",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Hetkel aktiivne",
"@currentlyActive": {
"type": "text",
@ -634,11 +624,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Avasta",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Kuvatav nimi on muudetud",
"@displaynameHasBeenChanged": {
"type": "text",
@ -805,11 +790,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Reede",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Alates liitumise hetkest",
"@fromJoining": {
"type": "text",
@ -1000,11 +980,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Krüptovõtmed on puhverdatud",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} müksas kasutaja {targetName} välja",
"@kicked": {
"type": "text",
@ -1139,11 +1114,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Esmaspäev",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Summuta vestlus",
"@muteChat": {
"type": "text",
@ -1537,11 +1507,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Laupäev",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Salvesta fail",
"@saveFile": {
"type": "text",
@ -1780,11 +1745,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Pühapäev",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Sünkroniseerin andmeid… Palun oota.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1805,16 +1765,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "See jututuba on arhiveeritud.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Neljapäev",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1851,11 +1801,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Teisipäev",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Eemal",
"@unavailable": {
"type": "text",
@ -2026,11 +1971,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Kolmapäev",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Me saatsime sulle e-kirja",
"@weSentYouAnEmail": {
"type": "text",
@ -2107,8 +2047,6 @@
"@addToSpace": {},
"scanQrCode": "Skaneeri QR-koodi",
"@scanQrCode": {},
"typeInInviteLinkManually": "Sisesta kutse link käsitsi...",
"@typeInInviteLinkManually": {},
"shareYourInviteLink": "Jaga oma kutselinki",
"@shareYourInviteLink": {},
"sendOnEnter": "Saada sõnum sisestusklahvi vajutusel",
@ -2135,8 +2073,6 @@
"@link": {},
"yourChatBackupHasBeenSetUp": "Sinu vestluste varundus on seadistatud.",
"@yourChatBackupHasBeenSetUp": {},
"yourUserId": "Sinu kasutajatunnus:",
"@yourUserId": {},
"unverified": "Verifitseerimata",
"@unverified": {},
"repeatPassword": "Korda salasõna",
@ -2374,8 +2310,6 @@
"@recoveryKey": {},
"users": "Kasutajad",
"@users": {},
"enableAutoBackups": "Võta kasutusele automaatne varundus",
"@enableAutoBackups": {},
"stories": "Jutustused",
"@stories": {},
"storeInSecureStorageDescription": "Salvesta taastevõti selle seadme turvahoidlas.",
@ -2402,8 +2336,6 @@
},
"dehydrate": "Ekspordi sessiooni teave ja kustuta nutiseadmest rakenduse andmed",
"@dehydrate": {},
"dehydrateShare": "See on sinu FluffyChat'i privaatsete andmete eksport. Palun hoia teda turvaliselt ja vaata, et sa seda ei kaotaks.",
"@dehydrateShare": {},
"dehydrateTor": "TOR'i kasutajad: Ekspordi sessioon",
"@dehydrateTor": {},
"hydrateTor": "TOR'i kasutajatele: impordi viimati eksporditud sessiooni andmed",
@ -2532,8 +2464,6 @@
"@deviceKeys": {},
"newSpaceDescription": "Kogukonnad võimaldavad sul koondada erinevaid vestlusi ning korraldada avalikku või privaatset ühistegevust.",
"@newSpaceDescription": {},
"noSearchResult": "Sobivaid otsingutulemusi ei leidu.",
"@noSearchResult": {},
"enterInviteLinkOrMatrixId": "Sisesta kutse link või Matrix ID...",
"@enterInviteLinkOrMatrixId": {},
"letsStart": "Sõidame!",
@ -2560,5 +2490,25 @@
"jump": "Hüppa",
"@jump": {},
"openLinkInBrowser": "Ava link veebibrauseris",
"@openLinkInBrowser": {}
"@openLinkInBrowser": {},
"discover": "Otsi ja leia",
"@discover": {
"type": "text",
"placeholders": {}
},
"report": "teata",
"@report": {},
"allRooms": "Kõik vestlusrühmad",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"reportErrorDescription": "Oh appike! Midagi läks valesti. Palun proovi hiljem uuesti. Kui soovid, võid sellest veast arendajatele teatada.",
"@reportErrorDescription": {},
"continueWith": "Jätkamiseks kasuta:",
"@continueWith": {},
"signInWithPassword": "Logi sisse salasõnaga",
"@signInWithPassword": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "Palun proovi hiljem uuesti või muuda serveri nime.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

View File

@ -62,11 +62,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Artxibatutako gela",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Ba al dute gonbidatutako erabiltzaileek bat egiteko baimenik?",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -271,12 +266,12 @@
"type": "text",
"placeholders": {}
},
"compareEmojiMatch": "Konparatu eta egiaztatu ondorengo emojiak beste gailukoarekin bat datozela:",
"compareEmojiMatch": "Konparatu ondorengo emojiak:",
"@compareEmojiMatch": {
"type": "text",
"placeholders": {}
},
"compareNumbersMatch": "Konparatu eta egiaztatu ondorengo zenbakiak beste gailukoarekin bat datozela:",
"compareNumbersMatch": "Konparatu ondorengo zenbakiak:",
"@compareNumbersMatch": {
"type": "text",
"placeholders": {}
@ -337,11 +332,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Zeharkako sinadura gaituta dago",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Unean aktibo",
"@currentlyActive": {
"type": "text",
@ -494,17 +484,12 @@
"type": "text",
"placeholders": {}
},
"friday": "Ostirala",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "sartzeaz",
"fromJoining": "Bat egiteaz geroztik",
"@fromJoining": {
"type": "text",
"placeholders": {}
},
"fromTheInvitation": "gonbidapenaz",
"fromTheInvitation": "Gonbidapenaz geroztik",
"@fromTheInvitation": {
"type": "text",
"placeholders": {}
@ -629,11 +614,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Gakoak katxean daude",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username}(e)k {targetName} kaleratu du",
"@kicked": {
"type": "text",
@ -736,11 +716,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Astelehena",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Mututu berriketa",
"@muteChat": {
"type": "text",
@ -949,11 +924,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Larunbata",
"@saturday": {
"type": "text",
"placeholders": {}
},
"seenByUser": "{username}(e)k ikusi du",
"@seenByUser": {
"type": "text",
@ -1110,11 +1080,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Igandea",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "Sistemak darabilena",
"@systemTheme": {
"type": "text",
@ -1130,16 +1095,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Gela hau artxibatu da.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Osteguna",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1151,11 +1106,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Asteartea",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unbannedUser": "{username}(e)k {targetName} baimendu du",
"@unbannedUser": {
"type": "text",
@ -1304,11 +1254,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Asteazkena",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"whoIsAllowedToJoinThisGroup": "Nork duen baimena talde honetara batzeko",
"@whoIsAllowedToJoinThisGroup": {
"type": "text",
@ -1525,7 +1470,7 @@
"type": "text",
"placeholders": {}
},
"unreadChats": "{unreadCount, plural, =1{irakurri gabeko txat 1} other {{unreadCount} txat irakurri gabe}}",
"unreadChats": "{unreadCount, plural, =1{irakurri gabeko txat 1} other {irakurri gabeko {unreadCount} txat}}",
"@unreadChats": {
"type": "text",
"placeholders": {
@ -1740,8 +1685,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "Zure erabiltzaile IDa:",
"@yourUserId": {},
"chatBackup": "Txataren babeskopia",
"@chatBackup": {
"type": "text",
@ -1873,8 +1816,6 @@
"type": "text",
"placeholders": {}
},
"typeInInviteLinkManually": "Idatzi eskuz gonbidapen esteka…",
"@typeInInviteLinkManually": {},
"online": "Linean",
"@online": {
"type": "text",
@ -2009,11 +1950,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Deskubritu",
"@discover": {
"type": "text",
"placeholders": {}
},
"emotePacks": "Emote sortak gelarako",
"@emotePacks": {
"type": "text",
@ -2064,7 +2000,7 @@
"type": "text",
"placeholders": {}
},
"noEncryptionForPublicRooms": "Zifraketa aktiba dezakezu soilik gela publikoa ez bada.",
"noEncryptionForPublicRooms": "Zifraketa aktiba dezakezu soilik gelak publikoa izateari utzi badio.",
"@noEncryptionForPublicRooms": {
"type": "text",
"placeholders": {}
@ -2296,7 +2232,7 @@
"@widgetEtherpad": {},
"widgetJitsi": "Jitsi Meet",
"@widgetJitsi": {},
"widgetCustom": "Neurrira egindakoa",
"widgetCustom": "Norberak ezarritakoa",
"@widgetCustom": {},
"widgetName": "Izena",
"@widgetName": {},
@ -2407,10 +2343,6 @@
"@hydrateTorLong": {},
"noEmailWarning": "Sartu baliozko posta helbide bat. Bestela ezingo duzu pasahitza berrezarri. Hala ere nahi ez baduzu, sakatu berriro botoia aurrera egiteko.",
"@noEmailWarning": {},
"enableAutoBackups": "Gaitu babeskopia automatikoak",
"@enableAutoBackups": {},
"dehydrateShare": "Hau zure FluffyChaten esportazio pribatua da. Ez galdu eta ez partekatu inorekin.",
"@dehydrateShare": {},
"dehydrateTor": "TOR Erabiltzaileak: Esportatu saioa",
"@dehydrateTor": {},
"hydrateTor": "TOR Erabiltzaileak: Inportatu esportatutako saioa",
@ -2498,7 +2430,7 @@
"@startFirstChat": {},
"newSpaceDescription": "Guneek txatak taldekatzea ahalbidetzen dute eta komunitate pribatu edo publikoak osatzea.",
"@newSpaceDescription": {},
"endToEndEncryption": "Puntuz puntuko zifraketa",
"endToEndEncryption": "Ertzetik ertzerako zifratzea",
"@endToEndEncryption": {},
"disableEncryptionWarning": "Segurtasun arrazoiak direla-eta, ezin duzu lehendik zifratuta zegoen txat bateko zifraketa ezgaitu.",
"@disableEncryptionWarning": {},
@ -2519,6 +2451,57 @@
"@sorryThatsNotPossible": {},
"reopenChat": "Ireki txata berriro",
"@reopenChat": {},
"noSearchResult": "Ez da emaitzarik aurkitu.",
"@noSearchResult": {}
"commandHint_googly": "Bidali begi dibertigarri batzuk",
"@commandHint_googly": {},
"commandHint_cuddle": "Bidali besarkada goxoa",
"@commandHint_cuddle": {},
"googlyEyesContent": "{senderName}(e)k begi dibertigarri batzuk bidali dizkizu",
"@googlyEyesContent": {
"type": "text",
"placeholders": {
"senderName": {}
}
},
"allRooms": "Talde-txat guztiak",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"jumpToLastReadMessage": "Joan irakurritako azken mezura",
"@jumpToLastReadMessage": {},
"reportErrorDescription": "Ez! Zerbaitek huts egin du. Saiatu berriro geroago. Nahi izanez gero, eman garatzaileei errorearen berri.",
"@reportErrorDescription": {},
"cuddleContent": "{senderName}(e)k samurki besarkatu zaitu",
"@cuddleContent": {
"type": "text",
"placeholders": {
"senderName": {}
}
},
"readUpToHere": "Honaino irakurrita",
"@readUpToHere": {},
"discover": "Deskubritu",
"@discover": {
"type": "text",
"placeholders": {}
},
"fileHasBeenSavedAt": "Fitxategia {path}(e)n gorde da",
"@fileHasBeenSavedAt": {
"type": "text",
"placeholders": {
"path": {}
}
},
"jump": "Joan",
"@jump": {},
"openLinkInBrowser": "Ireki esteka nabigatzailean",
"@openLinkInBrowser": {},
"report": "eman berri",
"@report": {},
"signInWithPassword": "Hasi saioa pasahitzarekin",
"@signInWithPassword": {},
"continueWith": "Jarraitu honekin:",
"@continueWith": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "Saiatu geroago edo hautatu beste zerbitzari bat.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

View File

@ -79,11 +79,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "اتاق بایگانی شده",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areYouSure": "مطمئن هستید؟",
"@areYouSure": {
"type": "text",
@ -647,11 +642,6 @@
"type": "text",
"placeholders": {}
},
"discover": "کشف کردن",
"@discover": {
"type": "text",
"placeholders": {}
},
"copy": "کپی",
"@copy": {
"type": "text",
@ -682,8 +672,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "هويت‌ کاربری شما:",
"@yourUserId": {},
"commandHint_html": "متن با فرمت HTML بفرستید",
"@commandHint_html": {
"type": "text",
@ -751,11 +739,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "امضا کردن متقابل فعال",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"dateWithYear": "{year}-{month}-{day}",
"@dateWithYear": {
"type": "text",
@ -1098,11 +1081,6 @@
"type": "text",
"placeholders": {}
},
"friday": "جمعه",
"@friday": {
"type": "text",
"placeholders": {}
},
"groupDescription": "توصیف گروه",
"@groupDescription": {
"type": "text",
@ -1184,11 +1162,6 @@
"type": "text",
"placeholders": {}
},
"monday": "دوشنبه",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "بی‌صدا کردن گپ",
"@muteChat": {
"type": "text",
@ -1415,8 +1388,6 @@
"type": "text",
"placeholders": {}
},
"noSearchResult": "نتایج جستجوی منطبقی وجود ندارد.",
"@noSearchResult": {},
"moderator": "مدیر",
"@moderator": {
"type": "text",
@ -1427,8 +1398,6 @@
"type": "text",
"placeholders": {}
},
"typeInInviteLinkManually": "پیوند دعوت را به صورت دستی وارد کنید...",
"@typeInInviteLinkManually": {},
"noPermission": "بدون اجازه",
"@noPermission": {
"type": "text",
@ -1521,11 +1490,6 @@
"targetName": {}
}
},
"keysCached": "کلیدها در حافظه پنهان هستند",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"joinedTheChat": "👋 {username} به گپ پیوست",
"@joinedTheChat": {
"type": "text",
@ -1548,8 +1512,6 @@
},
"dehydrateWarning": "این عمل قابل لغو نیست. مطمئن شوید که فایل پشتیبان را به صورت امن ذخیره می کنید.",
"@dehydrateWarning": {},
"dehydrateShare": "این صدور فلافی‌چت خصوصی شماست. مطمئن شوید که آن را از دست نمی‌دهید و آن را خصوصی نگه می‌دارید.",
"@dehydrateShare": {},
"locationDisabledNotice": "خدمات مکان غیرفعال است. لطفا آن را فعال کنید تا بتوانید موقعیت مکانی خود را به اشتراک بگذارید.",
"@locationDisabledNotice": {
"type": "text",
@ -1745,11 +1707,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "شنبه",
"@saturday": {
"type": "text",
"placeholders": {}
},
"search": "جستجو",
"@search": {
"type": "text",
@ -1979,11 +1936,6 @@
"type": "text",
"placeholders": {}
},
"thursday": "پنج‌شنبه",
"@thursday": {
"type": "text",
"placeholders": {}
},
"nextAccount": "حساب بعدی",
"@nextAccount": {},
"editWidgets": "ویرایش ویجت‌ها",
@ -2027,11 +1979,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "سه‌شنبه",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "خارج از دسترس",
"@unavailable": {
"type": "text",
@ -2062,11 +2009,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "چهارشنبه",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"whoCanPerformWhichAction": "چه کسی توان انجام کدام عمل را داراست",
"@whoCanPerformWhichAction": {
"type": "text",
@ -2131,21 +2073,11 @@
},
"startFirstChat": "اولین گپ خود را شروع کنید",
"@startFirstChat": {},
"sunday": "یک‌شنبه",
"@sunday": {
"type": "text",
"placeholders": {}
},
"theyMatch": "با هم منطبق هستند",
"@theyMatch": {
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "این اتاق بایگانی شده است.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"title": "فلافی‌چت",
"@title": {
"description": "Title for the application",
@ -2545,10 +2477,30 @@
"@stories": {},
"users": "کاربرها",
"@users": {},
"enableAutoBackups": "فعال‌سازی پشتیبان‌گیری خودکار",
"@enableAutoBackups": {},
"storeInSecureStorageDescription": "کلید بازیابی را در محل ذخیره‌سازی امن این دستگاه ذخیره کنید.",
"@storeInSecureStorageDescription": {},
"jump": "پرش",
"@jump": {}
"@jump": {},
"discover": "کشف کنید",
"@discover": {
"type": "text",
"placeholders": {}
},
"allRooms": "تمام چت‌های گروهی",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"report": "گزارش",
"@report": {},
"openLinkInBrowser": "بازکردن پیوند در مرورگر",
"@openLinkInBrowser": {},
"reportErrorDescription": "اوه نه. اشتباهی رخ داد. لطفا بعدا تلاش کنید. اگر تمایل دارید، می‌توانید این اشکال را با توسعه‌دهندگان گزارش دهید.",
"@reportErrorDescription": {},
"signInWithPassword": "ورود با رمزعبور",
"@signInWithPassword": {},
"continueWith": "ادامه دادن با:",
"@continueWith": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "لطفا بعدا تلاش کنید یا سرور دیگری انتخاب کنید.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,11 +9,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Dé Céadaoin",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"warning": "Rabhadh!",
"@warning": {
"type": "text",
@ -49,32 +44,17 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Dé Máirt",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
"type": "text",
"placeholders": {}
},
"thursday": "Déardaoin",
"@thursday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "Córas",
"@systemTheme": {
"type": "text",
"placeholders": {}
},
"sunday": "Dé Domhnaigh",
"@sunday": {
"type": "text",
"placeholders": {}
},
"submit": "Cuir isteach",
"@submit": {
"type": "text",
@ -120,11 +100,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Dé Sathairn",
"@saturday": {
"type": "text",
"placeholders": {}
},
"reply": "Freagair",
"@reply": {
"type": "text",
@ -205,11 +180,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Tá cros-shíniú tosaithe",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"createNewSpace": "Spás nua",
"@createNewSpace": {
"type": "text",
@ -267,11 +237,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Dé Luain",
"@monday": {
"type": "text",
"placeholders": {}
},
"moderator": "Modhnóir",
"@moderator": {
"type": "text",
@ -352,11 +317,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Dé hAoine",
"@friday": {
"type": "text",
"placeholders": {}
},
"forward": "Seol ar aghaidh",
"@forward": {
"type": "text",
@ -384,11 +344,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Tar ar",
"@discover": {
"type": "text",
"placeholders": {}
},
"devices": "Gléasanna",
"@devices": {
"type": "text",
@ -534,11 +489,6 @@
},
"sendOnEnter": "Seol ar iontráil",
"@sendOnEnter": {},
"archivedRoom": "Seomra cartlainne",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"archive": "Cartlann",
"@archive": {
"type": "text",
@ -1312,8 +1262,6 @@
},
"scanQrCode": "Scan cód QR",
"@scanQrCode": {},
"typeInInviteLinkManually": "Clóscríobh an nasc cuiridh de láimh...",
"@typeInInviteLinkManually": {},
"inviteText": "Thug {username} cuireadh duit chuig FluffyChat.\n1. Suiteáil FluffyChat: https://fluffychat.im\n2. Cláraigh nó sínigh isteach\n3. Oscail an nasc cuiridh: {link}",
"@inviteText": {
"type": "text",
@ -1451,11 +1399,6 @@
"targetName": {}
}
},
"keysCached": "Cuirtear eochracha i dtaisce",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"joinedTheChat": "Tháinig {username} isteach sa chomhrá",
"@joinedTheChat": {
"type": "text",
@ -1740,11 +1683,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Tá an seomra seo curtha i gcartlann.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"theyDontMatch": "Níl siad céanna",
"@theyDontMatch": {
"type": "text",
@ -2153,8 +2091,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "D'aitheantas úsáideora:",
"@yourUserId": {},
"yourChatBackupHasBeenSetUp": "Bunaíodh do chúltaca comhrá.",
"@yourChatBackupHasBeenSetUp": {},
"openVideoCamera": "Oscail físcheamara",

View File

@ -23,7 +23,7 @@
"type": "text",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐 {username} activou o cifrado extremo-a-extremo",
"activatedEndToEndEncryption": "🔐 {username} activou a cifraxe extremo-a-extremo",
"@activatedEndToEndEncryption": {
"type": "text",
"placeholders": {
@ -82,11 +82,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Sala arquivada",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Permitir o acceso de convidadas",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -319,7 +314,7 @@
"type": "text",
"placeholders": {}
},
"channelCorruptedDecryptError": "O cifrado está corrompido",
"channelCorruptedDecryptError": "A cifraxe está estragada",
"@channelCorruptedDecryptError": {
"type": "text",
"placeholders": {}
@ -544,11 +539,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Sinatura-Cruzada activada",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Actualmente activo",
"@currentlyActive": {
"type": "text",
@ -634,11 +624,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Descubrir",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "O nome público mudou",
"@displaynameHasBeenChanged": {
"type": "text",
@ -719,12 +704,12 @@
"type": "text",
"placeholders": {}
},
"enableEncryption": "Activar cifrado",
"enableEncryption": "Activar cifraxe",
"@enableEncryption": {
"type": "text",
"placeholders": {}
},
"enableEncryptionWarning": "Non poderás desactivar o cifrado posteriormente, tes certeza?",
"enableEncryptionWarning": "Non poderás desactivar a cifraxe posteriormente, tes certeza?",
"@enableEncryptionWarning": {
"type": "text",
"placeholders": {}
@ -734,12 +719,12 @@
"type": "text",
"placeholders": {}
},
"encryption": "Cifrado",
"encryption": "Cifraxe",
"@encryption": {
"type": "text",
"placeholders": {}
},
"encryptionNotEnabled": "O cifrado non está activado",
"encryptionNotEnabled": "A cifraxe non está activada",
"@encryptionNotEnabled": {
"type": "text",
"placeholders": {}
@ -805,11 +790,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Venres",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Desde que se una",
"@fromJoining": {
"type": "text",
@ -1000,11 +980,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Chaves almacenadas",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} expulsou a {targetName}",
"@kicked": {
"type": "text",
@ -1139,17 +1114,12 @@
"type": "text",
"placeholders": {}
},
"monday": "Luns",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Acalar chat",
"@muteChat": {
"type": "text",
"placeholders": {}
},
"needPantalaimonWarning": "Ten en conta que polo de agora precisas Pantalaimon para o cifrado extremo-a-extremo.",
"needPantalaimonWarning": "Ten en conta que polo de agora precisas Pantalaimon para a cifraxe extremo-a-extremo.",
"@needPantalaimonWarning": {
"type": "text",
"placeholders": {}
@ -1189,7 +1159,7 @@
"type": "text",
"placeholders": {}
},
"noEncryptionForPublicRooms": "Só podes activar o cifrado tan pronto como a sala non sexa públicamente accesible.",
"noEncryptionForPublicRooms": "Só podes activar a cifraxe tan pronto como a sala non sexa públicamente accesible.",
"@noEncryptionForPublicRooms": {
"type": "text",
"placeholders": {}
@ -1537,11 +1507,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sábado",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Gardar ficheiro",
"@saveFile": {
"type": "text",
@ -1780,11 +1745,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Domingo",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Sincronizando... Agarda.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1805,16 +1765,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "A sala foi arquivada.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Xoves",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1851,11 +1801,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Martes",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Non dispoñible",
"@unavailable": {
"type": "text",
@ -1879,7 +1824,7 @@
"type": "text",
"placeholders": {}
},
"unknownEncryptionAlgorithm": "Algoritmo de cifrado descoñecido",
"unknownEncryptionAlgorithm": "Algoritmo de cifraxe descoñecido",
"@unknownEncryptionAlgorithm": {
"type": "text",
"placeholders": {}
@ -2026,11 +1971,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Mércores",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Enviamosche un email",
"@weSentYouAnEmail": {
"type": "text",
@ -2107,8 +2047,6 @@
"@addToSpace": {},
"scanQrCode": "Escanear código QR",
"@scanQrCode": {},
"typeInInviteLinkManually": "Escribe manualmente a ligazón do convite...",
"@typeInInviteLinkManually": {},
"shareYourInviteLink": "Comparte a túa ligazón de convite",
"@shareYourInviteLink": {},
"sendOnEnter": "Enter para enviar",
@ -2129,8 +2067,6 @@
"@yourChatBackupHasBeenSetUp": {},
"unverified": "Sen verificar",
"@unverified": {},
"yourUserId": "O teu ID:",
"@yourUserId": {},
"pleaseEnterValidEmail": "Escribe un enderezo de email válido.",
"@pleaseEnterValidEmail": {},
"passwordsDoNotMatch": "Os contrasinais non concordan!",
@ -2167,7 +2103,7 @@
"type": "text",
"description": "Usage hint for the command /discardsession"
},
"commandHint_create": "Crear un grupo de conversa baleiro\nUsa --no-encryption para desactivar o cifrado",
"commandHint_create": "Crear un grupo de conversa baleiro\nUsa --no-encryption para desactivar a cifraxe",
"@commandHint_create": {
"type": "text",
"description": "Usage hint for the command /create"
@ -2177,7 +2113,7 @@
"type": "text",
"description": "Usage hint for the command /clearcache"
},
"commandHint_dm": "Iniciar un chat directo\nUsa --no-encryption para desactivar o cifrado",
"commandHint_dm": "Iniciar un chat directo\nUsa --no-encryption para desactivar a cifraxe",
"@commandHint_dm": {
"type": "text",
"description": "Usage hint for the command /dm"
@ -2388,8 +2324,6 @@
"@pleaseEnterRecoveryKeyDescription": {},
"users": "Usuarias",
"@users": {},
"enableAutoBackups": "Activar copia automática",
"@enableAutoBackups": {},
"storeInSecureStorageDescription": "Gardar a chave de recuperación na almacenaxe segura deste dispositivo.",
"@storeInSecureStorageDescription": {},
"countFiles": "{count} ficheiros",
@ -2400,8 +2334,6 @@
},
"unlockOldMessages": "Desbloquear mensaxes antigas",
"@unlockOldMessages": {},
"dehydrateShare": "Esta é a copia de apoio privada de FluffyChat. Pon coidado en non perdela e mantela segura.",
"@dehydrateShare": {},
"dehydrateTorLong": "Para usuarias de TOR, é recomendable exportar a sesión antes de pechar a ventál.",
"@dehydrateTorLong": {},
"hydrateTor": "Usuarias TOR: Importar a sesión exportada",
@ -2511,15 +2443,13 @@
"senderName": {}
}
},
"noSearchResult": "Non hai resultados para a busca.",
"@noSearchResult": {},
"enterInviteLinkOrMatrixId": "Escribe a ligazón de convite ou ID Matrix...",
"@enterInviteLinkOrMatrixId": {},
"encryptThisChat": "Cifrar esta conversa",
"@encryptThisChat": {},
"endToEndEncryption": "Cifrado de extremo a extremo",
"endToEndEncryption": "Cifraxe de extremo a extremo",
"@endToEndEncryption": {},
"disableEncryptionWarning": "Por razóns de seguridade non podes desactivar o cifrado dunha conversa onde foi activado previamente.",
"disableEncryptionWarning": "Por razóns de seguridade non podes desactivar a cifraxe dunha conversa onde foi activada previamente.",
"@disableEncryptionWarning": {},
"sorryThatsNotPossible": "Lamentámolo... iso non é posible",
"@sorryThatsNotPossible": {},
@ -2558,5 +2488,27 @@
"readUpToHere": "Lin ate aquí",
"@readUpToHere": {},
"openLinkInBrowser": "Abrir ligazón no navegador",
"@openLinkInBrowser": {}
"@openLinkInBrowser": {},
"jump": "Ir alá",
"@jump": {},
"report": "informar",
"@report": {},
"allRooms": "Todas as Conversas en grupo",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"reportErrorDescription": "Vaia! Algo fallou. Inténtao máis tarde. Se queres, podes informar do problema aos desenvolvedores.",
"@reportErrorDescription": {},
"discover": "Descubrir",
"@discover": {
"type": "text",
"placeholders": {}
},
"signInWithPassword": "Accede con contrasinal",
"@signInWithPassword": {},
"continueWith": "Continuar con:",
"@continueWith": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "Inténtao máis tarde ou elixe un servidor diferente.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

View File

@ -61,11 +61,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "חדר בארכיון",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "האם משתמשים אורחים מורשים להצטרף",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -343,8 +338,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "מזהה המשתמש שלך:",
"@yourUserId": {},
"yourChatBackupHasBeenSetUp": "גיבוי הצ'אט שלך הוגדר.",
"@yourChatBackupHasBeenSetUp": {},
"chatBackup": "גיבוי צ'אט",
@ -477,11 +470,6 @@
"username": {}
}
},
"crossSigningEnabled": "חתימה צולבת על",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "פעיל כעת",
"@currentlyActive": {
"type": "text",
@ -543,11 +531,6 @@
"type": "text",
"placeholders": {}
},
"discover": "לגלות",
"@discover": {
"type": "text",
"placeholders": {}
},
"downloadFile": "הורד קובץ",
"@downloadFile": {
"type": "text",
@ -630,11 +613,6 @@
"type": "text",
"placeholders": {}
},
"friday": "יום שישי",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "מהצטרפות",
"@fromJoining": {
"type": "text",
@ -755,11 +733,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "המפתחות נשמרים במטמון",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} בעט ב {targetName}",
"@kicked": {
"type": "text",
@ -1146,8 +1119,6 @@
},
"shareYourInviteLink": "שתף את קישור ההזמנה שלך",
"@shareYourInviteLink": {},
"typeInInviteLinkManually": "הקלד את קישור ההזמנה באופן ידני...",
"@typeInInviteLinkManually": {},
"noRoomsFound": "לא נמצאו חדרים…",
"@noRoomsFound": {
"type": "text",
@ -1312,11 +1283,6 @@
"type": "text",
"placeholders": {}
},
"monday": "יום שני",
"@monday": {
"type": "text",
"placeholders": {}
},
"noGoogleServicesWarning": "נראה שאין לך שירותי גוגל בטלפון שלך. זו החלטה טובה לפרטיות שלך! כדי לקבל התרעות ב- FluffyChat אנו ממליצים להשתמש https://microg.org/ או https://unifiedpush.org/.",
"@noGoogleServicesWarning": {
"type": "text",

View File

@ -77,11 +77,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Arhivirana soba",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Smiju li se gosti pridružiti",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -534,11 +529,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Unakrsno potpisivanje uključeno",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Trenutačno aktivni",
"@currentlyActive": {
"type": "text",
@ -624,11 +614,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Otkrij",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Prikazno ime je promijenjeno",
"@displaynameHasBeenChanged": {
"type": "text",
@ -788,11 +773,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Petak",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Od pridruživanja",
"@fromJoining": {
"type": "text",
@ -983,11 +963,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Ključevi su spremljeni u predmemoriji",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} je izbacio/la {targetName}",
"@kicked": {
"type": "text",
@ -1112,11 +1087,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Ponedjeljak",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Isključi zvuk razgovora",
"@muteChat": {
"type": "text",
@ -1492,11 +1462,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Subota",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Spremi datoteku",
"@saveFile": {
"type": "text",
@ -1730,11 +1695,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Nedjelja",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Sinkronizira se … Pričekaj.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1755,16 +1715,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Ova soba je arhivirana.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Četvrtak",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1801,11 +1751,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Utorak",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Nedostupno",
"@unavailable": {
"type": "text",
@ -1976,11 +1921,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Srijeda",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Poslali smo ti e-poruku",
"@weSentYouAnEmail": {
"type": "text",
@ -2109,8 +2049,6 @@
"@serverRequiresEmail": {},
"scanQrCode": "Snimi QR kod",
"@scanQrCode": {},
"typeInInviteLinkManually": "Upiši poveznicu za pozivnicu …",
"@typeInInviteLinkManually": {},
"shareYourInviteLink": "Dijeli svoju poveznicu za pozivnicu",
"@shareYourInviteLink": {},
"homeserver": "Domaći poslužitelj",
@ -2133,8 +2071,6 @@
"@addAccount": {},
"oneClientLoggedOut": "Jedan od tvojih klijenata je odjavljen",
"@oneClientLoggedOut": {},
"yourUserId": "Tvoj korisnički ID:",
"@yourUserId": {},
"unverified": "Nepotvrđeno",
"@unverified": {},
"yourChatBackupHasBeenSetUp": "Sigurnosna kopija tvog razgovora je postavljena.",
@ -2381,10 +2317,6 @@
},
"dehydrate": "Izvezi sesiju i izbriši uređaj",
"@dehydrate": {},
"dehydrateShare": "Ovo je izvoz tvog privatnog FluffyChata. Pazi da ga ne izgubiš i zadrži ga privatnim.",
"@dehydrateShare": {},
"enableAutoBackups": "Uključi automatsko spremanje sigurnosnih kopija",
"@enableAutoBackups": {},
"unlockOldMessages": "Otključaj stare poruke",
"@unlockOldMessages": {},
"storeInSecureStorageDescription": "Ključ za obnavljanje spremi u sigurno spremište na ovom uređaju.",
@ -2553,12 +2485,30 @@
"senderName": {}
}
},
"noSearchResult": "Nema poklapajućih rezultata.",
"@noSearchResult": {},
"noKeyForThisMessage": "To se može dogoditi ako je poruka poslana prije prijave na tvoj račun na ovom uređaju.\n\nTakođer je moguće da je pošiljatelj blokirao tvoj uređaj ili je došlo do greške s internetskom vezom.\n\nMožeš li pročitati poruku na jednoj drugoj sesiji? U tom slučaju možeš prenijeti poruku iz nje! Idi na Postavke > Uređaji i uvjeri se da su se tvoji uređaji međusobno provjerili. Kada sljedeći put otvoriš sobu i obje sesije su u prednjem planu, ključevi će se automatski prenijeti.\n\nNe želiš izgubiti ključeve kada se odjaviš ili zamijeniš uređaje? Aktiviraj spremanje sigurnosne kopije razgovora u postavkama.",
"@noKeyForThisMessage": {},
"reopenChat": "Ponovo otvori razgovor",
"@reopenChat": {},
"openLinkInBrowser": "Otvori poveznicu u pregledniku",
"@openLinkInBrowser": {}
"@openLinkInBrowser": {},
"discover": "Otkrij",
"@discover": {
"type": "text",
"placeholders": {}
},
"report": "prijavi",
"@report": {},
"allRooms": "Svi grupni razgovori",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"reportErrorDescription": "Dogodila se greška. Pokušaj ponovo kasnije. Ako želiš, grešku možeš prijaviti programerima.",
"@reportErrorDescription": {},
"signInWithPassword": "Prijavi se s lozinkom",
"@signInWithPassword": {},
"continueWith": "Nastavi sa:",
"@continueWith": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "Pokušaj ponovo kasnije ili odaberi jedan drugi poslužitelj.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

File diff suppressed because it is too large Load Diff

View File

@ -247,11 +247,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Jumat",
"@friday": {
"type": "text",
"placeholders": {}
},
"forward": "Teruskan",
"@forward": {
"type": "text",
@ -449,11 +444,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Tanda tangan silang dinyalakan",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"createNewGroup": "Buat grup baru",
"@createNewGroup": {
"type": "text",
@ -729,11 +719,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Ruangan yang Diarsipkan",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"appLock": "Kunci aplikasi",
"@appLock": {
"type": "text",
@ -885,11 +870,6 @@
"targetName": {}
}
},
"keysCached": "Kunci telah ditembolok",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"joinRoom": "Bergabung dengan ruangan",
"@joinRoom": {
"type": "text",
@ -967,11 +947,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Senin",
"@monday": {
"type": "text",
"placeholders": {}
},
"moderator": "Moderator",
"@moderator": {
"type": "text",
@ -1176,11 +1151,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Rabu",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"warning": "Peringatan!",
"@warning": {
"type": "text",
@ -1334,11 +1304,6 @@
"targetName": {}
}
},
"tuesday": "Selasa",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"tryToSendAgain": "Coba kirim lagi",
"@tryToSendAgain": {
"type": "text",
@ -1370,16 +1335,6 @@
"type": "text",
"placeholders": {}
},
"thursday": "Kamis",
"@thursday": {
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Ruangan ini telah diarsipkan.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"theyMatch": "Cocok",
"@theyMatch": {
"type": "text",
@ -1400,11 +1355,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Minggu",
"@sunday": {
"type": "text",
"placeholders": {}
},
"submit": "Kirim",
"@submit": {
"type": "text",
@ -1775,8 +1725,6 @@
},
"scanQrCode": "Pindai kode QR",
"@scanQrCode": {},
"typeInInviteLinkManually": "Masukkan tautan undangan secara manual...",
"@typeInInviteLinkManually": {},
"shareYourInviteLink": "Bagikan tautan undanganmu",
"@shareYourInviteLink": {},
"noMatrixServer": "{server1} itu bukan server Matrix, gunakan {server2} saja?",
@ -1885,11 +1833,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Temukan",
"@discover": {
"type": "text",
"placeholders": {}
},
"defaultPermissionLevel": "Level izin default",
"@defaultPermissionLevel": {
"type": "text",
@ -2068,11 +2011,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sabtu",
"@saturday": {
"type": "text",
"placeholders": {}
},
"removeDevice": "Hapus perangkat",
"@removeDevice": {
"type": "text",
@ -2134,8 +2072,6 @@
"@link": {},
"yourChatBackupHasBeenSetUp": "Cadangan obrolanmu telah disiapkan.",
"@yourChatBackupHasBeenSetUp": {},
"yourUserId": "ID penggunamu:",
"@yourUserId": {},
"unverified": "Tidak terverifikasi",
"@unverified": {},
"pleaseEnterValidEmail": "Mohon masukkan alamat email yang valid.",
@ -2389,8 +2325,6 @@
"@recoveryKeyLost": {},
"storeInAndroidKeystore": "Simpan di Android KeyStore",
"@storeInAndroidKeystore": {},
"enableAutoBackups": "Aktifkan cadangan otomatis",
"@enableAutoBackups": {},
"storeSecurlyOnThisDevice": "Simpan secara aman di perangkat ini",
"@storeSecurlyOnThisDevice": {},
"countFiles": "{count} file",
@ -2399,8 +2333,6 @@
"count": {}
}
},
"dehydrateShare": "Ini adalah ekspor FluffyChat privat kamu. Pastikan kamu tidak menghilangkannya dan tetap rahasia.",
"@dehydrateShare": {},
"hydrate": "Pulihkan dari file cadangan",
"@hydrate": {},
"indexedDbErrorTitle": "Masalah dengan mode privat",
@ -2531,8 +2463,6 @@
"@endToEndEncryption": {},
"disableEncryptionWarning": "Demi keamanan kamu tidak bisa menonaktifkan enkripsi dalam sebuah obrolan di mana sebelumbya sudah diaktifkan.",
"@disableEncryptionWarning": {},
"noSearchResult": "Tidak ada hasil pencarian yang cocok.",
"@noSearchResult": {},
"letsStart": "Mari kita mulai",
"@letsStart": {},
"enterInviteLinkOrMatrixId": "Masukkan tautan undangan atau ID Matrix...",
@ -2557,5 +2487,27 @@
"readUpToHere": "Baca sampai sini",
"@readUpToHere": {},
"jump": "Lompat",
"@jump": {}
"@jump": {},
"openLinkInBrowser": "Buka tautan dalam peramban",
"@openLinkInBrowser": {},
"discover": "Jelajahi",
"@discover": {
"type": "text",
"placeholders": {}
},
"allRooms": "Semua Percakapan Grup",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"report": "laporkan",
"@report": {},
"reportErrorDescription": "Aduh. Ada yang salah. Silakan coba lahi nanti. Jika kamu mau, kamu bisa melaporkan kutu ini kepada para pengembang.",
"@reportErrorDescription": {},
"signInWithPassword": "Masuk dengan kata sandi",
"@signInWithPassword": {},
"continueWith": "Lanjutkan dengan:",
"@continueWith": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "Silakan coba lagi nanti atau pilih server yang lain.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

View File

@ -34,11 +34,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Decovrir",
"@discover": {
"type": "text",
"placeholders": {}
},
"containsUserName": "Contene li nómine",
"@containsUserName": {
"type": "text",
@ -189,11 +184,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Claves es in cache",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"lastActiveAgo": "Ultim activité: {localizedTimeShort}",
"@lastActiveAgo": {
"type": "text",
@ -340,11 +330,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Mardí",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Índisponibil",
"@unavailable": {
"type": "text",
@ -465,11 +450,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Saturdí",
"@saturday": {
"type": "text",
"placeholders": {}
},
"dateWithYear": "{day}.{month}.{year}",
"@dateWithYear": {
"type": "text",
@ -494,11 +474,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Venerdí",
"@friday": {
"type": "text",
"placeholders": {}
},
"lightTheme": "Lucid",
"@lightTheme": {
"type": "text",
@ -529,11 +504,6 @@
"type": "text",
"placeholders": {}
},
"thursday": "Jovedí",
"@thursday": {
"type": "text",
"placeholders": {}
},
"username": "Nómine de usator",
"@username": {
"type": "text",
@ -544,11 +514,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Mercurdí",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"submit": "Inviar",
"@submit": {
"type": "text",
@ -683,11 +648,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Archivat chambre",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"changePassword": "Cambiar li contrasigne",
"@changePassword": {
"type": "text",
@ -970,8 +930,6 @@
},
"updateAvailable": "Un actualisament de FluffyChat es disponibil",
"@updateAvailable": {},
"yourUserId": "Vor ID de usator:",
"@yourUserId": {},
"editWidgets": "Modificar li widgets",
"@editWidgets": {},
"widgetEtherpad": "Textual nota",
@ -1165,11 +1123,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Lunedí",
"@monday": {
"type": "text",
"placeholders": {}
},
"newGroup": "Crear un gruppe",
"@newGroup": {},
"newSpace": "Crear un spacie",
@ -1218,11 +1171,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Soledí",
"@sunday": {
"type": "text",
"placeholders": {}
},
"unverified": "Ínverificat",
"@unverified": {},
"deviceId": "ID de aparate",

View File

@ -76,11 +76,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Stanza archiviata",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Gli utenti ospiti possono partecipare",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -432,11 +427,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Firma incrociata abilitata",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Attualmente attivo",
"@currentlyActive": {
"type": "text",
@ -522,11 +512,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Scopri",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Il nominativo è stato cambiato",
"@displaynameHasBeenChanged": {
"type": "text",
@ -679,11 +664,6 @@
"type": "text",
"placeholders": {}
},
"friday": "venerdì",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Dall'adesione",
"@fromJoining": {
"type": "text",
@ -874,11 +854,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Le chiave sono memorizzate nella cache",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} ha espulso {targetName}",
"@kicked": {
"type": "text",
@ -996,11 +971,6 @@
"type": "text",
"placeholders": {}
},
"monday": "lunedì",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Silenzia discussione",
"@muteChat": {
"type": "text",
@ -1346,11 +1316,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "sabato",
"@saturday": {
"type": "text",
"placeholders": {}
},
"search": "Cerca",
"@search": {
"type": "text",
@ -1550,11 +1515,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "domenica",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "Sistema",
"@systemTheme": {
"type": "text",
@ -1570,16 +1530,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Questa stanza è stata archiviata.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "giovedì",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1616,11 +1566,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "martedì",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Non disponibile",
"@unavailable": {
"type": "text",
@ -1791,11 +1736,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "mercoledì",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Ti abbiamo inviato un'e-mail",
"@weSentYouAnEmail": {
"type": "text",
@ -1936,8 +1876,6 @@
"@passwordsDoNotMatch": {},
"pleaseEnterValidEmail": "Inserire un indirizzo email valido.",
"@pleaseEnterValidEmail": {},
"yourUserId": "Il tuo ID utente:",
"@yourUserId": {},
"commandHint_leave": "Lascia questa stanza",
"@commandHint_leave": {
"type": "text",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -71,11 +71,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Arkivert rom",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Skal gjester tillates å ta del",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -401,11 +396,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Videreformidling av tillit på",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Aktiv nå",
"@currentlyActive": {
"type": "text",
@ -491,11 +481,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Oppdag",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Visningsnavn endret",
"@displaynameHasBeenChanged": {
"type": "text",
@ -648,11 +633,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Fredag",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Fra å ta del",
"@fromJoining": {
"type": "text",
@ -838,11 +818,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Nøkler hurtiglagret",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} kastet ut {targetName}",
"@kicked": {
"type": "text",
@ -960,11 +935,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Mandag",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Forstum sludring",
"@muteChat": {
"type": "text",
@ -1275,11 +1245,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Lørdag",
"@saturday": {
"type": "text",
"placeholders": {}
},
"search": "Søk",
"@search": {
"type": "text",
@ -1474,11 +1439,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Søndag",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "System",
"@systemTheme": {
"type": "text",
@ -1494,16 +1454,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Dette rommet har blitt arkivert.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Torsdag",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1525,11 +1475,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Tirsdag",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Utilgjengelig",
"@unavailable": {
"type": "text",
@ -1685,11 +1630,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Onsdag",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Du har fått en e-post",
"@weSentYouAnEmail": {
"type": "text",
@ -1839,7 +1779,5 @@
"@changeYourAvatar": {
"type": "text",
"placeholders": {}
},
"yourUserId": "Din bruker ID:",
"@yourUserId": {}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -67,11 +67,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Zarchiwizowane pokoje",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Czy użytkownicy-goście mogą dołączyć",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -532,7 +527,7 @@
"day": {}
}
},
"deactivateAccountWarning": "To dezaktywuje twoje konto. To jest nieodwracalne ! Czy jesteś pewien?",
"deactivateAccountWarning": "To zdezaktywuje twoje konto. To jest nieodwracalne! Na pewno chcesz to zrobić?",
"@deactivateAccountWarning": {
"type": "text",
"placeholders": {}
@ -704,11 +699,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Piątek",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Od dołączenia",
"@fromJoining": {
"type": "text",
@ -879,11 +869,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Klucze są załadowane",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} wyrzucił/-a {targetName}",
"@kicked": {
"type": "text",
@ -996,11 +981,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Poniedziałek",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Wycisz czat",
"@muteChat": {
"type": "text",
@ -1229,11 +1209,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sobota",
"@saturday": {
"type": "text",
"placeholders": {}
},
"seenByUser": "Zobaczone przez {username}",
"@seenByUser": {
"type": "text",
@ -1369,11 +1344,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Niedziela",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Synchronizacja… Proszę czekać.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1384,16 +1354,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Ten pokój został przeniesiony do archiwum.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Czwartek",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1410,11 +1370,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Wtorek",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unbannedUser": "{username} odbanował/-a {targetName}",
"@unbannedUser": {
"type": "text",
@ -1540,11 +1495,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Środa",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"whoIsAllowedToJoinThisGroup": "Kto może dołączyć do tej grupy",
"@whoIsAllowedToJoinThisGroup": {
"type": "text",
@ -1821,8 +1771,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "Twoja nazwa użytkownika:",
"@yourUserId": {},
"yourChatBackupHasBeenSetUp": "Twoja kopia zapasowa chatu została ustawiona.",
"@yourChatBackupHasBeenSetUp": {},
"chatHasBeenAddedToThisSpace": "Chat został dodany do tej przestrzeni",
@ -1832,11 +1780,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Odkrywaj",
"@discover": {
"type": "text",
"placeholders": {}
},
"editRoomAvatar": "Edytuj zdjęcie pokoju",
"@editRoomAvatar": {
"type": "text",
@ -1947,8 +1890,6 @@
"@scanQrCode": {},
"addToStory": "Dodaj do relacji",
"@addToStory": {},
"typeInInviteLinkManually": "Wpisz link ręcznie...",
"@typeInInviteLinkManually": {},
"createNewSpace": "Nowa przestrzeń",
"@createNewSpace": {
"type": "text",
@ -2183,12 +2124,8 @@
"@unsubscribeStories": {},
"updateNow": "Rozpocznij aktualizację w tle",
"@updateNow": {},
"dehydrateShare": "To jest twój prywatny eksport FluffyChat. Upewnij się, że nie zgubisz go i zachowaj go dla siebie.",
"@dehydrateShare": {},
"hydrateTorLong": "Czy ostatnio eksportowałeś/-aś swoją sesję na TOR? Szybko ją zaimportuj i kontynuuj rozmowy.",
"@hydrateTorLong": {},
"noSearchResult": "Brak pasujących wyników wyszukiwania.",
"@noSearchResult": {},
"dehydrateTorLong": "W przypadku użytkowników sieci TOR zaleca się eksportowanie sesji przed zamknięciem okna.",
"@dehydrateTorLong": {},
"hydrate": "Przywracanie z pliku kopii zapasowej",
@ -2267,11 +2204,6 @@
},
"commandHint_markasdm": "Oznacz jako pokój wiadomości bezpośrednich",
"@commandHint_markasdm": {},
"crossSigningEnabled": "Weryfikacja krzyżowa jest włączona",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"confirmMatrixId": "Potwierdź swój identyfikator Matrix w celu usunięcia konta.",
"@confirmMatrixId": {},
"commandHint_markasgroup": "Oznacz jako grupę",
@ -2333,8 +2265,6 @@
},
"noOtherDevicesFound": "Nie znaleziono innych urządzeń",
"@noOtherDevicesFound": {},
"enableAutoBackups": "Włącz automatyczne tworzenie kopii zapasowych",
"@enableAutoBackups": {},
"widgetUrlError": "Niepoprawny URL.",
"@widgetUrlError": {},
"widgetNameError": "Podaj nazwę wyświetlaną.",

View File

@ -10,21 +10,6 @@
"type": "text",
"placeholders": {}
},
"monday": "segunda-feira",
"@monday": {
"type": "text",
"placeholders": {}
},
"saturday": "sábado",
"@saturday": {
"type": "text",
"placeholders": {}
},
"wednesday": "quarta-feira",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"about": "Sobre",
"@about": {
"type": "text",
@ -107,11 +92,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "terça-feira",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"logout": "Terminar sessão",
"@logout": {
"type": "text",
@ -122,11 +102,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "domingo",
"@sunday": {
"type": "text",
"placeholders": {}
},
"users": "Utilizadores",
"@users": {},
"close": "Fechar",
@ -141,15 +116,5 @@
"month": {},
"day": {}
}
},
"friday": "sexta-feira",
"@friday": {
"type": "text",
"placeholders": {}
},
"thursday": "quinta-feira",
"@thursday": {
"type": "text",
"placeholders": {}
}
}

View File

@ -81,11 +81,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Sala arquivada",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Usuários convidados podem participar",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -543,11 +538,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Assinatura cruzada ativada",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Ativo",
"@currentlyActive": {
"type": "text",
@ -633,11 +623,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Desvendar",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "O nome de exibição foi alterado",
"@displaynameHasBeenChanged": {
"type": "text",
@ -804,11 +789,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Sexta-feira",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Desde que entrou",
"@fromJoining": {
"type": "text",
@ -999,11 +979,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Chaves guardadas",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} enxotou {targetName}",
"@kicked": {
"type": "text",
@ -1138,11 +1113,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Segunda-feira",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Silenciar",
"@muteChat": {
"type": "text",
@ -1536,11 +1506,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sábado",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Salvar arquivo",
"@saveFile": {
"type": "text",
@ -1779,11 +1744,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Domingo",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Sincronizando… Por favor, aguarde.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1804,16 +1764,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Esta sala foi arquivada.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Quinta-feira",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1850,11 +1800,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Terça-feira",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Indisponível",
"@unavailable": {
"type": "text",
@ -2025,11 +1970,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Quarta-feira",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Enviamos um e-mail para você",
"@weSentYouAnEmail": {
"type": "text",
@ -2102,8 +2042,6 @@
},
"shareYourInviteLink": "Compartilhar o link do convite",
"@shareYourInviteLink": {},
"typeInInviteLinkManually": "Digitar o link do convite manualmente...",
"@typeInInviteLinkManually": {},
"oneClientLoggedOut": "Um dos seus clientes foi desvinculado",
"@oneClientLoggedOut": {},
"addAccount": "Adicionar conta",
@ -2176,8 +2114,6 @@
"@sendOnEnter": {},
"homeserver": "Servidor matriz",
"@homeserver": {},
"yourUserId": "Seu ID de usuário:",
"@yourUserId": {},
"chatHasBeenAddedToThisSpace": "A conversa foi adicionada a este espaço",
"@chatHasBeenAddedToThisSpace": {},
"commandHint_clearcache": "Limpar dados temporários",
@ -2419,8 +2355,6 @@
"@commandHint_markasdm": {},
"commandHint_markasgroup": "Marcar como grupo",
"@commandHint_markasgroup": {},
"dehydrateShare": "Este é seu extrato FluffyChat. Cuidado para não perdê-lo e o mantenha privado.",
"@dehydrateShare": {},
"hydrateTor": "Usuários TOR: Importar sessão",
"@hydrateTor": {},
"hydrateTorLong": "Você exportou sua última sessão no TOR? Importe ela rapidamente e continue conversando.",
@ -2491,8 +2425,6 @@
"@dehydrateWarning": {},
"dehydrateTorLong": "Para usuários TOR, é recomendado exportar a sessão antes de fechar a janela.",
"@dehydrateTorLong": {},
"enableAutoBackups": "Habilitar backups automáticos",
"@enableAutoBackups": {},
"whyIsThisMessageEncrypted": "Por que esta mensagem está ilegível?",
"@whyIsThisMessageEncrypted": {},
"screenSharingTitle": "Compartilhar tela",

View File

@ -90,11 +90,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Sala arquivada",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Todos os visitantes podem entrar",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -294,8 +289,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "O teu ID de utilizador:",
"@yourUserId": {},
"yourChatBackupHasBeenSetUp": "A cópia de segurança foi configurada.",
"@yourChatBackupHasBeenSetUp": {},
"chatBackup": "Cópia de segurança de conversas",
@ -515,11 +508,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Assinatura cruzada ativada",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Ativo(a) agora",
"@currentlyActive": {
"type": "text",
@ -605,11 +593,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Descobrir",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Nome de exibição alterado",
"@displaynameHasBeenChanged": {
"type": "text",
@ -778,11 +761,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Sexta-feira",
"@friday": {
"type": "text",
"placeholders": {}
},
"goToTheNewRoom": "Ir para a nova sala",
"@goToTheNewRoom": {
"type": "text",
@ -963,11 +941,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Chaves estão armazenadas em cache",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} expulsou {targetName}",
"@kicked": {
"type": "text",
@ -1097,11 +1070,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Segunda-feira",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Silenciar conversa",
"@muteChat": {
"type": "text",
@ -1167,8 +1135,6 @@
},
"shareYourInviteLink": "Partilhar a ligação de convite",
"@shareYourInviteLink": {},
"typeInInviteLinkManually": "Escrever a ligação de convite manualmente...",
"@typeInInviteLinkManually": {},
"none": "Nenhum",
"@none": {
"type": "text",
@ -1581,11 +1547,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sábado",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Guardar ficheiro",
"@saveFile": {
"type": "text",
@ -1709,8 +1670,6 @@
"@dehydrate": {},
"dehydrateWarning": "Esta ação não pode ser revertida. Assegura-te que guardas bem a cópia de segurança.",
"@dehydrateWarning": {},
"dehydrateShare": "Esta é a tua exportação privada do FluffyChat. Assegura-te que não a perdes e que a manténs privada.",
"@dehydrateShare": {},
"hydrateTorLong": "Exportaste a tua sessão na última vez que estiveste no TOR? Importa-a rapidamente e continua a conversar.",
"@hydrateTorLong": {},
"dehydrateTor": "Utilizadores do TOR: Exportar sessão",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -55,11 +55,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Archivovaná miestnosť",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Môžu sa pripojiť hostia",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -330,11 +325,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Vzájomné overenie je zapnuté",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Momentálne prítomní",
"@currentlyActive": {
"type": "text",
@ -480,11 +470,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Piatok",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Od pripojenia",
"@fromJoining": {
"type": "text",
@ -610,11 +595,6 @@
"username": {}
}
},
"keysCached": "Kľúče sú uložené",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} vyhodili {targetName}",
"@kicked": {
"type": "text",
@ -717,11 +697,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Pondelok",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Stlmiť chat",
"@muteChat": {
"type": "text",
@ -920,11 +895,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Sobota",
"@saturday": {
"type": "text",
"placeholders": {}
},
"seenByUser": "Videné užívateľom {username}",
"@seenByUser": {
"type": "text",
@ -1060,11 +1030,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Nedeľa",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "Systémová farba",
"@systemTheme": {
"type": "text",
@ -1080,16 +1045,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Táto miestnosť bola archivovaná.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Štvrtok",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1101,11 +1056,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Utorok",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unbannedUser": "{username} odbanovali {targetName}",
"@unbannedUser": {
"type": "text",
@ -1256,11 +1206,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Streda",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"whoIsAllowedToJoinThisGroup": "Kto môže vstúpiť do tejto skupiny",
"@whoIsAllowedToJoinThisGroup": {
"type": "text",
@ -1440,8 +1385,6 @@
},
"sendOnEnter": "Odoslať pri vstupe",
"@sendOnEnter": {},
"yourUserId": "Vaše užívateľské ID:",
"@yourUserId": {},
"ignoredUsers": "Ignorovaní užívatelia",
"@ignoredUsers": {
"type": "text",

View File

@ -71,11 +71,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Arhivirana soba",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"askSSSSSign": "Če želite podpisati drugo osebo, vnesite geslo za varno trgovino ali obnovitveni ključ.",
"@askSSSSSign": {
"type": "text",
@ -259,8 +254,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "Vaš ID uporabnika:",
"@yourUserId": {},
"yourChatBackupHasBeenSetUp": "Varnostna kopija klepeta je nastavljena.",
"@yourChatBackupHasBeenSetUp": {},
"chatBackup": "Varnostno kopiranje klepeta",
@ -558,11 +551,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Navzkrižno podpisovanje DA",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Trenutno aktiven",
"@currentlyActive": {
"type": "text",

View File

@ -76,11 +76,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Архивирана соба",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Да ли је гостима дозвољен приступ",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -504,11 +499,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Међу-потписивање укључено",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Тренутно активно",
"@currentlyActive": {
"type": "text",
@ -594,11 +584,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Истражи",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Име за приказ је измењено",
"@displaynameHasBeenChanged": {
"type": "text",
@ -756,11 +741,6 @@
"type": "text",
"placeholders": {}
},
"friday": "петак",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "од приступања",
"@fromJoining": {
"type": "text",
@ -951,11 +931,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Кључеви су кеширани",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username} избаци корисника {targetName}",
"@kicked": {
"type": "text",
@ -1080,11 +1055,6 @@
"type": "text",
"placeholders": {}
},
"monday": "понедељак",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Ућуткај ћаскање",
"@muteChat": {
"type": "text",
@ -1460,11 +1430,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "субота",
"@saturday": {
"type": "text",
"placeholders": {}
},
"search": "Претражи",
"@search": {
"type": "text",
@ -1674,11 +1639,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "недеља",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "системски",
"@systemTheme": {
"type": "text",
@ -1694,16 +1654,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Ова соба је архивирана.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "четвртак",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1740,11 +1690,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "уторак",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Недоступно",
"@unavailable": {
"type": "text",
@ -1915,11 +1860,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "среда",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Послали смо вам е-пошту",
"@weSentYouAnEmail": {
"type": "text",

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
{}
{}

View File

@ -84,11 +84,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Arşivlenmiş Oda",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Misafir kullanıcıların katılmasına izin veriliyor mu",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -548,11 +543,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Çapraz imzalama açık",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Şu anda etkin",
"@currentlyActive": {
"type": "text",
@ -638,11 +628,6 @@
"type": "text",
"placeholders": {}
},
"discover": "Keşfet",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Görünen ad değiştirildi",
"@displaynameHasBeenChanged": {
"type": "text",
@ -809,11 +794,6 @@
"type": "text",
"placeholders": {}
},
"friday": "Cuma",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Katılmadan",
"@fromJoining": {
"type": "text",
@ -1004,11 +984,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "Anahtarlar önbelleğe alındı",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username}, {targetName} kişisini attı",
"@kicked": {
"type": "text",
@ -1143,11 +1118,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Pazartesi",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Sohbeti sessize al",
"@muteChat": {
"type": "text",
@ -1541,11 +1511,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Cumartesi",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "Dosyayı kaydet",
"@saveFile": {
"type": "text",
@ -1784,11 +1749,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Pazar",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "Eşzamanlanıyor… Lütfen bekleyin.",
"@synchronizingPleaseWait": {
"type": "text",
@ -1809,16 +1769,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Bu oda arşivlendi.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Perşembe",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1855,11 +1805,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Salı",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "Yok",
"@unavailable": {
"type": "text",
@ -2030,11 +1975,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Çarşamba",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Size bir e-posta gönderdik",
"@weSentYouAnEmail": {
"type": "text",
@ -2107,8 +2047,6 @@
},
"scanQrCode": "QR kodunu tarayın",
"@scanQrCode": {},
"typeInInviteLinkManually": "Davet bağlantısını el ile yazın...",
"@typeInInviteLinkManually": {},
"shareYourInviteLink": "Davet bağlantınızı paylaşın",
"@shareYourInviteLink": {},
"sendOnEnter": "Enter tuşu ile gönder",
@ -2137,8 +2075,6 @@
"@yourChatBackupHasBeenSetUp": {},
"unverified": "Doğrulanmadı",
"@unverified": {},
"yourUserId": "Kullanıcı kimliğiniz:",
"@yourUserId": {},
"repeatPassword": "Parolayı tekrarlayın",
"@repeatPassword": {},
"passwordsDoNotMatch": "Parolalar eşleşmiyor!",
@ -2380,8 +2316,6 @@
"@users": {},
"storeInSecureStorageDescription": "Kurtarma anahtarını bu aygıtın güvenli deposunda saklayın.",
"@storeInSecureStorageDescription": {},
"enableAutoBackups": "Otomatik yedeklemeleri etkinleştir",
"@enableAutoBackups": {},
"recoveryKey": "Kurtarma anahtarı",
"@recoveryKey": {},
"stories": "Hikayeler",
@ -2414,8 +2348,6 @@
"@indexedDbErrorTitle": {},
"dehydrateWarning": "Bu eylem geri alınamaz. Yedekleme dosyasını güvenli bir şekilde sakladığınızdan emin olun.",
"@dehydrateWarning": {},
"dehydrateShare": "Bu sizin özel FluffyChat dışa aktarımınızdır. Kaybetmediğinizden ve gizli tuttuğunuzdan emin olun.",
"@dehydrateShare": {},
"hydrateTorLong": "TOR'da en son oturumunuzu dışa aktardınız mı? Hızlıca içe aktarın ve sohbete devam edin.",
"@hydrateTorLong": {},
"indexedDbErrorLong": "Mesaj saklama özelliği ne yazık ki öntanımlı olarak gizli modda etkin değildir.\nLütfen\n - about:config sayfasına gidin ve\n - dom.indexedDB.privateBrowsing.enabled seçeneğini true olarak ayarlayın\nAksi takdirde FluffyChat çalıştırılamaz.",
@ -2532,8 +2464,6 @@
"@sorryThatsNotPossible": {},
"deviceKeys": "Aygıt anahtarları:",
"@deviceKeys": {},
"noSearchResult": "Eşleşen arama sonucu yok.",
"@noSearchResult": {},
"letsStart": "Başlayalım",
"@letsStart": {},
"enterInviteLinkOrMatrixId": "Davet bağlantısını veya Matris kimliğini girin...",
@ -2560,5 +2490,25 @@
"jump": "Atla",
"@jump": {},
"openLinkInBrowser": "Bağlantıyı tarayıcıda aç",
"@openLinkInBrowser": {}
"@openLinkInBrowser": {},
"allRooms": "Tüm Grup Sohbetleri",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"discover": "Keşfet",
"@discover": {
"type": "text",
"placeholders": {}
},
"reportErrorDescription": "Olamaz. Bir şeyler yanlış gitti. Lütfen daha sonra tekrar deneyin. İsterseniz hatayı geliştiricilere bildirebilirsiniz.",
"@reportErrorDescription": {},
"report": "bildir",
"@report": {},
"signInWithPassword": "Parola ile oturum aç",
"@signInWithPassword": {},
"continueWith": "Devam et:",
"@continueWith": {},
"pleaseTryAgainLaterOrChooseDifferentServer": "Lütfen daha sonra tekrar deneyin veya farklı bir sunucu seçin.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {}
}

View File

@ -62,11 +62,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Заархівована кімната",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Чи дозволено гостям приєднуватись",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -337,11 +332,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Перехресне підписування увімкнено",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "Зараз у мережі",
"@currentlyActive": {
"type": "text",
@ -494,11 +484,6 @@
"type": "text",
"placeholders": {}
},
"friday": "П'ятниця",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "З моменту приєднання",
"@fromJoining": {
"type": "text",
@ -624,11 +609,6 @@
"username": {}
}
},
"keysCached": "Ключі кешовано",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} вилучає {targetName}",
"@kicked": {
"type": "text",
@ -731,11 +711,6 @@
"type": "text",
"placeholders": {}
},
"monday": "Понеділок",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "Вимкнути сповіщення",
"@muteChat": {
"type": "text",
@ -934,11 +909,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "Субота",
"@saturday": {
"type": "text",
"placeholders": {}
},
"seenByUser": "Переглянуто {username}",
"@seenByUser": {
"type": "text",
@ -1066,11 +1036,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "Неділя",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "Системна",
"@systemTheme": {
"type": "text",
@ -1086,16 +1051,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "Цю кімнату було заархівовано.",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "Четвер",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1107,11 +1062,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "Вівторок",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unbannedUser": "{username} розблоковує {targetName}",
"@unbannedUser": {
"type": "text",
@ -1255,11 +1205,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "Середа",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"whoIsAllowedToJoinThisGroup": "Кому дозволено приєднуватися до цієї групи",
"@whoIsAllowedToJoinThisGroup": {
"type": "text",
@ -1494,8 +1439,6 @@
},
"shareYourInviteLink": "Поділіться своїм посиланням запрошення",
"@shareYourInviteLink": {},
"typeInInviteLinkManually": "Введіть посилання запрошення власноруч...",
"@typeInInviteLinkManually": {},
"scanQrCode": "Сканувати QR-код",
"@scanQrCode": {},
"noPasswordRecoveryDescription": "Ви ще не додали спосіб відновлення пароля.",
@ -1851,8 +1794,6 @@
"type": "text",
"description": "Usage hint for the command /html"
},
"yourUserId": "Ваш ID користувача:",
"@yourUserId": {},
"commandHint_invite": "Запросіть цього користувача до цієї кімнати",
"@commandHint_invite": {
"type": "text",
@ -1990,11 +1931,6 @@
"senderName": {}
}
},
"discover": "Огляд",
"@discover": {
"type": "text",
"placeholders": {}
},
"cantOpenUri": "Не вдалося відкрити URI {uri}",
"@cantOpenUri": {
"type": "text",
@ -2384,8 +2320,6 @@
"@recoveryKey": {},
"recoveryKeyLost": "Ключ відновлення втрачено?",
"@recoveryKeyLost": {},
"enableAutoBackups": "Увімкнути автоматичне резервне копіювання",
"@enableAutoBackups": {},
"users": "Користувачі",
"@users": {},
"stories": "Історії",
@ -2412,8 +2346,6 @@
"@dehydrate": {},
"dehydrateWarning": "Цю дію не можна скасувати. Переконайтеся, що ви безпечно зберігаєте файл резервної копії.",
"@dehydrateWarning": {},
"dehydrateShare": "Це ваш приватний експорт FluffyChat. Переконайтеся, що ви не втратите його та зберігайте його приватно.",
"@dehydrateShare": {},
"dehydrateTor": "Користувачі TOR: експорт сеансу",
"@dehydrateTor": {},
"dehydrateTorLong": "Для користувачів TOR рекомендується експортувати сеанс перед закриттям вікна.",
@ -2532,8 +2464,6 @@
"@sorryThatsNotPossible": {},
"deviceKeys": "Ключі пристрою:",
"@deviceKeys": {},
"noSearchResult": "Немає відповідних результатів пошуку.",
"@noSearchResult": {},
"letsStart": "Розпочнімо",
"@letsStart": {},
"enterInviteLinkOrMatrixId": "Введіть запрошувальне посилання або Matrix ID...",
@ -2560,5 +2490,25 @@
"jump": "Перейти",
"@jump": {},
"openLinkInBrowser": "Відкрити посилання у браузері",
"@openLinkInBrowser": {}
"@openLinkInBrowser": {},
"allRooms": "Усі групові бесіди",
"@allRooms": {
"type": "text",
"placeholders": {}
},
"reportErrorDescription": "О, ні. Щось пішло не так. Повторіть спробу пізніше. Якщо хочете, можете повідомити про помилку розробникам.",
"@reportErrorDescription": {},
"report": "повідомити",
"@report": {},
"discover": "Огляд",
"@discover": {
"type": "text",
"placeholders": {}
},
"pleaseTryAgainLaterOrChooseDifferentServer": "Спробуйте пізніше або виберіть інший сервер.",
"@pleaseTryAgainLaterOrChooseDifferentServer": {},
"signInWithPassword": "Увійти за допомогою пароля",
"@signInWithPassword": {},
"continueWith": "Продовжити за допомогою:",
"@continueWith": {}
}

View File

@ -61,11 +61,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "Phòng hội thảo đã lưu trữ",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Khách vãng lai có được tham gia không",
"@areGuestsAllowedToJoin": {
"type": "text",

View File

@ -77,11 +77,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "已存档的聊天室",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "是否允许游客加入",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -522,11 +517,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "交叉签名已启用",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "目前活跃",
"@currentlyActive": {
"type": "text",
@ -612,11 +602,6 @@
"type": "text",
"placeholders": {}
},
"discover": "探索",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "显示名称已被改变",
"@displaynameHasBeenChanged": {
"type": "text",
@ -774,11 +759,6 @@
"type": "text",
"placeholders": {}
},
"friday": "星期五",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "自加入起",
"@fromJoining": {
"type": "text",
@ -969,11 +949,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "密钥已被缓存",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} 踢了 {targetName}",
"@kicked": {
"type": "text",
@ -1098,11 +1073,6 @@
"type": "text",
"placeholders": {}
},
"monday": "星期一",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "将该聊天静音",
"@muteChat": {
"type": "text",
@ -1478,11 +1448,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "星期六",
"@saturday": {
"type": "text",
"placeholders": {}
},
"saveFile": "保存文件",
"@saveFile": {
"type": "text",
@ -1706,11 +1671,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "星期日",
"@sunday": {
"type": "text",
"placeholders": {}
},
"synchronizingPleaseWait": "同步中…请等待。",
"@synchronizingPleaseWait": {
"type": "text",
@ -1731,16 +1691,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "该聊天室已被归档。",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "星期四",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1777,11 +1727,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "星期二",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "不可用",
"@unavailable": {
"type": "text",
@ -1952,11 +1897,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "星期三",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "我们向您发送了一封电子邮件",
"@weSentYouAnEmail": {
"type": "text",
@ -2132,12 +2072,8 @@
"@pleaseEnterValidEmail": {},
"repeatPassword": "再次输入密码",
"@repeatPassword": {},
"yourUserId": "您的 ID",
"@yourUserId": {},
"shareYourInviteLink": "分享您的邀请链接",
"@shareYourInviteLink": {},
"typeInInviteLinkManually": "手动输入邀请链接…",
"@typeInInviteLinkManually": {},
"addAccount": "添加账户",
"@addAccount": {},
"editBundlesForAccount": "编辑该账户的集合",
@ -2388,8 +2324,6 @@
"@storeInAndroidKeystore": {},
"storeSecurlyOnThisDevice": "安全地存储在此设备上",
"@storeSecurlyOnThisDevice": {},
"enableAutoBackups": "启用自动备份",
"@enableAutoBackups": {},
"users": "用户",
"@users": {},
"stories": "故事",
@ -2400,8 +2334,6 @@
"count": {}
}
},
"dehydrateShare": "这是私人的 FluffyChat 导出。 确保你不会丢失它并将其保密。",
"@dehydrateShare": {},
"dehydrateTor": "TOR 用户:导出会话",
"@dehydrateTor": {},
"dehydrateTorLong": "建议 TOR 用户在关闭窗口之前导出会话。",
@ -2531,5 +2463,12 @@
"sorryThatsNotPossible": "非常抱歉……这是做不到的",
"@sorryThatsNotPossible": {},
"deviceKeys": "设备密钥:",
"@deviceKeys": {}
"@deviceKeys": {},
"report": "举报",
"@report": {},
"discover": "探索",
"@discover": {
"type": "text",
"placeholders": {}
}
}

View File

@ -76,11 +76,6 @@
"type": "text",
"placeholders": {}
},
"archivedRoom": "已封存的對話",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "是否允許訪客加入",
"@areGuestsAllowedToJoin": {
"type": "text",
@ -427,11 +422,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "第三方登入已啟用",
"@crossSigningEnabled": {
"type": "text",
"placeholders": {}
},
"currentlyActive": "目前活躍",
"@currentlyActive": {
"type": "text",
@ -517,11 +507,6 @@
"type": "text",
"placeholders": {}
},
"discover": "探索",
"@discover": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "顯示名稱已被變更",
"@displaynameHasBeenChanged": {
"type": "text",
@ -674,11 +659,6 @@
"type": "text",
"placeholders": {}
},
"friday": "星期五",
"@friday": {
"type": "text",
"placeholders": {}
},
"fromJoining": "自加入起",
"@fromJoining": {
"type": "text",
@ -864,11 +844,6 @@
"type": "text",
"placeholders": {}
},
"keysCached": "金鑰已被快取",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"kicked": "{username}踢了{targetName}",
"@kicked": {
"type": "text",
@ -986,11 +961,6 @@
"type": "text",
"placeholders": {}
},
"monday": "星期一",
"@monday": {
"type": "text",
"placeholders": {}
},
"muteChat": "將該聊天室靜音",
"@muteChat": {
"type": "text",
@ -1326,11 +1296,6 @@
"type": "text",
"placeholders": {}
},
"saturday": "星期六",
"@saturday": {
"type": "text",
"placeholders": {}
},
"search": "搜尋",
"@search": {
"type": "text",
@ -1530,11 +1495,6 @@
"type": "text",
"placeholders": {}
},
"sunday": "星期日",
"@sunday": {
"type": "text",
"placeholders": {}
},
"systemTheme": "自動",
"@systemTheme": {
"type": "text",
@ -1550,16 +1510,6 @@
"type": "text",
"placeholders": {}
},
"thisRoomHasBeenArchived": "這個聊天室已被封存。",
"@thisRoomHasBeenArchived": {
"type": "text",
"placeholders": {}
},
"thursday": "星期四",
"@thursday": {
"type": "text",
"placeholders": {}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1596,11 +1546,6 @@
"type": "text",
"placeholders": {}
},
"tuesday": "星期二",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"unavailable": "無法取得",
"@unavailable": {
"type": "text",
@ -1771,11 +1716,6 @@
"type": "text",
"placeholders": {}
},
"wednesday": "星期三",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "我們向您傳送了一封電子郵件",
"@weSentYouAnEmail": {
"type": "text",
@ -1972,8 +1912,6 @@
"type": "text",
"placeholders": {}
},
"yourUserId": "您的ID",
"@yourUserId": {},
"chatHasBeenAddedToThisSpace": "聊天室已添加到此空間",
"@chatHasBeenAddedToThisSpace": {},
"clearArchive": "清除存檔",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@ -55,7 +55,7 @@
<div class="flex mb-8 justify-center content-center">
<a rel="me"
class="inline-block text-indigo-500 no-underline hover:text-indigo-900 hover:scale-105 transition-all text-center h-auto p-4"
rel="me" href="https://metalhead.club/@krille">
rel="me" href="https://mastodon.art/@krille">
<svg class="fill-current h-6" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
@ -116,4 +116,4 @@
</body>
</html>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -291,6 +291,7 @@
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (

View File

@ -33,6 +33,11 @@ abstract class AppConfig {
static const String sourceCodeUrl = 'https://gitlab.com/famedly/fluffychat';
static const String supportUrl =
'https://gitlab.com/famedly/fluffychat/issues';
static final Uri newIssueUrl = Uri(
scheme: 'https',
host: 'gitlab.com',
path: '/famedly/fluffychat/-/issues/new',
);
static const bool enableSentry = true;
static const String sentryDns =
'https://8591d0d863b646feb4f3dda7e5dcab38@o256755.ingest.sentry.io/5243143';

View File

@ -9,7 +9,6 @@ import 'package:fluffychat/pages/chat_details/chat_details.dart';
import 'package:fluffychat/pages/chat_encryption_settings/chat_encryption_settings.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/chat_permissions_settings/chat_permissions_settings.dart';
import 'package:fluffychat/pages/connect/connect_page.dart';
import 'package:fluffychat/pages/device_settings/device_settings.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
import 'package:fluffychat/pages/invitation_selection/invitation_selection.dart';
@ -27,7 +26,6 @@ import 'package:fluffychat/pages/settings_notifications/settings_notifications.d
import 'package:fluffychat/pages/settings_security/settings_security.dart';
import 'package:fluffychat/pages/settings_stories/settings_stories.dart';
import 'package:fluffychat/pages/settings_style/settings_style.dart';
import 'package:fluffychat/pages/sign_up/signup.dart';
import 'package:fluffychat/pages/story/story_page.dart';
import 'package:fluffychat/widgets/layouts/empty_page.dart';
import 'package:fluffychat/widgets/layouts/loading_view.dart';
@ -266,23 +264,6 @@ class AppRoutes {
widget: const Login(),
buildTransition: _fadeTransition,
),
VWidget(
path: 'connect',
widget: const ConnectPage(),
buildTransition: _fadeTransition,
stackedRoutes: [
VWidget(
path: 'login',
widget: const Login(),
buildTransition: _fadeTransition,
),
VWidget(
path: 'signup',
widget: const SignupPage(),
buildTransition: _fadeTransition,
),
],
),
VWidget(
path: 'logs',
widget: const LogViewer(),
@ -358,23 +339,6 @@ class AppRoutes {
widget: const Login(),
buildTransition: _fadeTransition,
),
VWidget(
path: 'connect',
widget: const ConnectPage(),
buildTransition: _fadeTransition,
stackedRoutes: [
VWidget(
path: 'login',
widget: const Login(),
buildTransition: _fadeTransition,
),
VWidget(
path: 'signup',
widget: const SignupPage(),
buildTransition: _fadeTransition,
),
],
),
],
),
VWidget(

View File

@ -41,6 +41,22 @@ abstract class FluffyThemes {
titleSmall: fallbackTextStyle,
);
static LinearGradient backgroundGradient(
BuildContext context,
int alpha,
) {
final colorScheme = Theme.of(context).colorScheme;
return LinearGradient(
begin: Alignment.topCenter,
colors: [
colorScheme.primaryContainer.withAlpha(alpha),
colorScheme.secondaryContainer.withAlpha(alpha),
colorScheme.tertiaryContainer.withAlpha(alpha),
colorScheme.primaryContainer.withAlpha(alpha),
],
);
}
static const Duration animationDuration = Duration(milliseconds: 250);
static const Curve animationCurve = Curves.easeInOut;

View File

@ -23,6 +23,7 @@ import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat/event_info_dialog.dart';
import 'package:fluffychat/pages/chat/recording_dialog.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/error_reporter.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/ios_badge_client_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
@ -76,7 +77,7 @@ class ChatPageWithRoom extends StatefulWidget {
}
class ChatController extends State<ChatPageWithRoom> {
Room get room => widget.room;
Room get room => sendingClient.getRoomById(roomId) ?? widget.room;
late Client sendingClient;
@ -151,7 +152,10 @@ class ChatController extends State<ChatPageWithRoom> {
Event? editEvent;
bool showScrollDownButton = false;
bool _scrolledUp = false;
bool get showScrollDownButton =>
_scrolledUp || timeline?.allowNewEvent == false;
bool get selectMode => selectedEvents.isNotEmpty;
@ -200,6 +204,7 @@ class ChatController extends State<ChatPageWithRoom> {
void requestHistory() async {
if (!timeline!.canRequestHistory) return;
Logs().v('Requesting history...');
try {
await timeline!.requestHistory(historyCount: _loadHistoryCount);
} catch (err) {
@ -218,6 +223,7 @@ class ChatController extends State<ChatPageWithRoom> {
final timeline = this.timeline;
if (timeline == null) return;
if (!timeline.canRequestFuture) return;
Logs().v('Requesting future...');
try {
final mostRecentEventId = timeline.events.first.eventId;
await timeline.requestFuture(historyCount: _loadHistoryCount);
@ -240,18 +246,11 @@ class ChatController extends State<ChatPageWithRoom> {
}
setReadMarker();
if (!scrollController.hasClients) return;
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
requestHistory();
} else if (scrollController.position.pixels == 0) {
requestFuture();
}
if (timeline?.allowNewEvent == false ||
scrollController.position.pixels > 0 && showScrollDownButton == false) {
setState(() => showScrollDownButton = true);
} else if (scrollController.position.pixels == 0 &&
showScrollDownButton == true) {
setState(() => showScrollDownButton = false);
scrollController.position.pixels > 0 && _scrolledUp == false) {
setState(() => _scrolledUp = true);
} else if (scrollController.position.pixels == 0 && _scrolledUp == true) {
setState(() => _scrolledUp = false);
}
}
@ -272,7 +271,10 @@ class ChatController extends State<ChatPageWithRoom> {
super.initState();
sendingClient = Matrix.of(context).client;
readMarkerEventId = room.fullyRead;
loadTimelineFuture = _getTimeline();
loadTimelineFuture =
_getTimeline(eventContextId: readMarkerEventId).onError(
ErrorReporter(context, 'Unable to load timeline').onErrorCallback,
);
}
void updateView() {
@ -284,12 +286,12 @@ class ChatController extends State<ChatPageWithRoom> {
Future<void> _getTimeline({
String? eventContextId,
Duration timeout = const Duration(seconds: 5),
Duration timeout = const Duration(seconds: 7),
}) async {
await Matrix.of(context).client.roomsLoading;
await Matrix.of(context).client.accountDataLoading;
eventContextId ??= room.fullyRead;
if (!eventContextId.isValidMatrixId || eventContextId.sigil != '\$') {
if (eventContextId != null &&
(!eventContextId.isValidMatrixId || eventContextId.sigil != '\$')) {
eventContextId = null;
}
try {
@ -299,19 +301,22 @@ class ChatController extends State<ChatPageWithRoom> {
eventContextId: eventContextId,
)
.timeout(timeout);
} on TimeoutException catch (_) {
} catch (e, s) {
Logs().w('Unable to load timeline on event ID $eventContextId', e, s);
if (!mounted) return;
timeline = await room.getTimeline(onUpdate: updateView);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.jumpToLastReadMessage),
action: SnackBarAction(
label: L10n.of(context)!.jump,
onPressed: () => scrollToEventId(eventContextId!),
if (e is TimeoutException || e is IOException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.jumpToLastReadMessage),
action: SnackBarAction(
label: L10n.of(context)!.jump,
onPressed: () => scrollToEventId(eventContextId!),
),
),
),
);
);
}
}
timeline!.requestKeys(onlineKeyBackupOnly: false);
if (timeline!.events.isNotEmpty) {
@ -351,7 +356,7 @@ class ChatController extends State<ChatPageWithRoom> {
eventId ??= timeline.events.first.eventId;
Logs().v('Set read marker...', eventId);
// ignore: unawaited_futures
_setReadMarkerFuture = timeline.setReadMarker(eventId).then((_) {
_setReadMarkerFuture = timeline.setReadMarker(eventId: eventId).then((_) {
_setReadMarkerFuture = null;
});
room.client.updateIosBadge();
@ -368,7 +373,7 @@ class ChatController extends State<ChatPageWithRoom> {
TextEditingController sendController = TextEditingController();
void setSendingClient(Client c) {
// first cancle typing with the old sending client
// first cancel typing with the old sending client
if (currentlyTyping) {
// no need to have the setting typing to false be blocking
typingCoolDown?.cancel();
@ -376,6 +381,15 @@ class ChatController extends State<ChatPageWithRoom> {
room.setTyping(false);
currentlyTyping = false;
}
// then cancel the old timeline
// fixes bug with read reciepts and quick switching
loadTimelineFuture = _getTimeline(eventContextId: room.fullyRead).onError(
ErrorReporter(
context,
'Unable to load timeline after changing sending Client',
).onErrorCallback,
);
// then set the new sending client
setState(() => sendingClient = c);
}
@ -393,7 +407,7 @@ class ChatController extends State<ChatPageWithRoom> {
final commandMatch = RegExp(r'^\/(\w+)').firstMatch(sendController.text);
if (commandMatch != null &&
!room.client.commands.keys.contains(commandMatch[1]!.toLowerCase())) {
!sendingClient.commands.keys.contains(commandMatch[1]!.toLowerCase())) {
final l10n = L10n.of(context)!;
final dialogResult = await showOkCancelAlertDialog(
context: context,
@ -801,9 +815,13 @@ class ChatController extends State<ChatPageWithRoom> {
if (eventIndex == -1) {
setState(() {
timeline = null;
_scrolledUp = false;
loadTimelineFuture = _getTimeline(
eventContextId: eventId,
timeout: const Duration(seconds: 30),
).onError(
ErrorReporter(context, 'Unable to load timeline after scroll to ID')
.onErrorCallback,
);
});
await loadTimelineFuture;
@ -823,7 +841,11 @@ class ChatController extends State<ChatPageWithRoom> {
if (!timeline!.allowNewEvent) {
setState(() {
timeline = null;
loadTimelineFuture = _getTimeline();
_scrolledUp = false;
loadTimelineFuture = _getTimeline().onError(
ErrorReporter(context, 'Unable to load timeline after scroll down')
.onErrorCallback,
);
});
await loadTimelineFuture;
setReadMarker(eventId: timeline!.events.first.eventId);
@ -847,8 +869,11 @@ class ChatController extends State<ChatPageWithRoom> {
setState(() => showEmojiPicker = false);
if (emoji == null) return;
// make sure we don't send the same emoji twice
if (_allReactionEvents
.any((e) => e.content['m.relates_to']['key'] == emoji.emoji)) return;
if (_allReactionEvents.any(
(e) => e.content.tryGetMap('m.relates_to')?['key'] == emoji.emoji,
)) {
return;
}
return sendEmojiAction(emoji.emoji);
}

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
@ -54,14 +53,18 @@ class ChatEventList extends StatelessWidget {
);
}
if (controller.timeline!.canRequestFuture) {
Center(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
),
onPressed: controller.requestFuture,
child: Text(L10n.of(context)!.loadMore),
),
return Builder(
builder: (context) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => controller.requestFuture(),
);
return Center(
child: IconButton(
onPressed: controller.requestFuture,
icon: const Icon(Icons.refresh_outlined),
),
);
},
);
}
return Column(
@ -81,14 +84,18 @@ class ChatEventList extends StatelessWidget {
);
}
if (controller.timeline!.canRequestHistory) {
Center(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
),
onPressed: controller.requestHistory,
child: Text(L10n.of(context)!.loadMore),
),
return Builder(
builder: (context) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => controller.requestHistory(),
);
return Center(
child: IconButton(
onPressed: controller.requestHistory,
icon: const Icon(Icons.refresh_outlined),
),
);
},
);
}
return const SizedBox.shrink();

View File

@ -146,7 +146,6 @@ class ChatView extends StatelessWidget {
);
}
final bottomSheetPadding = FluffyThemes.isColumnMode(context) ? 16.0 : 8.0;
final colorScheme = Theme.of(context).colorScheme;
return VWidgetGuard(
onSystemPop: (redirector) async {
@ -197,6 +196,7 @@ class ChatView extends StatelessWidget {
padding: const EdgeInsets.only(bottom: 56.0),
child: FloatingActionButton(
onPressed: controller.scrollDown,
heroTag: null,
mini: true,
child: const Icon(Icons.arrow_downward_outlined),
),
@ -219,14 +219,9 @@ class ChatView extends StatelessWidget {
else
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
colors: [
colorScheme.primaryContainer.withAlpha(64),
colorScheme.secondaryContainer.withAlpha(64),
colorScheme.tertiaryContainer.withAlpha(64),
colorScheme.primaryContainer.withAlpha(64),
],
gradient: FluffyThemes.backgroundGradient(
context,
64,
),
),
),

View File

@ -20,7 +20,9 @@ class EncryptionButton extends StatelessWidget {
.where((s) => s.deviceLists != null),
builder: (context, snapshot) {
return FutureBuilder<EncryptionHealthState>(
future: room.calcEncryptionHealthState(),
future: room.encrypted
? room.calcEncryptionHealthState()
: Future.value(EncryptionHealthState.allVerified),
builder: (BuildContext context, snapshot) => IconButton(
tooltip: room.encrypted
? L10n.of(context)!.encrypted

View File

@ -4,12 +4,12 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:just_audio/just_audio.dart';
import 'package:matrix/matrix.dart';
import 'package:path_provider/path_provider.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/error_reporter.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import '../../../utils/matrix_sdk_extensions/event_extension.dart';
@ -132,14 +132,10 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
} else {
await audioPlayer.setAudioSource(MatrixFileAudioSource(matrixFile!));
}
audioPlayer.play().catchError((e, s) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(L10n.of(context)!.oopsSomethingWentWrong),
),
);
Logs().w('Error while playing audio', e, s);
});
audioPlayer.play().onError(
ErrorReporter(context, 'Unable to play audio message')
.onErrorCallback,
);
}
static const double buttonSize = 36;

View File

@ -36,19 +36,16 @@ class _CuteContentState extends State<CuteContent> {
return GestureDetector(
onTap: addOverlay,
child: SizedBox.square(
dimension: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
widget.event.text,
style: const TextStyle(fontSize: 150),
),
if (label != null) Text(label)
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
widget.event.text,
style: const TextStyle(fontSize: 150),
),
if (label != null) Text(label)
],
),
);
},
@ -144,24 +141,26 @@ class _CuteEventOverlayState extends State<CuteEventOverlay>
return SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth,
child: Stack(
alignment: Alignment.bottomLeft,
fit: StackFit.expand,
children: items
.map(
(position) => Positioned(
left: position.width * width,
bottom: (height *
.25 *
position.height *
(controller?.value ?? 0)) -
_CuteOverlayContent.size,
child: _CuteOverlayContent(
emoji: widget.emoji,
child: OverflowBox(
child: Stack(
alignment: Alignment.bottomLeft,
fit: StackFit.expand,
children: items
.map(
(position) => Positioned(
left: position.width * width,
bottom: (height *
.25 *
position.height *
(controller?.value ?? 0)) -
_CuteOverlayContent.size,
child: _CuteOverlayContent(
emoji: widget.emoji,
),
),
),
)
.toList(),
)
.toList(),
),
),
);
},

View File

@ -1,31 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_matrix_html/flutter_html.dart';
import 'package:collection/collection.dart';
import 'package:flutter_highlighter/flutter_highlighter.dart';
import 'package:flutter_highlighter/themes/shades-of-purple.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_table/flutter_html_table.dart';
import 'package:flutter_math_fork/flutter_math.dart';
import 'package:linkify/linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../../config/app_config.dart';
import '../../../config/setting_keys.dart';
import '../../../utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
import '../../../utils/url_launcher.dart';
class HtmlMessage extends StatelessWidget {
final String html;
final int? maxLines;
final Room room;
final TextStyle? defaultTextStyle;
final TextStyle? linkStyle;
final double? emoteSize;
final Color textColor;
const HtmlMessage({
Key? key,
required this.html,
this.maxLines,
required this.room,
this.defaultTextStyle,
this.linkStyle,
this.emoteSize,
this.textColor = Colors.black,
}) : super(key: key);
@override
@ -46,101 +44,461 @@ class HtmlMessage extends StatelessWidget {
'',
);
// there is no need to pre-validate the html, as we validate it while rendering
final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor;
final matrix = Matrix.of(context);
final themeData = Theme.of(context);
return Html(
data: renderHtml,
defaultTextStyle: defaultTextStyle,
emoteSize: emoteSize,
linkStyle: linkStyle ??
themeData.textTheme.bodyMedium!.copyWith(
color: themeData.colorScheme.secondary,
decoration: TextDecoration.underline,
decorationColor: themeData.colorScheme.secondary,
),
shrinkToFit: true,
maxLines: maxLines,
onLinkTap: (url) => UrlLauncher(context, url).launchUrl(),
onPillTap: (url) => UrlLauncher(context, url).launchUrl(),
getMxcUrl: (
String mxc,
double? width,
double? height, {
bool? animated = false,
}) {
final ratio = MediaQuery.of(context).devicePixelRatio;
return Uri.parse(mxc)
.getThumbnail(
matrix.client,
width: (width ?? 800) * ratio,
height: (height ?? 800) * ratio,
method: ThumbnailMethod.scale,
animated: AppConfig.autoplayImages ? animated : false,
)
.toString();
},
onImageTap: (url) => UrlLauncher(context, url).launchUrl(),
setCodeLanguage: (String key, String value) async {
await matrix.store.setItem('${SettingKeys.codeLanguage}.$key', value);
},
getCodeLanguage: (String key) async {
return await matrix.store.getItem('${SettingKeys.codeLanguage}.$key');
},
getPillInfo: (String url) async {
final identityParts = url.parseIdentifierIntoParts();
final identifier = identityParts?.primaryIdentifier;
if (identifier == null) {
return {};
}
if (identifier.sigil == '@') {
// we have a user pill
final user = room.getState('m.room.member', identifier);
if (user != null) {
return user.content;
}
// there might still be a profile...
final profile = await room.client.getProfileFromUserId(identifier);
return {
'displayname': profile.displayName,
'avatar_url': profile.avatarUrl.toString(),
};
}
if (identifier.sigil == '#') {
// we have an alias pill
for (final r in room.client.rooms) {
final state = r.getState('m.room.canonical_alias');
if (state != null &&
((state.content['alias'] is String &&
state.content['alias'] == identifier) ||
(state.content['alt_aliases'] is List &&
state.content['alt_aliases'].contains(identifier)))) {
// we have a room!
return {
'displayname':
r.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)),
'avatar_url': r.getState('m.room.avatar')?.content['url'],
};
final linkifiedRenderHtml = linkify(
renderHtml,
options: const LinkifyOptions(humanize: false),
)
.map(
(element) {
if (element is! UrlElement ||
element.text.contains('<') ||
element.text.contains('>') ||
element.text.contains('"')) {
return element.text;
}
}
return {};
}
if (identifier.sigil == '!') {
// we have a room ID pill
final r = room.client.getRoomById(identifier);
if (r == null) {
return {};
}
return {
'displayname':
r.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)),
'avatar_url': r.getState('m.room.avatar')?.content['url'],
};
}
return {};
return '<a href="${element.url}">${element.text}</a>';
},
)
.join('')
.replaceAll('\n', '');
final linkColor = textColor.withAlpha(150);
// there is no need to pre-validate the html, as we validate it while rendering
return Html(
data: linkifiedRenderHtml,
style: {
'*': Style(
color: textColor,
margin: Margins.all(0),
fontSize: FontSize(fontSize),
),
'a': Style(color: linkColor, textDecorationColor: linkColor),
'h1': Style(
fontSize: FontSize(fontSize * 2),
lineHeight: LineHeight.number(1.5),
fontWeight: FontWeight.w600,
),
'h2': Style(
fontSize: FontSize(fontSize * 1.75),
lineHeight: LineHeight.number(1.5),
fontWeight: FontWeight.w500,
),
'h3': Style(
fontSize: FontSize(fontSize * 1.5),
lineHeight: LineHeight.number(1.5),
),
'h4': Style(
fontSize: FontSize(fontSize * 1.25),
lineHeight: LineHeight.number(1.5),
),
'h5': Style(
fontSize: FontSize(fontSize * 1.25),
lineHeight: LineHeight.number(1.5),
),
'h6': Style(
fontSize: FontSize(fontSize),
lineHeight: LineHeight.number(1.5),
),
'blockquote': Style(
border: Border(
left: BorderSide(
width: 3,
color: textColor,
),
),
padding: HtmlPaddings.only(left: 6, bottom: 0),
),
'hr': Style(
border: Border.all(color: textColor, width: 0.5),
),
'table': Style(
border: Border.all(color: textColor, width: 0.5),
),
'tr': Style(
border: Border.all(color: textColor, width: 0.5),
),
'td': Style(
border: Border.all(color: textColor, width: 0.5),
padding: HtmlPaddings.all(2),
),
'th': Style(
border: Border.all(color: textColor, width: 0.5),
),
},
extensions: [
RoomPillExtension(context, room),
CodeExtension(fontSize: fontSize),
MatrixMathExtension(
style: TextStyle(fontSize: fontSize, color: textColor),
),
const TableHtmlExtension(),
SpoilerExtension(textColor: textColor),
const ImageExtension(),
FontColorExtension(),
],
onLinkTap: (url, _, __) => UrlLauncher(context, url).launchUrl(),
onlyRenderTheseTags: const {
...allowedHtmlTags,
// Needed to make it work properly
'body',
'html',
},
shrinkWrap: true,
);
}
/// Keep in sync with: https://spec.matrix.org/v1.6/client-server-api/#mroommessage-msgtypes
static const Set<String> allowedHtmlTags = {
'font',
'del',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'blockquote',
'p',
'a',
'ul',
'ol',
'sup',
'sub',
'li',
'b',
'i',
'u',
'strong',
'em',
'strike',
'code',
'hr',
'br',
'div',
'table',
'thead',
'tbody',
'tr',
'th',
'td',
'caption',
'pre',
'span',
'img',
'details',
'summary',
// Not in the allowlist of the matrix spec yet but should be harmless:
'ruby',
'rp',
'rt',
};
}
class FontColorExtension extends HtmlExtension {
static const String colorAttribute = 'color';
static const String mxColorAttribute = 'data-mx-color';
static const String bgColorAttribute = 'data-mx-bg-color';
@override
Set<String> get supportedTags => {'font', 'span'};
@override
bool matches(ExtensionContext context) {
if (!supportedTags.contains(context.elementName)) return false;
return context.element?.attributes.keys.any(
{
colorAttribute,
mxColorAttribute,
bgColorAttribute,
}.contains,
) ??
false;
}
Color? hexToColor(String? hexCode) {
if (hexCode == null) return null;
if (hexCode.startsWith('#')) hexCode = hexCode.substring(1);
if (hexCode.length == 6) hexCode = 'FF$hexCode';
final colorValue = int.tryParse(hexCode, radix: 16);
return colorValue == null ? null : Color(colorValue);
}
@override
InlineSpan build(
ExtensionContext context,
) {
final colorText = context.element?.attributes[colorAttribute] ??
context.element?.attributes[mxColorAttribute];
final bgColor = context.element?.attributes[bgColorAttribute];
return TextSpan(
style: TextStyle(
color: hexToColor(colorText),
backgroundColor: hexToColor(bgColor),
),
text: context.innerHtml,
);
}
}
class ImageExtension extends HtmlExtension {
final double defaultDimension;
const ImageExtension({this.defaultDimension = 64});
@override
Set<String> get supportedTags => {'img'};
@override
InlineSpan build(ExtensionContext context) {
final mxcUrl = Uri.tryParse(context.attributes['src'] ?? '');
if (mxcUrl == null || mxcUrl.scheme != 'mxc') {
return TextSpan(text: context.attributes['alt']);
}
final width = double.tryParse(context.attributes['width'] ?? '');
final height = double.tryParse(context.attributes['height'] ?? '');
return WidgetSpan(
child: SizedBox(
width: width ?? height ?? defaultDimension,
height: height ?? width ?? defaultDimension,
child: MxcImage(
uri: mxcUrl,
width: width ?? height ?? defaultDimension,
height: height ?? width ?? defaultDimension,
cacheKey: mxcUrl.toString(),
),
),
);
}
}
class SpoilerExtension extends HtmlExtension {
final Color textColor;
const SpoilerExtension({required this.textColor});
@override
Set<String> get supportedTags => {'span'};
static const String customDataAttribute = 'data-mx-spoiler';
@override
bool matches(ExtensionContext context) {
if (context.elementName != 'span') return false;
return context.element?.attributes.containsKey(customDataAttribute) ??
false;
}
@override
InlineSpan build(ExtensionContext context) {
var obscure = true;
final children = context.inlineSpanChildren;
return WidgetSpan(
child: StatefulBuilder(
builder: (context, setState) {
return InkWell(
onTap: () => setState(() {
obscure = !obscure;
}),
child: RichText(
text: TextSpan(
style: obscure ? TextStyle(backgroundColor: textColor) : null,
children: children,
),
),
);
},
),
);
}
}
class MatrixMathExtension extends HtmlExtension {
final TextStyle? style;
MatrixMathExtension({this.style});
@override
Set<String> get supportedTags => {'div'};
@override
bool matches(ExtensionContext context) {
if (context.elementName != 'div') return false;
final mathData = context.element?.attributes['data-mx-maths'];
return mathData != null;
}
@override
InlineSpan build(ExtensionContext context) {
final data = context.element?.attributes['data-mx-maths'] ?? '';
return WidgetSpan(
child: Math.tex(
data,
textStyle: style,
onErrorFallback: (e) {
Logs().d('Flutter math parse error', e);
return Text(
data,
style: style,
);
},
),
);
}
}
class CodeExtension extends HtmlExtension {
final double fontSize;
CodeExtension({required this.fontSize});
@override
Set<String> get supportedTags => {'code'};
@override
InlineSpan build(ExtensionContext context) => WidgetSpan(
child: Material(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.circular(4),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: HighlightView(
context.element?.text ?? '',
language: context.element?.className
.split(' ')
.singleWhereOrNull(
(className) => className.startsWith('language-'),
)
?.split('language-')
.last ??
'md',
theme: shadesOfPurpleTheme,
padding: EdgeInsets.symmetric(
horizontal: 6,
vertical: context.element?.parent?.localName == 'pre' ? 6 : 0,
),
textStyle: TextStyle(fontSize: fontSize),
),
),
),
);
}
class RoomPillExtension extends HtmlExtension {
final Room room;
final BuildContext context;
RoomPillExtension(this.context, this.room);
@override
Set<String> get supportedTags => {'a'};
@override
bool matches(ExtensionContext context) {
if (context.elementName != 'a') return false;
final userId = context.element?.attributes['href']
?.parseIdentifierIntoParts()
?.primaryIdentifier;
return userId != null;
}
static final _cachedUsers = <String, User?>{};
Future<User?> _fetchUser(String matrixId) async =>
_cachedUsers[room.id + matrixId] ??= await room.requestUser(matrixId);
@override
InlineSpan build(ExtensionContext context) {
final href = context.element?.attributes['href'];
final matrixId = href?.parseIdentifierIntoParts()?.primaryIdentifier;
if (href == null || matrixId == null) {
return TextSpan(text: context.innerHtml);
}
if (matrixId.sigil == '@') {
return WidgetSpan(
child: FutureBuilder<User?>(
future: _fetchUser(matrixId),
builder: (context, snapshot) => MatrixPill(
key: Key('user_pill_$matrixId'),
name: _cachedUsers[room.id + matrixId]?.calcDisplayname() ??
matrixId.localpart ??
matrixId,
avatar: _cachedUsers[room.id + matrixId]?.avatarUrl,
uri: href,
outerContext: this.context,
),
),
);
}
if (matrixId.sigil == '#' || matrixId.sigil == '!') {
final room = matrixId.sigil == '!'
? this.room.client.getRoomById(matrixId)
: this.room.client.getRoomByAlias(matrixId);
if (room != null) {
return WidgetSpan(
child: MatrixPill(
name: room.getLocalizedDisplayname(),
avatar: room.avatar,
uri: href,
outerContext: this.context,
),
);
}
}
return TextSpan(text: context.innerHtml);
}
}
class MatrixPill extends StatelessWidget {
final String name;
final BuildContext outerContext;
final Uri? avatar;
final String uri;
const MatrixPill({
super.key,
required this.name,
required this.outerContext,
this.avatar,
required this.uri,
});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: UrlLauncher(outerContext, uri).launchUrl,
child: Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
side: BorderSide(
color: Theme.of(outerContext).colorScheme.onPrimaryContainer,
width: 0.5,
),
),
color: Theme.of(outerContext).colorScheme.primaryContainer,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Avatar(
mxContent: avatar,
name: name,
size: 16,
),
const SizedBox(width: 6),
Text(
name,
style: TextStyle(
color: Theme.of(outerContext).colorScheme.onPrimaryContainer,
),
),
],
),
),
),
);
}
}

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix_link_text/link_text.dart';
import 'package:fluffychat/pages/chat/events/video_player.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
@ -150,23 +150,10 @@ class MessageContent extends StatelessWidget {
if (event.messageType == MessageTypes.Emote) {
html = '* $html';
}
final bigEmotes = event.onlyEmotes &&
event.numberEmotes > 0 &&
event.numberEmotes <= 10;
return HtmlMessage(
html: html,
defaultTextStyle: TextStyle(
color: textColor,
fontSize: bigEmotes ? fontSize * 3 : fontSize,
),
linkStyle: TextStyle(
color: textColor.withAlpha(150),
fontSize: bigEmotes ? fontSize * 3 : fontSize,
decoration: TextDecoration.underline,
decorationColor: textColor.withAlpha(150),
),
textColor: textColor,
room: event.room,
emoteSize: bigEmotes ? fontSize * 3 : fontSize * 1.5,
);
}
// else we fall through to the normal message rendering
@ -242,25 +229,26 @@ class MessageContent extends StatelessWidget {
hideReply: true,
),
builder: (context, snapshot) {
return LinkText(
return Linkify(
text: snapshot.data ??
event.calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),
hideReply: true,
),
textStyle: TextStyle(
style: TextStyle(
color: textColor,
fontSize: bigEmotes ? fontSize * 3 : fontSize,
decoration:
event.redacted ? TextDecoration.lineThrough : null,
),
options: const LinkifyOptions(humanize: false),
linkStyle: TextStyle(
color: textColor.withAlpha(150),
fontSize: bigEmotes ? fontSize * 3 : fontSize,
decoration: TextDecoration.underline,
decorationColor: textColor.withAlpha(150),
),
onLinkTap: (url) => UrlLauncher(context, url).launchUrl(),
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
);
},
);

View File

@ -37,14 +37,17 @@ class MessageDownloadContent extends StatelessWidget {
color: textColor,
),
const SizedBox(width: 16),
Text(
filename,
maxLines: 1,
style: TextStyle(
color: textColor,
fontWeight: FontWeight.bold,
Flexible(
child: Text(
filename,
maxLines: 1,
style: TextStyle(
color: textColor,
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.ellipsis,
),
),
)
],
),
),

View File

@ -61,7 +61,7 @@ class MessageReactions extends StatelessWidget {
final evt = allReactionEvents.firstWhereOrNull(
(e) =>
e.senderId == e.room.client.userID &&
e.content['m.relates_to']['key'] == r.key,
e.content.tryGetMap('m.relates_to')?['key'] == r.key,
);
if (evt != null) {
showFutureLoadingDialog(

View File

@ -5,7 +5,6 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import '../../../config/app_config.dart';
import 'html_message.dart';
class ReplyContent extends StatelessWidget {
final Event replyEvent;
@ -26,47 +25,23 @@ class ReplyContent extends StatelessWidget {
final displayEvent =
timeline != null ? replyEvent.getDisplayEvent(timeline) : replyEvent;
final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor;
if (AppConfig.renderHtml &&
[EventTypes.Message, EventTypes.Encrypted]
.contains(displayEvent.type) &&
[MessageTypes.Text, MessageTypes.Notice, MessageTypes.Emote]
.contains(displayEvent.messageType) &&
!displayEvent.redacted &&
displayEvent.content['format'] == 'org.matrix.custom.html' &&
displayEvent.content['formatted_body'] is String) {
String? html = displayEvent.content['formatted_body'];
if (displayEvent.messageType == MessageTypes.Emote) {
html = '* $html';
}
replyBody = HtmlMessage(
html: html!,
defaultTextStyle: TextStyle(
color: ownMessage
? Theme.of(context).colorScheme.onPrimary
: Theme.of(context).colorScheme.onBackground,
fontSize: fontSize,
),
maxLines: 1,
room: displayEvent.room,
emoteSize: fontSize * 1.5,
);
} else {
replyBody = Text(
displayEvent.calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),
withSenderNamePrefix: false,
hideReply: true,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
color: ownMessage
? Theme.of(context).colorScheme.onPrimary
: Theme.of(context).colorScheme.onBackground,
fontSize: fontSize,
),
);
}
replyBody = Text(
displayEvent.calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),
withSenderNamePrefix: false,
hideReply: true,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
color: ownMessage
? Theme.of(context).colorScheme.onPrimary
: Theme.of(context).colorScheme.onBackground,
fontSize: fontSize,
),
);
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[

View File

@ -14,6 +14,7 @@ import 'package:video_player/video_player.dart';
import 'package:fluffychat/pages/chat/events/image_bubble.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import '../../../utils/error_reporter.dart';
class EventVideoPlayer extends StatefulWidget {
final Event event;
@ -51,7 +52,8 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
final networkUri = _networkUri;
if (kIsWeb && networkUri != null && _chewieManager == null) {
_chewieManager ??= ChewieController(
videoPlayerController: VideoPlayerController.network(networkUri),
videoPlayerController:
VideoPlayerController.networkUrl(Uri.parse(networkUri)),
autoPlay: true,
autoInitialize: true,
);
@ -69,12 +71,7 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
),
);
} catch (e, s) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.toLocalizedString(context)),
),
);
Logs().w('Error while playing video', e, s);
ErrorReporter(context, 'Unable to play video').onErrorCallback(e, s);
} finally {
// Workaround for Chewie needs time to get the aspectRatio
await Future.delayed(const Duration(milliseconds: 100));

View File

@ -183,12 +183,13 @@ class InputBar extends StatelessWidget {
final state = r.getState(EventTypes.RoomCanonicalAlias);
if ((state != null &&
((state.content['alias'] is String &&
state.content['alias']
state.content
.tryGet<String>('alias')!
.split(':')[0]
.toLowerCase()
.contains(roomSearch)) ||
(state.content['alt_aliases'] is List &&
state.content['alt_aliases'].any(
(state.content['alt_aliases'] as List).any(
(l) =>
l is String &&
l
@ -263,6 +264,8 @@ class InputBar extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
MxcImage(
// ensure proper ordering ...
key: ValueKey(suggestion['name']),
uri: suggestion['mxc'] is String
? Uri.parse(suggestion['mxc'] ?? '')
: null,

View File

@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix_link_text/link_text.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat.dart';
@ -101,15 +101,16 @@ class PinnedEvents extends StatelessWidget {
hideReply: true,
),
builder: (context, snapshot) {
return LinkText(
return Linkify(
text: snapshot.data ??
event.calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),
withSenderNamePrefix: true,
hideReply: true,
),
options: const LinkifyOptions(humanize: false),
maxLines: 2,
textStyle: TextStyle(
style: TextStyle(
color:
Theme.of(context).colorScheme.onSurfaceVariant,
overflow: TextOverflow.ellipsis,
@ -126,8 +127,8 @@ class PinnedEvents extends StatelessWidget {
decorationColor:
Theme.of(context).colorScheme.onSurfaceVariant,
),
onLinkTap: (url) =>
UrlLauncher(context, url).launchUrl(),
onOpen: (url) =>
UrlLauncher(context, url.url).launchUrl(),
);
},
),

View File

@ -52,7 +52,7 @@ class ReactionsPicker extends StatelessWidget {
for (final event in allReactionEvents) {
try {
emojis.remove(event.content['m.relates_to']['key']);
emojis.remove(event.content.tryGetMap('m.relates_to')!['key']);
} catch (_) {}
}
return Row(

View File

@ -83,7 +83,9 @@ class ChatDetailsController extends State<ChatDetails> {
RequestType.GET,
'/client/unstable/org.matrix.msc2432/rooms/${Uri.encodeComponent(room.id)}/aliases',
)
.then((response) => List<String>.from(response['aliases'])),
.then(
(response) => List<String>.from(response['aliases'] as Iterable),
),
);
// Switch to the stable api once it is implemented.

View File

@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix_link_text/link_text.dart';
import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
@ -125,13 +125,14 @@ class ChatDetailsView extends StatelessWidget {
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
),
child: LinkText(
child: Linkify(
text: room.topic.isEmpty
? L10n.of(context)!.addGroupDescription
: room.topic,
options: const LinkifyOptions(humanize: false),
linkStyle:
const TextStyle(color: Colors.blueAccent),
textStyle: TextStyle(
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
@ -142,8 +143,8 @@ class ChatDetailsView extends StatelessWidget {
.bodyMedium!
.color,
),
onLinkTap: (url) =>
UrlLauncher(context, url).launchUrl(),
onOpen: (url) =>
UrlLauncher(context, url.url).launchUrl(),
),
),
const SizedBox(height: 8),

View File

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -29,7 +30,7 @@ class ChatEncryptionSettingsView extends StatelessWidget {
onPressed: () =>
VRouter.of(context).toSegments(['rooms', controller.roomId!]),
),
title: Text(L10n.of(context)!.endToEndEncryption),
title: Text(L10n.of(context)!.encryption),
actions: [
TextButton(
onPressed: () => launchUrlString(AppConfig.encryptionTutorial),
@ -50,13 +51,12 @@ class ChatEncryptionSettingsView extends StatelessWidget {
value: room.encrypted,
onChanged: controller.enableEncryption,
),
Center(
child: Image.asset(
'assets/encryption.png',
width: 212,
),
Icon(
CupertinoIcons.lock_shield,
size: 128,
color: Theme.of(context).colorScheme.onInverseSurface,
),
const Divider(height: 1),
const Divider(),
if (room.isDirectChat)
Padding(
padding: const EdgeInsets.all(16.0),

View File

@ -253,7 +253,7 @@ class ChatListController extends State<ChatList>
BoxConstraints? snappingSheetContainerSize;
final ScrollController scrollController = ScrollController();
bool scrolledToTop = true;
final ValueNotifier<bool> scrolledToTop = ValueNotifier(true);
final StreamController<Client> _clientStream = StreamController.broadcast();
@ -263,10 +263,8 @@ class ChatListController extends State<ChatList>
void _onScroll() {
final newScrolledToTop = scrollController.position.pixels <= 0;
if (newScrolledToTop != scrolledToTop) {
setState(() {
scrolledToTop = newScrolledToTop;
});
if (newScrolledToTop != scrolledToTop.value) {
scrolledToTop.value = newScrolledToTop;
}
}

View File

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
@ -8,7 +9,6 @@ import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart';
import 'package:fluffychat/pages/chat_list/space_view.dart';
import 'package:fluffychat/pages/chat_list/start_chat_fab.dart';
import 'package:fluffychat/pages/chat_list/stories_header.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
@ -32,6 +32,11 @@ class ChatListViewBody extends StatelessWidget {
final roomSearchResult = controller.roomSearchResult;
final userSearchResult = controller.userSearchResult;
final client = Matrix.of(context).client;
const dummyChatCount = 4;
final titleColor =
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(100);
final subtitleColor =
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(50);
return PageTransitionSwitcher(
transitionBuilder: (
@ -65,157 +70,203 @@ class ChatListViewBody extends StatelessWidget {
key: Key(controller.activeSpaceId ?? 'Spaces'),
);
}
if (controller.waitForFirstSync && client.prevBatch != null) {
final rooms = controller.filteredRooms;
final displayStoriesHeader = {
ActiveFilter.allChats,
ActiveFilter.messages,
}.contains(controller.activeFilter) &&
client.storiesRooms.isNotEmpty;
return SafeArea(
child: CustomScrollView(
controller: controller.scrollController,
slivers: [
ChatListHeader(controller: controller),
SliverList(
delegate: SliverChildListDelegate(
[
if (controller.isSearchMode) ...[
SearchTitle(
title: L10n.of(context)!.publicRooms,
icon: const Icon(Icons.explore_outlined),
),
AnimatedContainer(
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
height: roomSearchResult == null ||
roomSearchResult.chunk.isEmpty
? 0
: 106,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: roomSearchResult == null
? null
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: roomSearchResult.chunk.length,
itemBuilder: (context, i) => _SearchItem(
title: roomSearchResult.chunk[i].name ??
roomSearchResult.chunk[i]
.canonicalAlias?.localpart ??
L10n.of(context)!.group,
avatar:
roomSearchResult.chunk[i].avatarUrl,
onPressed: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => PublicRoomBottomSheet(
roomAlias: roomSearchResult
.chunk[i].canonicalAlias ??
roomSearchResult.chunk[i].roomId,
outerContext: context,
chunk: roomSearchResult.chunk[i],
),
),
),
),
),
SearchTitle(
title: L10n.of(context)!.users,
icon: const Icon(Icons.group_outlined),
),
AnimatedContainer(
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
height: userSearchResult == null ||
userSearchResult.results.isEmpty
? 0
: 106,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: userSearchResult == null
? null
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: userSearchResult.results.length,
itemBuilder: (context, i) => _SearchItem(
title: userSearchResult
.results[i].displayName ??
userSearchResult
.results[i].userId.localpart ??
L10n.of(context)!.unknownDevice,
avatar:
userSearchResult.results[i].avatarUrl,
onPressed: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => ProfileBottomSheet(
userId: userSearchResult
.results[i].userId,
outerContext: context,
),
),
),
),
),
SearchTitle(
title: L10n.of(context)!.stories,
icon: const Icon(Icons.camera_alt_outlined),
),
],
if (displayStoriesHeader)
StoriesHeader(
key: const Key('stories_header'),
filter: controller.searchController.text,
),
const ConnectionStatusHeader(),
final rooms = controller.filteredRooms;
final displayStoriesHeader = {
ActiveFilter.allChats,
ActiveFilter.messages,
}.contains(controller.activeFilter) &&
client.storiesRooms.isNotEmpty;
return SafeArea(
child: CustomScrollView(
controller: controller.scrollController,
slivers: [
ChatListHeader(controller: controller),
SliverList(
delegate: SliverChildListDelegate(
[
if (controller.isSearchMode) ...[
SearchTitle(
title: L10n.of(context)!.publicRooms,
icon: const Icon(Icons.explore_outlined),
),
AnimatedContainer(
height: controller.isTorBrowser ? 64 : 0,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
child: Material(
color: Theme.of(context).colorScheme.surface,
child: ListTile(
leading: const Icon(Icons.vpn_key),
title: Text(L10n.of(context)!.dehydrateTor),
subtitle:
Text(L10n.of(context)!.dehydrateTorLong),
trailing:
const Icon(Icons.chevron_right_outlined),
onTap: controller.dehydrate,
),
height: roomSearchResult == null ||
roomSearchResult.chunk.isEmpty
? 0
: 106,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: roomSearchResult == null
? null
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: roomSearchResult.chunk.length,
itemBuilder: (context, i) => _SearchItem(
title: roomSearchResult.chunk[i].name ??
roomSearchResult.chunk[i].canonicalAlias
?.localpart ??
L10n.of(context)!.group,
avatar: roomSearchResult.chunk[i].avatarUrl,
onPressed: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => PublicRoomBottomSheet(
roomAlias: roomSearchResult
.chunk[i].canonicalAlias ??
roomSearchResult.chunk[i].roomId,
outerContext: context,
chunk: roomSearchResult.chunk[i],
),
),
),
),
),
SearchTitle(
title: L10n.of(context)!.users,
icon: const Icon(Icons.group_outlined),
),
AnimatedContainer(
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
height: userSearchResult == null ||
userSearchResult.results.isEmpty
? 0
: 106,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: userSearchResult == null
? null
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: userSearchResult.results.length,
itemBuilder: (context, i) => _SearchItem(
title: userSearchResult
.results[i].displayName ??
userSearchResult
.results[i].userId.localpart ??
L10n.of(context)!.unknownDevice,
avatar:
userSearchResult.results[i].avatarUrl,
onPressed: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => ProfileBottomSheet(
userId:
userSearchResult.results[i].userId,
outerContext: context,
),
),
),
),
),
SearchTitle(
title: L10n.of(context)!.stories,
icon: const Icon(Icons.camera_alt_outlined),
),
],
if (displayStoriesHeader)
StoriesHeader(
key: const Key('stories_header'),
filter: controller.searchController.text,
),
const ConnectionStatusHeader(),
AnimatedContainer(
height: controller.isTorBrowser ? 64 : 0,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
child: Material(
color: Theme.of(context).colorScheme.surface,
child: ListTile(
leading: const Icon(Icons.vpn_key),
title: Text(L10n.of(context)!.dehydrateTor),
subtitle: Text(L10n.of(context)!.dehydrateTorLong),
trailing: const Icon(Icons.chevron_right_outlined),
onTap: controller.dehydrate,
),
),
if (controller.isSearchMode)
SearchTitle(
title: L10n.of(context)!.chats,
icon: const Icon(Icons.forum_outlined),
),
if (controller.isSearchMode)
SearchTitle(
title: L10n.of(context)!.chats,
icon: const Icon(Icons.forum_outlined),
),
if (client.prevBatch != null &&
rooms.isEmpty &&
!controller.isSearchMode) ...[
Padding(
padding: const EdgeInsets.all(32.0),
child: Icon(
CupertinoIcons.chat_bubble_2,
size: 128,
color:
Theme.of(context).colorScheme.onInverseSurface,
),
if (rooms.isEmpty && !controller.isSearchMode) ...[
Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/start_chat.png',
height: 256,
),
const Divider(height: 1),
],
),
),
Center(
child: StartChatFloatingActionButton(
activeFilter: controller.activeFilter,
roomsIsEmpty: true,
scrolledToTop: controller.scrolledToTop,
),
),
],
),
],
],
),
),
if (client.prevBatch == null)
SliverList(
delegate: SliverChildBuilderDelegate(
(context, i) => Opacity(
opacity: (dummyChatCount - i) / dummyChatCount,
child: ListTile(
leading: CircleAvatar(
backgroundColor: titleColor,
child: CircularProgressIndicator(
strokeWidth: 1,
color:
Theme.of(context).textTheme.bodyLarge!.color,
),
),
title: Row(
children: [
Expanded(
child: Container(
height: 14,
decoration: BoxDecoration(
color: titleColor,
borderRadius: BorderRadius.circular(3),
),
),
),
const SizedBox(width: 36),
Container(
height: 14,
width: 14,
decoration: BoxDecoration(
color: subtitleColor,
borderRadius: BorderRadius.circular(14),
),
),
const SizedBox(width: 12),
Container(
height: 14,
width: 14,
decoration: BoxDecoration(
color: subtitleColor,
borderRadius: BorderRadius.circular(14),
),
),
],
),
subtitle: Container(
decoration: BoxDecoration(
color: subtitleColor,
borderRadius: BorderRadius.circular(3),
),
height: 12,
margin: const EdgeInsets.only(right: 22),
),
),
),
childCount: dummyChatCount,
),
),
if (client.prevBatch != null)
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i) {
@ -245,68 +296,7 @@ class ChatListViewBody extends StatelessWidget {
childCount: rooms.length,
),
),
],
),
);
}
const dummyChatCount = 5;
final titleColor =
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(100);
final subtitleColor =
Theme.of(context).textTheme.bodyLarge!.color!.withAlpha(50);
return ListView.builder(
key: const Key('dummychats'),
itemCount: dummyChatCount,
itemBuilder: (context, i) => Opacity(
opacity: (dummyChatCount - i) / dummyChatCount,
child: ListTile(
leading: CircleAvatar(
backgroundColor: titleColor,
child: CircularProgressIndicator(
strokeWidth: 1,
color: Theme.of(context).textTheme.bodyLarge!.color,
),
),
title: Row(
children: [
Expanded(
child: Container(
height: 14,
decoration: BoxDecoration(
color: titleColor,
borderRadius: BorderRadius.circular(3),
),
),
),
const SizedBox(width: 36),
Container(
height: 14,
width: 14,
decoration: BoxDecoration(
color: subtitleColor,
borderRadius: BorderRadius.circular(14),
),
),
const SizedBox(width: 12),
Container(
height: 14,
width: 14,
decoration: BoxDecoration(
color: subtitleColor,
borderRadius: BorderRadius.circular(14),
),
),
],
),
subtitle: Container(
decoration: BoxDecoration(
color: subtitleColor,
borderRadius: BorderRadius.circular(3),
),
height: 12,
margin: const EdgeInsets.only(right: 22),
),
),
],
),
);
},

View File

@ -192,7 +192,6 @@ class ChatListView extends StatelessWidget {
VRouter.of(context).to('/newprivatechat'),
helpLabel: L10n.of(context)!.newChat,
child: selectMode == SelectMode.normal &&
controller.filteredRooms.isNotEmpty &&
!controller.isSearchMode
? StartChatFloatingActionButton(
activeFilter: controller.activeFilter,

View File

@ -8,7 +8,7 @@ import 'chat_list.dart';
class StartChatFloatingActionButton extends StatelessWidget {
final ActiveFilter activeFilter;
final bool scrolledToTop;
final ValueNotifier<bool> scrolledToTop;
final bool roomsIsEmpty;
const StartChatFloatingActionButton({
@ -61,27 +61,26 @@ class StartChatFloatingActionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
width: roomsIsEmpty
? null
: scrolledToTop
? 144
: 56,
child: scrolledToTop
? FloatingActionButton.extended(
onPressed: () => _onPressed(context),
icon: Icon(icon),
label: Text(
getLabel(context),
overflow: TextOverflow.fade,
return ValueListenableBuilder<bool>(
valueListenable: scrolledToTop,
builder: (context, scrolledToTop, _) => AnimatedSize(
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.none,
child: scrolledToTop
? FloatingActionButton.extended(
onPressed: () => _onPressed(context),
icon: Icon(icon),
label: Text(
getLabel(context),
overflow: TextOverflow.fade,
),
)
: FloatingActionButton(
onPressed: () => _onPressed(context),
child: Icon(icon),
),
)
: FloatingActionButton(
onPressed: () => _onPressed(context),
child: Icon(icon),
),
),
);
}
}

View File

@ -73,8 +73,10 @@ class ChatPermissionsSettingsController extends State<ChatPermissionsSettings> {
void updateRoomAction(Capabilities capabilities) async {
final room = Matrix.of(context).client.getRoomById(roomId!)!;
final String roomVersion =
room.getState(EventTypes.RoomCreate)!.content['room_version'] ?? '1';
final roomVersion = room
.getState(EventTypes.RoomCreate)!
.content['room_version'] as String? ??
'1';
final newVersion = await showConfirmationDialog<String>(
context: context,
title: L10n.of(context)!.replaceRoomWithNewerVersion,

View File

@ -127,9 +127,9 @@ class ChatPermissionsSettingsView extends StatelessWidget {
),
);
}
final String roomVersion = room
final roomVersion = room
.getState(EventTypes.RoomCreate)!
.content['room_version'] ??
.content['room_version'] as String? ??
'1';
return ListTile(

View File

@ -1,197 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:image_picker/image_picker.dart';
import 'package:matrix/matrix.dart';
import 'package:universal_html/html.dart' as html;
import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/connect/connect_page_view.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/matrix.dart';
class ConnectPage extends StatefulWidget {
const ConnectPage({Key? key}) : super(key: key);
@override
State<ConnectPage> createState() => ConnectPageController();
}
class ConnectPageController extends State<ConnectPage> {
final TextEditingController usernameController = TextEditingController();
String? signupError;
bool loading = false;
void pickAvatar() async {
final source = !PlatformInfos.isMobile
? ImageSource.gallery
: await showModalActionSheet<ImageSource>(
context: context,
title: L10n.of(context)!.changeYourAvatar,
actions: [
SheetAction(
key: ImageSource.camera,
label: L10n.of(context)!.openCamera,
isDefaultAction: true,
icon: Icons.camera_alt_outlined,
),
SheetAction(
key: ImageSource.gallery,
label: L10n.of(context)!.openGallery,
icon: Icons.photo_outlined,
),
],
);
if (source == null) return;
final picked = await ImagePicker().pickImage(
source: source,
imageQuality: 50,
maxWidth: 512,
maxHeight: 512,
);
setState(() {
Matrix.of(context).loginAvatar = picked;
});
}
void signUp() async {
usernameController.text = usernameController.text.trim();
final localpart =
usernameController.text.toLowerCase().replaceAll(' ', '_');
if (localpart.isEmpty) {
setState(() {
signupError = L10n.of(context)!.pleaseChooseAUsername;
});
return;
}
setState(() {
signupError = null;
loading = true;
});
try {
try {
await Matrix.of(context).getLoginClient().register(username: localpart);
} on MatrixException catch (e) {
if (!e.requireAdditionalAuthentication) rethrow;
}
setState(() {
loading = false;
});
Matrix.of(context).loginUsername = usernameController.text;
VRouter.of(context).to('signup');
} catch (e, s) {
Logs().d('Sign up failed', e, s);
setState(() {
signupError = e.toLocalizedString(context);
loading = false;
});
}
}
bool _supportsFlow(String flowType) =>
Matrix.of(context)
.loginHomeserverSummary
?.loginFlows
.any((flow) => flow.type == flowType) ??
false;
bool get supportsSso => _supportsFlow('m.login.sso');
bool isDefaultPlatform =
(PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS);
bool get supportsLogin => _supportsFlow('m.login.password');
void login() => VRouter.of(context).to('login');
Map<String, dynamic>? _rawLoginTypes;
List<IdentityProvider>? get identityProviders {
final loginTypes = _rawLoginTypes;
if (loginTypes == null) return null;
final rawProviders = loginTypes.tryGetList('flows')!.singleWhere(
(flow) => flow['type'] == AuthenticationTypes.sso,
)['identity_providers'];
final list = (rawProviders as List)
.map((json) => IdentityProvider.fromJson(json))
.toList();
if (PlatformInfos.isCupertinoStyle) {
list.sort((a, b) => a.brand == 'apple' ? -1 : 1);
}
return list;
}
void ssoLoginAction(String id) async {
final redirectUrl = kIsWeb
? '${html.window.origin!}/web/auth.html'
: isDefaultPlatform
? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login'
: 'http://localhost:3001//login';
final url =
'${Matrix.of(context).getLoginClient().homeserver?.toString()}/_matrix/client/r0/login/sso/redirect/${Uri.encodeComponent(id)}?redirectUrl=${Uri.encodeQueryComponent(redirectUrl)}';
final urlScheme = isDefaultPlatform
? Uri.parse(redirectUrl).scheme
: "http://localhost:3001";
final result = await FlutterWebAuth2.authenticate(
url: url,
callbackUrlScheme: urlScheme,
);
final token = Uri.parse(result).queryParameters['loginToken'];
if (token?.isEmpty ?? false) return;
await showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context).getLoginClient().login(
LoginType.mLoginToken,
token: token,
initialDeviceDisplayName: PlatformInfos.clientName,
),
);
}
@override
void initState() {
super.initState();
if (supportsSso) {
Matrix.of(context)
.getLoginClient()
.request(
RequestType.GET,
'/client/r0/login',
)
.then(
(loginTypes) => setState(() {
_rawLoginTypes = loginTypes;
}),
);
}
}
@override
Widget build(BuildContext context) => ConnectPageView(this);
}
class IdentityProvider {
final String? id;
final String? name;
final String? icon;
final String? brand;
IdentityProvider({this.id, this.name, this.icon, this.brand});
factory IdentityProvider.fromJson(Map<String, dynamic> json) =>
IdentityProvider(
id: json['id'],
name: json['name'],
icon: json['icon'],
brand: json['brand'],
);
}

View File

@ -1,226 +0,0 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/connect/connect_page.dart';
import 'package:fluffychat/widgets/layouts/login_scaffold.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'sso_button.dart';
class ConnectPageView extends StatelessWidget {
final ConnectPageController controller;
const ConnectPageView(this.controller, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final avatar = Matrix.of(context).loginAvatar;
final identityProviders = controller.identityProviders;
return LoginScaffold(
appBar: AppBar(
leading: controller.loading ? null : const BackButton(),
automaticallyImplyLeading: !controller.loading,
centerTitle: true,
title: Text(
Matrix.of(context).getLoginClient().homeserver?.host ?? '',
),
),
body: ListView(
key: const Key('ConnectPageListView'),
children: [
if (Matrix.of(context).loginRegistrationSupported ?? false) ...[
Padding(
padding: const EdgeInsets.all(12.0),
child: Center(
child: Stack(
children: [
Material(
borderRadius: BorderRadius.circular(64),
elevation: Theme.of(context)
.appBarTheme
.scrolledUnderElevation ??
10,
color: Colors.transparent,
shadowColor: Theme.of(context)
.colorScheme
.onBackground
.withAlpha(64),
clipBehavior: Clip.hardEdge,
child: CircleAvatar(
radius: 64,
backgroundColor: Colors.white,
child: avatar == null
? const Icon(
Icons.person,
color: Colors.black,
size: 64,
)
: FutureBuilder<Uint8List>(
future: avatar.readAsBytes(),
builder: (context, snapshot) {
final bytes = snapshot.data;
if (bytes == null) {
return const CircularProgressIndicator
.adaptive();
}
return Image.memory(
bytes,
fit: BoxFit.cover,
width: 128,
height: 128,
);
},
),
),
),
Positioned(
bottom: 0,
right: 0,
child: FloatingActionButton(
mini: true,
onPressed: controller.pickAvatar,
backgroundColor: Colors.white,
foregroundColor: Colors.black,
child: const Icon(Icons.camera_alt_outlined),
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: controller.usernameController,
onSubmitted: (_) => controller.signUp(),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.account_box_outlined),
hintText: L10n.of(context)!.chooseAUsername,
errorText: controller.signupError,
errorStyle: const TextStyle(color: Colors.orange),
),
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Hero(
tag: 'loginButton',
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: controller.loading ? () {} : controller.signUp,
icon: const Icon(Icons.person_add_outlined),
label: controller.loading
? const LinearProgressIndicator()
: Text(L10n.of(context)!.signUp),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
Expanded(
child: Divider(
thickness: 1,
color: Theme.of(context).dividerColor,
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
L10n.of(context)!.or,
style: const TextStyle(fontSize: 18),
),
),
Expanded(
child: Divider(
thickness: 1,
color: Theme.of(context).dividerColor,
),
),
],
),
),
],
if (controller.supportsSso)
identityProviders == null
? const SizedBox(
height: 74,
child: Center(child: CircularProgressIndicator.adaptive()),
)
: Center(
child: identityProviders.length == 1
? Container(
width: double.infinity,
padding: const EdgeInsets.all(12.0),
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context)
.colorScheme
.primaryContainer,
foregroundColor: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
icon: identityProviders.single.icon == null
? const Icon(
Icons.web_outlined,
size: 16,
)
: Image.network(
Uri.parse(identityProviders.single.icon!)
.getDownloadLink(
Matrix.of(context).getLoginClient(),
)
.toString(),
width: 32,
height: 32,
),
onPressed: () => controller
.ssoLoginAction(identityProviders.single.id!),
label: Text(
identityProviders.single.name ??
identityProviders.single.brand ??
L10n.of(context)!.loginWithOneClick,
),
),
)
: Wrap(
children: [
for (final identityProvider in identityProviders)
SsoButton(
onPressed: () => controller
.ssoLoginAction(identityProvider.id!),
identityProvider: identityProvider,
),
].toList(),
),
),
if (controller.supportsLogin)
Padding(
padding: const EdgeInsets.all(12.0),
child: Hero(
tag: 'signinButton',
child: ElevatedButton.icon(
icon: const Icon(Icons.login_outlined),
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.primaryContainer,
foregroundColor:
Theme.of(context).colorScheme.onPrimaryContainer,
),
onPressed: controller.loading ? () {} : controller.login,
label: Text(L10n.of(context)!.login),
),
),
),
],
),
);
}
}

View File

@ -1,63 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/connect/connect_page.dart';
import 'package:fluffychat/widgets/matrix.dart';
class SsoButton extends StatelessWidget {
final IdentityProvider identityProvider;
final void Function()? onPressed;
const SsoButton({
Key? key,
required this.identityProvider,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(7),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Material(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
clipBehavior: Clip.hardEdge,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: identityProvider.icon == null
? const Icon(Icons.web_outlined)
: Image.network(
Uri.parse(identityProvider.icon!)
.getDownloadLink(
Matrix.of(context).getLoginClient(),
)
.toString(),
width: 32,
height: 32,
),
),
),
const SizedBox(height: 8),
Text(
identityProvider.name ??
identityProvider.brand ??
L10n.of(context)!.singlesignon,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}

View File

@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:matrix_homeserver_recommendations/matrix_homeserver_recommendations.dart';
import 'package:fluffychat/config/app_config.dart';
import 'homeserver_bottom_sheet.dart';
import 'homeserver_picker.dart';
class HomeserverAppBar extends StatelessWidget {
@ -13,25 +16,57 @@ class HomeserverAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextField(
focusNode: controller.homeserverFocusNode,
controller: controller.homeserverController,
onChanged: controller.onChanged,
decoration: InputDecoration(
prefixIcon: Navigator.of(context).canPop()
? IconButton(
onPressed: Navigator.of(context).pop,
icon: const Icon(Icons.arrow_back),
)
: null,
prefixText: '${L10n.of(context)!.homeserver}: ',
hintText: L10n.of(context)!.enterYourHomeserver,
suffixIcon: const Icon(Icons.search),
errorText: controller.error,
return TypeAheadField<HomeserverBenchmarkResult>(
suggestionsBoxDecoration: SuggestionsBoxDecoration(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
elevation: Theme.of(context).appBarTheme.scrolledUnderElevation ?? 4,
shadowColor: Theme.of(context).appBarTheme.shadowColor ?? Colors.black,
constraints: const BoxConstraints(maxHeight: 256),
),
itemBuilder: (context, homeserver) => ListTile(
title: Text(homeserver.homeserver.baseUrl.toString()),
subtitle: Text(homeserver.homeserver.description ?? ''),
trailing: IconButton(
icon: const Icon(Icons.info_outlined),
onPressed: () => showModalBottomSheet(
context: context,
builder: (_) => HomeserverBottomSheet(
homeserver: homeserver,
),
),
),
),
suggestionsCallback: (pattern) async {
final homeserverList =
await const JoinmatrixOrgParser().fetchHomeservers();
final benchmark = await HomeserverListProvider.benchmarkHomeserver(
homeserverList,
timeout: const Duration(seconds: 3),
);
return benchmark;
},
onSuggestionSelected: (suggestion) {
controller.homeserverController.text =
suggestion.homeserver.baseUrl.host;
controller.checkHomeserverAction();
},
textFieldConfiguration: TextFieldConfiguration(
controller: controller.homeserverController,
decoration: InputDecoration(
prefixIcon: Navigator.of(context).canPop()
? IconButton(
onPressed: Navigator.of(context).pop,
icon: const Icon(Icons.arrow_back),
)
: null,
prefixText: '${L10n.of(context)!.homeserver}: ',
hintText: L10n.of(context)!.enterYourHomeserver,
suffixIcon: const Icon(Icons.search),
),
textInputAction: TextInputAction.search,
onSubmitted: controller.checkHomeserverAction,
autocorrect: false,
),
readOnly: !AppConfig.allowOtherHomeservers,
onSubmitted: (_) => controller.checkHomeserverAction(),
autocorrect: false,
);
}
}

View File

@ -7,16 +7,16 @@ import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix_homeserver_recommendations/matrix_homeserver_recommendations.dart';
import 'package:universal_html/html.dart' as html;
import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_bottom_sheet.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../utils/localized_exception_extension.dart';
@ -35,14 +35,8 @@ class HomeserverPickerController extends State<HomeserverPicker> {
final TextEditingController homeserverController = TextEditingController(
text: AppConfig.defaultHomeserver,
);
final FocusNode homeserverFocusNode = FocusNode();
String? error;
List<HomeserverBenchmarkResult>? benchmarkResults;
bool displayServerList = false;
bool get loadingHomeservers =>
AppConfig.allowOtherHomeservers && benchmarkResults == null;
String searchTerm = '';
String? error;
bool isTorBrowser = false;
@ -65,98 +59,34 @@ class HomeserverPickerController extends State<HomeserverPicker> {
isTorBrowser = isTor;
}
void _updateFocus() {
if (benchmarkResults == null) _loadHomeserverList();
if (homeserverFocusNode.hasFocus) {
setState(() {
displayServerList = true;
});
}
}
void showServerInfo(HomeserverBenchmarkResult server) =>
showAdaptiveBottomSheet(
context: context,
builder: (_) => HomeserverBottomSheet(
homeserver: server,
),
);
void onChanged(String text) => setState(() {
searchTerm = text;
});
List<HomeserverBenchmarkResult> get filteredHomeservers => benchmarkResults!
.where(
(element) =>
element.homeserver.baseUrl.host.contains(searchTerm) ||
(element.homeserver.description?.contains(searchTerm) ?? false),
)
.toList();
void _loadHomeserverList() async {
try {
final homeserverList =
await const JoinmatrixOrgParser().fetchHomeservers();
final benchmark = await HomeserverListProvider.benchmarkHomeserver(
homeserverList,
timeout: const Duration(seconds: 10),
);
if (!mounted) return;
setState(() {
benchmarkResults = benchmark;
});
} catch (e, s) {
Logs().e('Homeserver benchmark failed', e, s);
benchmarkResults = [];
}
}
void setServer(String server) => setState(() {
homeserverController.text = server;
searchTerm = '';
homeserverFocusNode.unfocus();
displayServerList = false;
});
String? _lastCheckedUrl;
/// Starts an analysis of the given homeserver. It uses the current domain and
/// makes sure that it is prefixed with https. Then it searches for the
/// well-known information and forwards to the login page depending on the
/// login type.
Future<void> checkHomeserverAction() async {
Future<void> checkHomeserverAction([_]) async {
homeserverController.text =
homeserverController.text.trim().toLowerCase().replaceAll(' ', '-');
if (homeserverController.text == _lastCheckedUrl) return;
_lastCheckedUrl = homeserverController.text;
setState(() {
homeserverFocusNode.unfocus();
error = null;
error = _rawLoginTypes = loginHomeserverSummary = null;
isLoading = true;
searchTerm = '';
displayServerList = false;
});
try {
homeserverController.text =
homeserverController.text.trim().toLowerCase().replaceAll(' ', '-');
var homeserver = Uri.parse(homeserverController.text);
if (homeserver.scheme.isEmpty) {
homeserver = Uri.https(homeserverController.text, '');
}
final matrix = Matrix.of(context);
matrix.loginHomeserverSummary =
await matrix.getLoginClient().checkHomeserver(homeserver);
final ssoSupported = matrix.loginHomeserverSummary!.loginFlows
.any((flow) => flow.type == 'm.login.sso');
try {
await Matrix.of(context).getLoginClient().register();
matrix.loginRegistrationSupported = true;
} on MatrixException catch (e) {
matrix.loginRegistrationSupported = e.requireAdditionalAuthentication;
}
if (!ssoSupported && matrix.loginRegistrationSupported == false) {
// Server does not support SSO or registration. We can skip to login page:
VRouter.of(context).to('login');
} else {
VRouter.of(context).to('connect');
final client = Matrix.of(context).getLoginClient();
loginHomeserverSummary = await client.checkHomeserver(homeserver);
if (supportsSso) {
_rawLoginTypes = await client.request(
RequestType.GET,
'/client/r0/login',
);
}
} catch (e) {
setState(() => error = (e).toLocalizedString(context));
@ -167,17 +97,71 @@ class HomeserverPickerController extends State<HomeserverPicker> {
}
}
@override
void dispose() {
homeserverFocusNode.removeListener(_updateFocus);
super.dispose();
HomeserverSummary? loginHomeserverSummary;
bool _supportsFlow(String flowType) =>
loginHomeserverSummary?.loginFlows.any((flow) => flow.type == flowType) ??
false;
bool get supportsSso => _supportsFlow('m.login.sso');
bool isDefaultPlatform =
(PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS);
bool get supportsPasswordLogin => _supportsFlow('m.login.password');
Map<String, dynamic>? _rawLoginTypes;
void ssoLoginAction(String id) async {
final redirectUrl = kIsWeb
? '${html.window.origin!}/web/auth.html'
: isDefaultPlatform
? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login'
: 'http://localhost:3001//login';
final url =
'${Matrix.of(context).getLoginClient().homeserver?.toString()}/_matrix/client/r0/login/sso/redirect/${Uri.encodeComponent(id)}?redirectUrl=${Uri.encodeQueryComponent(redirectUrl)}';
final urlScheme = isDefaultPlatform
? Uri.parse(redirectUrl).scheme
: "http://localhost:3001";
final result = await FlutterWebAuth2.authenticate(
url: url,
callbackUrlScheme: urlScheme,
);
final token = Uri.parse(result).queryParameters['loginToken'];
if (token?.isEmpty ?? false) return;
await showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context).getLoginClient().login(
LoginType.mLoginToken,
token: token,
initialDeviceDisplayName: PlatformInfos.clientName,
),
);
}
List<IdentityProvider>? get identityProviders {
final loginTypes = _rawLoginTypes;
if (loginTypes == null) return null;
final rawProviders = loginTypes.tryGetList('flows')!.singleWhere(
(flow) => flow['type'] == AuthenticationTypes.sso,
)['identity_providers'];
final list = (rawProviders as List)
.map((json) => IdentityProvider.fromJson(json))
.toList();
if (PlatformInfos.isCupertinoStyle) {
list.sort((a, b) => a.brand == 'apple' ? -1 : 1);
}
return list;
}
void login() => VRouter.of(context).to('login');
@override
void initState() {
homeserverFocusNode.addListener(_updateFocus);
_checkTorBrowser();
super.initState();
WidgetsBinding.instance.addPostFrameCallback(checkHomeserverAction);
}
@override
@ -204,3 +188,20 @@ class HomeserverPickerController extends State<HomeserverPicker> {
);
}
}
class IdentityProvider {
final String? id;
final String? name;
final String? icon;
final String? brand;
IdentityProvider({this.id, this.name, this.icon, this.brand});
factory IdentityProvider.fromJson(Map<String, dynamic> json) =>
IdentityProvider(
id: json['id'],
name: json['name'],
icon: json['icon'],
brand: json['brand'],
);
}

View File

@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/widgets/layouts/login_scaffold.dart';
import '../../config/themes.dart';
import '../../widgets/mxc_image.dart';
import 'homeserver_app_bar.dart';
import 'homeserver_picker.dart';
@ -16,15 +16,19 @@ class HomeserverPickerView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final benchmarkResults = controller.benchmarkResults;
final identityProviders = controller.identityProviders;
final errorText = controller.error;
return LoginScaffold(
appBar: AppBar(
titleSpacing: 12,
title: Padding(
padding: const EdgeInsets.all(0.0),
child: HomeserverAppBar(controller: controller),
),
),
body: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: HomeserverAppBar(controller: controller),
),
// display a prominent banner to import session for TOR browser
// users. This feature is just some UX sugar as TOR users are
// usually forced to logout as TOR browser is non-persistent
@ -49,108 +53,119 @@ class HomeserverPickerView extends StatelessWidget {
),
),
Expanded(
child: controller.displayServerList
? ListView(
child: controller.isLoading
? const Center(child: CircularProgressIndicator.adaptive())
: ListView(
children: [
if (controller.displayServerList)
Padding(
padding: const EdgeInsets.all(12.0),
child: Material(
borderRadius:
BorderRadius.circular(AppConfig.borderRadius),
color: Theme.of(context)
.colorScheme
.onInverseSurface,
clipBehavior: Clip.hardEdge,
child: benchmarkResults == null
? const Center(
child: Padding(
padding: EdgeInsets.all(12.0),
child: CircularProgressIndicator
.adaptive(),
),
)
: Column(
children: controller.filteredHomeservers
.map(
(server) => ListTile(
trailing: IconButton(
icon: const Icon(
Icons.info_outlined,
color: Colors.black,
),
onPressed: () => controller
.showServerInfo(server),
),
onTap: () => controller.setServer(
server.homeserver.baseUrl.host,
),
title: Text(
server.homeserver.baseUrl.host,
style: const TextStyle(
color: Colors.black,
),
),
subtitle: Text(
server.homeserver.description ??
'',
style: TextStyle(
color: Colors.grey.shade700,
),
),
),
)
.toList(),
),
Image.asset(
'assets/info-logo.png',
height: 96,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
children: [
Expanded(
child: Divider(
thickness: 1,
height: 1,
color: Theme.of(context).dividerColor,
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
L10n.of(context)!.continueWith,
style: const TextStyle(fontSize: 12),
),
),
Expanded(
child: Divider(
thickness: 1,
height: 1,
color: Theme.of(context).dividerColor,
),
),
],
),
),
if (errorText != null) ...[
const Center(
child: Icon(
Icons.error_outline,
size: 48,
color: Colors.orange,
),
),
],
)
: Container(
alignment: Alignment.topCenter,
child: Image.asset(
'assets/banner_transparent.png',
filterQuality: FilterQuality.medium,
),
),
),
SafeArea(
child: Container(
padding: const EdgeInsets.all(12),
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextButton(
onPressed: () => launchUrlString(AppConfig.privacyUrl),
child: Text(L10n.of(context)!.privacy),
),
TextButton(
onPressed: controller.restoreBackup,
child: Text(L10n.of(context)!.hydrate),
),
Hero(
tag: 'loginButton',
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).colorScheme.primary,
foregroundColor:
Theme.of(context).colorScheme.onPrimary,
const SizedBox(height: 12),
Center(
child: Text(
errorText,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 18,
),
),
),
Center(
child: Text(
L10n.of(context)!
.pleaseTryAgainLaterOrChooseDifferentServer,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.error,
fontSize: 12,
),
),
),
const SizedBox(height: 12),
],
if (identityProviders != null) ...[
...identityProviders.map(
(provider) => _LoginButton(
icon: provider.icon == null
? const Icon(Icons.open_in_new_outlined)
: Material(
color: Colors.white,
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
clipBehavior: Clip.hardEdge,
child: MxcImage(
placeholder: (_) =>
const Icon(Icons.web_outlined),
uri: Uri.parse(provider.icon!),
width: 24,
height: 24,
),
),
label: provider.name ??
provider.brand ??
L10n.of(context)!.singlesignon,
onPressed: () =>
controller.ssoLoginAction(provider.id!),
),
),
],
if (controller.supportsPasswordLogin)
_LoginButton(
onPressed: controller.login,
icon: const Icon(Icons.login_outlined),
label: L10n.of(context)!.signInWithPassword,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: TextButton(
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
onPressed: controller.restoreBackup,
child: Text(L10n.of(context)!.hydrate),
),
),
onPressed: controller.isLoading
? null
: controller.checkHomeserverAction,
icon: const Icon(Icons.start_outlined),
label: controller.isLoading
? const LinearProgressIndicator()
: Text(L10n.of(context)!.letsStart),
),
],
),
],
),
),
),
],
),
@ -158,3 +173,33 @@ class HomeserverPickerView extends StatelessWidget {
);
}
}
class _LoginButton extends StatelessWidget {
final Widget icon;
final String label;
final void Function() onPressed;
const _LoginButton({
required this.icon,
required this.label,
required this.onPressed,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
margin: const EdgeInsets.only(bottom: 16),
width: double.infinity,
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
onPressed: onPressed,
icon: icon,
label: Text(label),
),
);
}
}

Some files were not shown because too many files have changed in this diff Show More