Compare commits

...

44 Commits

Author SHA1 Message Date
josé m 85d3a11030
Translated using Weblate (Galician)
Currently translated at 100.0% (551 of 551 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/
2023-01-16 07:47:59 +01:00
Krille bf084f1ccc chore: Remove unused dependency 2023-01-15 10:06:02 +01:00
Krille 4afb9a4790 chore: Follow up leave abandoned DM room 2023-01-15 10:05:54 +01:00
TheOneWithTheBraid ddb7cc841b chore: add integration tests for spaces
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-01-14 10:46:18 +01:00
Krille a1f60b7ff9 fix: Archive 2023-01-13 10:38:39 +00:00
Krille 8632154832 style: Redesign public room bottomsheets 2023-01-13 10:38:39 +00:00
Krille 1f71227221 Merge branch 'braid/less-tests' into 'main'
refactor: disable some redundant tests

See merge request famedly/fluffychat!1075
2023-01-13 09:45:09 +00:00
TheOneWithTheBraid 3d9e94f08d refactor: disable some redundant tests
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-01-13 10:26:43 +01:00
Christian b76f270e24
Deleted translation using Weblate (Yue (yue_HK)) 2023-01-08 11:37:34 +01:00
Krille 8f9e1a9142 Merge branch 'krille/nicer-modal-bottom-sheet' into 'main'
style: New modal bottom sheets

See merge request famedly/fluffychat!1071
2023-01-08 10:35:31 +00:00
Krille fbb68686ea style: New modal bottom sheets 2023-01-08 11:07:31 +01:00
Priit Jõerüüt 9eee50dbae
Translated using Weblate (Estonian)
Currently translated at 100.0% (551 of 551 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/et/
2023-01-08 00:08:00 +01:00
Raatty 3be35991b5
Added translation using Weblate (Yue (yue_HK)) 2023-01-08 00:00:41 +01:00
Linerly 1aa0ea2cea
Translated using Weblate (Indonesian)
Currently translated at 100.0% (551 of 551 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/id/
2023-01-07 19:49:08 +01:00
Jelv a7dd62c721
Translated using Weblate (Dutch)
Currently translated at 100.0% (551 of 551 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/nl/
2023-01-07 19:49:08 +01:00
Ihor Hordiichuk 1542a4b66c
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (551 of 551 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/uk/
2023-01-07 19:49:07 +01:00
Oğuz Ersen d39bcbafde
Translated using Weblate (Turkish)
Currently translated at 100.0% (551 of 551 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/tr/
2023-01-07 19:49:07 +01:00
Krille 8513d74cc1 refactor: Same animations everywhere in app 2023-01-07 09:22:31 +01:00
Krille 22abd54176 style: Animate in out search results 2023-01-07 09:14:14 +01:00
josé m ba885ca69e
Translated using Weblate (Galician)
Currently translated at 100.0% (550 of 550 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/
2023-01-06 08:54:29 +01:00
Christian Pauly 754b919531 feat: Nicer design for abandonded DM rooms 2023-01-06 08:54:17 +01:00
Christian Pauly 8fd2d3918c chore: Fix google services patch 2023-01-06 08:47:03 +01:00
Krille d000f6e5a7 chore: Update dependencies 2023-01-05 18:21:13 +01:00
Linerly 66858cdf12
Translated using Weblate (Indonesian)
Currently translated at 100.0% (550 of 550 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/id/
2023-01-04 23:48:23 +01:00
Ihor Hordiichuk 4fb1a76060
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (550 of 550 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/uk/
2023-01-04 23:48:23 +01:00
Oğuz Ersen de23cb0f5b
Translated using Weblate (Turkish)
Currently translated at 100.0% (550 of 550 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/tr/
2023-01-04 23:48:23 +01:00
Priit Jõerüüt cf7053f338
Translated using Weblate (Estonian)
Currently translated at 100.0% (550 of 550 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/et/
2023-01-04 23:48:22 +01:00
The one with the Braid 20e26b3747 Merge branch 'braid/integration-tests' into 'main'
chore: add integration tests

See merge request famedly/fluffychat!1062
2023-01-03 19:17:06 +00:00
TheOneWithTheBraid ed075a35b6 chore: add integration tests
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-01-03 19:59:56 +01:00
Krille 6b3252b6ad docs: Update website 2023-01-03 19:13:03 +01:00
Krille 5e5132c290 chore: Change invite link textfield label 2023-01-03 18:33:58 +01:00
Krille b4df8c129d design: More clear chat background and rounded popup menu 2023-01-03 18:29:03 +01:00
Krille 37bf943ac7 chore: Follow up dark mode color 2023-01-03 18:01:53 +01:00
Krille 264f36ea59 design: Nicer navigationrail 2023-01-03 18:00:56 +01:00
Krille b894a4542a chore: Update flutter_map 2023-01-03 17:31:03 +01:00
Krille 6e9e3d05d2 chore: Remove unused translations 2023-01-03 17:23:09 +01:00
Krille d0b32e44ce Merge branch 'main' into 'main'
feat: Bring back disabling the header bar on Linux desktop

See merge request famedly/fluffychat!1064
2023-01-03 16:19:52 +00:00
Christian caa3823c26
Translated using Weblate (German)
Currently translated at 100.0% (649 of 649 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/de/
2023-01-03 12:49:18 +01:00
Michal Bedáň df33df35da
Translated using Weblate (Czech)
Currently translated at 85.6% (556 of 649 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/cs/
2023-01-03 12:49:18 +01:00
Krille 63abbf403a Merge branch 'braid/web-build-job-permissions' into 'main'
fix: permission of web builds

See merge request famedly/fluffychat!1067
2023-01-03 07:54:41 +00:00
TheOneWithTheBraid 6ff4f480ac fix: permission of web builds
Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
2023-01-03 07:40:13 +01:00
Krille fd152baa28 refactor: Stories header with futurebuilder 2023-01-02 17:12:24 +01:00
Krille 09a74bf3ee docs: More minimalistic website 2023-01-01 18:44:00 +01:00
q234rty 4cd501d00c feat: Bring back disabling the header bar on Linux desktop
(cherry picked from commit 5ca4b66157)
2022-12-31 22:43:36 +08:00
124 changed files with 68097 additions and 84525 deletions

2
.gitignore vendored
View File

@ -10,7 +10,6 @@
.buildlog/
.history
.svn/
lib/generated_plugin_registrant.dart
prime
# libolm package
@ -38,7 +37,6 @@ prime
/build/
# Web related
lib/generated_plugin_registrant.dart
docs/build/
docs/.jekyll-cache/
docs/_site/

View File

@ -1,7 +1,9 @@
variables:
FLUTTER_VERSION: 3.3.9
image: cirrusci/flutter:${FLUTTER_VERSION}
image:
name: cirrusci/flutter:${FLUTTER_VERSION}
pull_policy: if-not-present
.shared_windows_runners:
tags:
@ -16,7 +18,7 @@ stages:
code_analyze:
stage: test
script: [./scripts/code_analyze.sh]
script: [ ./scripts/code_analyze.sh ]
artifacts:
reports:
codequality: code-quality-report.json
@ -26,13 +28,13 @@ code_analyze:
widget_test:
stage: test
script: [flutter test]
script: [ flutter test ]
tags:
- docker
- famedly
# the basic integration test configuration testing FLOSS builds on Synapse
.integration_test:
integration_test:
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/integration/stable:${FLUTTER_VERSION}
stage: test
services:
@ -49,15 +51,13 @@ widget_test:
FF_NETWORK_PER_BUILD: "true"
# Tell docker CLI how to talk to Docker daemon.
DOCKER_HOST: tcp://docker:2375/
# Use the overlayfs driver for improved performance.
DOCKER_DRIVER: overlay2
# Use the btrfs driver for improved performance.
DOCKER_DRIVER: btrfs
# Disable TLS since we're running inside local network.
DOCKER_TLS_CERTDIR: ""
HOMESERVER: "docker"
HOMESERVER: docker
before_script:
# start AVD and keep running in background
- scripts/integration-start-avd.sh &
- scripts/integration-prepare-alpine.sh
- scripts/integration-prepare-host.sh
# create test user environment variables
- source scripts/integration-create-environment-variables.sh
# create Synapse instance
@ -65,31 +65,60 @@ widget_test:
# properly set the homeserver IP and create test users
- scripts/integration-prepare-homeserver.sh
script:
# start AVD and keep running in background
- scripts/integration-start-avd.sh &
- flutter pub get
- flutter test integration_test
timeout: 20m
- scrcpy --no-display --record video.mkv &
- flutter test integration_test --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:
- ffmpeg -i video.mkv -vf scale=iw/2:-2 -crf 40 -b:v 2000k -preset fast video.mp4 || true
timeout: 30m
retry: 2
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
artifacts:
when: always
paths:
- video.mp4
tags:
- docker
- famedly
# integration tests for Linux builds
### disabled because of Linux headless issues
.integration_test_linux:
extends: .integration_test
image: cirrusci/flutter:${FLUTTER_VERSION}
extends: integration_test
parallel:
matrix:
- HOMESERVER_IMPLEMENTATION:
- conduit
script:
- apk add cmake ninja gtk+3.0-dev clang pkgconf xz-dev libsecret-dev jsoncpp-dev
- apt-get update
- 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
- 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: [ ]
artifacts:
# extending the default tests to test the Google-flavored builds
.integration_test_proprietary:
extends: .integration_test
integration_test_proprietary:
extends: integration_test
parallel:
matrix:
- HOMESERVER_IMPLEMENTATION:
- conduit
script:
# start AVD and keep running in background
- scripts/integration-start-avd.sh &
- git apply ./scripts/enable-android-google-services.patch
- flutter pub get
- flutter test integration_test
- scrcpy --no-display --record video.mkv &
- flutter test integration_test --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 )
.release_mode_launches:
release_mode_launches:
parallel:
matrix:
- FLAVOR:
@ -99,9 +128,9 @@ widget_test:
stage: test
before_script:
- |
if [ "$FLAVOR" == "proprietary" ]; then
git apply ./scripts/enable-android-google-services.patch
fi
if [ "$FLAVOR" == "proprietary" ]; then
git apply ./scripts/enable-android-google-services.patch
fi
script:
# start AVD and keep running in background
- scripts/integration-start-avd.sh &
@ -115,8 +144,8 @@ widget_test:
build_web:
stage: build
before_script:
[sudo apt update && sudo apt install curl -y, ./scripts/prepare-web.sh]
script: [./scripts/build-web.sh]
[ sudo apt update && sudo apt install curl -y, ./scripts/prepare-web.sh ]
script: [ ./scripts/build-web.sh ]
artifacts:
paths:
- build/web/
@ -166,7 +195,7 @@ build_windows:
build_android_debug:
stage: build
script: [./scripts/build-android-debug.sh]
script: [ ./scripts/build-android-debug.sh ]
artifacts:
when: on_success
paths:
@ -183,7 +212,7 @@ build_android_apk:
before_script:
- git apply ./scripts/enable-android-google-services.patch
- ./scripts/prepare-android-release.sh
script: [./scripts/build-android-apk.sh]
script: [ ./scripts/build-android-apk.sh ]
artifacts:
when: on_success
paths:
@ -200,7 +229,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:
@ -267,7 +296,7 @@ build_linux_x86:
[
sudo apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install keyboard-configuration -y && 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: [./scripts/build-linux.sh]
script: [ ./scripts/build-linux.sh ]
tags:
- docker
- famedly
@ -278,9 +307,9 @@ build_linux_x86:
build_linux_arm64:
stage: build
before_script: [flutter upgrade]
script: [./scripts/build-linux.sh]
tags: [docker_arm64]
before_script: [ flutter upgrade ]
script: [ ./scripts/build-linux.sh ]
tags: [ docker_arm64 ]
only:
- main
- tags
@ -292,7 +321,7 @@ build_linux_arm64:
update_dependencies:
stage: build
needs: []
needs: [ ]
tags:
- docker
only:
@ -339,7 +368,8 @@ upload_android:
upload_web:
extends: .release
script:
- tar czf package.tar.gz -C build/web/ .
# workaround bug of Flutter engine
- tar czf package.tar.gz --ignore-failed-read -C build/web/ .
- |
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-web.tar.gz
@ -373,7 +403,7 @@ deploy_playstore:
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

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +1,25 @@
{
"@@last_modified": "2021-08-14 12:41:10.154280",
"about": "সম্পর্কে",
"@about": {
"type": "text",
"placeholders": {}
},
"accept": "স্বীকার করি",
"@accept": {
"type": "text",
"placeholders": {}
},
"acceptedTheInvitation": "{username} আমন্ত্রণ গ্রহণ করেছে",
"@acceptedTheInvitation": {
"type": "text",
"placeholders": {
"username": {}
"@@last_modified": "2021-08-14 12:41:10.154280",
"about": "সম্পর্কে",
"@about": {
"type": "text",
"placeholders": {}
},
"accept": "স্বীকার করি",
"@accept": {
"type": "text",
"placeholders": {}
},
"acceptedTheInvitation": "{username} আমন্ত্রণ গ্রহণ করেছে",
"@acceptedTheInvitation": {
"type": "text",
"placeholders": {
"username": {}
}
},
"account": "অ্যাকাউন্ট",
"@account": {
"type": "text",
"placeholders": {}
}
},
"account": "অ্যাকাউন্ট",
"@account": {
"type": "text",
"placeholders": {}
},
"accountInformation": "অ্যাকাউন্ট তথ্য",
"@accountInformation": {
"type": "text",
"placeholders": {}
}
}

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

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

@ -23,11 +23,6 @@
"type": "text",
"placeholders": {}
},
"accountInformation": "Kasutajakonto teave",
"@accountInformation": {
"type": "text",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐{username} võttis kasutusele läbiva krüptimise",
"@activatedEndToEndEncryption": {
"type": "text",
@ -45,11 +40,6 @@
"type": "text",
"placeholders": {}
},
"addNewFriend": "Lisa uus sõber",
"@addNewFriend": {
"type": "text",
"placeholders": {}
},
"admin": "Peakasutaja",
"@admin": {
"type": "text",
@ -70,11 +60,6 @@
"type": "text",
"placeholders": {}
},
"alreadyHaveAnAccount": "Sul juba on kasutajakonto olemas?",
"@alreadyHaveAnAccount": {
"type": "text",
"placeholders": {}
},
"answeredTheCall": "{senderName} vastas kõnele",
"@answeredTheCall": {
"type": "text",
@ -117,21 +102,11 @@
"type": "text",
"placeholders": {}
},
"askSSSSCache": "Krüptovõtmete puhverdamiseks palun sisesta oma turvahoidla paroolifraas või taastevõti.",
"@askSSSSCache": {
"type": "text",
"placeholders": {}
},
"askSSSSSign": "Selleks, et teist osapoolt identifitseerivat allkirja anda, palun sisesta oma turvahoidla paroolifraas või taastevõti.",
"@askSSSSSign": {
"type": "text",
"placeholders": {}
},
"askSSSSVerify": "Oma sessiooni verifitseerimiseks palun sisesta oma turvahoidla paroolifraas või taastevõti.",
"@askSSSSVerify": {
"type": "text",
"placeholders": {}
},
"askVerificationRequest": "Kas võtad vastu selle verifitseerimispalve kasutajalt {username}?",
"@askVerificationRequest": {
"type": "text",
@ -139,31 +114,11 @@
"username": {}
}
},
"audioPlayerPause": "Peata",
"@audioPlayerPause": {
"type": "text",
"placeholders": {}
},
"audioPlayerPlay": "Esita",
"@audioPlayerPlay": {
"type": "text",
"placeholders": {}
},
"authentication": "Autentimine",
"@authentication": {
"type": "text",
"placeholders": {}
},
"autoplayImages": "Esita liikuvad kleepse ja emotikone automaatselt",
"@autoplayImages": {
"type": "text",
"placeholder": {}
},
"avatarHasBeenChanged": "Tunnuspilt on muutunud",
"@avatarHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"badServerLoginTypesException": "See koduserver toetab Matrixi võrku sisselogimiseks:\n{serverVersions}\nAga see rakendus toetab vaid järgmisi võimalusi:\n{supportedVersions}",
"@badServerLoginTypesException": {
"type": "text",
@ -213,11 +168,6 @@
"type": "text",
"placeholders": {}
},
"cachedKeys": "Puhverdatud krüptovõtmed",
"@cachedKeys": {
"type": "text",
"placeholders": {}
},
"cancel": "Katkesta",
"@cancel": {
"type": "text",
@ -339,21 +289,11 @@
"username": {}
}
},
"changelog": "Muudatuste logi",
"@changelog": {
"type": "text",
"placeholders": {}
},
"changePassword": "Muuda salasõna",
"@changePassword": {
"type": "text",
"placeholders": {}
},
"changesHaveBeenSaved": "Salvestasin muudatused",
"@changesHaveBeenSaved": {
"type": "text",
"placeholders": {}
},
"changeTheHomeserver": "Muuda koduserverit",
"@changeTheHomeserver": {
"type": "text",
@ -369,11 +309,6 @@
"type": "text",
"placeholders": {}
},
"changeTheServer": "Muuda serverit",
"@changeTheServer": {
"type": "text",
"placeholders": {}
},
"changeWallpaper": "Muuda taustapilti",
"@changeWallpaper": {
"type": "text",
@ -426,11 +361,6 @@
},
"clearArchive": "Kustuta arhiiv",
"@clearArchive": {},
"clearText": "Kustuta tekst",
"@clearText": {
"type": "text",
"placeholders": {}
},
"close": "Sulge",
"@close": {
"type": "text",
@ -543,11 +473,6 @@
"type": "text",
"placeholders": {}
},
"connectionAttemptFailed": "Ühenduse loomise katse ebaõnnestus",
"@connectionAttemptFailed": {
"type": "text",
"placeholders": {}
},
"contactHasBeenInvitedToTheGroup": "Sinu kontakt on kutsutud liituma vestlusrühma",
"@contactHasBeenInvitedToTheGroup": {
"type": "text",
@ -568,11 +493,6 @@
"type": "text",
"placeholders": {}
},
"contentViewer": "Sisukuvaja",
"@contentViewer": {
"type": "text",
"placeholders": {}
},
"copiedToClipboard": "Kopeerisin lõikelauale",
"@copiedToClipboard": {
"type": "text",
@ -595,16 +515,6 @@
"error": {}
}
},
"couldNotSetAvatar": "Tunnuspildi seadmine ei õnnestunud",
"@couldNotSetAvatar": {
"type": "text",
"placeholders": {}
},
"couldNotSetDisplayname": "Kuvatava nime määramine ei õnnestunud",
"@couldNotSetDisplayname": {
"type": "text",
"placeholders": {}
},
"countParticipants": "{count} osalejat",
"@countParticipants": {
"type": "text",
@ -617,11 +527,6 @@
"type": "text",
"placeholders": {}
},
"createAccountNow": "Tee nüüd kasutajakonto",
"@createAccountNow": {
"type": "text",
"placeholders": {}
},
"createdTheChat": "💬 {username} algatas vestluse",
"@createdTheChat": {
"type": "text",
@ -639,11 +544,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningDisabled": "Risttunnustamine ei ole kasutusel",
"@crossSigningDisabled": {
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Risttunnustamine on kasutusel",
"@crossSigningEnabled": {
"type": "text",
@ -729,46 +629,21 @@
"type": "text",
"placeholders": {}
},
"deviceVerifyDescription": "Krüptimisel on mõte vaid siis, kui ka kõik vestlusega seotud seadmed on verifitseeritud.",
"@deviceVerifyDescription": {
"type": "text",
"placeholders": {}
},
"directChats": "Otsevestlused",
"@directChats": {
"type": "text",
"placeholders": {}
},
"discardPicture": "Emalda pilt",
"@discardPicture": {
"type": "text",
"placeholders": {}
},
"discover": "Avasta",
"@discover": {
"type": "text",
"placeholders": {}
},
"discoverGroups": "Otsi vestlusrühmi",
"@discoverGroups": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Kuvatav nimi on muudetud",
"@displaynameHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"donate": "Toeta",
"@donate": {
"type": "text",
"placeholders": {}
},
"dontAskAgain": "Katkesta ja ära küsi enam uuesti",
"@dontAskAgain": {
"type": "text",
"placeholders": {}
},
"downloadFile": "Laadi fail alla",
"@downloadFile": {
"type": "text",
@ -794,11 +669,6 @@
"type": "text",
"placeholders": {}
},
"editJitsiInstance": "Muuda Jitsi liidestust",
"@editJitsiInstance": {
"type": "text",
"placeholders": {}
},
"editRoomAliases": "Muuda jututoa aliast",
"@editRoomAliases": {
"type": "text",
@ -844,11 +714,6 @@
"type": "text",
"placeholders": {}
},
"enableChatBackup": "Selleks, et sa ei kaotaks ligipääsu oma vestlustele, palun võta kasutusele vestluste varundamine.",
"@enableChatBackup": {
"type": "text",
"placeholders": {}
},
"enableEmotesGlobally": "Võta emotsioonitegevuste pakid läbivalt kasutusele",
"@enableEmotesGlobally": {
"type": "text",
@ -874,21 +739,11 @@
"type": "text",
"placeholders": {}
},
"encryptionAlgorithm": "Krüptoalgoritm",
"@encryptionAlgorithm": {
"type": "text",
"placeholders": {}
},
"encryptionNotEnabled": "Krüptimine ei ole kasutusel",
"@encryptionNotEnabled": {
"type": "text",
"placeholders": {}
},
"end2endEncryptionSettings": "Läbiva krüptimise seadistused",
"@end2endEncryptionSettings": {
"type": "text",
"placeholders": {}
},
"endedTheCall": "{senderName} lõpetas kõne",
"@endedTheCall": {
"type": "text",
@ -908,11 +763,6 @@
},
"enterASpacepName": "Sisesta kogukonna nimi",
"@enterASpacepName": {},
"enterAUsername": "Sisesta kasutajanimi",
"@enterAUsername": {
"type": "text",
"placeholders": {}
},
"enterYourHomeserver": "Sisesta oma koduserveri aadress",
"@enterYourHomeserver": {
"type": "text",
@ -940,11 +790,6 @@
"type": "text",
"placeholders": {}
},
"fileSize": "Faili suurus",
"@fileSize": {
"type": "text",
"placeholders": {}
},
"fluffychat": "FluffyChat",
"@fluffychat": {
"type": "text",
@ -965,11 +810,6 @@
"type": "text",
"placeholders": {}
},
"friends": "Sõbrad",
"@friends": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Alates liitumise hetkest",
"@fromJoining": {
"type": "text",
@ -1050,11 +890,6 @@
"type": "text",
"placeholders": {}
},
"homeserverIsNotCompatible": "Koduserver ei ole ühilduv",
"@homeserverIsNotCompatible": {
"type": "text",
"placeholders": {}
},
"howOffensiveIsThisContent": "Kui solvav see sisu on?",
"@howOffensiveIsThisContent": {
"type": "text",
@ -1105,11 +940,6 @@
"type": "text",
"placeholders": {}
},
"invalidEmail": "Vigane e-posti aadress",
"@invalidEmail": {
"type": "text",
"placeholders": {}
},
"inviteContact": "Kutsu sõpru ja tuttavaid",
"@inviteContact": {
"type": "text",
@ -1153,11 +983,6 @@
"link": {}
}
},
"isDeviceKeyCorrect": "Kas järgnev seadmevõti on õige?",
"@isDeviceKeyCorrect": {
"type": "text",
"placeholders": {}
},
"isTyping": "kirjutab…",
"@isTyping": {
"type": "text",
@ -1180,11 +1005,6 @@
"type": "text",
"placeholders": {}
},
"keysMissing": "Krüptovõtmed on puudu",
"@keysMissing": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} müksas kasutaja {targetName} välja",
"@kicked": {
"type": "text",
@ -1213,11 +1033,6 @@
"localizedTimeShort": {}
}
},
"lastSeenIp": "Viimati nähtud IP-aadress",
"@lastSeenIp": {
"type": "text",
"placeholders": {}
},
"lastSeenLongTimeAgo": "Nähtud ammu aega tagasi",
"@lastSeenLongTimeAgo": {
"type": "text",
@ -1294,16 +1109,6 @@
"type": "text",
"placeholders": {}
},
"makeAModerator": "Määra moderaatoriks",
"@makeAModerator": {
"type": "text",
"placeholders": {}
},
"makeAnAdmin": "Määra peakasutajaks",
"@makeAnAdmin": {
"type": "text",
"placeholders": {}
},
"makeSureTheIdentifierIsValid": "Kontrolli, et see tunnus oleks õige",
"@makeSureTheIdentifierIsValid": {
"type": "text",
@ -1339,13 +1144,6 @@
"type": "text",
"placeholders": {}
},
"moreEvents": "{count,plural, =1{Veel 1 sündmus} other{Veel {count} sündmust}}",
"@moreEvents": {
"type": "text",
"placeholders": {
"count": {}
}
},
"muteChat": "Summuta vestlus",
"@muteChat": {
"type": "text",
@ -1386,16 +1184,6 @@
"type": "text",
"placeholders": {}
},
"noCrossSignBootstrap": "FluffyChat ei toeta hetkel risttunnustamist. Palun võta ta kasutusele Element'i vahendusel.",
"@noCrossSignBootstrap": {
"type": "text",
"placeholders": {}
},
"noDescription": "Kirjeldus puudub",
"@noDescription": {
"type": "text",
"placeholders": {}
},
"noEmotesFound": "Ühtegi emotsioonitegevust ei leidunud. 😕",
"@noEmotesFound": {
"type": "text",
@ -1419,11 +1207,6 @@
"server2": {}
}
},
"noMegolmBootstrap": "Palun võta krüptovõtmete võrgupõhine varundus kasutusele vestusrakenduse Element vahendusel.",
"@noMegolmBootstrap": {
"type": "text",
"placeholders": {}
},
"none": "Mitte midagi",
"@none": {
"type": "text",
@ -1439,21 +1222,11 @@
"type": "text",
"placeholders": {}
},
"noPublicRoomsFound": "Avalikke jututubasid ei leidunud…",
"@noPublicRoomsFound": {
"type": "text",
"placeholders": {}
},
"noRoomsFound": "Jututubasid ei leidunud…",
"@noRoomsFound": {
"type": "text",
"placeholders": {}
},
"noStatusesFound": "Pole veel ühtegi olekut leidnud.",
"@noStatusesFound": {
"type": "text",
"placeholders": {}
},
"notifications": "Teavitused",
"@notifications": {
"type": "text",
@ -1464,18 +1237,6 @@
"type": "text",
"placeholders": {}
},
"notSupportedInWeb": "See funktsionaalsus ei ole veebiliideses toetatud",
"@notSupportedInWeb": {
"type": "text",
"placeholders": {}
},
"numberSelected": "{number} valitud",
"@numberSelected": {
"type": "text",
"placeholders": {
"number": {}
}
},
"numUsersTyping": "{count} kasutajat kirjutavad…",
"@numUsersTyping": {
"type": "text",
@ -1508,11 +1269,6 @@
"type": "text",
"placeholders": {}
},
"onlineKeyBackupDisabled": "Krüptovõtmete veebipõhine varundus ei ole kasutusel",
"@onlineKeyBackupDisabled": {
"type": "text",
"placeholders": {}
},
"onlineKeyBackupEnabled": "Krüptovõtmete veebipõhine varundus on kasutusel",
"@onlineKeyBackupEnabled": {
"type": "text",
@ -1543,11 +1299,6 @@
"type": "text",
"placeholders": {}
},
"optionalAddEmail": "Sinu e-posti aadress (kui soovid lisada)",
"@optionalAddEmail": {
"type": "text",
"placeholders": {}
},
"optionalGroupName": "(Kui soovid) Vestlusrühma nimi",
"@optionalGroupName": {
"type": "text",
@ -1563,11 +1314,6 @@
"type": "text",
"placeholders": {}
},
"participatingUserDevices": "Kaasatud kasutajate seadmed",
"@participatingUserDevices": {
"type": "text",
"placeholders": {}
},
"passphraseOrKey": "paroolifraas või taastevõti",
"@passphraseOrKey": {
"type": "text",
@ -1645,11 +1391,6 @@
"type": "text",
"placeholders": {}
},
"pleaseEnterSecurityKey": "Palun sisesta oma turvavõti:",
"@pleaseEnterSecurityKey": {
"type": "text",
"placeholders": {}
},
"pleaseEnterYourPassword": "Palun sisesta oma salasõna",
"@pleaseEnterYourPassword": {
"type": "text",
@ -1675,26 +1416,11 @@
"type": "text",
"placeholders": {}
},
"publicGroups": "Avalikud vestlusrühmad",
"@publicGroups": {
"type": "text",
"placeholders": {}
},
"publicKey": "Avalik võti",
"@publicKey": {
"type": "text",
"placeholders": {}
},
"publicRooms": "Avalikud jututoad",
"@publicRooms": {
"type": "text",
"placeholders": {}
},
"publicSpace": "Avalik kogukond",
"@publicSpace": {
"type": "text",
"placeholders": {}
},
"pushRules": "Tõukereeglid",
"@pushRules": {
"type": "text",
@ -1771,11 +1497,6 @@
"type": "text",
"placeholders": {}
},
"removeMessage": "Eemalda sõnum",
"@removeMessage": {
"type": "text",
"placeholders": {}
},
"removeYourAvatar": "Kustuta oma tunnuspilt",
"@removeYourAvatar": {
"type": "text",
@ -1806,16 +1527,6 @@
"type": "text",
"placeholders": {}
},
"requestToReadOlderMessages": "Palu õigust lugeda vanu sõnumeid",
"@requestToReadOlderMessages": {
"type": "text",
"placeholders": {}
},
"revokeAllPermissions": "Tühista kõik õigused",
"@revokeAllPermissions": {
"type": "text",
"placeholders": {}
},
"roomHasBeenUpgraded": "Jututoa vesrioon on uuendatud",
"@roomHasBeenUpgraded": {
"type": "text",
@ -1831,48 +1542,21 @@
"type": "text",
"placeholders": {}
},
"savedFileAs": "Salvestasin faili nimega {filename}",
"@savedFileAs": {
"type": "text",
"placeholders": {
"filename": {}
}
},
"saveFile": "Salvesta fail",
"@saveFile": {
"type": "text",
"placeholders": {}
},
"saveFileToFolder": "Salvesta fail sellesse kausta",
"@saveFileToFolder": {
"type": "text",
"placeholders": {}
},
"search": "Otsi",
"@search": {
"type": "text",
"placeholders": {}
},
"searchForAChat": "Otsi vestlust",
"@searchForAChat": {
"type": "text",
"placeholders": {}
},
"security": "Turvalisus",
"@security": {
"type": "text",
"placeholders": {}
},
"securityKey": "Turvavõti",
"@securityKey": {
"type": "text",
"placeholders": {}
},
"securityKeyLost": "Kas kaotasid turvavõtme?",
"@securityKeyLost": {
"type": "text",
"placeholders": {}
},
"seenByUser": "Sõnumit nägi {username}",
"@seenByUser": {
"type": "text",
@ -1915,11 +1599,6 @@
"type": "text",
"placeholders": {}
},
"sendBugReports": "Luba veateadete saatmist sentry.io vahendusel",
"@sendBugReports": {
"type": "text",
"placeholders": {}
},
"sendFile": "Saada fail",
"@sendFile": {
"type": "text",
@ -1992,21 +1671,6 @@
"senderName": {}
}
},
"sentryInfo": "Teave sinu privaatsuse kohta: https://sentry.io/security/",
"@sentryInfo": {
"type": "text",
"placeholders": {}
},
"sessionVerified": "Sessioon on verifitseeritud",
"@sessionVerified": {
"type": "text",
"placeholders": {}
},
"setAProfilePicture": "Seadista profiilipilt",
"@setAProfilePicture": {
"type": "text",
"placeholders": {}
},
"setAsCanonicalAlias": "Määra põhinimeks",
"@setAsCanonicalAlias": {
"type": "text",
@ -2079,11 +1743,6 @@
"type": "text",
"placeholders": {}
},
"soundVibrationLedColor": "Heli, värin, LED-värvid",
"@soundVibrationLedColor": {
"type": "text",
"placeholders": {}
},
"sourceCode": "Lähtekood",
"@sourceCode": {
"type": "text",
@ -2106,11 +1765,6 @@
"senderName": {}
}
},
"startYourFirstChat": "Alusta oma esimest vestlust kohe nüüd 🙂\n- klõpsi nuppu „Uus vestlus“\n- skaneeri teise osapoole QR-koodi\n- ja lase vestlusel kulgeda",
"@startYourFirstChat": {
"type": "text",
"placeholders": {}
},
"status": "Olek",
"@status": {
"type": "text",
@ -2141,21 +1795,6 @@
"type": "text",
"placeholders": {}
},
"tapOnDeviceToVerify": "Verifitseerimiseks klõpsi seadme nime",
"@tapOnDeviceToVerify": {
"type": "text",
"placeholders": {}
},
"tapToShowImage": "Pildi vaatamiseks klõpsi",
"@tapToShowImage": {
"type": "text",
"placeholders": {}
},
"tapToShowMenu": "Menüü kuvamiseks puuduta",
"@tapToShowMenu": {
"type": "text",
"placeholders": {}
},
"theyDontMatch": "Nad ei klapi omavahel",
"@theyDontMatch": {
"type": "text",
@ -2176,16 +1815,6 @@
"type": "text",
"placeholders": {}
},
"timeOfDay": "{hours24}:{minutes}",
"@timeOfDay": {
"type": "text",
"placeholders": {
"hours12": {},
"hours24": {},
"minutes": {},
"suffix": {}
}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -2262,16 +1891,6 @@
"type": {}
}
},
"unknownSessionVerify": "Tundmatu sessioon, palun tee talle verifitseerimine",
"@unknownSessionVerify": {
"type": "text",
"placeholders": {}
},
"unlockChatBackup": "Krüpti lahti oma vestluste varukoopia",
"@unlockChatBackup": {
"type": "text",
"placeholders": {}
},
"unmuteChat": "Lõpeta vestluse vaigistamine",
"@unmuteChat": {
"type": "text",
@ -2289,18 +1908,6 @@
"unreadCount": {}
}
},
"unreadMessages": "{unreadEvents, plural, =1{1 lugemata sõnum} other{{unreadEvents} lugemata sõnumit}}",
"@unreadMessages": {
"type": "text",
"placeholders": {
"unreadEvents": {}
}
},
"useAmoledTheme": "Kas kasutame AMOLED-tehnoloogiaga ühilduvaid värve?",
"@useAmoledTheme": {
"type": "text",
"placeholders": {}
},
"userAndOthersAreTyping": "{username} ja {count} muud kirjutavad…",
"@userAndOthersAreTyping": {
"type": "text",
@ -2336,11 +1943,6 @@
"type": "text",
"placeholders": {}
},
"userNotVerified": "Kasutaja on verifitseerimata",
"@userNotVerified": {
"type": "text",
"placeholders": {}
},
"userSentUnknownEvent": "{username} saatis {type} sündmuse",
"@userSentUnknownEvent": {
"type": "text",
@ -2349,36 +1951,16 @@
"type": {}
}
},
"userUnknownVerification": "Kasutaja verifitseerimisolek on teadmata",
"@userUnknownVerification": {
"type": "text",
"placeholders": {}
},
"userVerified": "Kasutaja on verifitseeritud",
"@userVerified": {
"type": "text",
"placeholders": {}
},
"verified": "Verifitseeritud",
"@verified": {
"type": "text",
"placeholders": {}
},
"verifiedSession": "Sessiooni verifitseerimine õnnestus!",
"@verifiedSession": {
"type": "text",
"placeholders": {}
},
"verify": "Verifitseeri",
"@verify": {
"type": "text",
"placeholders": {}
},
"verifyManual": "Verifitseeri käsitsi",
"@verifyManual": {
"type": "text",
"placeholders": {}
},
"verifyStart": "Alusta verifitseerimist",
"@verifyStart": {
"type": "text",
@ -2394,11 +1976,6 @@
"type": "text",
"placeholders": {}
},
"verifyUser": "Verifitseeri kasutajat",
"@verifyUser": {
"type": "text",
"placeholders": {}
},
"videoCall": "Videokõne",
"@videoCall": {
"type": "text",
@ -2449,21 +2026,11 @@
"type": "text",
"placeholders": {}
},
"warningEncryptionInBeta": "Läbiv krüptimine on parasjagu beetatestimise faasis! Kasuta seda omal vastutusel!",
"@warningEncryptionInBeta": {
"type": "text",
"placeholders": {}
},
"wednesday": "Kolmapäev",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"welcomeText": "Tere tulemast kasutama kõige vahvamat sõnumiklienti Matrix'i võrgus.",
"@welcomeText": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Me saatsime sulle e-kirja",
"@weSentYouAnEmail": {
"type": "text",
@ -2529,43 +2096,11 @@
"type": "text",
"placeholders": {}
},
"yourChatsAreBeingSynced": "Sünkroniseerin sinu vestlusi…",
"@yourChatsAreBeingSynced": {
"type": "text",
"placeholders": {}
},
"yourOwnUsername": "Sinu oma kasutajanimi",
"@yourOwnUsername": {
"type": "text",
"placeholders": {}
},
"yourPublicKey": "Sinu avalik võti",
"@yourPublicKey": {
"type": "text",
"placeholders": {}
},
"youWillBeConnectedTo": "Sinu ühendus on koduserveriga {homeserver}",
"@youWillBeConnectedTo": {
"type": "text",
"placeholders": {
"homeserver": {}
}
},
"zoomIn": "Suumi sisse",
"@zoomIn": {
"type": "text",
"placeholders": {}
},
"zoomOut": "Suumi välja",
"@zoomOut": {
"type": "text",
"placeholders": {}
},
"chatHasBeenRemovedFromThisSpace": "Eemaldasime vestluse kogukonnast",
"@chatHasBeenRemovedFromThisSpace": {
"type": "text",
"placeholders": {}
},
"chatHasBeenAddedToThisSpace": "Lisasime vestluse kogukonda",
"@chatHasBeenAddedToThisSpace": {},
"addToSpace": "Lisa kogukonda",
@ -2576,18 +2111,12 @@
"@typeInInviteLinkManually": {},
"shareYourInviteLink": "Jaga oma kutselinki",
"@shareYourInviteLink": {},
"createNewChatExplaination": "Lihtsalt skaneeri QR-koodi või kui te pole kõrvuti, siis jaga kutse linki.",
"@createNewChatExplaination": {},
"sendOnEnter": "Saada sõnum sisestusklahvi vajutusel",
"@sendOnEnter": {},
"homeserver": "Koduserver",
"@homeserver": {},
"serverRequiresEmail": "See koduserver eeldab registreerimisel kasutatava e-postiaadressi kinnitamist.",
"@serverRequiresEmail": {},
"newUsernameDescription": "Sinu Matrix'i kasutajatunnus saab olema vormingus @kasutajanimi:koduserver",
"@newUsernameDescription": {},
"newPasswordDescription": "Selleks, et saaksid vajadusel oma salasõna taastada, peaksid hiljem lisama oma kasutajakontole e-posti aadressi.",
"@newPasswordDescription": {},
"enableMultiAccounts": "(KATSELINE) Pruugi selles seadmes mitut Matrix'i kasutajakontot",
"@enableMultiAccounts": {},
"bundleName": "Köite nimi",
@ -2604,14 +2133,8 @@
"@oneClientLoggedOut": {},
"link": "Link",
"@link": {},
"setupChatBackup": "Võta kasutusele vestluste varundus",
"@setupChatBackup": {},
"iWroteDownTheKey": "Panin krüptovõtme kirja",
"@iWroteDownTheKey": {},
"yourChatBackupHasBeenSetUp": "Sinu vestluste varundus on seadistatud.",
"@yourChatBackupHasBeenSetUp": {},
"setupChatBackupDescription": "Et sinu sõnumid ei oleks võõrastele loetavad, me genereerisime taastamiseks mõeldud krüptovõtme.\nPalun hoia seda turvalises kohas, näiteks salasõnade halduris.",
"@setupChatBackupDescription": {},
"yourUserId": "Sinu kasutajatunnus:",
"@yourUserId": {},
"unverified": "Verifitseerimata",
@ -2645,16 +2168,8 @@
"@loginWithOneClick": {},
"removeFromSpace": "Eemalda kogukonnast",
"@removeFromSpace": {},
"removeFromSpaceDescription": "Järgnevaga eemaldad antud vestluse sellest kogukonnast. Vestlus on jätkuvalt leitav vaatest „Kõik vestlused“.",
"@removeFromSpaceDescription": {},
"start": "Alusta",
"@start": {},
"setupChatBackupNow": "Seadista oma vestluste varundus",
"@setupChatBackupNow": {},
"saveTheSecurityKeyNow": "Salvesta turvavõti nüüd",
"@saveTheSecurityKeyNow": {},
"pleaseEnterSecurityKeyDescription": "Kui soovid vestluste varundust kasutada, siis palun sisesta oma turvavõti, mille me varasemas sessioonis tegime. Turvavõti EI OLE sama kui salasõna.",
"@pleaseEnterSecurityKeyDescription": {},
"commandHint_discardsession": "Loobu sessioonist",
"@commandHint_discardsession": {
"type": "text",
@ -2697,10 +2212,6 @@
"@reportUser": {},
"openChat": "Ava vestlus",
"@openChat": {},
"editIntegrations": "Muuda vidinaid ja lõiminguid",
"@editIntegrations": {},
"integrationsNotImplemented": "Vidinate ja lõimingute muutmine pole veel võimalik.",
"@integrationsNotImplemented": {},
"matrixWidgets": "Matrix'i vidinad",
"@matrixWidgets": {},
"dismiss": "Loobu",
@ -2723,8 +2234,6 @@
"@voiceCall": {},
"confirmEventUnpin": "Kas sa oled kindel, et tahad klammerdatud sündmuse eemaldada?",
"@confirmEventUnpin": {},
"pinnedEventsError": "Viga klammerdatud sõnumite laadimisel",
"@pinnedEventsError": {},
"pinMessage": "Klammerda sõnum jututuppa",
"@pinMessage": {},
"videoCallsBetaWarning": "Palun arvesta, et videokõned on veel beetajärgus. Nad ei pruugi veel toimida kõikidel platvormidel korrektselt.",
@ -2857,16 +2366,12 @@
"@unsubscribeStories": {},
"yourStory": "Sinu jutustused",
"@yourStory": {},
"showSpaces": "Näita kogukondade loendit",
"@showSpaces": {},
"noEmailWarning": "Palun sisesta korrektne e-posti aadress. Vastasel juhul ei saa te oma salasõna taastada. Kui te seda ei soovi, siis jätkamiseks klõpsige nuppu uuesti.",
"@noEmailWarning": {},
"pleaseEnterRecoveryKey": "Palun sisesta oma taastevõti:",
"@pleaseEnterRecoveryKey": {},
"recoveryKey": "Taastevõti",
"@recoveryKey": {},
"saveTheRecoveryKeyNow": "Salvesta taastevõti nüüd",
"@saveTheRecoveryKeyNow": {},
"users": "Kasutajad",
"@users": {},
"enableAutoBackups": "Võta kasutusele automaatne varundus",
@ -2905,8 +2410,6 @@
"@hydrateTor": {},
"hydrateTorLong": "Kui viimati TOR'i võrku kasutasid, siis kas sa eksportisid oma sessiooni andmed? Kui jah, siis impordi nad mugavasti ja jätka suhtlemist.",
"@hydrateTorLong": {},
"advanced": "Lisaseadistused",
"@advanced": {},
"indexedDbErrorTitle": "Brauseri privaatse akna kasutamisega seotud asjaolud",
"@indexedDbErrorTitle": {},
"dehydrateWarning": "Seda tegevust ei saa tagasi pöörata. Palun kontrolli, et sa oled varukoopia turvaliselt salvestanud.",
@ -2921,19 +2424,8 @@
"@user": {},
"custom": "Kohandatud",
"@custom": {},
"numberRoomMembers": "{number} liiget",
"@numberRoomMembers": {
"type": "number",
"placeholders": {
"number": {}
}
},
"suggestedRooms": "Otsi jututube selles kogukonnas",
"@suggestedRooms": {},
"updateNow": "Alusta uuendamist taustal",
"@updateNow": {},
"allSuggestedRoomsJoined": "Sa liitusid kõikide soovitatud jututubadega",
"@allSuggestedRoomsJoined": {},
"updateAvailable": "On olemas FluffyChat'i uuendus",
"@updateAvailable": {},
"confirmMatrixId": "Konto kustutamiseks palun kinnitage oma Matrix'i ID.",
@ -3039,5 +2531,13 @@
"deviceKeys": "Seadme võtmed:",
"@deviceKeys": {},
"newSpaceDescription": "Kogukonnad võimaldavad sul koondada erinevaid vestlusi ning korraldada avalikku või privaatset ühistegevust.",
"@newSpaceDescription": {}
"@newSpaceDescription": {},
"noSearchResult": "Sobivaid otsingutulemusi ei leidu.",
"@noSearchResult": {},
"enterInviteLinkOrMatrixId": "Sisesta kutse link või Matrix ID...",
"@enterInviteLinkOrMatrixId": {},
"letsStart": "Sõidame!",
"@letsStart": {},
"reopenChat": "Alusta vestlust uuesti",
"@reopenChat": {}
}

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

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

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
{}
{}

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

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

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

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

@ -1,155 +1,155 @@
{
"@@last_modified": "2021-08-14 12:41:09.940318",
"copiedToClipboard": "Copiada para a área de transferência",
"@copiedToClipboard": {
"type": "text",
"placeholders": {}
},
"login": "Iniciar sessão",
"@login": {
"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",
"placeholders": {}
},
"admin": "Admin",
"@admin": {
"type": "text",
"placeholders": {}
},
"areYouSure": "Tens a certeza?",
"@areYouSure": {
"type": "text",
"placeholders": {}
},
"notifications": "Notificações",
"@notifications": {
"type": "text",
"placeholders": {}
},
"account": "Conta",
"@account": {
"type": "text",
"placeholders": {}
},
"cancel": "Cancelar",
"@cancel": {
"type": "text",
"placeholders": {}
},
"delete": "Eliminar",
"@delete": {
"type": "text",
"placeholders": {}
},
"dateAndTimeOfDay": "{date}, {timeOfDay}",
"@dateAndTimeOfDay": {
"type": "text",
"placeholders": {
"date": {},
"timeOfDay": {}
"@@last_modified": "2021-08-14 12:41:09.940318",
"copiedToClipboard": "Copiada para a área de transferência",
"@copiedToClipboard": {
"type": "text",
"placeholders": {}
},
"login": "Iniciar sessão",
"@login": {
"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",
"placeholders": {}
},
"admin": "Admin",
"@admin": {
"type": "text",
"placeholders": {}
},
"areYouSure": "Tens a certeza?",
"@areYouSure": {
"type": "text",
"placeholders": {}
},
"notifications": "Notificações",
"@notifications": {
"type": "text",
"placeholders": {}
},
"account": "Conta",
"@account": {
"type": "text",
"placeholders": {}
},
"cancel": "Cancelar",
"@cancel": {
"type": "text",
"placeholders": {}
},
"delete": "Eliminar",
"@delete": {
"type": "text",
"placeholders": {}
},
"dateAndTimeOfDay": "{date}, {timeOfDay}",
"@dateAndTimeOfDay": {
"type": "text",
"placeholders": {
"date": {},
"timeOfDay": {}
}
},
"dateWithYear": "{day}-{month}-{year}",
"@dateWithYear": {
"type": "text",
"placeholders": {
"year": {},
"month": {},
"day": {}
}
},
"help": "Ajuda",
"@help": {
"type": "text",
"placeholders": {}
},
"messages": "Mensagens",
"@messages": {
"type": "text",
"placeholders": {}
},
"reason": "Razão",
"@reason": {
"type": "text",
"placeholders": {}
},
"privacy": "Privacidade",
"@privacy": {
"type": "text",
"placeholders": {}
},
"openCamera": "Abrir câmara",
"@openCamera": {
"type": "text",
"placeholders": {}
},
"settings": "Configurações",
"@settings": {
"type": "text",
"placeholders": {}
},
"tuesday": "terça-feira",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"logout": "Terminar sessão",
"@logout": {
"type": "text",
"placeholders": {}
},
"search": "Pesquisar",
"@search": {
"type": "text",
"placeholders": {}
},
"sunday": "domingo",
"@sunday": {
"type": "text",
"placeholders": {}
},
"users": "Utilizadores",
"@users": {},
"close": "Fechar",
"@close": {
"type": "text",
"placeholders": {}
},
"dateWithoutYear": "{day}-{month}",
"@dateWithoutYear": {
"type": "text",
"placeholders": {
"month": {},
"day": {}
}
},
"friday": "sexta-feira",
"@friday": {
"type": "text",
"placeholders": {}
},
"thursday": "quinta-feira",
"@thursday": {
"type": "text",
"placeholders": {}
}
},
"dateWithYear": "{day}-{month}-{year}",
"@dateWithYear": {
"type": "text",
"placeholders": {
"year": {},
"month": {},
"day": {}
}
},
"help": "Ajuda",
"@help": {
"type": "text",
"placeholders": {}
},
"messages": "Mensagens",
"@messages": {
"type": "text",
"placeholders": {}
},
"reason": "Razão",
"@reason": {
"type": "text",
"placeholders": {}
},
"privacy": "Privacidade",
"@privacy": {
"type": "text",
"placeholders": {}
},
"openCamera": "Abrir câmara",
"@openCamera": {
"type": "text",
"placeholders": {}
},
"settings": "Configurações",
"@settings": {
"type": "text",
"placeholders": {}
},
"tuesday": "terça-feira",
"@tuesday": {
"type": "text",
"placeholders": {}
},
"logout": "Terminar sessão",
"@logout": {
"type": "text",
"placeholders": {}
},
"search": "Pesquisar",
"@search": {
"type": "text",
"placeholders": {}
},
"sunday": "domingo",
"@sunday": {
"type": "text",
"placeholders": {}
},
"users": "Utilizadores",
"@users": {},
"close": "Fechar",
"@close": {
"type": "text",
"placeholders": {}
},
"dateWithoutYear": "{day}-{month}",
"@dateWithoutYear": {
"type": "text",
"placeholders": {
"month": {},
"day": {}
}
},
"friday": "sexta-feira",
"@friday": {
"type": "text",
"placeholders": {}
},
"thursday": "quinta-feira",
"@thursday": {
"type": "text",
"placeholders": {}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,182 +1,147 @@
{
"@@last_modified": "2021-08-14 12:41:09.918296",
"about": "Despre",
"@about": {
"type": "text",
"placeholders": {}
},
"accept": "Accept",
"@accept": {
"type": "text",
"placeholders": {}
},
"acceptedTheInvitation": "{username} a aceptat invitați",
"@acceptedTheInvitation": {
"type": "text",
"placeholders": {
"username": {}
"@@last_modified": "2021-08-14 12:41:09.918296",
"about": "Despre",
"@about": {
"type": "text",
"placeholders": {}
},
"accept": "Accept",
"@accept": {
"type": "text",
"placeholders": {}
},
"acceptedTheInvitation": "{username} a aceptat invitați",
"@acceptedTheInvitation": {
"type": "text",
"placeholders": {
"username": {}
}
},
"account": "Cont",
"@account": {
"type": "text",
"placeholders": {}
},
"activatedEndToEndEncryption": "{username} a activat criptarea end-to-end",
"@activatedEndToEndEncryption": {
"type": "text",
"placeholders": {
"username": {}
}
},
"addGroupDescription": "Adaugă o descriere de",
"@addGroupDescription": {
"type": "text",
"placeholders": {}
},
"admin": "Administrator",
"@admin": {
"type": "text",
"placeholders": {}
},
"alias": "poreclă",
"@alias": {
"type": "text",
"placeholders": {}
},
"answeredTheCall": "{sendername} a acceptat apelul",
"@answeredTheCall": {
"type": "text",
"placeholders": {
"senderName": {}
}
},
"anyoneCanJoin": "Oricine se poate alătura",
"@anyoneCanJoin": {
"type": "text",
"placeholders": {}
},
"archive": "Arhivă",
"@archive": {
"type": "text",
"placeholders": {}
},
"archivedRoom": "Grup arhivat",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Vizitatorii \"guest\" se pot alătura",
"@areGuestsAllowedToJoin": {
"type": "text",
"placeholders": {}
},
"areYouSure": "Ești sigur?",
"@areYouSure": {
"type": "text",
"placeholders": {}
},
"askSSSSSign": "Pentru a putea conecta cealaltă persoană, te rog introdu parola sau cheia ta de recuperare.",
"@askSSSSSign": {
"type": "text",
"placeholders": {}
},
"askVerificationRequest": "Accepți cererea de verificare de la {username}?",
"@askVerificationRequest": {
"type": "text",
"placeholders": {
"username": {}
}
},
"banFromChat": "Interzis din conversație",
"@banFromChat": {
"type": "text",
"placeholders": {}
},
"banned": "Interzis",
"@banned": {
"type": "text",
"placeholders": {}
},
"bannedUser": "{username} a interzis pe {targetName}",
"@bannedUser": {
"type": "text",
"placeholders": {
"username": {},
"targetName": {}
}
},
"blockDevice": "Blochează dispozitiv",
"@blockDevice": {
"type": "text",
"placeholders": {}
},
"cancel": "Anulează",
"@cancel": {
"type": "text",
"placeholders": {}
},
"changeDeviceName": "Schimbă numele dispozitiv",
"@changeDeviceName": {
"type": "text",
"placeholders": {}
},
"changedTheChatAvatar": "{username} a schimbat poza conversați",
"@changedTheChatAvatar": {
"type": "text",
"placeholders": {
"username": {}
}
},
"changedTheChatDescriptionTo": "{username} a schimbat descrierea grupului în '{description}'",
"@changedTheChatDescriptionTo": {
"type": "text",
"placeholders": {
"username": {},
"description": {}
}
},
"changedTheChatNameTo": "{username} a schimbat porecla în '{chatname}'",
"@changedTheChatNameTo": {
"type": "text",
"placeholders": {
"username": {},
"chatname": {}
}
}
},
"account": "Cont",
"@account": {
"type": "text",
"placeholders": {}
},
"accountInformation": "Informații despre cont",
"@accountInformation": {
"type": "text",
"placeholders": {}
},
"activatedEndToEndEncryption": "{username} a activat criptarea end-to-end",
"@activatedEndToEndEncryption": {
"type": "text",
"placeholders": {
"username": {}
}
},
"addGroupDescription": "Adaugă o descriere de",
"@addGroupDescription": {
"type": "text",
"placeholders": {}
},
"admin": "Administrator",
"@admin": {
"type": "text",
"placeholders": {}
},
"alias": "poreclă",
"@alias": {
"type": "text",
"placeholders": {}
},
"alreadyHaveAnAccount": "Ai deja un cont?",
"@alreadyHaveAnAccount": {
"type": "text",
"placeholders": {}
},
"answeredTheCall": "{sendername} a acceptat apelul",
"@answeredTheCall": {
"type": "text",
"placeholders": {
"senderName": {}
}
},
"anyoneCanJoin": "Oricine se poate alătura",
"@anyoneCanJoin": {
"type": "text",
"placeholders": {}
},
"archive": "Arhivă",
"@archive": {
"type": "text",
"placeholders": {}
},
"archivedRoom": "Grup arhivat",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Vizitatorii \"guest\" se pot alătura",
"@areGuestsAllowedToJoin": {
"type": "text",
"placeholders": {}
},
"areYouSure": "Ești sigur?",
"@areYouSure": {
"type": "text",
"placeholders": {}
},
"askSSSSCache": "Te rog introdu parola ta sau cheile de recuparare pentru a depozita cheile.",
"@askSSSSCache": {
"type": "text",
"placeholders": {}
},
"askSSSSSign": "Pentru a putea conecta cealaltă persoană, te rog introdu parola sau cheia ta de recuperare.",
"@askSSSSSign": {
"type": "text",
"placeholders": {}
},
"askSSSSVerify": "Te rog introdu parola sau cheia ta de recuperare pentru a-ți verifica sesiunea.",
"@askSSSSVerify": {
"type": "text",
"placeholders": {}
},
"askVerificationRequest": "Accepți cererea de verificare de la {username}?",
"@askVerificationRequest": {
"type": "text",
"placeholders": {
"username": {}
}
},
"authentication": "Autentificare",
"@authentication": {
"type": "text",
"placeholders": {}
},
"avatarHasBeenChanged": "Image de profil schimbată",
"@avatarHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"banFromChat": "Interzis din conversație",
"@banFromChat": {
"type": "text",
"placeholders": {}
},
"banned": "Interzis",
"@banned": {
"type": "text",
"placeholders": {}
},
"bannedUser": "{username} a interzis pe {targetName}",
"@bannedUser": {
"type": "text",
"placeholders": {
"username": {},
"targetName": {}
}
},
"blockDevice": "Blochează dispozitiv",
"@blockDevice": {
"type": "text",
"placeholders": {}
},
"cachedKeys": "Chei salvate",
"@cachedKeys": {
"type": "text",
"placeholders": {}
},
"cancel": "Anulează",
"@cancel": {
"type": "text",
"placeholders": {}
},
"changeDeviceName": "Schimbă numele dispozitiv",
"@changeDeviceName": {
"type": "text",
"placeholders": {}
},
"changedTheChatAvatar": "{username} a schimbat poza conversați",
"@changedTheChatAvatar": {
"type": "text",
"placeholders": {
"username": {}
}
},
"changedTheChatDescriptionTo": "{username} a schimbat descrierea grupului în '{description}'",
"@changedTheChatDescriptionTo": {
"type": "text",
"placeholders": {
"username": {},
"description": {}
}
},
"changedTheChatNameTo": "{username} a schimbat porecla în '{chatname}'",
"@changedTheChatNameTo": {
"type": "text",
"placeholders": {
"username": {},
"chatname": {}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,374 +1,292 @@
{
"@@last_modified": "2021-08-14 12:41:09.895217",
"about": "පිළිබඳව",
"@about": {
"type": "text",
"placeholders": {}
},
"accept": "පිළිගන්න",
"@accept": {
"type": "text",
"placeholders": {}
},
"account": "ගිණුම",
"@account": {
"type": "text",
"placeholders": {}
},
"accountInformation": "ගිණුමේ තොරතුරු",
"@accountInformation": {
"type": "text",
"placeholders": {}
},
"addEmail": "වි-තැපෑල එකතු කරන්න",
"@addEmail": {
"type": "text",
"placeholders": {}
},
"admin": "පරිපාලක",
"@admin": {
"type": "text",
"placeholders": {}
},
"allChats": "සියලුම සංවාද",
"@allChats": {
"type": "text",
"placeholders": {}
},
"alreadyHaveAnAccount": "දැනටමත් ගිණුමක් තිබේද?",
"@alreadyHaveAnAccount": {
"type": "text",
"placeholders": {}
},
"anyoneCanJoin": "ඕනෑම කෙනෙකුට එක්විය හැකිය",
"@anyoneCanJoin": {
"type": "text",
"placeholders": {}
},
"archive": "සංරක්ෂිතය",
"@archive": {
"type": "text",
"placeholders": {}
},
"archivedRoom": "සංරක්ෂිත කාමරය",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "ආගන්තුක පරිශීලකයින්ට එක්වීමට අවසර තිබේද",
"@areGuestsAllowedToJoin": {
"type": "text",
"placeholders": {}
},
"areYouSure": "ඔබට විශ්වාසද?",
"@areYouSure": {
"type": "text",
"placeholders": {}
},
"areYouSureYouWantToLogout": "ඔබට නික්මීමට අවශ්‍ය බව විශ්වාසද?",
"@areYouSureYouWantToLogout": {
"type": "text",
"placeholders": {}
},
"audioPlayerPlay": "ධාවනය",
"@audioPlayerPlay": {
"type": "text",
"placeholders": {}
},
"blockDevice": "උපාංගය අවහිර කරන්න",
"@blockDevice": {
"type": "text",
"placeholders": {}
},
"cachedKeys": "යතුරු නිහිතගතයි",
"@cachedKeys": {
"type": "text",
"placeholders": {}
},
"cancel": "අවලංගු කරන්න",
"@cancel": {
"type": "text",
"placeholders": {}
},
"changeDeviceName": "උපාංගයේ නම වෙනස් කරන්න",
"@changeDeviceName": {
"type": "text",
"placeholders": {}
},
"changePassword": "මුරපදය වෙනස් කරන්න",
"@changePassword": {
"type": "text",
"placeholders": {}
},
"chat": "සංවාදය",
"@chat": {
"type": "text",
"placeholders": {}
},
"chatBackup": "සංවාද උපස්ථය",
"@chatBackup": {
"type": "text",
"placeholders": {}
},
"chatDetails": "සංවාදයේ විස්තර",
"@chatDetails": {
"type": "text",
"placeholders": {}
},
"chats": "සංවාද",
"@chats": {
"type": "text",
"placeholders": {}
},
"chooseAStrongPassword": "ශක්තිමත් මුරපදයක් තෝරන්න",
"@chooseAStrongPassword": {
"type": "text",
"placeholders": {}
},
"chooseAUsername": "පරිශීලක නාමයක් තෝරන්න",
"@chooseAUsername": {
"type": "text",
"placeholders": {}
},
"clearArchive": "සංරක්ෂිතය හිස් කරන්න",
"@clearArchive": {},
"close": "වසන්න",
"@close": {
"type": "text",
"placeholders": {}
},
"commandHint_join": "දී ඇති කාමරයට එක්වන්න",
"@commandHint_join": {
"type": "text",
"description": "Usage hint for the command /join"
},
"commandHint_leave": "මෙම කාමරය හැරයන්න",
"@commandHint_leave": {
"type": "text",
"description": "Usage hint for the command /leave"
},
"commandInvalid": "විධානය වලංගු නොවේ",
"@commandInvalid": {
"type": "text"
},
"commandMissing": "{{command} විධානයක් නොවේ.",
"@commandMissing": {
"type": "text",
"placeholders": {
"command": {}
"@@last_modified": "2021-08-14 12:41:09.895217",
"about": "පිළිබඳව",
"@about": {
"type": "text",
"placeholders": {}
},
"description": "State that {command} is not a valid /command."
},
"compareEmojiMatch": "සසඳා බලා පහත දැක්වෙන ඉමොජි අනෙක් උපාංගයට නිසැකවම ගැලපෙන බවට වග බලා ගන්න:",
"@compareEmojiMatch": {
"type": "text",
"placeholders": {}
},
"compareNumbersMatch": "සංසන්දනය කර පහත දැක්වෙන අංක අනෙක් උපාංගට නිසැකව ගැලපෙන බවට වග බලා ගන්න:",
"@compareNumbersMatch": {
"type": "text",
"placeholders": {}
},
"confirm": "තහවුරු කරන්න",
"@confirm": {
"type": "text",
"placeholders": {}
},
"connect": "සබඳින්න",
"@connect": {
"type": "text",
"placeholders": {}
},
"connectionAttemptFailed": "සබැඳීමේ උත්සාහය අසාර්ථකයි",
"@connectionAttemptFailed": {
"type": "text",
"placeholders": {}
},
"contactHasBeenInvitedToTheGroup": "සමූහය වෙත සබඳතාවයකට ආරාධනා කර ඇත",
"@contactHasBeenInvitedToTheGroup": {
"type": "text",
"placeholders": {}
},
"copy": "පිටපත්",
"@copy": {
"type": "text",
"placeholders": {}
},
"create": "සාදන්න",
"@create": {
"type": "text",
"placeholders": {}
},
"createAccountNow": "දැන් ගිණුමක් සාදන්න",
"@createAccountNow": {
"type": "text",
"placeholders": {}
},
"createNewGroup": "නව සමූහයක් සාදන්න",
"@createNewGroup": {
"type": "text",
"placeholders": {}
},
"donate": "පරිත්‍යාග",
"@donate": {
"type": "text",
"placeholders": {}
},
"encryption": "සංකේතාංකනය",
"@encryption": {
"type": "text",
"placeholders": {}
},
"everythingReady": "සියල්ල සූදානම්!",
"@everythingReady": {
"type": "text",
"placeholders": {}
},
"fontSize": "මුද්‍රණඅකුරේ ප්‍රමාණය",
"@fontSize": {
"type": "text",
"placeholders": {}
},
"goToTheNewRoom": "නව කාමරයට යන්න",
"@goToTheNewRoom": {
"type": "text",
"placeholders": {}
},
"joinRoom": "කාමරයට එක්වන්න",
"@joinRoom": {
"type": "text",
"placeholders": {}
},
"keysCached": "යතුරු නිහිතගත යි",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"next": "ඊලඟ",
"@next": {
"type": "text",
"placeholders": {}
},
"noPublicRoomsFound": "ප්‍රසිද්ධ කාමර හමු නොවිණි…",
"@noPublicRoomsFound": {
"type": "text",
"placeholders": {}
},
"people": "මිනිසුන්",
"@people": {
"type": "text",
"placeholders": {}
},
"publicGroups": "ප්‍රසිද්ධ සමූහ",
"@publicGroups": {
"type": "text",
"placeholders": {}
},
"removeDevice": "උපාංගය ඉවත්කරන්න",
"@removeDevice": {
"type": "text",
"placeholders": {}
},
"roomVersion": "කාමරයේ අනුවාදය",
"@roomVersion": {
"type": "text",
"placeholders": {}
},
"savedFileAs": "ලෙස ගොනුව සුරකින්න {filename}",
"@savedFileAs": {
"type": "text",
"placeholders": {
"filename": {}
"accept": "පිළිගන්න",
"@accept": {
"type": "text",
"placeholders": {}
},
"account": "ගිණුම",
"@account": {
"type": "text",
"placeholders": {}
},
"addEmail": "වි-තැපෑල එකතු කරන්න",
"@addEmail": {
"type": "text",
"placeholders": {}
},
"admin": "පරිපාලක",
"@admin": {
"type": "text",
"placeholders": {}
},
"allChats": "සියලුම සංවාද",
"@allChats": {
"type": "text",
"placeholders": {}
},
"anyoneCanJoin": "ඕනෑම කෙනෙකුට එක්විය හැකිය",
"@anyoneCanJoin": {
"type": "text",
"placeholders": {}
},
"archive": "සංරක්ෂිතය",
"@archive": {
"type": "text",
"placeholders": {}
},
"archivedRoom": "සංරක්ෂිත කාමරය",
"@archivedRoom": {
"type": "text",
"placeholders": {}
},
"areGuestsAllowedToJoin": "ආගන්තුක පරිශීලකයින්ට එක්වීමට අවසර තිබේද",
"@areGuestsAllowedToJoin": {
"type": "text",
"placeholders": {}
},
"areYouSure": "ඔබට විශ්වාසද?",
"@areYouSure": {
"type": "text",
"placeholders": {}
},
"areYouSureYouWantToLogout": "ඔබට නික්මීමට අවශ්‍ය බව විශ්වාසද?",
"@areYouSureYouWantToLogout": {
"type": "text",
"placeholders": {}
},
"blockDevice": "උපාංගය අවහිර කරන්න",
"@blockDevice": {
"type": "text",
"placeholders": {}
},
"cancel": "අවලංගු කරන්න",
"@cancel": {
"type": "text",
"placeholders": {}
},
"changeDeviceName": "උපාංගයේ නම වෙනස් කරන්න",
"@changeDeviceName": {
"type": "text",
"placeholders": {}
},
"changePassword": "මුරපදය වෙනස් කරන්න",
"@changePassword": {
"type": "text",
"placeholders": {}
},
"chat": "සංවාදය",
"@chat": {
"type": "text",
"placeholders": {}
},
"chatBackup": "සංවාද උපස්ථය",
"@chatBackup": {
"type": "text",
"placeholders": {}
},
"chatDetails": "සංවාදයේ විස්තර",
"@chatDetails": {
"type": "text",
"placeholders": {}
},
"chats": "සංවාද",
"@chats": {
"type": "text",
"placeholders": {}
},
"chooseAStrongPassword": "ශක්තිමත් මුරපදයක් තෝරන්න",
"@chooseAStrongPassword": {
"type": "text",
"placeholders": {}
},
"chooseAUsername": "පරිශීලක නාමයක් තෝරන්න",
"@chooseAUsername": {
"type": "text",
"placeholders": {}
},
"clearArchive": "සංරක්ෂිතය හිස් කරන්න",
"@clearArchive": {},
"close": "වසන්න",
"@close": {
"type": "text",
"placeholders": {}
},
"commandHint_join": "දී ඇති කාමරයට එක්වන්න",
"@commandHint_join": {
"type": "text",
"description": "Usage hint for the command /join"
},
"commandHint_leave": "මෙම කාමරය හැරයන්න",
"@commandHint_leave": {
"type": "text",
"description": "Usage hint for the command /leave"
},
"commandInvalid": "විධානය වලංගු නොවේ",
"@commandInvalid": {
"type": "text"
},
"commandMissing": "{{command} විධානයක් නොවේ.",
"@commandMissing": {
"type": "text",
"placeholders": {
"command": {}
},
"description": "State that {command} is not a valid /command."
},
"compareEmojiMatch": "සසඳා බලා පහත දැක්වෙන ඉමොජි අනෙක් උපාංගයට නිසැකවම ගැලපෙන බවට වග බලා ගන්න:",
"@compareEmojiMatch": {
"type": "text",
"placeholders": {}
},
"compareNumbersMatch": "සංසන්දනය කර පහත දැක්වෙන අංක අනෙක් උපාංගට නිසැකව ගැලපෙන බවට වග බලා ගන්න:",
"@compareNumbersMatch": {
"type": "text",
"placeholders": {}
},
"confirm": "තහවුරු කරන්න",
"@confirm": {
"type": "text",
"placeholders": {}
},
"connect": "සබඳින්න",
"@connect": {
"type": "text",
"placeholders": {}
},
"contactHasBeenInvitedToTheGroup": "සමූහය වෙත සබඳතාවයකට ආරාධනා කර ඇත",
"@contactHasBeenInvitedToTheGroup": {
"type": "text",
"placeholders": {}
},
"copy": "පිටපත්",
"@copy": {
"type": "text",
"placeholders": {}
},
"create": "සාදන්න",
"@create": {
"type": "text",
"placeholders": {}
},
"createNewGroup": "නව සමූහයක් සාදන්න",
"@createNewGroup": {
"type": "text",
"placeholders": {}
},
"encryption": "සංකේතාංකනය",
"@encryption": {
"type": "text",
"placeholders": {}
},
"everythingReady": "සියල්ල සූදානම්!",
"@everythingReady": {
"type": "text",
"placeholders": {}
},
"fontSize": "මුද්‍රණඅකුරේ ප්‍රමාණය",
"@fontSize": {
"type": "text",
"placeholders": {}
},
"goToTheNewRoom": "නව කාමරයට යන්න",
"@goToTheNewRoom": {
"type": "text",
"placeholders": {}
},
"joinRoom": "කාමරයට එක්වන්න",
"@joinRoom": {
"type": "text",
"placeholders": {}
},
"keysCached": "යතුරු නිහිතගත යි",
"@keysCached": {
"type": "text",
"placeholders": {}
},
"next": "ඊලඟ",
"@next": {
"type": "text",
"placeholders": {}
},
"people": "මිනිසුන්",
"@people": {
"type": "text",
"placeholders": {}
},
"removeDevice": "උපාංගය ඉවත්කරන්න",
"@removeDevice": {
"type": "text",
"placeholders": {}
},
"roomVersion": "කාමරයේ අනුවාදය",
"@roomVersion": {
"type": "text",
"placeholders": {}
},
"saveFile": "ගොනුව සුරකින්න",
"@saveFile": {
"type": "text",
"placeholders": {}
},
"send": "යවන්න",
"@send": {
"type": "text",
"placeholders": {}
},
"showPassword": "මුරපදය පෙන්වන්න",
"@showPassword": {
"type": "text",
"placeholders": {}
},
"sunday": "ඉරිදා",
"@sunday": {
"type": "text",
"placeholders": {}
},
"username": "පරිශීලක නාමය",
"@username": {
"type": "text",
"placeholders": {}
},
"videoCall": "දෘශ්‍ය ඇමතුම",
"@videoCall": {
"type": "text",
"placeholders": {}
},
"wallpaper": "බිතුපත",
"@wallpaper": {
"type": "text",
"placeholders": {}
},
"warning": "අවවාදයයි!",
"@warning": {
"type": "text",
"placeholders": {}
},
"wednesday": "බදාදා",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"writeAMessage": "පණිවිඩයක් ලියන්න…",
"@writeAMessage": {
"type": "text",
"placeholders": {}
},
"yes": "ඔව්",
"@yes": {
"type": "text",
"placeholders": {}
},
"you": "ඔබ",
"@you": {
"type": "text",
"placeholders": {}
}
},
"saveFile": "ගොනුව සුරකින්න",
"@saveFile": {
"type": "text",
"placeholders": {}
},
"saveFileToFolder": "ගොනුව මෙම බහාලුමට සුරකින්න",
"@saveFileToFolder": {
"type": "text",
"placeholders": {}
},
"securityKey": "ආරක්ෂක යතුර",
"@securityKey": {
"type": "text",
"placeholders": {}
},
"securityKeyLost": "ආරක්ෂක යතුර නැතිවුනාද?",
"@securityKeyLost": {
"type": "text",
"placeholders": {}
},
"send": "යවන්න",
"@send": {
"type": "text",
"placeholders": {}
},
"showPassword": "මුරපදය පෙන්වන්න",
"@showPassword": {
"type": "text",
"placeholders": {}
},
"sunday": "ඉරිදා",
"@sunday": {
"type": "text",
"placeholders": {}
},
"username": "පරිශීලක නාමය",
"@username": {
"type": "text",
"placeholders": {}
},
"videoCall": "දෘශ්‍ය ඇමතුම",
"@videoCall": {
"type": "text",
"placeholders": {}
},
"wallpaper": "බිතුපත",
"@wallpaper": {
"type": "text",
"placeholders": {}
},
"warning": "අවවාදයයි!",
"@warning": {
"type": "text",
"placeholders": {}
},
"wednesday": "බදාදා",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"writeAMessage": "පණිවිඩයක් ලියන්න…",
"@writeAMessage": {
"type": "text",
"placeholders": {}
},
"yes": "ඔව්",
"@yes": {
"type": "text",
"placeholders": {}
},
"you": "ඔබ",
"@you": {
"type": "text",
"placeholders": {}
},
"yourOwnUsername": "ඔබට හිමි පරිශීලකනාමය",
"@yourOwnUsername": {
"type": "text",
"placeholders": {}
},
"zoomIn": "විශාලනය",
"@zoomIn": {
"type": "text",
"placeholders": {}
},
"zoomOut": "කුඩාලනය",
"@zoomOut": {
"type": "text",
"placeholders": {}
}
}
}

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

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,20 @@
{
"@@last_modified": "2021-08-14 12:41:09.826673",
"acceptedTheInvitation": "{username} அழைப்பை ஏற்றுக்கொண்டார்",
"@acceptedTheInvitation": {
"type": "text",
"placeholders": {
"username": {}
"@@last_modified": "2021-08-14 12:41:09.826673",
"acceptedTheInvitation": "{username} அழைப்பை ஏற்றுக்கொண்டார்",
"@acceptedTheInvitation": {
"type": "text",
"placeholders": {
"username": {}
}
},
"accept": "ஏற்றுக்கொள்",
"@accept": {
"type": "text",
"placeholders": {}
},
"about": "பற்றி",
"@about": {
"type": "text",
"placeholders": {}
}
},
"accept": "ஏற்றுக்கொள்",
"@accept": {
"type": "text",
"placeholders": {}
},
"about": "பற்றி",
"@about": {
"type": "text",
"placeholders": {}
}
}
}

View File

@ -23,11 +23,6 @@
"type": "text",
"placeholders": {}
},
"accountInformation": "Hesap bilgileri",
"@accountInformation": {
"type": "text",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐 {username} uçtan uca şifrelemeyi etkinleştirdi",
"@activatedEndToEndEncryption": {
"type": "text",
@ -45,11 +40,6 @@
"type": "text",
"placeholders": {}
},
"addNewFriend": "Yeni arkadaş ekle",
"@addNewFriend": {
"type": "text",
"placeholders": {}
},
"addToSpace": "Alana ekle",
"@addToSpace": {},
"admin": "Yönetici",
@ -72,11 +62,6 @@
"type": "text",
"placeholders": {}
},
"alreadyHaveAnAccount": "Hesabınız var mı?",
"@alreadyHaveAnAccount": {
"type": "text",
"placeholders": {}
},
"answeredTheCall": "{senderName} aramayı yanıtladı",
"@answeredTheCall": {
"type": "text",
@ -119,21 +104,11 @@
"type": "text",
"placeholders": {}
},
"askSSSSCache": "Anahtarları önbelleğe almak için lütfen güvenli depolama parolanızı veya kurtarma anahtarınızı girin.",
"@askSSSSCache": {
"type": "text",
"placeholders": {}
},
"askSSSSSign": "Diğer kişiyi imzalayabilmek için lütfen güvenli depolama parolanızı veya kurtarma anahtarınızı girin.",
"@askSSSSSign": {
"type": "text",
"placeholders": {}
},
"askSSSSVerify": "Lütfen oturumunuzu doğrulamak için güvenli depolama parolanızı veya kurtarma anahtarınızı girin.",
"@askSSSSVerify": {
"type": "text",
"placeholders": {}
},
"askVerificationRequest": "{username} kişisinden gelen bu doğrulama isteği kabul edilsin mi?",
"@askVerificationRequest": {
"type": "text",
@ -141,31 +116,11 @@
"username": {}
}
},
"audioPlayerPause": "Duraklat",
"@audioPlayerPause": {
"type": "text",
"placeholders": {}
},
"audioPlayerPlay": "Oynat",
"@audioPlayerPlay": {
"type": "text",
"placeholders": {}
},
"authentication": "Doğrulama",
"@authentication": {
"type": "text",
"placeholders": {}
},
"autoplayImages": "Canlandırmalı çıkartmaları ve ifadeleri otomatik olarak oynat",
"@autoplayImages": {
"type": "text",
"placeholder": {}
},
"avatarHasBeenChanged": "Avatar değiştirildi",
"@avatarHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"badServerLoginTypesException": "Ana sunucu aşağıdaki oturum açma türlerini destekliyor:\n{serverVersions}\nAncak bu uygulama yalnızca aşağıdakileri destekliyor:\n{supportedVersions}",
"@badServerLoginTypesException": {
"type": "text",
@ -215,11 +170,6 @@
"type": "text",
"placeholders": {}
},
"cachedKeys": "Önbelleğe alınan anahtarlar",
"@cachedKeys": {
"type": "text",
"placeholders": {}
},
"cancel": "İptal",
"@cancel": {
"type": "text",
@ -341,21 +291,11 @@
"username": {}
}
},
"changelog": "Değişiklikler",
"@changelog": {
"type": "text",
"placeholders": {}
},
"changePassword": "Parolayı değiştir",
"@changePassword": {
"type": "text",
"placeholders": {}
},
"changesHaveBeenSaved": "Değişiklikler kaydedildi",
"@changesHaveBeenSaved": {
"type": "text",
"placeholders": {}
},
"changeTheHomeserver": "Ana sunucuyu değiştir",
"@changeTheHomeserver": {
"type": "text",
@ -371,11 +311,6 @@
"type": "text",
"placeholders": {}
},
"changeTheServer": "Sunucuyu değiştir",
"@changeTheServer": {
"type": "text",
"placeholders": {}
},
"changeWallpaper": "Duvar kağıdını değiştir",
"@changeWallpaper": {
"type": "text",
@ -413,11 +348,6 @@
},
"chatHasBeenAddedToThisSpace": "Sohbet bu alana eklendi",
"@chatHasBeenAddedToThisSpace": {},
"chatHasBeenRemovedFromThisSpace": "Sohbet bu alandan kaldırıldı",
"@chatHasBeenRemovedFromThisSpace": {
"type": "text",
"placeholders": {}
},
"chats": "Sohbetler",
"@chats": {
"type": "text",
@ -435,11 +365,6 @@
},
"clearArchive": "Arşivi temizle",
"@clearArchive": {},
"clearText": "Metni temizle",
"@clearText": {
"type": "text",
"placeholders": {}
},
"close": "Kapat",
"@close": {
"type": "text",
@ -552,11 +477,6 @@
"type": "text",
"placeholders": {}
},
"connectionAttemptFailed": "Bağlantı denemesi başarısız oldu",
"@connectionAttemptFailed": {
"type": "text",
"placeholders": {}
},
"contactHasBeenInvitedToTheGroup": "Kişi gruba davet edildi",
"@contactHasBeenInvitedToTheGroup": {
"type": "text",
@ -577,11 +497,6 @@
"type": "text",
"placeholders": {}
},
"contentViewer": "İçerik görüntüleyici",
"@contentViewer": {
"type": "text",
"placeholders": {}
},
"copiedToClipboard": "Panoya kopyalandı",
"@copiedToClipboard": {
"type": "text",
@ -604,16 +519,6 @@
"error": {}
}
},
"couldNotSetAvatar": "Avatar ayarlanamadı",
"@couldNotSetAvatar": {
"type": "text",
"placeholders": {}
},
"couldNotSetDisplayname": "Görünen ad ayarlanamadı",
"@couldNotSetDisplayname": {
"type": "text",
"placeholders": {}
},
"countParticipants": "{count} katılımcı",
"@countParticipants": {
"type": "text",
@ -626,11 +531,6 @@
"type": "text",
"placeholders": {}
},
"createAccountNow": "Şimdi hesap oluştur",
"@createAccountNow": {
"type": "text",
"placeholders": {}
},
"createdTheChat": "💬 {username} sohbeti oluşturdu",
"@createdTheChat": {
"type": "text",
@ -648,11 +548,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningDisabled": "Çapraz imzalama kapalı",
"@crossSigningDisabled": {
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Çapraz imzalama açık",
"@crossSigningEnabled": {
"type": "text",
@ -738,46 +633,21 @@
"type": "text",
"placeholders": {}
},
"deviceVerifyDescription": "Şifreleme yalnızca tüm aygıtlar doğrulandığında güvenlidir.",
"@deviceVerifyDescription": {
"type": "text",
"placeholders": {}
},
"directChats": "Doğrudan Sohbetler",
"@directChats": {
"type": "text",
"placeholders": {}
},
"discardPicture": "Resmi at",
"@discardPicture": {
"type": "text",
"placeholders": {}
},
"discover": "Keşfet",
"@discover": {
"type": "text",
"placeholders": {}
},
"discoverGroups": "Grupları keşfet",
"@discoverGroups": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Görünen ad değiştirildi",
"@displaynameHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"donate": "Bağış",
"@donate": {
"type": "text",
"placeholders": {}
},
"dontAskAgain": "İptal et ve bir daha sorma",
"@dontAskAgain": {
"type": "text",
"placeholders": {}
},
"downloadFile": "Dosyayı indir",
"@downloadFile": {
"type": "text",
@ -803,11 +673,6 @@
"type": "text",
"placeholders": {}
},
"editJitsiInstance": "Jitsi örneğini düzenle",
"@editJitsiInstance": {
"type": "text",
"placeholders": {}
},
"editRoomAliases": "Oda takma adlarını düzenle",
"@editRoomAliases": {
"type": "text",
@ -853,11 +718,6 @@
"type": "text",
"placeholders": {}
},
"enableChatBackup": "Sohbetlerinize erişimi asla kaybetmemek için sohbet yedeklemeyi etkinleştirin.",
"@enableChatBackup": {
"type": "text",
"placeholders": {}
},
"enableEmotesGlobally": "İfade paketini küresel olarak etkinleştir",
"@enableEmotesGlobally": {
"type": "text",
@ -883,21 +743,11 @@
"type": "text",
"placeholders": {}
},
"encryptionAlgorithm": "Şifreleme algoritması",
"@encryptionAlgorithm": {
"type": "text",
"placeholders": {}
},
"encryptionNotEnabled": "Şifreleme etkinleştirilmedi",
"@encryptionNotEnabled": {
"type": "text",
"placeholders": {}
},
"end2endEncryptionSettings": "Uçtan uca şifreleme ayarları",
"@end2endEncryptionSettings": {
"type": "text",
"placeholders": {}
},
"endedTheCall": "{senderName} aramayı sonlandırdı",
"@endedTheCall": {
"type": "text",
@ -917,11 +767,6 @@
},
"enterASpacepName": "Bir alan adı girin",
"@enterASpacepName": {},
"enterAUsername": "Bir kullanıcı adı girin",
"@enterAUsername": {
"type": "text",
"placeholders": {}
},
"enterYourHomeserver": "Ana sunucunuzu girin",
"@enterYourHomeserver": {
"type": "text",
@ -949,11 +794,6 @@
"type": "text",
"placeholders": {}
},
"fileSize": "Dosya boyutu",
"@fileSize": {
"type": "text",
"placeholders": {}
},
"fluffychat": "FluffyChat",
"@fluffychat": {
"type": "text",
@ -974,11 +814,6 @@
"type": "text",
"placeholders": {}
},
"friends": "Arkadaşlar",
"@friends": {
"type": "text",
"placeholders": {}
},
"fromJoining": "Katılmadan",
"@fromJoining": {
"type": "text",
@ -1059,11 +894,6 @@
"type": "text",
"placeholders": {}
},
"homeserverIsNotCompatible": "Ana sunucu uyumlu değil",
"@homeserverIsNotCompatible": {
"type": "text",
"placeholders": {}
},
"howOffensiveIsThisContent": "Bu içerik ne kadar rahatsız edici?",
"@howOffensiveIsThisContent": {
"type": "text",
@ -1114,11 +944,6 @@
"type": "text",
"placeholders": {}
},
"invalidEmail": "Geçersiz e-posta",
"@invalidEmail": {
"type": "text",
"placeholders": {}
},
"inviteContact": "Kişi davet et",
"@inviteContact": {
"type": "text",
@ -1162,11 +987,6 @@
"link": {}
}
},
"isDeviceKeyCorrect": "Aşağıdaki aygıt anahtarı doğru mu?",
"@isDeviceKeyCorrect": {
"type": "text",
"placeholders": {}
},
"isTyping": "yazıyor…",
"@isTyping": {
"type": "text",
@ -1189,11 +1009,6 @@
"type": "text",
"placeholders": {}
},
"keysMissing": "Anahtarlar eksik",
"@keysMissing": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username}, {targetName} kişisini attı",
"@kicked": {
"type": "text",
@ -1222,11 +1037,6 @@
"localizedTimeShort": {}
}
},
"lastSeenIp": "Son görülen IP",
"@lastSeenIp": {
"type": "text",
"placeholders": {}
},
"lastSeenLongTimeAgo": "Uzun zaman önce görüldü",
"@lastSeenLongTimeAgo": {
"type": "text",
@ -1303,16 +1113,6 @@
"type": "text",
"placeholders": {}
},
"makeAModerator": "Moderatör yap",
"@makeAModerator": {
"type": "text",
"placeholders": {}
},
"makeAnAdmin": "Yönetici yap",
"@makeAnAdmin": {
"type": "text",
"placeholders": {}
},
"makeSureTheIdentifierIsValid": "Tanımlayıcının geçerli olduğundan emin olun",
"@makeSureTheIdentifierIsValid": {
"type": "text",
@ -1348,13 +1148,6 @@
"type": "text",
"placeholders": {}
},
"moreEvents": "{count,plural, =1{1 etkinlik daha} other{{count} etkinlik daha}}",
"@moreEvents": {
"type": "text",
"placeholders": {
"count": {}
}
},
"muteChat": "Sohbeti sessize al",
"@muteChat": {
"type": "text",
@ -1395,16 +1188,6 @@
"type": "text",
"placeholders": {}
},
"noCrossSignBootstrap": "FluffyChat şu anda çapraz imzalamanın etkinleştirilmesini desteklemiyor. Lütfen bunu Element içinden etkinleştirin.",
"@noCrossSignBootstrap": {
"type": "text",
"placeholders": {}
},
"noDescription": "Açıklama yok",
"@noDescription": {
"type": "text",
"placeholders": {}
},
"noEmotesFound": "İfade bulunamadı. 😕",
"@noEmotesFound": {
"type": "text",
@ -1428,11 +1211,6 @@
"server2": {}
}
},
"noMegolmBootstrap": "Lütfen bunun yerine Element içinden çevrim içi anahtar yedeklemeyi açın.",
"@noMegolmBootstrap": {
"type": "text",
"placeholders": {}
},
"none": "Yok",
"@none": {
"type": "text",
@ -1448,21 +1226,11 @@
"type": "text",
"placeholders": {}
},
"noPublicRoomsFound": "Herkese açık oda bulunamadı…",
"@noPublicRoomsFound": {
"type": "text",
"placeholders": {}
},
"noRoomsFound": "Oda bulunamadı…",
"@noRoomsFound": {
"type": "text",
"placeholders": {}
},
"noStatusesFound": "Şimdiye kadar hiçbir durum bulunamadı.",
"@noStatusesFound": {
"type": "text",
"placeholders": {}
},
"notifications": "Bildirimler",
"@notifications": {
"type": "text",
@ -1473,18 +1241,6 @@
"type": "text",
"placeholders": {}
},
"notSupportedInWeb": "Web'de desteklenmiyor",
"@notSupportedInWeb": {
"type": "text",
"placeholders": {}
},
"numberSelected": "{number} seçildi",
"@numberSelected": {
"type": "text",
"placeholders": {
"number": {}
}
},
"numUsersTyping": "{count} kullanıcı yazıyor…",
"@numUsersTyping": {
"type": "text",
@ -1517,11 +1273,6 @@
"type": "text",
"placeholders": {}
},
"onlineKeyBackupDisabled": "Çevrim içi anahtar yedekleme devre dışı bırakıldı",
"@onlineKeyBackupDisabled": {
"type": "text",
"placeholders": {}
},
"onlineKeyBackupEnabled": "Çevrim içi anahtar yedekleme etkinleştirildi",
"@onlineKeyBackupEnabled": {
"type": "text",
@ -1552,11 +1303,6 @@
"type": "text",
"placeholders": {}
},
"optionalAddEmail": "(İsteğe bağlı) E-posta adresiniz",
"@optionalAddEmail": {
"type": "text",
"placeholders": {}
},
"optionalGroupName": "(İsteğe bağlı) Grup adı",
"@optionalGroupName": {
"type": "text",
@ -1572,11 +1318,6 @@
"type": "text",
"placeholders": {}
},
"participatingUserDevices": "Katılan kullanıcı aygıtları",
"@participatingUserDevices": {
"type": "text",
"placeholders": {}
},
"passphraseOrKey": "parola veya kurtarma anahtarı",
"@passphraseOrKey": {
"type": "text",
@ -1654,11 +1395,6 @@
"type": "text",
"placeholders": {}
},
"pleaseEnterSecurityKey": "Lütfen güvenlik anahtarınızı girin:",
"@pleaseEnterSecurityKey": {
"type": "text",
"placeholders": {}
},
"pleaseEnterYourPassword": "Lütfen parolanızı girin",
"@pleaseEnterYourPassword": {
"type": "text",
@ -1684,26 +1420,11 @@
"type": "text",
"placeholders": {}
},
"publicGroups": "Herkese Açık Gruplar",
"@publicGroups": {
"type": "text",
"placeholders": {}
},
"publicKey": "Ortak Anahtar",
"@publicKey": {
"type": "text",
"placeholders": {}
},
"publicRooms": "Herkese Açık Odalar",
"@publicRooms": {
"type": "text",
"placeholders": {}
},
"publicSpace": "Herkese açık alan",
"@publicSpace": {
"type": "text",
"placeholders": {}
},
"pushRules": "Gönderme kuralları",
"@pushRules": {
"type": "text",
@ -1780,11 +1501,6 @@
"type": "text",
"placeholders": {}
},
"removeMessage": "Mesajı kaldır",
"@removeMessage": {
"type": "text",
"placeholders": {}
},
"removeYourAvatar": "Avatarınızı kaldırın",
"@removeYourAvatar": {
"type": "text",
@ -1815,16 +1531,6 @@
"type": "text",
"placeholders": {}
},
"requestToReadOlderMessages": "Eski mesajları okumayı iste",
"@requestToReadOlderMessages": {
"type": "text",
"placeholders": {}
},
"revokeAllPermissions": "Tüm izinleri iptal et",
"@revokeAllPermissions": {
"type": "text",
"placeholders": {}
},
"roomHasBeenUpgraded": "Oda yükseltildi",
"@roomHasBeenUpgraded": {
"type": "text",
@ -1840,48 +1546,21 @@
"type": "text",
"placeholders": {}
},
"savedFileAs": "Dosya {filename} olarak kaydedildi",
"@savedFileAs": {
"type": "text",
"placeholders": {
"filename": {}
}
},
"saveFile": "Dosyayı kaydet",
"@saveFile": {
"type": "text",
"placeholders": {}
},
"saveFileToFolder": "Dosyayı bu klasöre kaydet",
"@saveFileToFolder": {
"type": "text",
"placeholders": {}
},
"search": "Ara",
"@search": {
"type": "text",
"placeholders": {}
},
"searchForAChat": "Sohbet ara",
"@searchForAChat": {
"type": "text",
"placeholders": {}
},
"security": "Güvenlik",
"@security": {
"type": "text",
"placeholders": {}
},
"securityKey": "Güvenlik anahtarı",
"@securityKey": {
"type": "text",
"placeholders": {}
},
"securityKeyLost": "Güvenlik anahtarı kayıp mı?",
"@securityKeyLost": {
"type": "text",
"placeholders": {}
},
"seenByUser": "{username} tarafından görüldü",
"@seenByUser": {
"type": "text",
@ -1924,11 +1603,6 @@
"type": "text",
"placeholders": {}
},
"sendBugReports": "sentry.io ile hata raporları göndermeye izin ver",
"@sendBugReports": {
"type": "text",
"placeholders": {}
},
"sendFile": "Dosya gönder",
"@sendFile": {
"type": "text",
@ -2001,21 +1675,6 @@
"senderName": {}
}
},
"sentryInfo": "Gizliliğiniz hakkında bilgiler: https://sentry.io/security/",
"@sentryInfo": {
"type": "text",
"placeholders": {}
},
"sessionVerified": "Oturum doğrulandı",
"@sessionVerified": {
"type": "text",
"placeholders": {}
},
"setAProfilePicture": "Profil fotoğrafı ayarla",
"@setAProfilePicture": {
"type": "text",
"placeholders": {}
},
"setAsCanonicalAlias": "Ana takma ad olarak ayarla",
"@setAsCanonicalAlias": {
"type": "text",
@ -2088,11 +1747,6 @@
"type": "text",
"placeholders": {}
},
"soundVibrationLedColor": "Ses, titreşim, LED rengi",
"@soundVibrationLedColor": {
"type": "text",
"placeholders": {}
},
"sourceCode": "Kaynak kodları",
"@sourceCode": {
"type": "text",
@ -2115,11 +1769,6 @@
"senderName": {}
}
},
"startYourFirstChat": "Hemen ilk sohbetinize başlayın! 🙂\n- 'Yeni sohbet' düğmesine dokunun\n- Bir arkadaşınızın QR kodunu tarayın\n- Eğlenceli bir şekilde sohbet edin",
"@startYourFirstChat": {
"type": "text",
"placeholders": {}
},
"status": "Durum",
"@status": {
"type": "text",
@ -2150,21 +1799,6 @@
"type": "text",
"placeholders": {}
},
"tapOnDeviceToVerify": "Doğrulamak için bir aygıta dokunun",
"@tapOnDeviceToVerify": {
"type": "text",
"placeholders": {}
},
"tapToShowImage": "Resmi göstermek için dokunun",
"@tapToShowImage": {
"type": "text",
"placeholders": {}
},
"tapToShowMenu": "Menüyü göstermek için dokunun",
"@tapToShowMenu": {
"type": "text",
"placeholders": {}
},
"theyDontMatch": "Eşleşmediler",
"@theyDontMatch": {
"type": "text",
@ -2185,16 +1819,6 @@
"type": "text",
"placeholders": {}
},
"timeOfDay": "{hours12}:{minutes} {suffix}",
"@timeOfDay": {
"type": "text",
"placeholders": {
"hours12": {},
"hours24": {},
"minutes": {},
"suffix": {}
}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -2271,16 +1895,6 @@
"type": {}
}
},
"unknownSessionVerify": "Bilinmeyen oturum, lütfen doğrulayın",
"@unknownSessionVerify": {
"type": "text",
"placeholders": {}
},
"unlockChatBackup": "Sohbet yedeklemesinin kilidini aç",
"@unlockChatBackup": {
"type": "text",
"placeholders": {}
},
"unmuteChat": "Sohbeti sessizden çıkar",
"@unmuteChat": {
"type": "text",
@ -2298,18 +1912,6 @@
"unreadCount": {}
}
},
"unreadMessages": "{unreadEvents, plural, =1{1 okunmamış mesaj} other{{unreadEvents} okunmamış mesaj}}",
"@unreadMessages": {
"type": "text",
"placeholders": {
"unreadEvents": {}
}
},
"useAmoledTheme": "AMOLED ile uyumlu renkler kullanılsın mı?",
"@useAmoledTheme": {
"type": "text",
"placeholders": {}
},
"userAndOthersAreTyping": "{username} ve {count} diğer kişi yazıyor…",
"@userAndOthersAreTyping": {
"type": "text",
@ -2345,11 +1947,6 @@
"type": "text",
"placeholders": {}
},
"userNotVerified": "Kullanıcı doğrulanmadı",
"@userNotVerified": {
"type": "text",
"placeholders": {}
},
"userSentUnknownEvent": "{username} bir {type} etkinliği gönderdi",
"@userSentUnknownEvent": {
"type": "text",
@ -2358,36 +1955,16 @@
"type": {}
}
},
"userUnknownVerification": "Kullanıcının bilinmeyen bir doğrulama durumu var",
"@userUnknownVerification": {
"type": "text",
"placeholders": {}
},
"userVerified": "Kullanıcı doğrulandı",
"@userVerified": {
"type": "text",
"placeholders": {}
},
"verified": "Doğrulandı",
"@verified": {
"type": "text",
"placeholders": {}
},
"verifiedSession": "Oturum başarıyla doğrulandı!",
"@verifiedSession": {
"type": "text",
"placeholders": {}
},
"verify": "Doğrula",
"@verify": {
"type": "text",
"placeholders": {}
},
"verifyManual": "Manuel Olarak Doğrula",
"@verifyManual": {
"type": "text",
"placeholders": {}
},
"verifyStart": "Doğrulamayı Başlat",
"@verifyStart": {
"type": "text",
@ -2403,11 +1980,6 @@
"type": "text",
"placeholders": {}
},
"verifyUser": "Kullanıcıyı Doğrula",
"@verifyUser": {
"type": "text",
"placeholders": {}
},
"videoCall": "Görüntülü arama",
"@videoCall": {
"type": "text",
@ -2458,21 +2030,11 @@
"type": "text",
"placeholders": {}
},
"warningEncryptionInBeta": "Uçtan uca şifreleme şimdilik Beta aşamasında! Risk alarak kullanın!",
"@warningEncryptionInBeta": {
"type": "text",
"placeholders": {}
},
"wednesday": "Çarşamba",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"welcomeText": "Matrix ağındaki en şirin anlık mesajlaşma uygulamasına hoş geldiniz.",
"@welcomeText": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Size bir e-posta gönderdik",
"@weSentYouAnEmail": {
"type": "text",
@ -2538,56 +2100,23 @@
"type": "text",
"placeholders": {}
},
"yourChatsAreBeingSynced": "Sohbetleriniz eşzamanlanıyor…",
"@yourChatsAreBeingSynced": {
"type": "text",
"placeholders": {}
},
"yourOwnUsername": "Kullanıcı adınız",
"@yourOwnUsername": {
"type": "text",
"placeholders": {}
},
"yourPublicKey": "Ortak anahtarınız",
"@yourPublicKey": {
"type": "text",
"placeholders": {}
},
"youWillBeConnectedTo": "{homeserver} sunucusuna bağlanacaksınız",
"@youWillBeConnectedTo": {
"type": "text",
"placeholders": {
"homeserver": {}
}
},
"zoomIn": "Yakınlaştır",
"@zoomIn": {
"type": "text",
"placeholders": {}
},
"zoomOut": "Uzaklaştır",
"@zoomOut": {
"type": "text",
"placeholders": {}
},
"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": {},
"createNewChatExplaination": "Sadece QR kodunu tarayın veya yan yana değilseniz davet bağlantınızı paylaşın.",
"@createNewChatExplaination": {},
"sendOnEnter": "Enter tuşu ile gönder",
"@sendOnEnter": {},
"homeserver": "Ana sunucu",
"@homeserver": {},
"serverRequiresEmail": "Bu sunucunun kayıt için e-posta adresinizi doğrulaması gerekiyor.",
"@serverRequiresEmail": {},
"newUsernameDescription": "Kullanıcı kimliğiniz @kullanıcıadı:sunucuadı biçiminde olacaktır.",
"@newUsernameDescription": {},
"newPasswordDescription": "Parolanızı kurtarabilmek için daha sonra hesabınıza bir e-posta adresi eklemelisiniz.",
"@newPasswordDescription": {},
"enableMultiAccounts": "(BETA) Bu aygıtta çoklu hesapları etkinleştir",
"@enableMultiAccounts": {},
"bundleName": "Paket adı",
@ -2604,14 +2133,8 @@
"@oneClientLoggedOut": {},
"link": "Bağlantı",
"@link": {},
"setupChatBackup": "Sohbet yedeklemeyi ayarla",
"@setupChatBackup": {},
"iWroteDownTheKey": "Anahtarı yazdım",
"@iWroteDownTheKey": {},
"yourChatBackupHasBeenSetUp": "Sohbet yedeklemeniz ayarlandı.",
"@yourChatBackupHasBeenSetUp": {},
"setupChatBackupDescription": "Mesajlarınızı korumak için sizin için bir kurtarma anahtarı oluşturduk.\nLütfen bunu parola yöneticisi gibi güvenli bir yerde saklayın.",
"@setupChatBackupDescription": {},
"unverified": "Doğrulanmadı",
"@unverified": {},
"yourUserId": "Kullanıcı kimliğiniz:",
@ -2643,18 +2166,10 @@
"@removeFromSpace": {},
"addToSpaceDescription": "Bu sohbeti eklemek için bir alan seçin.",
"@addToSpaceDescription": {},
"removeFromSpaceDescription": "Bu, sohbeti geçerli alandan kaldırır. Daha sonra \"Tüm sohbetler\" altında görünmeye devam edecektir.",
"@removeFromSpaceDescription": {},
"loginWithOneClick": "Tek tıklamayla oturum aç",
"@loginWithOneClick": {},
"start": "Başla",
"@start": {},
"setupChatBackupNow": "Sohbet yedeklemenizi şimdi ayarlayın",
"@setupChatBackupNow": {},
"pleaseEnterSecurityKeyDescription": "Sohbet yedeklemenizin kilidini açmak için lütfen önceki bir oturumda oluşturulan güvenlik anahtarınızı girin. Güvenlik anahtarınız parolanız DEĞİLDİR.",
"@pleaseEnterSecurityKeyDescription": {},
"saveTheSecurityKeyNow": "Güvenlik anahtarını şimdi kaydet",
"@saveTheSecurityKeyNow": {},
"commandHint_clearcache": "Önbelleği temizleyin",
"@commandHint_clearcache": {
"type": "text",
@ -2734,10 +2249,6 @@
"@openChat": {},
"matrixWidgets": "Matrix Widget'ları",
"@matrixWidgets": {},
"integrationsNotImplemented": "Widget'lar ve bütünleşmeler henüz düzenlenemiyor.",
"@integrationsNotImplemented": {},
"editIntegrations": "Widget'ları ve bütünleşmeleri düzenle",
"@editIntegrations": {},
"reactedWith": "{sender}, {reaction} ile tepki verdi",
"@reactedWith": {
"type": "text",
@ -2758,8 +2269,6 @@
"@unsupportedAndroidVersionLong": {},
"pinMessage": "Odaya sabitle",
"@pinMessage": {},
"pinnedEventsError": "Sabitlenmiş mesajlar yüklenirken hata oluştu",
"@pinnedEventsError": {},
"confirmEventUnpin": "Etkinliğin sabitlemesini kalıcı olarak kaldırmak istediğinizden emin misiniz?",
"@confirmEventUnpin": {},
"videoCallsBetaWarning": "Görüntülü aramaların şu anda beta aşamasında olduğunu lütfen unutmayın. Tüm platformlarda beklendiği gibi veya hiç çalışmayabilirler.",
@ -2857,8 +2366,6 @@
"user": {}
}
},
"showSpaces": "Alanlar listesini göster",
"@showSpaces": {},
"noEmailWarning": "Lütfen geçerli bir e-posta adresi girin. Aksi takdirde parolanızı sıfırlayamazsınız. İstemiyorsanız, devam etmek için düğmeye tekrar dokunun.",
"@noEmailWarning": {},
"storeInAppleKeyChain": "Apple KeyChain'de sakla",
@ -2877,8 +2384,6 @@
"@enableAutoBackups": {},
"recoveryKey": "Kurtarma anahtarı",
"@recoveryKey": {},
"saveTheRecoveryKeyNow": "Kurtarma anahtarını şimdi kaydet",
"@saveTheRecoveryKeyNow": {},
"stories": "Hikayeler",
"@stories": {},
"storeInAndroidKeystore": "Android KeyStore'da sakla",
@ -2913,19 +2418,8 @@
"@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": {},
"advanced": "Gelişmiş",
"@advanced": {},
"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.",
"@indexedDbErrorLong": {},
"numberRoomMembers": "{number} üye",
"@numberRoomMembers": {
"type": "number",
"placeholders": {
"number": {}
}
},
"suggestedRooms": "Bu alandaki grupları keşfet",
"@suggestedRooms": {},
"user": "Kullanıcı",
"@user": {},
"custom": "Özel",
@ -2934,8 +2428,6 @@
"@updateAvailable": {},
"updateNow": "Güncellemeyi arka planda başlat",
"@updateNow": {},
"allSuggestedRoomsJoined": "Önerilen tüm odalara katıldınız",
"@allSuggestedRoomsJoined": {},
"confirmMatrixId": "Hesabınızı silmek için lütfen Matrix kimliğinizi doğrulayın.",
"@confirmMatrixId": {},
"supposedMxid": "Bu {mxid} olmalıdır",
@ -3043,5 +2535,9 @@
"noSearchResult": "Eşleşen arama sonucu yok.",
"@noSearchResult": {},
"letsStart": "Başlayalım",
"@letsStart": {}
"@letsStart": {},
"enterInviteLinkOrMatrixId": "Davet bağlantısını veya Matris kimliğini girin...",
"@enterInviteLinkOrMatrixId": {},
"reopenChat": "Sohbeti yeniden aç",
"@reopenChat": {}
}

View File

@ -23,11 +23,6 @@
"type": "text",
"placeholders": {}
},
"accountInformation": "Інформація про обліковий запис",
"@accountInformation": {
"type": "text",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐 {username} активує наскрізне шифрування",
"@activatedEndToEndEncryption": {
"type": "text",
@ -50,11 +45,6 @@
"type": "text",
"placeholders": {}
},
"alreadyHaveAnAccount": "Уже маєте обліковий запис?",
"@alreadyHaveAnAccount": {
"type": "text",
"placeholders": {}
},
"answeredTheCall": "{senderName} відповідає на виклик",
"@answeredTheCall": {
"type": "text",
@ -87,21 +77,11 @@
"type": "text",
"placeholders": {}
},
"askSSSSCache": "Введіть свою парольну фразу або ключ відновлення для кешування ключів.",
"@askSSSSCache": {
"type": "text",
"placeholders": {}
},
"askSSSSSign": "Для підпису ключа іншого користувача введіть свою парольну фразу або ключ відновлення.",
"@askSSSSSign": {
"type": "text",
"placeholders": {}
},
"askSSSSVerify": "Введіть свою парольну фразу або ключ відновлення для підтвердження сеансу.",
"@askSSSSVerify": {
"type": "text",
"placeholders": {}
},
"askVerificationRequest": "Прийняти цей запит на підтвердження від {username}?",
"@askVerificationRequest": {
"type": "text",
@ -109,16 +89,6 @@
"username": {}
}
},
"authentication": "Автентифікація",
"@authentication": {
"type": "text",
"placeholders": {}
},
"avatarHasBeenChanged": "Аватар змінено",
"@avatarHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"banFromChat": "Заблокувати в бесіді",
"@banFromChat": {
"type": "text",
@ -142,11 +112,6 @@
"type": "text",
"placeholders": {}
},
"cachedKeys": "Ключі кешовано",
"@cachedKeys": {
"type": "text",
"placeholders": {}
},
"cancel": "Скасувати",
"@cancel": {
"type": "text",
@ -256,11 +221,6 @@
"username": {}
}
},
"changelog": "Журнал змін",
"@changelog": {
"type": "text",
"placeholders": {}
},
"changeTheHomeserver": "Змінити домашній сервер",
"@changeTheHomeserver": {
"type": "text",
@ -276,11 +236,6 @@
"type": "text",
"placeholders": {}
},
"changeTheServer": "Змінити сервер",
"@changeTheServer": {
"type": "text",
"placeholders": {}
},
"changeWallpaper": "Змінити тло",
"@changeWallpaper": {
"type": "text",
@ -336,21 +291,11 @@
"type": "text",
"placeholders": {}
},
"connectionAttemptFailed": "Не вдалося під'єднатися",
"@connectionAttemptFailed": {
"type": "text",
"placeholders": {}
},
"contactHasBeenInvitedToTheGroup": "Контакт був запрошений в групу",
"@contactHasBeenInvitedToTheGroup": {
"type": "text",
"placeholders": {}
},
"contentViewer": "Переглядач вмісту",
"@contentViewer": {
"type": "text",
"placeholders": {}
},
"copiedToClipboard": "Скопійовано в буфер обміну",
"@copiedToClipboard": {
"type": "text",
@ -368,16 +313,6 @@
"error": {}
}
},
"couldNotSetAvatar": "Помилка встановлення аватара",
"@couldNotSetAvatar": {
"type": "text",
"placeholders": {}
},
"couldNotSetDisplayname": "Помилка встановлення показуваного імені",
"@couldNotSetDisplayname": {
"type": "text",
"placeholders": {}
},
"countParticipants": "Учасників: {count}",
"@countParticipants": {
"type": "text",
@ -390,11 +325,6 @@
"type": "text",
"placeholders": {}
},
"createAccountNow": "Створити обліковий запис зараз",
"@createAccountNow": {
"type": "text",
"placeholders": {}
},
"createdTheChat": "💬 {username} створює бесіду",
"@createdTheChat": {
"type": "text",
@ -407,11 +337,6 @@
"type": "text",
"placeholders": {}
},
"crossSigningDisabled": "Перехресне підписування вимкнено",
"@crossSigningDisabled": {
"type": "text",
"placeholders": {}
},
"crossSigningEnabled": "Перехресне підписування увімкнено",
"@crossSigningEnabled": {
"type": "text",
@ -477,21 +402,11 @@
"type": "text",
"placeholders": {}
},
"discardPicture": "Видалити зображення",
"@discardPicture": {
"type": "text",
"placeholders": {}
},
"displaynameHasBeenChanged": "Показуване ім'я було змінено",
"@displaynameHasBeenChanged": {
"type": "text",
"placeholders": {}
},
"donate": "Підтримати",
"@donate": {
"type": "text",
"placeholders": {}
},
"downloadFile": "Завантажити файл",
"@downloadFile": {
"type": "text",
@ -502,11 +417,6 @@
"type": "text",
"placeholders": {}
},
"editJitsiInstance": "Редагувати сервер Jitsi",
"@editJitsiInstance": {
"type": "text",
"placeholders": {}
},
"emoteExists": "Емодзі вже існує!",
"@emoteExists": {
"type": "text",
@ -547,21 +457,11 @@
"type": "text",
"placeholders": {}
},
"encryptionAlgorithm": "Алгоритм шифрування",
"@encryptionAlgorithm": {
"type": "text",
"placeholders": {}
},
"encryptionNotEnabled": "Шифрування вимкнено",
"@encryptionNotEnabled": {
"type": "text",
"placeholders": {}
},
"end2endEncryptionSettings": "Налаштування наскрізного шифрування",
"@end2endEncryptionSettings": {
"type": "text",
"placeholders": {}
},
"endedTheCall": "{senderName} завершує виклик",
"@endedTheCall": {
"type": "text",
@ -574,11 +474,6 @@
"type": "text",
"placeholders": {}
},
"enterAUsername": "Введіть ім'я користувача",
"@enterAUsername": {
"type": "text",
"placeholders": {}
},
"enterYourHomeserver": "Введіть адресу домашнього сервера",
"@enterYourHomeserver": {
"type": "text",
@ -589,11 +484,6 @@
"type": "text",
"placeholders": {}
},
"fileSize": "Розмір файлу",
"@fileSize": {
"type": "text",
"placeholders": {}
},
"fluffychat": "FluffyChat",
"@fluffychat": {
"type": "text",
@ -669,11 +559,6 @@
"type": "text",
"placeholders": {}
},
"homeserverIsNotCompatible": "Домашній сервер не сумісний",
"@homeserverIsNotCompatible": {
"type": "text",
"placeholders": {}
},
"id": "ID",
"@id": {
"type": "text",
@ -727,11 +612,6 @@
"link": {}
}
},
"isDeviceKeyCorrect": "Чи правильний цей ключ пристрою?",
"@isDeviceKeyCorrect": {
"type": "text",
"placeholders": {}
},
"isTyping": "пише…",
"@isTyping": {
"type": "text",
@ -749,11 +629,6 @@
"type": "text",
"placeholders": {}
},
"keysMissing": "Немає ключів",
"@keysMissing": {
"type": "text",
"placeholders": {}
},
"kicked": "👞 {username} вилучає {targetName}",
"@kicked": {
"type": "text",
@ -782,11 +657,6 @@
"localizedTimeShort": {}
}
},
"lastSeenIp": "Остання IP-адреса входу",
"@lastSeenIp": {
"type": "text",
"placeholders": {}
},
"lastSeenLongTimeAgo": "Давно не було в мережі",
"@lastSeenLongTimeAgo": {
"type": "text",
@ -846,16 +716,6 @@
"type": "text",
"placeholders": {}
},
"makeAModerator": "Призначити модератором",
"@makeAModerator": {
"type": "text",
"placeholders": {}
},
"makeAnAdmin": "Призначити адміністратором",
"@makeAnAdmin": {
"type": "text",
"placeholders": {}
},
"makeSureTheIdentifierIsValid": "Переконайтеся, що ідентифікатор дійсний",
"@makeSureTheIdentifierIsValid": {
"type": "text",
@ -896,11 +756,6 @@
"type": "text",
"placeholders": {}
},
"noCrossSignBootstrap": "Fluffychat зараз не підтримує увімкнення перехресного підписування. Увімкніть його з Element.",
"@noCrossSignBootstrap": {
"type": "text",
"placeholders": {}
},
"noEmotesFound": "Емоджі не знайдено. 😕",
"@noEmotesFound": {
"type": "text",
@ -911,11 +766,6 @@
"type": "text",
"placeholders": {}
},
"noMegolmBootstrap": "Замість цього увімкніть резервне копіювання онлайн-ключів з Element.",
"@noMegolmBootstrap": {
"type": "text",
"placeholders": {}
},
"none": "Нічого",
"@none": {
"type": "text",
@ -931,28 +781,11 @@
"type": "text",
"placeholders": {}
},
"notSupportedInWeb": "Не підтримується вебверсією",
"@notSupportedInWeb": {
"type": "text",
"placeholders": {}
},
"numberSelected": "Вибрано {number}",
"@numberSelected": {
"type": "text",
"placeholders": {
"number": {}
}
},
"ok": "Гаразд",
"@ok": {
"type": "text",
"placeholders": {}
},
"onlineKeyBackupDisabled": "Резервне онлайн-копіювання ключів вимкнено",
"@onlineKeyBackupDisabled": {
"type": "text",
"placeholders": {}
},
"onlineKeyBackupEnabled": "Резервне онлайн-копіювання ключів увімкнено",
"@onlineKeyBackupEnabled": {
"type": "text",
@ -978,11 +811,6 @@
"type": "text",
"placeholders": {}
},
"participatingUserDevices": "Пристрої користувачів-учасників",
"@participatingUserDevices": {
"type": "text",
"placeholders": {}
},
"passphraseOrKey": "парольна фраза або ключ відновлення",
"@passphraseOrKey": {
"type": "text",
@ -1086,11 +914,6 @@
"type": "text",
"placeholders": {}
},
"removeMessage": "Вилучити повідомлення",
"@removeMessage": {
"type": "text",
"placeholders": {}
},
"renderRichContent": "Показувати форматований вміст повідомлення",
"@renderRichContent": {
"type": "text",
@ -1106,16 +929,6 @@
"type": "text",
"placeholders": {}
},
"requestToReadOlderMessages": "Запит на читання давніших повідомлень",
"@requestToReadOlderMessages": {
"type": "text",
"placeholders": {}
},
"revokeAllPermissions": "Відкликати всі дозволи",
"@revokeAllPermissions": {
"type": "text",
"placeholders": {}
},
"roomHasBeenUpgraded": "Кімнату було оновлено",
"@roomHasBeenUpgraded": {
"type": "text",
@ -1126,11 +939,6 @@
"type": "text",
"placeholders": {}
},
"searchForAChat": "Пошук бесіди",
"@searchForAChat": {
"type": "text",
"placeholders": {}
},
"seenByUser": "Переглянуто {username}",
"@seenByUser": {
"type": "text",
@ -1201,16 +1009,6 @@
"username": {}
}
},
"sessionVerified": "Сеанс звірено",
"@sessionVerified": {
"type": "text",
"placeholders": {}
},
"setAProfilePicture": "Додати зображення профілю",
"@setAProfilePicture": {
"type": "text",
"placeholders": {}
},
"setGroupDescription": "Додати опис групи",
"@setGroupDescription": {
"type": "text",
@ -1258,11 +1056,6 @@
"type": "text",
"placeholders": {}
},
"startYourFirstChat": "Почніть свою першу бесіду просто зараз! 🙂\n- Торкніться «Нова бесіда»\n- Скануйте QR-код друга\n- Отримуйте задоволення від спілкування",
"@startYourFirstChat": {
"type": "text",
"placeholders": {}
},
"statusExampleMessage": "Як справи сьогодні?",
"@statusExampleMessage": {
"type": "text",
@ -1283,11 +1076,6 @@
"type": "text",
"placeholders": {}
},
"tapToShowMenu": "Торкніться, щоб відкрити меню",
"@tapToShowMenu": {
"type": "text",
"placeholders": {}
},
"theyDontMatch": "Вони відрізняються",
"@theyDontMatch": {
"type": "text",
@ -1308,16 +1096,6 @@
"type": "text",
"placeholders": {}
},
"timeOfDay": "{hours12}:{minutes} {suffix}",
"@timeOfDay": {
"type": "text",
"placeholders": {
"hours12": {},
"hours24": {},
"minutes": {},
"suffix": {}
}
},
"title": "FluffyChat",
"@title": {
"description": "Title for the application",
@ -1364,21 +1142,11 @@
"type": {}
}
},
"unknownSessionVerify": "Невідомий сеанс, будь ласка, перевірте",
"@unknownSessionVerify": {
"type": "text",
"placeholders": {}
},
"unmuteChat": "Увімкнути сповіщення",
"@unmuteChat": {
"type": "text",
"placeholders": {}
},
"useAmoledTheme": "Використовувати сумісні з AMOLED кольори?",
"@useAmoledTheme": {
"type": "text",
"placeholders": {}
},
"userAndOthersAreTyping": "{username} та {count} інших пишуть…",
"@userAndOthersAreTyping": {
"type": "text",
@ -1422,21 +1190,11 @@
"type": {}
}
},
"verifiedSession": "Сеанс успішно перевірено!",
"@verifiedSession": {
"type": "text",
"placeholders": {}
},
"verify": "Перевірити",
"@verify": {
"type": "text",
"placeholders": {}
},
"verifyManual": "Перевірити вручну",
"@verifyManual": {
"type": "text",
"placeholders": {}
},
"verifyStart": "Почати перевірку",
"@verifyStart": {
"type": "text",
@ -1452,11 +1210,6 @@
"type": "text",
"placeholders": {}
},
"verifyUser": "Перевірити користувача",
"@verifyUser": {
"type": "text",
"placeholders": {}
},
"videoCall": "Відеовиклик",
"@videoCall": {
"type": "text",
@ -1502,21 +1255,11 @@
"type": "text",
"placeholders": {}
},
"warningEncryptionInBeta": "Наскрізне шифрування наразі в бета-версії! Користуйтеся на свій страх і ризик!",
"@warningEncryptionInBeta": {
"type": "text",
"placeholders": {}
},
"wednesday": "Середа",
"@wednesday": {
"type": "text",
"placeholders": {}
},
"welcomeText": "Ласкаво просимо до найсимпатичнішого месенджера в мережі Matrix.",
"@welcomeText": {
"type": "text",
"placeholders": {}
},
"whoIsAllowedToJoinThisGroup": "Кому дозволено приєднуватися до цієї групи",
"@whoIsAllowedToJoinThisGroup": {
"type": "text",
@ -1557,11 +1300,6 @@
"type": "text",
"placeholders": {}
},
"yourOwnUsername": "Ваше власне ім'я користувача",
"@yourOwnUsername": {
"type": "text",
"placeholders": {}
},
"pushRules": "Правила сповіщень",
"@pushRules": {
"type": "text",
@ -1734,11 +1472,6 @@
"type": "text",
"placeholders": {}
},
"invalidEmail": "Неприпустима е-пошта",
"@invalidEmail": {
"type": "text",
"placeholders": {}
},
"joinRoom": "Приєднатися до кімнати",
"@joinRoom": {
"type": "text",
@ -1761,8 +1494,6 @@
},
"shareYourInviteLink": "Поділіться своїм посиланням запрошення",
"@shareYourInviteLink": {},
"createNewChatExplaination": "Просто зіскануйте QR-код або поділіться посиланням на запрошення, якщо ви не поруч один з одним.",
"@createNewChatExplaination": {},
"typeInInviteLinkManually": "Введіть посилання запрошення власноруч...",
"@typeInInviteLinkManually": {},
"scanQrCode": "Сканувати QR-код",
@ -1819,11 +1550,6 @@
"type": "text",
"placeholders": {}
},
"securityKey": "Ключ безпеки",
"@securityKey": {
"type": "text",
"placeholders": {}
},
"replaceRoomWithNewerVersion": "Замінити кімнату новішою версією",
"@replaceRoomWithNewerVersion": {
"type": "text",
@ -1839,16 +1565,6 @@
"type": "text",
"placeholders": {}
},
"tapOnDeviceToVerify": "Торкніться пристрою, щоб перевірити",
"@tapOnDeviceToVerify": {
"type": "text",
"placeholders": {}
},
"userUnknownVerification": "Користувач має невідомий стан перевірки",
"@userUnknownVerification": {
"type": "text",
"placeholders": {}
},
"weSentYouAnEmail": "Ми надіслали вам електронний лист",
"@weSentYouAnEmail": {
"type": "text",
@ -1859,11 +1575,6 @@
"type": "text",
"placeholders": {}
},
"zoomIn": "Збільшити",
"@zoomIn": {
"type": "text",
"placeholders": {}
},
"addToSpace": "Додати простір",
"@addToSpace": {},
"roomVersion": "Версія кімнати",
@ -1881,21 +1592,6 @@
"type": "text",
"placeholders": {}
},
"sentryInfo": "Відомості про вашу приватність: https://sentry.io/security/",
"@sentryInfo": {
"type": "text",
"placeholders": {}
},
"changesHaveBeenSaved": "Зміни збережено",
"@changesHaveBeenSaved": {
"type": "text",
"placeholders": {}
},
"discoverGroups": "Огляд груп",
"@discoverGroups": {
"type": "text",
"placeholders": {}
},
"startedACall": "{senderName} розпочинає виклик",
"@startedACall": {
"type": "text",
@ -1908,11 +1604,6 @@
"type": "text",
"placeholders": {}
},
"dontAskAgain": "Скасувати та не запитувати знову",
"@dontAskAgain": {
"type": "text",
"placeholders": {}
},
"commandInvalid": "Неприпустима команда",
"@commandInvalid": {
"type": "text"
@ -1947,16 +1638,6 @@
"type": "text",
"placeholders": {}
},
"clearText": "Очистити текст",
"@clearText": {
"type": "text",
"placeholders": {}
},
"addNewFriend": "Додати нового друга",
"@addNewFriend": {
"type": "text",
"placeholders": {}
},
"badServerVersionsException": "Домашній сервер підтримує такі версії специфікацій:\n{serverVersions}\nАле цей застосунок підтримує лише {supportedVersions}",
"@badServerVersionsException": {
"type": "text",
@ -2015,11 +1696,6 @@
"type": "text",
"placeholders": {}
},
"securityKeyLost": "Ключ безпеки втрачено?",
"@securityKeyLost": {
"type": "text",
"placeholders": {}
},
"seenByUserAndCountOthers": "{count, plural, other{Переглянули {username} і {count} інших}}",
"@seenByUserAndCountOthers": {
"type": "text",
@ -2028,11 +1704,6 @@
"count": {}
}
},
"tapToShowImage": "Торкніться, щоб показати зображення",
"@tapToShowImage": {
"type": "text",
"placeholders": {}
},
"errorObtainingLocation": "Помилка під час отримання розташування: {error}",
"@errorObtainingLocation": {
"type": "text",
@ -2050,21 +1721,6 @@
"type": "text",
"placeholders": {}
},
"audioPlayerPause": "Пауза",
"@audioPlayerPause": {
"type": "text",
"placeholders": {}
},
"audioPlayerPlay": "Відтворити",
"@audioPlayerPlay": {
"type": "text",
"placeholders": {}
},
"noDescription": "Без опису",
"@noDescription": {
"type": "text",
"placeholders": {}
},
"noMatrixServer": "{server1} не є сервером matrix, використовувати {server2} натомість?",
"@noMatrixServer": {
"type": "text",
@ -2097,13 +1753,6 @@
"type": "text",
"placeholder": {}
},
"savedFileAs": "Файл збережено як {filename}",
"@savedFileAs": {
"type": "text",
"placeholders": {
"filename": {}
}
},
"pleaseChooseAPasscode": "Виберіть код доступу",
"@pleaseChooseAPasscode": {
"type": "text",
@ -2159,11 +1808,6 @@
"type": "text",
"placeholders": {}
},
"friends": "Друзі",
"@friends": {
"type": "text",
"placeholders": {}
},
"homeserver": "Домашній сервер",
"@homeserver": {},
"goToTheNewRoom": "Перейти до нової кімнати",
@ -2186,11 +1830,6 @@
"type": "text",
"placeholders": {}
},
"chatHasBeenRemovedFromThisSpace": "Бесіду видалено з цього простору",
"@chatHasBeenRemovedFromThisSpace": {
"type": "text",
"placeholders": {}
},
"chatHasBeenAddedToThisSpace": "Бесіду додано до цього простору",
"@chatHasBeenAddedToThisSpace": {},
"chatBackupDescription": "Ваші старі повідомлення захищені ключем відновлення. Переконайтеся, що ви не втратите його.",
@ -2205,12 +1844,6 @@
},
"yourChatBackupHasBeenSetUp": "Резервне копіювання бесіди налаштовано.",
"@yourChatBackupHasBeenSetUp": {},
"setupChatBackup": "Налаштувати резервне копіювання бесіди",
"@setupChatBackup": {},
"iWroteDownTheKey": "Ключ записано",
"@iWroteDownTheKey": {},
"setupChatBackupDescription": "Щоб захистити ваші повідомлення, ми створили для вас ключ відновлення.\nЗберігайте його в надійному місці, наприклад, у менеджері паролів.",
"@setupChatBackupDescription": {},
"clearArchive": "Очистити архів",
"@clearArchive": {},
"commandHint_html": "Надіслати текст у форматі HTML",
@ -2250,11 +1883,6 @@
"type": "text",
"placeholders": {}
},
"enableChatBackup": "Увімкніть резервне копіювання бесід, щоб ніколи не втратити доступ до них.",
"@enableChatBackup": {
"type": "text",
"placeholders": {}
},
"loginWith": "Увійти за допомогою {brand}",
"@loginWith": {
"type": "text",
@ -2262,16 +1890,6 @@
"brand": {}
}
},
"noPublicRoomsFound": "Загальнодоступних кімнат не знайдено…",
"@noPublicRoomsFound": {
"type": "text",
"placeholders": {}
},
"noStatusesFound": "Поки що статусів не знайдено.",
"@noStatusesFound": {
"type": "text",
"placeholders": {}
},
"obtainingLocation": "Отримання розташування…",
"@obtainingLocation": {
"type": "text",
@ -2296,8 +1914,6 @@
"type": "text",
"placeholders": {}
},
"newUsernameDescription": "Ваш ID користувача матиме формат @username:servername",
"@newUsernameDescription": {},
"serverRequiresEmail": "Цей сервер потребує перевірки вашої адресу е-пошти для реєстрації.",
"@serverRequiresEmail": {},
"pleaseFollowInstructionsOnWeb": "Виконайте вказівки вебсайту та торкніться далі.",
@ -2305,11 +1921,6 @@
"type": "text",
"placeholders": {}
},
"saveFileToFolder": "Зберегти файл до цієї теки",
"@saveFileToFolder": {
"type": "text",
"placeholders": {}
},
"sendVideo": "Надіслати відео",
"@sendVideo": {
"type": "text",
@ -2350,13 +1961,6 @@
"type": "text",
"placeholders": {}
},
"unreadMessages": "{unreadEvents, plural, =1{1 непрочитане повідомлення} few{{unreadEvents} непрочитані повідомлення} many{{unreadEvents} непрочитаних повідомлень} other{{unreadEvents} непрочитані повідомлення}}",
"@unreadMessages": {
"type": "text",
"placeholders": {
"unreadEvents": {}
}
},
"unreadChats": "{unreadCount, plural, =1{1 непрочитана бесіда} few{{unreadCount} непрочитані бесіди} many{{unreadCount} непрочитаних бесід} other{{unreadCount} непрочитані бесіди}}",
"@unreadChats": {
"type": "text",
@ -2364,28 +1968,11 @@
"unreadCount": {}
}
},
"unlockChatBackup": "Розблокувати резервну копію бесіди",
"@unlockChatBackup": {
"type": "text",
"placeholders": {}
},
"withTheseAddressesRecoveryDescription": "За допомогою цих адрес ви можете відновити свій пароль.",
"@withTheseAddressesRecoveryDescription": {
"type": "text",
"placeholders": {}
},
"youWillBeConnectedTo": "Ви будете під'єднані до {homeserver}",
"@youWillBeConnectedTo": {
"type": "text",
"placeholders": {
"homeserver": {}
}
},
"yourChatsAreBeingSynced": "Ваші бесіди синхронізуються…",
"@yourChatsAreBeingSynced": {
"type": "text",
"placeholders": {}
},
"privacy": "Приватність",
"@privacy": {
"type": "text",
@ -2450,38 +2037,11 @@
"type": "text",
"placeholders": {}
},
"deviceVerifyDescription": "Шифрування безпечне лише тоді, коли всі пристрої перевірено.",
"@deviceVerifyDescription": {
"type": "text",
"placeholders": {}
},
"pleaseEnterSecurityKey": "Введіть ключ безпеки:",
"@pleaseEnterSecurityKey": {
"type": "text",
"placeholders": {}
},
"editBlockedServers": "Редагувати заблоковані сервери",
"@editBlockedServers": {
"type": "text",
"placeholders": {}
},
"moreEvents": "{count,plural, =1{ще 1 подія} few{ще {count} події} many{ще {count} подій} other{ще {count} події}}",
"@moreEvents": {
"type": "text",
"placeholders": {
"count": {}
}
},
"publicGroups": "Загальнодоступні групи",
"@publicGroups": {
"type": "text",
"placeholders": {}
},
"publicKey": "Відкритий ключ",
"@publicKey": {
"type": "text",
"placeholders": {}
},
"showPassword": "Показати пароль",
"@showPassword": {
"type": "text",
@ -2497,11 +2057,6 @@
"type": "text",
"placeholders": {}
},
"sendBugReports": "Дозволити надсилання звітів про вади за допомогою sentry.io",
"@sendBugReports": {
"type": "text",
"placeholders": {}
},
"passwordHasBeenChanged": "Пароль змінено",
"@passwordHasBeenChanged": {
"type": "text",
@ -2522,21 +2077,11 @@
"type": "text",
"placeholders": {}
},
"soundVibrationLedColor": "Звук, вібрація, колір світлодіода",
"@soundVibrationLedColor": {
"type": "text",
"placeholders": {}
},
"pleaseEnterYourPin": "Введіть свій PIN-код",
"@pleaseEnterYourPin": {
"type": "text",
"placeholders": {}
},
"publicSpace": "Загальнодоступний простір",
"@publicSpace": {
"type": "text",
"placeholders": {}
},
"spaceName": "Назва простору",
"@spaceName": {
"type": "text",
@ -2562,23 +2107,8 @@
"type": "text",
"placeholders": {}
},
"userNotVerified": "Користувача не перевірено",
"@userNotVerified": {
"type": "text",
"placeholders": {}
},
"userVerified": "Перевірений користувач",
"@userVerified": {
"type": "text",
"placeholders": {}
},
"unverified": "Неперевірений",
"@unverified": {},
"zoomOut": "Зменшити",
"@zoomOut": {
"type": "text",
"placeholders": {}
},
"locationDisabledNotice": "Служби визначення місцеположення вимкнені. Увімкніть їх, щоб могти надавати доступ до вашого місцеположення.",
"@locationDisabledNotice": {
"type": "text",
@ -2589,8 +2119,6 @@
"type": "text",
"placeholders": {}
},
"newPasswordDescription": "Щоб мати можливість відновити пароль потрібно буде додати адресу е-пошти до свого облікового запису.",
"@newPasswordDescription": {},
"oneClientLoggedOut": "На одному з ваших клієнтів виконано вихід із системи",
"@oneClientLoggedOut": {},
"bundleName": "Назва вузла",
@ -2638,18 +2166,10 @@
"@addToSpaceDescription": {},
"loginWithOneClick": "Увійти одним натисканням",
"@loginWithOneClick": {},
"removeFromSpaceDescription": "Це вилучає цей бесіду з поточного простору. Її все одно буде видно у розділі «Усі бесіди».",
"@removeFromSpaceDescription": {},
"removeFromSpace": "Вилучити з простору",
"@removeFromSpace": {},
"start": "Почати",
"@start": {},
"setupChatBackupNow": "Налаштуйте резервне копіювання бесіди зараз",
"@setupChatBackupNow": {},
"pleaseEnterSecurityKeyDescription": "Щоб розблокувати резервну копію бесіди, введіть ключ безпеки, який був створений під час попереднього сеансу. Ключ безпеки — це не ваш пароль.",
"@pleaseEnterSecurityKeyDescription": {},
"saveTheSecurityKeyNow": "Зберегти ключ безпеки зараз",
"@saveTheSecurityKeyNow": {},
"commandHint_discardsession": "Відкинути сеанс",
"@commandHint_discardsession": {
"type": "text",
@ -2727,10 +2247,6 @@
"@reportUser": {},
"openChat": "Відкрити бесіду",
"@openChat": {},
"integrationsNotImplemented": "Редагування віджетів та інтеграцій поки що неможливе.",
"@integrationsNotImplemented": {},
"editIntegrations": "Редагувати віджети та інтеграції",
"@editIntegrations": {},
"matrixWidgets": "Віджети Matrix",
"@matrixWidgets": {},
"reactedWith": "{sender} реагує з {reaction}",
@ -2745,8 +2261,6 @@
"@emojis": {},
"pinMessage": "Прикріпити в кімнаті",
"@pinMessage": {},
"pinnedEventsError": "Помилка завантаження закріплених повідомлень",
"@pinnedEventsError": {},
"confirmEventUnpin": "Ви впевнені, що бажаєте назавжди відкріпите подію?",
"@confirmEventUnpin": {},
"placeCall": "Здійснити виклик",
@ -2852,12 +2366,8 @@
"user": {}
}
},
"showSpaces": "Показати список просторів",
"@showSpaces": {},
"noEmailWarning": "Введіть справжню адресу електронної пошти. В іншому випадку ви не зможете скинути пароль. Якщо ви цього не хочете, торкніться кнопки ще раз, щоб продовжити.",
"@noEmailWarning": {},
"saveTheRecoveryKeyNow": "Збережіть ключ відновлення зараз",
"@saveTheRecoveryKeyNow": {},
"saveKeyManuallyDescription": "Збережіть цей ключ вручну, запустивши діалогове вікно спільного доступу до системи або буфер обміну.",
"@saveKeyManuallyDescription": {},
"storeInAndroidKeystore": "Зберегти в Android KeyStore",
@ -2894,8 +2404,6 @@
"@hydrate": {},
"hydrateTorLong": "Минулого разу ви експортували свій сеанс із TOR? Швидко імпортуйте його та продовжуйте спілкування.",
"@hydrateTorLong": {},
"advanced": "Додатково",
"@advanced": {},
"indexedDbErrorTitle": "Проблеми приватного режиму",
"@indexedDbErrorTitle": {},
"indexedDbErrorLong": "На жаль, сховище повідомлень не ввімкнуто у приватному режимі типово.\nВідкрийте\n - about:config\n - установіть для dom.indexedDB.privateBrowsing.enabled значення true\nІнакше запустити FluffyChat буде неможливо.",
@ -2912,15 +2420,6 @@
"@dehydrateTorLong": {},
"hydrateTor": "Користувачі TOR: імпорт експортованого сеансу",
"@hydrateTor": {},
"numberRoomMembers": "Учасників: {number}",
"@numberRoomMembers": {
"type": "number",
"placeholders": {
"number": {}
}
},
"suggestedRooms": "Знайти групи у просторі",
"@suggestedRooms": {},
"user": "Користувач",
"@user": {},
"custom": "Користувацький",
@ -2929,8 +2428,6 @@
"@updateAvailable": {},
"updateNow": "Почати оновлення у фоновому режимі",
"@updateNow": {},
"allSuggestedRoomsJoined": "Ви приєдналися до всіх запропонованих кімнат",
"@allSuggestedRoomsJoined": {},
"supposedMxid": "Це має бути {mxid}",
"@supposedMxid": {
"type": "text",
@ -3038,5 +2535,9 @@
"noSearchResult": "Немає відповідних результатів пошуку.",
"@noSearchResult": {},
"letsStart": "Розпочнімо",
"@letsStart": {}
"@letsStart": {},
"enterInviteLinkOrMatrixId": "Введіть запрошувальне посилання або Matrix ID...",
"@enterInviteLinkOrMatrixId": {},
"reopenChat": "Відновити бесіду",
"@reopenChat": {}
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -1,557 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>FluffyChat - Official Website</title>
<meta name="description" content="A cute and secure chatclient for the matrix protocol">
<meta name="keywords"
content="Fluffychat, Matrix, Web, Android, iOS, Desktop, Chat, Client, Chatclient, Matrix.org, Secure, E2EE, End to End, Encryption, End to End Encryption, F-Droid, Foss, FOSS, OpenSource, Free, Community, Open">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "MobileApplication",
"name": "Fluffychat",
"applicationCategory": "CommunicationApplication",
"countriesNotSupported": "fr",
"operatingSystem": "ANDROID",
"releaseNotes": "https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md",
"screenshot": "https://gitlab.com/famedly/fluffychat/-/raw/main/docs/screenshots/mobile.png",
"softwareHelp": "https://gitlab.com/famedly/fluffychat/-/wikis/FAQ",
"author": {
"@type": "Person",
"callSign": "KrilleFear"
},
"license": "https://gitlab.com/famedly/fluffychat/-/blob/main/LICENSE",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"ratingCount": "133"
},
"installUrl": "https://play.google.com/store/apps/details?id=chat.fluffy.fluffychat"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "MobileApplication",
"name": "Fluffychat",
"applicationCategory": "CommunicationApplication",
"countriesNotSupported": "fr",
"operatingSystem": "ANDROID",
"releaseNotes": "https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md",
"screenshot": "https://gitlab.com/famedly/fluffychat/-/raw/main/docs/screenshots/mobile.png",
"softwareHelp": "https://gitlab.com/famedly/fluffychat/-/wikis/FAQ",
"author": {
"@type": "Person",
"callSign": "KrilleFear"
},
"license": "https://gitlab.com/famedly/fluffychat/-/blob/main/LICENSE",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"ratingCount": "133"
},
"installUrl": "https://f-droid.org/de/packages/chat.fluffy.fluffychat/"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "MobileApplication",
"name": "Fluffychat",
"applicationCategory": "CommunicationApplication",
"countriesNotSupported": "fr",
"operatingSystem": "IOS",
"releaseNotes": "https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md",
"screenshot": "https://gitlab.com/famedly/fluffychat/-/raw/main/docs/screenshots/mobile.png",
"softwareHelp": "https://gitlab.com/famedly/fluffychat/-/wikis/FAQ",
"author": {
"@type": "Person",
"callSign": "KrilleFear"
},
"license": "https://gitlab.com/famedly/fluffychat/-/blob/main/LICENSE",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.4",
"ratingCount": "28"
},
"installUrl": "https://apps.apple.com/app/fluffychat/id1551469600"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "Fluffychat",
"applicationCategory": "CommunicationApplication",
"countriesNotSupported": "fr",
"operatingSystem": "WEB",
"releaseNotes": "https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md",
"screenshot": "https://gitlab.com/famedly/fluffychat/-/raw/main/docs/screenshots/mobile.png",
"softwareHelp": "https://gitlab.com/famedly/fluffychat/-/wikis/FAQ",
"author": {
"@type": "Person",
"callSign": "KrilleFear"
},
"license": "https://gitlab.com/famedly/fluffychat/-/blob/main/LICENSE",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"ratingCount": "133"
},
"url": "https://fluffychat.im/web",
"downloadUrl": "https://fluffychat.im/web",
"installUrl": "https://fluffychat.im/web"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Fluffychat",
"applicationCategory": "CommunicationApplication",
"countriesNotSupported": "fr",
"operatingSystem": "LINUX",
"releaseNotes": "https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md",
"screenshot": "https://gitlab.com/famedly/fluffychat/-/raw/main/docs/screenshots/mobile.png",
"softwareHelp": "https://gitlab.com/famedly/fluffychat/-/wikis/FAQ",
"author": {
"@type": "Person",
"callSign": "KrilleFear"
},
"license": "https://gitlab.com/famedly/fluffychat/-/blob/main/LICENSE",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"ratingCount": "133"
},
"downloadUrl": "https://snapcraft.io/fluffychat",
"installUrl": "https://snapcraft.io/fluffychat"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Fluffychat",
"applicationCategory": "CommunicationApplication",
"countriesNotSupported": "fr",
"operatingSystem": "LINUX",
"releaseNotes": "https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md",
"screenshot": "https://gitlab.com/famedly/fluffychat/-/raw/main/docs/screenshots/mobile.png",
"softwareHelp": "https://gitlab.com/famedly/fluffychat/-/wikis/FAQ",
"author": {
"@type": "Person",
"callSign": "KrilleFear"
},
"license": "https://gitlab.com/famedly/fluffychat/-/blob/main/LICENSE",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"ratingCount": "133"
},
"downloadUrl": "https://flathub.org/apps/details/im.fluffychat.Fluffychat",
"installUrl": "https://flathub.org/apps/details/im.fluffychat.Fluffychat"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "FluffyChat - Official Website",
"url": "https://fluffychat.im",
"description": "A cute and secure chatclient for the matrix protocol",
"thumbnailUrl": "https://fluffychat.im/favicon.png",
"inLanguage": "de-de"
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"description": "Breadcrumbs list",
"name": "Breadcrumbs",
"itemListElement": [
{
"@type": "ListItem",
"item": {
"@id": "https://fluffychat.im",
"name": "Homepage"
},
"position": 1
}
]
}
</script>
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" href="tailwind.css">
<!-- Animation CSS-->
<meta charset="utf-8">
<title>FluffyChat Official Website</title>
<meta name="identifier-url" content="https://fluffychat.im" />
<meta name="title" content="FluffyChat Official Website" />
<meta name="description" content="The cutest messenger in the Matrix network" />
<meta name="abstract" content="FluffyChat is the cutest messenger in the Matrix network" />
<meta name="keywords" content="FluffyChat, Matrix, Flutter, App" />
<meta name="author" content="Krille Fear" />
<meta name="revisit-after" content="15" />
<meta name="language" content="EN" />
<meta name="robots" content="All" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.png">
<link href="tailwind.css" rel="stylesheet">
<style>
@font-face {
font-family: Zen Kurenaido;
src: url(ZenKurenaido-Regular.ttf);
}
/* ----------------------------------------------
* Generated by Animista
* w: http://animista.net, t: @cssanimista
* ---------------------------------------------- */
.slide-in-bottom {
-webkit-animation: slide-in-bottom .5s cubic-bezier(.25, .46, .45, .94) both;
animation: slide-in-bottom .5s cubic-bezier(.25, .46, .45, .94) both
}
.slide-in-bottom-h1 {
-webkit-animation: slide-in-bottom .5s cubic-bezier(.25, .46, .45, .94) .5s both;
animation: slide-in-bottom .5s cubic-bezier(.25, .46, .45, .94) .5s both
}
.slide-in-bottom-subtitle {
-webkit-animation: slide-in-bottom .5s cubic-bezier(.25, .46, .45, .94) .75s both;
animation: slide-in-bottom .5s cubic-bezier(.25, .46, .45, .94) .75s both
}
.fade-in {
-webkit-animation: fade-in 1.2s cubic-bezier(.39, .575, .565, 1.000) 1s both;
animation: fade-in 1.2s cubic-bezier(.39, .575, .565, 1.000) 1s both
}
.bounce-top-icons {
-webkit-animation: bounce-top .9s 1s both;
animation: bounce-top .9s 1s both
}
@-webkit-keyframes slide-in-bottom {
0% {
-webkit-transform: translateY(1000px);
transform: translateY(1000px);
opacity: 0
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1
}
}
@keyframes slide-in-bottom {
0% {
-webkit-transform: translateY(1000px);
transform: translateY(1000px);
opacity: 0
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
opacity: 1
}
}
@-webkit-keyframes bounce-top {
0% {
-webkit-transform: translateY(-45px);
transform: translateY(-45px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
opacity: 1
}
24% {
opacity: 1
}
40% {
-webkit-transform: translateY(-24px);
transform: translateY(-24px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
65% {
-webkit-transform: translateY(-12px);
transform: translateY(-12px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
82% {
-webkit-transform: translateY(-6px);
transform: translateY(-6px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
93% {
-webkit-transform: translateY(-4px);
transform: translateY(-4px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
25%,
55%,
75%,
87% {
-webkit-transform: translateY(0);
transform: translateY(0);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
opacity: 1
}
}
@keyframes bounce-top {
0% {
-webkit-transform: translateY(-45px);
transform: translateY(-45px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
opacity: 1
}
24% {
opacity: 1
}
40% {
-webkit-transform: translateY(-24px);
transform: translateY(-24px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
65% {
-webkit-transform: translateY(-12px);
transform: translateY(-12px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
82% {
-webkit-transform: translateY(-6px);
transform: translateY(-6px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
93% {
-webkit-transform: translateY(-4px);
transform: translateY(-4px);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in
}
25%,
55%,
75%,
87% {
-webkit-transform: translateY(0);
transform: translateY(0);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
opacity: 1
}
}
@-webkit-keyframes fade-in {
0% {
opacity: 0
}
100% {
opacity: 1
}
}
@keyframes fade-in {
0% {
opacity: 0
}
100% {
opacity: 1
}
}
</style>
</head>
<body
class="flex flex-col items-center justify-center min-h-screen w-screen bg-gradient-to-t from-purple-200 to-blue-50 dark:from-gray-800 dark:to-slate-900 p-4"
style="font-family: 'Zen Kurenaido', sans-serif;">
<img src="favicon.png" class="h-10" />
<h1 class="flex text-4xl items-center mb-4">
<span style="color: #5625BA">Fluffy</span>
<span style="color: #41a2bc">Chat</span>
</h1>
<img src="screenshots/screenshots.png" class="sm:max-w-lg max-w-screen mb-8" />
<body class="leading-normal tracking-normal text-gray-900" style="font-family: 'Zen Kurenaido', sans-serif;">
<div class="h-screen pb-14 bg-right bg-cover" style="background-image:url('bg.svg');">
<!--Nav-->
<div class="w-full container mx-auto p-6">
<div class="w-full flex items-center justify-between">
<a class="flex items-center no-underline hover:no-underline font-bold text-2xl lg:text-4xl" href="#">
<img src="favicon.png" class="h-8 fill-current text-indigo-600 pr-2" /> <span
style="color: #5625BA">Fluffy</span><span style="color: #41a2bc">Chat</span>
</a>
<div class="flex w-1/2 justify-end content-center">
<a class="inline-block text-blue-300 no-underline hover:text-indigo-800 hover:text-underline text-center h-10 p-2 md:h-auto md:p-4"
href="https://matrix.to/#/#fluffychat:matrix.org">
<svg class="fill-current h-6" enable-background="new -91 49.217 56.693 56.693" id="Layer_1"
version="1.1" viewBox="-91 49.217 56.693 56.693" xml:space="preserve"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path
d="M-38.3289,79.8244c-0.7526-2.2362-3.1756-3.4388-5.4117-2.6861l-4.5351,1.5264l-3.0737-9.1321l4.4169-1.4866 c2.2362-0.7526,3.4388-3.1756,2.6861-5.4117c-0.7526-2.2362-3.1756-3.4388-5.4117-2.6861l-4.4168,1.4866l-1.4877-4.4201 c-0.7527-2.2362-3.1756-3.4388-5.4117-2.6861v0c-2.2362,0.7526-3.4388,3.1756-2.6861,5.4117l1.4877,4.4201l-9.3246,3.1385 l-1.4697-4.3666c-0.7527-2.2362-3.1756-3.4388-5.4117-2.6861c-2.2362,0.7527-3.4388,3.1756-2.6861,5.4117l1.4697,4.3666 l-4.445,1.4961c-2.2362,0.7527-3.4388,3.1756-2.6861,5.4117v0c0.7526,2.2362,3.1756,3.4388,5.4117,2.6861l4.445-1.4961 l3.0737,9.1321l-4.3268,1.4563c-2.2362,0.7527-3.4388,3.1756-2.6861,5.4117c0.7526,2.2362,3.1756,3.4388,5.4117,2.6861 l4.3268-1.4563l1.5778,4.6877c0.7527,2.2362,3.1756,3.4388,5.4117,2.6861c2.2362-0.7527,3.4388-3.1756,2.6861-5.4117l-1.5778-4.6877 l9.3246-3.1385l1.5598,4.6342c0.7527,2.2362,3.1756,3.4388,5.4117,2.6861c2.2362-0.7527,3.4388-3.1756,2.6861-5.4117l-1.5598-4.6342 l4.5351-1.5264C-38.7789,84.4835-37.5762,82.0606-38.3289,79.8244z M-65.6982,84.5288l-3.0737-9.1321l9.3246-3.1385l3.0737,9.1321 L-65.6982,84.5288z" />
</svg>
</a>
<a class="inline-block text-blue-300 no-underline hover:text-indigo-800 hover:text-underline text-center h-10 p-2 md:h-auto md:p-4"
href="https://metalhead.club/@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;">
<clipPath id="_clip1">
<rect x="33.6" y="-0.035" width="932.844" height="1000" />
</clipPath>
<g clip-path="url(#_clip1)">
<path
d="M946.586,599.455c-13.713,70.541 -122.816,147.742 -248.121,162.703c-65.341,7.796 -129.674,14.962 -198.275,11.815c-112.191,-5.139 -200.716,-26.776 -200.716,-26.776c0,10.92 0.673,21.319 2.02,31.044c14.586,110.711 109.787,117.344 199.967,120.436c91.021,3.114 172.068,-22.44 172.068,-22.44l3.74,82.281c0,0 -63.666,34.185 -177.079,40.473c-62.539,3.437 -140.192,-1.573 -230.636,-25.511c-196.158,-51.916 -229.893,-260.996 -235.055,-473.143c-1.573,-62.987 -0.603,-122.381 -0.603,-172.056c0,-216.931 142.142,-280.516 142.142,-280.516c71.672,-32.914 194.655,-46.755 322.508,-47.8l3.142,0c127.853,1.045 250.917,14.886 322.583,47.8c0,0 142.138,63.585 142.138,280.516c0,0 1.783,160.053 -19.823,271.174"
style="fill-rule:nonzero;" />
<path
d="M798.748,345.11l0,262.667l-104.07,0l0,-254.946c0,-53.743 -22.614,-81.021 -67.847,-81.021c-50.012,0 -75.077,32.359 -75.077,96.343l0,139.547l-103.457,0l0,-139.547c0,-63.984 -25.07,-96.343 -75.082,-96.343c-45.233,0 -67.847,27.278 -67.847,81.021l0,254.946l-104.07,0l0,-262.667c0,-53.683 13.669,-96.343 41.127,-127.904c28.314,-31.561 65.395,-47.741 111.425,-47.741c53.256,0 93.585,20.468 120.251,61.41l25.922,43.451l25.927,-43.451c26.66,-40.942 66.99,-61.41 120.251,-61.41c46.025,0 83.106,16.18 111.425,47.741c27.453,31.561 41.122,74.221 41.122,127.904"
style="fill:#fff;fill-rule:nonzero;" />
</g>
</svg>
</a>
<a class="inline-block text-blue-300 no-underline hover:text-indigo-800 hover:text-underline text-center h-10 p-2 md:h-auto md:p-4"
href="https://ko-fi.com/krille">
<img class="w-10 hover:animate-bounce" src="Kofi_pixel_logo.png"/>
</a>
</div>
</div>
</div>
<!--Main-->
<div class="container pt-8 px-6 mx-auto flex flex-wrap flex-col md:flex-row items-center">
<!--Left Col-->
<div class="flex flex-col w-full xl:w-2/5 justify-center lg:items-start overflow-y-hidden">
<h1
class="my-4 text-3xl md:text-5xl text-purple-800 font-bold leading-tight text-center md:text-left slide-in-bottom-h1">
Open. Nonprofit. Cute.</h1>
<p class="leading-normal text-base md:text-2xl mb-8 text-center md:text-left slide-in-bottom-subtitle">
Easy to use (<a class="underline hover:text-blue-700 transition-all"
href="https://matrix.org">matrix</a>) messenger. Secure and decentralized.</p>
<p class="text-blue-700 font-bold pb-4 text-center md:text-left fade-in">Mobile app:</p>
<div class="w-full flex justify-center md:justify-start pb-24 lg:pb-0 fade-in">
<a href="https://apps.apple.com/app/fluffychat/id1551469600"><img src="appstore-badge.png"
class="max-h-12 pr-2 mb-2 bounce-top-icons inline"></a>
<a href="https://play.google.com/store/apps/details?id=chat.fluffy.fluffychat"><img
src="google-play-badge.png" class="max-h-12 pr-2 mb-2 bounce-top-icons inline">
</a><a href="https://f-droid.org/de/packages/chat.fluffy.fluffychat/"><img src="fdroid_button.png"
class="max-h-12 pr-2 mb-2 bounce-top-icons inline">
</a>
</div>
<p class="text-blue-700 font-bold py-4 text-center md:text-left fade-in">Desktop app:</p>
<div class="w-full flex justify-center md:justify-start pb-24 lg:pb-0 fade-in">
<a href="https://fluffychat.im/web">
<img src="browser-badge.png" class="max-h-12 pr-2 mb-2 bounce-top-icons inline"></a>
<a href="https://snapcraft.io/fluffychat"><img
src="https://snapcraft.io/static/images/badges/en/snap-store-black.svg"
class="max-h-12 pr-2 mb-2 bounce-top-icons inline"></a>
<a href="https://flathub.org/apps/details/im.fluffychat.Fluffychat"><img src="flathub-badge-en.png"
class="max-h-12 pr-2 mb-2 bounce-top-icons inline"></a>
</div>
</div>
<!--Right Col-->
<div class="w-full xl:w-3/5 py-6 relative">
<img class="w-full mx-auto slide-in-bottom" src="screenshots/screenshots.png">
</div>
<!--Footer-->
<div class="w-full pt-16 pb-6 text-sm text-center md:text-left fade-in">
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat">Source code</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md">Privacy</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md">Changelog</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://hosted.weblate.org/projects/fluffychat/">Translations</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat/-/blob/main/docs/fdroid_repo.md">FluffyChat F-Droid repository</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://liberapay.com/KrilleChritzelius/donate">Donate</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800"
href="https://keys.mailvelope.com/pks/lookup?op=get&search=christian-pauly%40posteo.de">Contact</a>
-
<a class="text-gray-500 no-underline hover:text-purple-800" href="https://krillefear.gitlab.io">Created
by Krille Fear</a>
</div>
</div>
<div class="max-w-lg mb-8 flex justify-center flex-wrap">
<a href="https://apps.apple.com/app/fluffychat/id1551469600"><img src="appstore-badge.png"
class="w-36 pr-2 mb-2 inline hover:scale-105 transition-transform"></a>
<a href="https://play.google.com/store/apps/details?id=chat.fluffy.fluffychat"><img src="google-play-badge.png"
class="w-36 pr-2 mb-2 hover:scale-105 transition-transform inline">
</a><a href="https://f-droid.org/de/packages/chat.fluffy.fluffychat/"><img src="fdroid_button.png"
class="w-36 pr-2 mb-2 hover:scale-105 transition-transform inline">
</a>
<a href="https://fluffychat.im/web">
<img src="browser-badge.png" class="w-36 pr-2 mb-2 hover:scale-105 transition-transform inline"></a>
<a href="https://snapcraft.io/fluffychat"><img
src="https://snapcraft.io/static/images/badges/en/snap-store-black.svg"
class="w-36 pr-2 mb-2 hover:scale-105 transition-transform inline"></a>
<a href="https://flathub.org/apps/details/im.fluffychat.Fluffychat"><img src="flathub-badge-en.png"
class="w-36 pr-2 mb-2 hover:scale-105 transition-transform inline"></a>
</div>
<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"
href="https://metalhead.club/@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;">
<clipPath id="_clip1">
<rect x="33.6" y="-0.035" width="932.844" height="1000" />
</clipPath>
<g clip-path="url(#_clip1)">
<path
d="M946.586,599.455c-13.713,70.541 -122.816,147.742 -248.121,162.703c-65.341,7.796 -129.674,14.962 -198.275,11.815c-112.191,-5.139 -200.716,-26.776 -200.716,-26.776c0,10.92 0.673,21.319 2.02,31.044c14.586,110.711 109.787,117.344 199.967,120.436c91.021,3.114 172.068,-22.44 172.068,-22.44l3.74,82.281c0,0 -63.666,34.185 -177.079,40.473c-62.539,3.437 -140.192,-1.573 -230.636,-25.511c-196.158,-51.916 -229.893,-260.996 -235.055,-473.143c-1.573,-62.987 -0.603,-122.381 -0.603,-172.056c0,-216.931 142.142,-280.516 142.142,-280.516c71.672,-32.914 194.655,-46.755 322.508,-47.8l3.142,0c127.853,1.045 250.917,14.886 322.583,47.8c0,0 142.138,63.585 142.138,280.516c0,0 1.783,160.053 -19.823,271.174"
style="fill-rule:nonzero;" />
<path
d="M798.748,345.11l0,262.667l-104.07,0l0,-254.946c0,-53.743 -22.614,-81.021 -67.847,-81.021c-50.012,0 -75.077,32.359 -75.077,96.343l0,139.547l-103.457,0l0,-139.547c0,-63.984 -25.07,-96.343 -75.082,-96.343c-45.233,0 -67.847,27.278 -67.847,81.021l0,254.946l-104.07,0l0,-262.667c0,-53.683 13.669,-96.343 41.127,-127.904c28.314,-31.561 65.395,-47.741 111.425,-47.741c53.256,0 93.585,20.468 120.251,61.41l25.922,43.451l25.927,-43.451c26.66,-40.942 66.99,-61.41 120.251,-61.41c46.025,0 83.106,16.18 111.425,47.741c27.453,31.561 41.122,74.221 41.122,127.904"
style="fill:#fff;fill-rule:nonzero;" />
</g>
</svg>
</a>
<a class="inline-block text-indigo-500 no-underline hover:text-indigo-900 hover:scale-105 transition-all text-center h-auto p-4"
href="https://matrix.to/#/#fluffychat:matrix.org">
<svg class="fill-current h-6" enable-background="new -91 49.217 56.693 56.693" id="Layer_1" version="1.1"
viewBox="-91 49.217 56.693 56.693" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<path
d="M-38.3289,79.8244c-0.7526-2.2362-3.1756-3.4388-5.4117-2.6861l-4.5351,1.5264l-3.0737-9.1321l4.4169-1.4866 c2.2362-0.7526,3.4388-3.1756,2.6861-5.4117c-0.7526-2.2362-3.1756-3.4388-5.4117-2.6861l-4.4168,1.4866l-1.4877-4.4201 c-0.7527-2.2362-3.1756-3.4388-5.4117-2.6861v0c-2.2362,0.7526-3.4388,3.1756-2.6861,5.4117l1.4877,4.4201l-9.3246,3.1385 l-1.4697-4.3666c-0.7527-2.2362-3.1756-3.4388-5.4117-2.6861c-2.2362,0.7527-3.4388,3.1756-2.6861,5.4117l1.4697,4.3666 l-4.445,1.4961c-2.2362,0.7527-3.4388,3.1756-2.6861,5.4117v0c0.7526,2.2362,3.1756,3.4388,5.4117,2.6861l4.445-1.4961 l3.0737,9.1321l-4.3268,1.4563c-2.2362,0.7527-3.4388,3.1756-2.6861,5.4117c0.7526,2.2362,3.1756,3.4388,5.4117,2.6861 l4.3268-1.4563l1.5778,4.6877c0.7527,2.2362,3.1756,3.4388,5.4117,2.6861c2.2362-0.7527,3.4388-3.1756,2.6861-5.4117l-1.5778-4.6877 l9.3246-3.1385l1.5598,4.6342c0.7527,2.2362,3.1756,3.4388,5.4117,2.6861c2.2362-0.7527,3.4388-3.1756,2.6861-5.4117l-1.5598-4.6342 l4.5351-1.5264C-38.7789,84.4835-37.5762,82.0606-38.3289,79.8244z M-65.6982,84.5288l-3.0737-9.1321l9.3246-3.1385l3.0737,9.1321 L-65.6982,84.5288z" />
</svg>
</a>
<a class="inline-block no-underline hover:scale-105 transition-all text-center h-auto p-4"
href="https://ko-fi.com/krille">
<img src="kofi_button_dark.png" class="h-6 fill-current" />
</a>
</div>
<!--Footer-->
<div class="w-full text-sm text-center max-w-lg">
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat">Source
code</a>
-
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat/-/blob/main/PRIVACY.md">Privacy</a>
-
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat/-/blob/main/CHANGELOG.md">Changelog</a>
-
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://hosted.weblate.org/projects/fluffychat/">Translations</a>
-
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://gitlab.com/famedly/fluffychat/-/blob/main/docs/fdroid_repo.md">FluffyChat F-Droid
repository</a>
-
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://keys.mailvelope.com/pks/lookup?op=get&search=christian-pauly%40posteo.de">Contact</a>
-
<a class="text-slate-700 dark:text-slate-200 no-underline hover:text-purple-800"
href="https://krillefear.gitlab.io">Created
by Krille Fear</a>
</div>
</body>
</html>
</html>

BIN
docs/kofi_button_dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,49 +1,188 @@
import 'dart:developer';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/pages/chat/chat_view.dart';
import 'package:fluffychat/pages/chat_list/chat_list_body.dart';
import 'package:fluffychat/pages/chat_list/search_title.dart';
import 'package:fluffychat/pages/invitation_selection/invitation_selection_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:integration_test/integration_test.dart';
import 'package:fluffychat/main.dart' as app;
import 'package:shared_preferences/shared_preferences.dart';
import 'extensions/default_flows.dart';
import 'extensions/wait_for.dart';
import 'users.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Integration Test', () {
testWidgets('Test if the app starts', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
group(
'Integration Test',
() {
setUpAll(
() async {
// this random dialog popping up is super hard to cover in tests
SharedPreferences.setMockInitialValues({
SettingKeys.showNoGoogle: false,
});
try {
Hive.deleteFromDisk();
Hive.initFlutter();
} catch (_) {}
},
);
await Future.delayed(const Duration(seconds: 10));
testWidgets(
'Start app, login and logout',
(WidgetTester tester) async {
app.main();
await tester.ensureAppStartedHomescreen();
await tester.ensureLoggedOut();
},
);
await tester.pumpAndSettle();
testWidgets(
'Login again',
(WidgetTester tester) async {
app.main();
await tester.ensureAppStartedHomescreen();
},
);
expect(find.text('Connect'), findsOneWidget);
testWidgets(
'Start chat and send message',
(WidgetTester tester) async {
app.main();
await tester.ensureAppStartedHomescreen();
await tester.waitFor(find.byType(TextField));
await tester.enterText(find.byType(TextField), Users.user2.name);
await tester.pumpAndSettle();
final input = find.byType(TextField);
await tester.scrollUntilVisible(
find.text('Chats').first,
500,
scrollable: find
.descendant(
of: find.byType(ChatListViewBody),
matching: find.byType(Scrollable),
)
.first,
);
await tester.pumpAndSettle();
await tester.tap(find.text('Chats'));
await tester.pumpAndSettle();
await tester.waitFor(find.byType(SearchTitle));
await tester.pumpAndSettle();
expect(input, findsOneWidget);
await tester.scrollUntilVisible(
find.text(Users.user2.name).first,
500,
scrollable: find
.descendant(
of: find.byType(ChatListViewBody),
matching: find.byType(Scrollable),
)
.first,
);
await tester.pumpAndSettle();
await tester.tap(find.text(Users.user2.name).first);
await tester.enterText(input, homeserver);
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
try {
await tester.waitFor(
find.byType(ChatView),
timeout: const Duration(seconds: 5),
);
} catch (_) {
// in case the homeserver sends the username as search result
if (find.byIcon(Icons.send_outlined).evaluate().isNotEmpty) {
await tester.tap(find.byIcon(Icons.send_outlined));
await tester.pumpAndSettle();
}
}
// in case registration is allowed
try {
await tester.tap(find.text('Login'));
await tester.waitFor(find.byType(ChatView));
await tester.enterText(find.byType(TextField).last, 'Test');
await tester.pumpAndSettle();
try {
await tester.waitFor(find.byIcon(Icons.send_outlined));
await tester.tap(find.byIcon(Icons.send_outlined));
} catch (_) {
await tester.testTextInput.receiveAction(TextInputAction.done);
}
await tester.pumpAndSettle();
await tester.waitFor(find.text('Test'));
await tester.pumpAndSettle();
},
);
testWidgets('Spaces', (tester) async {
app.main();
await tester.ensureAppStartedHomescreen();
await tester.waitFor(find.byTooltip('Show menu'));
await tester.tap(find.byTooltip('Show menu'));
await tester.pumpAndSettle();
} catch (e) {
log('Registration is not allowed. Proceeding with login...');
}
await tester.pumpAndSettle();
final inputs = find.byType(TextField);
await tester.waitFor(find.byIcon(Icons.workspaces_outlined));
await tester.tap(find.byIcon(Icons.workspaces_outlined));
await tester.pumpAndSettle();
await tester.enterText(inputs.first, Users.user1.name);
await tester.enterText(inputs.last, Users.user1.password);
await tester.testTextInput.receiveAction(TextInputAction.done);
});
});
await tester.waitFor(find.byType(TextField));
await tester.enterText(find.byType(TextField).last, 'Test Space');
await tester.pumpAndSettle();
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
await tester.waitFor(find.text('Invite contact'));
await tester.tap(find.text('Invite contact'));
await tester.pumpAndSettle();
await tester.waitFor(
find.descendant(
of: find.byType(InvitationSelectionView),
matching: find.byType(TextField)),
);
await tester.enterText(
find.descendant(
of: find.byType(InvitationSelectionView),
matching: find.byType(TextField)),
Users.user2.name,
);
await Future.delayed(const Duration(milliseconds: 250));
await tester.testTextInput.receiveAction(TextInputAction.done);
await Future.delayed(const Duration(milliseconds: 1000));
await tester.pumpAndSettle();
await tester.tap(find
.descendant(
of: find.descendant(
of: find.byType(InvitationSelectionView),
matching: find.byType(ListTile),
),
matching: find.text(Users.user2.name))
.last);
await tester.pumpAndSettle();
await tester.waitFor(find.maybeUppercaseText('Yes'));
await tester.tap(find.maybeUppercaseText('Yes'));
await tester.pumpAndSettle();
await tester.tap(find.byTooltip('Back'));
await tester.pumpAndSettle();
await tester.waitFor(find.text('Load 2 more participants'));
await tester.tap(find.text('Load 2 more participants'));
await tester.pumpAndSettle();
expect(find.text(Users.user2.name), findsOneWidget);
});
},
);
}

View File

@ -0,0 +1,182 @@
import 'dart:developer';
import 'package:fluffychat/pages/chat_list/chat_list_body.dart';
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
import 'package:fluffychat/pages/settings_account/settings_account_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../users.dart';
import 'wait_for.dart';
extension DefaultFlowExtensions on WidgetTester {
Future<void> login() async {
final tester = this;
await tester.pumpAndSettle();
await tester.waitFor(find.text('Let\'s start'));
expect(find.text('Let\'s start'), findsOneWidget);
final input = find.byType(TextField);
expect(input, findsOneWidget);
// getting the placeholder in place
await tester.tap(find.byIcon(Icons.search));
await tester.pumpAndSettle();
await tester.enterText(input, homeserver);
await tester.pumpAndSettle();
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
// in case registration is allowed
// try {
await Future.delayed(const Duration(milliseconds: 50));
await tester.scrollUntilVisible(
find.text('Login'),
500,
scrollable: find.descendant(
of: find.byKey(const Key('ConnectPageListView')),
matching: find.byType(Scrollable).first,
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('Login'));
await tester.pumpAndSettle();
/*} catch (e) {
log('Registration is not allowed. Proceeding with login...');
}*/
await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 50));
final inputs = find.byType(TextField);
await tester.enterText(inputs.first, Users.user1.name);
await tester.enterText(inputs.last, Users.user1.password);
await tester.pumpAndSettle();
await tester.testTextInput.receiveAction(TextInputAction.done);
try {
// pumpAndSettle does not work in here as setState is called
// asynchronously
await tester.waitFor(
find.byType(LinearProgressIndicator),
timeout: const Duration(milliseconds: 1500),
skipPumpAndSettle: true,
);
} catch (_) {
// in case the input action does not work on the desired platform
if (find.text('Login').evaluate().isNotEmpty) {
await tester.tap(find.text('Login'));
}
}
try {
await tester.pumpAndSettle();
} catch (_) {
// may fail because of ongoing animation below dialog
}
await tester.waitFor(
find.byType(ChatListViewBody),
skipPumpAndSettle: true,
);
}
/// ensure PushProvider check passes
Future<void> acceptPushWarning() async {
final tester = this;
final matcher = find.maybeUppercaseText('Do not show again');
try {
await tester.waitFor(matcher, timeout: const Duration(seconds: 5));
// the FCM push error dialog to be handled...
await tester.tap(matcher);
await tester.pumpAndSettle();
} catch (_) {}
}
Future<void> ensureLoggedOut() async {
final tester = this;
await tester.pumpAndSettle();
if (find.byType(ChatListViewBody).evaluate().isNotEmpty) {
await tester.tap(find.byTooltip('Show menu'));
await tester.pumpAndSettle();
await tester.tap(find.text('Settings'));
await tester.pumpAndSettle();
await tester.scrollUntilVisible(
find.text('Account'),
500,
scrollable: find.descendant(
of: find.byKey(const Key('SettingsListViewContent')),
matching: find.byType(Scrollable),
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('Account'));
await tester.pumpAndSettle();
await tester.scrollUntilVisible(
find.text('Logout'),
500,
scrollable: find.descendant(
of: find.byType(SettingsAccountView),
matching: find.byType(Scrollable),
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('Logout'));
await tester.pumpAndSettle();
await tester.tap(find.maybeUppercaseText('Yes'));
await tester.pumpAndSettle();
}
}
Future<void> ensureAppStartedHomescreen({
Duration timeout = const Duration(seconds: 20),
}) async {
final tester = this;
await tester.pumpAndSettle();
final homeserverPickerFinder = find.byType(HomeserverPicker);
final chatListFinder = find.byType(ChatListViewBody);
final end = DateTime.now().add(timeout);
log(
'Waiting for HomeserverPicker or ChatListViewBody...',
name: 'Test Runner',
);
do {
if (DateTime.now().isAfter(end)) {
throw Exception(
'Timed out waiting for HomeserverPicker or ChatListViewBody');
}
await pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 100));
} while (homeserverPickerFinder.evaluate().isEmpty &&
chatListFinder.evaluate().isEmpty);
if (homeserverPickerFinder.evaluate().isNotEmpty) {
log(
'Found HomeserverPicker, performing login.',
name: 'Test Runner',
);
await tester.login();
} else {
log(
'Found ChatListViewBody, skipping login.',
name: 'Test Runner',
);
}
await tester.acceptPushWarning();
}
}

View File

@ -0,0 +1,49 @@
import 'package:flutter_test/flutter_test.dart';
/// Workaround for https://github.com/flutter/flutter/issues/88765
extension WaitForExtension on WidgetTester {
Future<void> waitFor(
Finder finder, {
Duration timeout = const Duration(seconds: 20),
bool skipPumpAndSettle = false,
}) async {
final end = DateTime.now().add(timeout);
do {
if (DateTime.now().isAfter(end)) {
throw Exception('Timed out waiting for $finder');
}
if (!skipPumpAndSettle) {
await pumpAndSettle();
}
await Future.delayed(const Duration(milliseconds: 100));
} while (finder.evaluate().isEmpty);
}
}
extension MaybeUppercaseFinder on CommonFinders {
/// On Android some button labels are in uppercase while on iOS they
/// are not. This method tries both.
Finder maybeUppercaseText(
String text, {
bool findRichText = false,
bool skipOffstage = true,
}) {
try {
final finder = find.text(
text.toUpperCase(),
findRichText: findRichText,
skipOffstage: skipOffstage,
);
expect(finder, findsOneWidget);
return finder;
} catch (_) {
return find.text(
text,
findRichText: findRichText,
skipOffstage: skipOffstage,
);
}
}
}

View File

@ -1,15 +1,25 @@
import 'dart:io';
abstract class Users {
const Users._();
static final user1 = User(
Platform.environment['USER1_NAME'] ?? 'alice',
Platform.environment['USER1_PW'] ?? 'AliceInWonderland',
static const user1 = User(
String.fromEnvironment(
'USER1_NAME',
defaultValue: 'alice',
),
String.fromEnvironment(
'USER1_PW',
defaultValue: 'AliceInWonderland',
),
);
static final user2 = User(
Platform.environment['USER2_NAME'] ?? 'bob',
Platform.environment['USER2_PW'] ?? 'JoWirSchaffenDas',
static const user2 = User(
String.fromEnvironment(
'USER2_NAME',
defaultValue: 'bob',
),
String.fromEnvironment(
'USER2_PW',
defaultValue: 'JoWirSchaffenDas',
),
);
}
@ -20,5 +30,7 @@ class User {
const User(this.name, this.password);
}
final homeserver =
'http://${Platform.environment['HOMESERVER'] ?? 'localhost'}';
const homeserver = 'http://${const String.fromEnvironment(
'HOMESERVER',
defaultValue: 'localhost',
)}';

View File

@ -94,6 +94,13 @@ class AppRoutes {
VWidget(
path: '/archive',
widget: const Archive(),
stackedRoutes: [
VWidget(
path: ':roomid',
widget: const Chat(),
buildTransition: _dynamicTransition,
),
],
),
VWidget(
path: '/newprivatechat',
@ -220,13 +227,25 @@ class AppRoutes {
),
],
),
VWidget(
VNester(
path: '/archive',
widget: const TwoColumnLayout(
mainView: Archive(),
sideView: EmptyPage(),
widgetBuilder: (child) => TwoColumnLayout(
mainView: const Archive(),
sideView: child,
),
buildTransition: _fadeTransition,
nestedRoutes: [
VWidget(
path: '',
widget: const EmptyPage(),
buildTransition: _dynamicTransition,
),
VWidget(
path: ':roomid',
widget: const Chat(),
buildTransition: _dynamicTransition,
),
],
),
],
),

View File

@ -38,6 +38,9 @@ abstract class FluffyThemes {
subtitle2: fallbackTextStyle,
);
static const Duration animationDuration = Duration(milliseconds: 250);
static const Curve animationCurve = Curves.easeInOut;
static ThemeData buildTheme(Brightness brightness, [Color? seed]) =>
ThemeData(
visualDensity: VisualDensity.standard,

View File

@ -21,11 +21,9 @@ class ArchiveController extends State<Archive> {
Future<List<Room>> getArchive(BuildContext context) async {
final archive = this.archive;
if (archive != null) return archive;
return await Matrix.of(context).client.loadArchive();
return this.archive = await Matrix.of(context).client.loadArchive();
}
void forgetAction(int i) => setState(() => archive?.removeAt(i));
void forgetAllAction() async {
final archive = this.archive;
if (archive == null) return;

View File

@ -21,10 +21,14 @@ class ArchiveView extends StatelessWidget {
leading: const BackButton(),
title: Text(L10n.of(context)!.archive),
actions: [
if (snapshot.hasData && archive != null && archive!.isNotEmpty)
TextButton(
onPressed: controller.forgetAllAction,
child: Text(L10n.of(context)!.clearArchive),
if (snapshot.data?.isNotEmpty ?? false)
Padding(
padding: const EdgeInsets.all(8.0),
child: TextButton.icon(
onPressed: controller.forgetAllAction,
label: Text(L10n.of(context)!.clearArchive),
icon: const Icon(Icons.cleaning_services_outlined),
),
)
],
),
@ -50,7 +54,6 @@ class ArchiveView extends StatelessWidget {
itemCount: archive!.length,
itemBuilder: (BuildContext context, int i) => ChatListItem(
archive![i],
onForget: controller.forgetAction,
),
);
}

View File

@ -22,6 +22,7 @@ import 'package:vrouter/vrouter.dart';
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/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';
@ -133,6 +134,51 @@ class ChatController extends State<Chat> {
bool showEmojiPicker = false;
bool get isLeftDMRoom {
final room = this.room;
final userId = room?.directChatMatrixID;
if (room == null || userId == null) return false;
return room.isDirectChat &&
room.unsafeGetUserFromMemoryOrFallback(userId).membership ==
Membership.leave;
}
void recreateChat() async {
final room = this.room;
final userId = room?.directChatMatrixID;
if (room == null || userId == null) {
throw Exception(
'Try to recreate a room with is not a DM room. This should not be possible from the UI!');
}
final success = await showFutureLoadingDialog(
context: context,
future: () async {
final client = room.client;
final waitForSync = client.onSync.stream
.firstWhere((s) => s.rooms?.leave?.containsKey(room.id) ?? false);
await room.leave();
await waitForSync;
return await client.startDirectChat(userId);
});
final roomId = success.result;
if (roomId == null) return;
VRouter.of(context).toSegments(['rooms', roomId]);
}
void leaveChat() async {
final room = this.room;
if (room == null) {
throw Exception(
'Leave room button clicked while room is null. This should not be possible from the UI!');
}
final success = await showFutureLoadingDialog(
context: context,
future: room.leave,
);
if (success.error != null) return;
VRouter.of(context).to('/rooms');
}
EmojiPickerType emojiPickerType = EmojiPickerType.keyboard;
void requestHistory() async {
@ -391,9 +437,8 @@ class ChatController extends State<Chat> {
}
void sendStickerAction() async {
final sticker = await showModalBottomSheet<ImagePackImageContent>(
final sticker = await showAdaptiveBottomSheet<ImagePackImageContent>(
context: context,
useRootNavigator: false,
builder: (c) => StickerPickerDialog(room: room!),
);
if (sticker == null) return;
@ -599,6 +644,7 @@ class ChatController extends State<Chat> {
}
bool get canRedactSelectedEvents {
if (isArchived) return false;
final clients = matrix!.currentBundle;
for (final event in selectedEvents) {
if (event.canRedact == false &&
@ -608,7 +654,9 @@ class ChatController extends State<Chat> {
}
bool get canEditSelectedEvents {
if (selectedEvents.length != 1 || !selectedEvents.first.status.isSent) {
if (isArchived ||
selectedEvents.length != 1 ||
!selectedEvents.first.status.isSent) {
return false;
}
return currentRoomBundle
@ -726,6 +774,15 @@ class ChatController extends State<Chat> {
return sendEmojiAction(emoji.emoji);
}
void forgetRoom() async {
final result = await showFutureLoadingDialog(
context: context,
future: room!.forget,
);
if (result.error != null) return;
VRouter.of(context).to('/archive');
}
void typeEmoji(Emoji? emoji) {
if (emoji == null) return;
final text = sendController.text;
@ -977,6 +1034,9 @@ class ChatController extends State<Chat> {
setState(() => inputText = text);
}
bool get isArchived =>
{Membership.leave, Membership.ban}.contains(room?.membership);
void showEventInfo([Event? event]) =>
(event ?? selectedEvents.single).showInfoDialog(context);

View File

@ -5,6 +5,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar.dart';
@ -26,7 +27,7 @@ class ChatAppBarTitle extends StatelessWidget {
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: directChatMatrixID != null
? () => showModalBottomSheet(
? () => showAdaptiveBottomSheet(
context: context,
builder: (c) => UserBottomSheet(
user: room
@ -36,7 +37,10 @@ class ChatAppBarTitle extends StatelessWidget {
'${room.unsafeGetUserFromMemoryOrFallback(directChatMatrixID).mention} ',
),
)
: () => VRouter.of(context).toSegments(['rooms', room.id, 'details']),
: controller.isArchived
? null
: () =>
VRouter.of(context).toSegments(['rooms', room.id, 'details']),
child: Row(
children: [
Hero(

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import 'package:fluffychat/config/themes.dart';
import 'chat.dart';
class ChatEmojiPicker extends StatelessWidget {
@ -11,7 +12,8 @@ class ChatEmojiPicker extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
height: controller.showEmojiPicker
? MediaQuery.of(context).size.height / 2
: 0,

View File

@ -10,6 +10,7 @@ import 'package:fluffychat/pages/chat/events/message.dart';
import 'package:fluffychat/pages/chat/seen_by_row.dart';
import 'package:fluffychat/pages/chat/typing_indicators.dart';
import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -89,7 +90,7 @@ class ChatEventList extends StatelessWidget {
onSwipe: (direction) =>
controller.replyAction(replyTo: event),
onInfoTab: controller.showEventInfo,
onAvatarTab: (Event event) => showModalBottomSheet(
onAvatarTab: (Event event) => showAdaptiveBottomSheet(
context: context,
builder: (c) => UserBottomSheet(
user: event.senderFromMemoryOrFallback,

View File

@ -10,6 +10,7 @@ import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../config/themes.dart';
import '../../widgets/m2_popup_menu_button.dart';
import 'chat.dart';
import 'input_bar.dart';
@ -84,7 +85,8 @@ class ChatInputRow extends StatelessWidget {
controller.onAddPopupMenuButtonSelected('file'),
helpLabel: L10n.of(context)!.sendFile,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
height: 56,
width: controller.inputText.isEmpty ? 56 : 0,
alignment: Alignment.center,

View File

@ -108,6 +108,20 @@ class ChatView extends StatelessWidget {
],
),
];
} else if (controller.isArchived) {
return [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextButton.icon(
onPressed: controller.forgetRoom,
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.error,
),
icon: const Icon(Icons.delete_forever_outlined),
label: Text(L10n.of(context)!.delete),
),
)
];
} else {
return [
if (Matrix.of(context).voipPlugin != null &&
@ -221,10 +235,10 @@ class ChatView extends StatelessWidget {
gradient: LinearGradient(
begin: Alignment.topCenter,
colors: [
colorScheme.primaryContainer.withAlpha(32),
colorScheme.secondaryContainer.withAlpha(32),
colorScheme.tertiaryContainer.withAlpha(32),
colorScheme.primaryContainer.withAlpha(32),
colorScheme.primaryContainer.withAlpha(64),
colorScheme.secondaryContainer.withAlpha(64),
colorScheme.tertiaryContainer.withAlpha(64),
colorScheme.primaryContainer.withAlpha(64),
],
),
),
@ -277,16 +291,53 @@ class ChatView extends StatelessWidget {
Brightness.light
? Colors.white
: Colors.black,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ConnectionStatusHeader(),
ReactionsPicker(controller),
ReplyDisplay(controller),
ChatInputRow(controller),
ChatEmojiPicker(controller),
],
),
child: controller.isLeftDMRoom
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
TextButton.icon(
style: TextButton.styleFrom(
padding:
const EdgeInsets.all(16),
foregroundColor:
Theme.of(context)
.colorScheme
.error,
),
icon: const Icon(
Icons.archive_outlined,
),
onPressed: controller.leaveChat,
label: Text(
L10n.of(context)!.leave,
),
),
TextButton.icon(
style: TextButton.styleFrom(
padding:
const EdgeInsets.all(16),
),
icon: const Icon(
Icons.chat_outlined,
),
onPressed:
controller.recreateChat,
label: Text(
L10n.of(context)!.reopenChat),
),
],
)
: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ConnectionStatusHeader(),
ReactionsPicker(controller),
ReplyDisplay(controller),
ChatInputRow(controller),
ChatEmojiPicker(controller),
],
),
),
),
],

View File

@ -6,11 +6,12 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
extension EventInfoDialogExtension on Event {
void showInfoDialog(BuildContext context) => showModalBottomSheet(
void showInfoDialog(BuildContext context) => showAdaptiveBottomSheet(
context: context,
builder: (context) =>
EventInfoDialog(l10n: L10n.of(context)!, event: this),

View File

@ -85,7 +85,7 @@ class ImageBubble extends StatelessWidget {
child: Hero(
tag: event.eventId,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 1000),
duration: const Duration(seconds: 1),
child: Container(
constraints: maxSize
? BoxConstraints(

View File

@ -35,15 +35,15 @@ class MapBubble extends StatelessWidget {
center: LatLng(latitude, longitude),
zoom: zoom,
),
layers: [
TileLayerOptions(
children: [
TileLayer(
maxZoom: 20,
minZoom: 0,
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
subdomains: const ['a', 'b', 'c'],
),
MarkerLayerOptions(
MarkerLayer(
rotate: true,
markers: [
Marker(

View File

@ -5,6 +5,7 @@ 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';
import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/widgets/avatar.dart';
@ -52,7 +53,7 @@ class MessageContent extends StatelessWidget {
}
event.requestKey();
final sender = event.senderFromMemoryOrFallback;
await showModalBottomSheet(
await showAdaptiveBottomSheet(
context: context,
builder: (context) => Scaffold(
appBar: AppBar(

View File

@ -21,10 +21,11 @@ class PinnedEvents extends StatelessWidget {
BuildContext context, List<Event?> events) async {
final eventId = events.length == 1
? events.single?.eventId
: await showModalActionSheet<String>(
: await showConfirmationDialog<String>(
context: context,
title: L10n.of(context)!.pinMessage,
actions: events
.map((event) => SheetAction(
.map((event) => AlertDialogAction(
key: event?.eventId ?? '',
label: event?.calcLocalizedBodyFallback(
MatrixLocals(L10n.of(context)!),

View File

@ -6,6 +6,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/app_emojis.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import '../../config/themes.dart';
class ReactionsPicker extends StatelessWidget {
final ChatController controller;
@ -20,7 +21,8 @@ class ReactionsPicker extends StatelessWidget {
controller.room!.canSendDefaultMessages &&
controller.selectedEvents.isNotEmpty;
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
height: (display) ? 56 : 0,
child: Material(
color: Colors.transparent,

View File

@ -4,6 +4,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import '../../config/themes.dart';
import 'chat.dart';
import 'events/reply_content.dart';
@ -14,7 +15,8 @@ class ReplyDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
height: controller.editEvent != null || controller.replyEvent != null
? 56
: 0,

View File

@ -22,8 +22,9 @@ class SeenByRow extends StatelessWidget {
const BoxConstraints(maxWidth: FluffyThemes.columnWidth * 2.5),
height: seenByUsers.isEmpty ? 0 : 24,
duration: seenByUsers.isEmpty
? const Duration(milliseconds: 0)
: const Duration(milliseconds: 300),
? Duration.zero
: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
alignment: controller.timeline!.events.isNotEmpty &&
controller.timeline!.events.first.senderId ==
Matrix.of(context).client.userID

View File

@ -24,8 +24,8 @@ class TypingIndicators extends StatelessWidget {
constraints:
const BoxConstraints(maxWidth: FluffyThemes.columnWidth * 2.5),
height: typingUsers.isEmpty ? 0 : Avatar.defaultSize + bottomPadding,
duration: const Duration(milliseconds: 300),
curve: Curves.bounceInOut,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
alignment: controller.timeline!.events.isNotEmpty &&
controller.timeline!.events.first.senderId ==
Matrix.of(context).client.userID

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import '../../widgets/avatar.dart';
import '../user_bottom_sheet/user_bottom_sheet.dart';
@ -28,7 +29,7 @@ class ParticipantListItem extends StatelessWidget {
return Opacity(
opacity: user.membership == Membership.join ? 1 : 0.5,
child: ListTile(
onTap: () => showModalBottomSheet(
onTap: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => UserBottomSheet(
user: user,

View File

@ -9,11 +9,13 @@ 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/stories_header.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
import 'package:fluffychat/utils/stream_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/profile_bottom_sheet.dart';
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
import '../../config/themes.dart';
import '../../widgets/connection_status_header.dart';
import '../../widgets/matrix.dart';
@ -79,14 +81,17 @@ class ChatListViewBody extends StatelessWidget {
title: L10n.of(context)!.publicRooms,
icon: const Icon(Icons.explore_outlined),
),
SizedBox(
height: 106,
child: roomSearchResult == null ||
AnimatedContainer(
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
height: roomSearchResult == null ||
roomSearchResult.chunk.isEmpty
? Center(
child:
Text(L10n.of(context)!.noSearchResult),
)
? 0
: 106,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: roomSearchResult == null
? null
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: roomSearchResult.chunk.length,
@ -97,7 +102,7 @@ class ChatListViewBody extends StatelessWidget {
L10n.of(context)!.group,
avatar:
roomSearchResult.chunk[i].avatarUrl,
onPressed: () => showModalBottomSheet(
onPressed: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => PublicRoomBottomSheet(
roomAlias: roomSearchResult
@ -114,14 +119,17 @@ class ChatListViewBody extends StatelessWidget {
title: L10n.of(context)!.users,
icon: const Icon(Icons.group_outlined),
),
SizedBox(
height: 106,
child: userSearchResult == null ||
AnimatedContainer(
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
height: userSearchResult == null ||
userSearchResult.results.isEmpty
? Center(
child:
Text(L10n.of(context)!.noSearchResult),
)
? 0
: 106,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: userSearchResult == null
? null
: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: userSearchResult.results.length,
@ -133,7 +141,7 @@ class ChatListViewBody extends StatelessWidget {
L10n.of(context)!.unknownDevice,
avatar:
userSearchResult.results[i].avatarUrl,
onPressed: () => showModalBottomSheet(
onPressed: () => showAdaptiveBottomSheet(
context: context,
builder: (c) => ProfileBottomSheet(
userId: userSearchResult
@ -157,9 +165,9 @@ class ChatListViewBody extends StatelessWidget {
const ConnectionStatusHeader(),
AnimatedContainer(
height: controller.isTorBrowser ? 64 : 0,
duration: const Duration(milliseconds: 300),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.hardEdge,
curve: Curves.bounceInOut,
decoration: const BoxDecoration(),
child: Material(
color: Theme.of(context).colorScheme.surface,

View File

@ -9,6 +9,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/room_status_extension.dart';
import '../../config/themes.dart';
import '../../utils/date_time_extension.dart';
import '../../widgets/avatar.dart';
import '../../widgets/matrix.dart';
@ -20,7 +21,6 @@ class ChatListItem extends StatelessWidget {
final Room room;
final bool activeChat;
final bool selected;
final Function? onForget;
final void Function()? onTap;
final void Function()? onLongPress;
@ -30,7 +30,6 @@ class ChatListItem extends StatelessWidget {
this.selected = false,
this.onTap,
this.onLongPress,
this.onForget,
Key? key,
}) : super(key: key);
@ -61,35 +60,7 @@ class ChatListItem extends StatelessWidget {
}
if (room.membership == Membership.leave) {
final action = await showModalActionSheet<ArchivedRoomAction>(
context: context,
title: L10n.of(context)!.archivedRoom,
message: L10n.of(context)!.thisRoomHasBeenArchived,
actions: [
SheetAction(
label: L10n.of(context)!.rejoin,
key: ArchivedRoomAction.rejoin,
),
SheetAction(
label: L10n.of(context)!.delete,
key: ArchivedRoomAction.delete,
isDestructiveAction: true,
),
],
);
if (action != null) {
switch (action) {
case ArchivedRoomAction.delete:
await archiveAction(context);
break;
case ArchivedRoomAction.rejoin:
await showFutureLoadingDialog(
context: context,
future: () => room.join(),
);
break;
}
}
VRouter.of(context).toSegments(['archive', room.id]);
}
if (room.membership == Membership.join) {
@ -121,13 +92,10 @@ class ChatListItem extends StatelessWidget {
Future<void> archiveAction(BuildContext context) async {
{
if ([Membership.leave, Membership.ban].contains(room.membership)) {
final success = await showFutureLoadingDialog(
await showFutureLoadingDialog(
context: context,
future: () => room.forget(),
);
if (success.error == null) {
if (onForget != null) onForget!();
}
return;
}
final confirmed = await showOkCancelAlertDialog(
@ -241,8 +209,8 @@ class ChatListItem extends StatelessWidget {
width: typingText.isEmpty ? 0 : 18,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
duration: const Duration(milliseconds: 300),
curve: Curves.bounceInOut,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
padding: const EdgeInsets.only(right: 4),
child: Icon(
Icons.edit_outlined,
@ -304,8 +272,8 @@ class ChatListItem extends StatelessWidget {
),
const SizedBox(width: 8),
AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.bounceInOut,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
padding: const EdgeInsets.symmetric(horizontal: 7),
height: unreadBubbleSize,
width:

View File

@ -9,6 +9,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat_list/chat_list.dart';
import 'package:fluffychat/pages/chat_list/navi_rail_item.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/unread_rooms_badge.dart';
import '../../widgets/matrix.dart';
@ -126,90 +127,28 @@ class ChatListView extends StatelessWidget {
itemCount: rootSpaces.length + destinations.length,
itemBuilder: (context, i) {
if (i < destinations.length) {
final isSelected = i == controller.selectedIndex;
return Container(
height: 64,
width: 64,
decoration: BoxDecoration(
border: Border(
bottom: i == (destinations.length - 1)
? BorderSide(
width: 1,
color: Theme.of(context).dividerColor,
)
: BorderSide.none,
left: BorderSide(
color: isSelected
? Theme.of(context).colorScheme.primary
: Colors.transparent,
width: 4,
),
right: const BorderSide(
color: Colors.transparent,
width: 4,
),
),
),
alignment: Alignment.center,
child: IconButton(
color: isSelected
? Theme.of(context).colorScheme.secondary
: null,
icon: CircleAvatar(
backgroundColor: isSelected
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.background,
foregroundColor: isSelected
? Theme.of(context)
.colorScheme
.onSecondary
: Theme.of(context)
.colorScheme
.onBackground,
child: i == controller.selectedIndex
? destinations[i].selectedIcon ??
destinations[i].icon
: destinations[i].icon),
tooltip: destinations[i].label,
onPressed: () =>
controller.onDestinationSelected(i),
),
return NaviRailItem(
isSelected: i == controller.selectedIndex,
onTap: () => controller.onDestinationSelected(i),
icon: destinations[i].icon,
selectedIcon: destinations[i].selectedIcon,
toolTip: destinations[i].label,
);
}
i -= destinations.length;
final isSelected =
controller.activeFilter == ActiveFilter.spaces &&
rootSpaces[i].id == controller.activeSpaceId;
return Container(
height: 64,
width: 64,
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: isSelected
? Theme.of(context).colorScheme.secondary
: Colors.transparent,
width: 4,
),
right: const BorderSide(
color: Colors.transparent,
width: 4,
),
),
),
alignment: Alignment.center,
child: IconButton(
tooltip: rootSpaces[i].displayname,
icon: Avatar(
mxContent: rootSpaces[i].avatar,
name: rootSpaces[i].displayname,
size: 32,
fontSize: 12,
),
onPressed: () =>
controller.setActiveSpace(rootSpaces[i].id),
return NaviRailItem(
toolTip: rootSpaces[i].displayname,
isSelected: isSelected,
onTap: () =>
controller.setActiveSpace(rootSpaces[i].id),
icon: Avatar(
mxContent: rootSpaces[i].avatar,
name: rootSpaces[i].displayname,
size: 32,
fontSize: 12,
),
);
},
@ -266,12 +205,3 @@ class ChatListView extends StatelessWidget {
);
}
}
enum ChatListPopupMenuItemActions {
createGroup,
createSpace,
discover,
setStatus,
inviteContact,
settings,
}

View File

@ -66,6 +66,16 @@ class ClientChooserButton extends StatelessWidget {
],
),
),
PopupMenuItem(
value: SettingsAction.archive,
child: Row(
children: [
const Icon(Icons.archive_outlined),
const SizedBox(width: 18),
Text(L10n.of(context)!.archive),
],
),
),
PopupMenuItem(
value: SettingsAction.settings,
child: Row(
@ -104,8 +114,13 @@ class ClientChooserButton extends StatelessWidget {
.map(
(client) => PopupMenuItem(
value: client,
child: FutureBuilder<Profile>(
future: client!.fetchOwnProfile(),
child: FutureBuilder<Profile?>(
// analyzer does not understand this type cast for error
// handling
//
// ignore: unnecessary_cast
future: (client!.fetchOwnProfile() as Future<Profile?>)
.onError((e, s) => null),
builder: (context, snapshot) => Row(
children: [
Avatar(
@ -254,6 +269,9 @@ class ClientChooserButton extends StatelessWidget {
case SettingsAction.settings:
VRouter.of(context).to('/settings');
break;
case SettingsAction.archive:
VRouter.of(context).to('/archive');
break;
}
}
}
@ -331,4 +349,5 @@ enum SettingsAction {
newSpace,
invite,
settings,
archive,
}

View File

@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import '../../config/themes.dart';
class NaviRailItem extends StatelessWidget {
final String toolTip;
final bool isSelected;
final void Function() onTap;
final Widget icon;
final Widget? selectedIcon;
const NaviRailItem({
required this.toolTip,
required this.isSelected,
required this.onTap,
required this.icon,
this.selectedIcon,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 64,
width: 64,
child: Stack(
children: [
Positioned(
top: 16,
bottom: 16,
left: 0,
child: AnimatedContainer(
width: isSelected ? 4 : 0,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(90),
bottomRight: Radius.circular(90),
),
),
),
),
Center(
child: IconButton(
onPressed: onTap,
tooltip: toolTip,
icon: Material(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
color: isSelected
? Theme.of(context).colorScheme.primaryContainer
: Theme.of(context).colorScheme.background,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 8.0,
),
child: isSelected ? selectedIcon ?? icon : icon,
)),
),
),
],
),
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:vrouter/vrouter.dart';
import '../../config/themes.dart';
import 'chat_list.dart';
class StartChatFloatingActionButton extends StatelessWidget {
@ -55,13 +56,13 @@ class StartChatFloatingActionButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
width: controller.filteredRooms.isEmpty
? null
: controller.scrolledToTop
? 144
: 64,
: 56,
child: controller.scrolledToTop
? FloatingActionButton.extended(
backgroundColor: Theme.of(context).colorScheme.primary,

View File

@ -115,32 +115,28 @@ class StoriesHeader extends StatelessWidget {
itemCount: stories.length,
itemBuilder: (context, i) {
final room = stories[i];
return FutureBuilder<Profile>(
future: room.getCreatorProfile(),
builder: (context, snapshot) {
final userId = room.creatorId;
final displayname = snapshot.data?.displayName ??
userId?.localpart ??
'Unknown';
final avatarUrl = snapshot.data?.avatarUrl;
if (!displayname.toLowerCase().contains(filter.toLowerCase())) {
return Container();
}
return _StoryButton(
profile: Profile(
displayName: displayname,
avatarUrl: avatarUrl,
userId: userId ?? 'Unknown',
),
heroTag: 'stories_${room.id}',
hasPosts: room.hasPosts || room == ownStoryRoom,
showEditFab: userId == client.userID,
unread: room.membership == Membership.invite ||
(room.hasNewMessages && room.hasPosts),
onPressed: () => _goToStoryAction(context, room.id),
onLongPressed: () => _contextualActions(context, room),
);
});
final creator = room
.unsafeGetUserFromMemoryOrFallback(room.creatorId ?? 'Unknown');
final userId = room.creatorId;
final displayname = creator.calcDisplayname();
final avatarUrl = creator.avatarUrl;
if (!displayname.toLowerCase().contains(filter.toLowerCase())) {
return Container();
}
return _StoryButton(
profile: Profile(
displayName: displayname,
avatarUrl: avatarUrl,
userId: userId ?? 'Unknown',
),
heroTag: 'stories_${room.id}',
hasPosts: room.hasPosts || room == ownStoryRoom,
showEditFab: userId == client.userID,
unread: room.membership == Membership.invite ||
(room.hasNewMessages && room.hasPosts),
onPressed: () => _goToStoryAction(context, room.id),
onLongPressed: () => _contextualActions(context, room),
);
},
),
);
@ -148,9 +144,6 @@ class StoriesHeader extends StatelessWidget {
}
extension on Room {
Future<Profile> getCreatorProfile() =>
client.getProfileFromUserId(getState(EventTypes.RoomCreate)!.senderId);
bool get hasPosts {
if (membership == Membership.invite) return true;
final lastEvent = this.lastEvent;

View File

@ -28,6 +28,7 @@ class ConnectPageView extends StatelessWidget {
),
),
body: ListView(
key: const Key('ConnectPageListView'),
children: [
if (Matrix.of(context).loginRegistrationSupported ?? false) ...[
Padding(

View File

@ -1 +0,0 @@
const defaultAnimationDuration = Duration(milliseconds: 200);

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'constants.dart';
import 'package:fluffychat/config/themes.dart';
import 'dismiss_keyboard.dart';
class PIPView extends StatefulWidget {
@ -45,11 +45,11 @@ class PIPViewState extends State<PIPView> with TickerProviderStateMixin {
super.initState();
_corner = widget.initialCorner;
_toggleFloatingAnimationController = AnimationController(
duration: defaultAnimationDuration,
duration: FluffyThemes.animationDuration,
vsync: this,
);
_dragAnimationController = AnimationController(
duration: defaultAnimationDuration,
duration: FluffyThemes.animationDuration,
vsync: this,
);
}

View File

@ -15,6 +15,7 @@ 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/widgets/matrix.dart';
import '../../utils/localized_exception_extension.dart';
@ -71,7 +72,8 @@ class HomeserverPickerController extends State<HomeserverPicker> {
}
}
void showServerInfo(HomeserverBenchmarkResult server) => showModalBottomSheet(
void showServerInfo(HomeserverBenchmarkResult server) =>
showAdaptiveBottomSheet(
context: context,
builder: (_) => HomeserverBottomSheet(
homeserver: server,

View File

@ -5,6 +5,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/widgets/layouts/login_scaffold.dart';
import '../../config/themes.dart';
import 'homeserver_app_bar.dart';
import 'homeserver_picker.dart';
@ -29,9 +30,9 @@ class HomeserverPickerView extends StatelessWidget {
// usually forced to logout as TOR browser is non-persistent
AnimatedContainer(
height: controller.isTorBrowser ? 64 : 0,
duration: const Duration(milliseconds: 300),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.hardEdge,
curve: Curves.bounceInOut,
decoration: const BoxDecoration(),
child: Material(
clipBehavior: Clip.hardEdge,

View File

@ -10,13 +10,13 @@ import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/widgets/avatar.dart';
class KeyVerificationDialog extends StatefulWidget {
Future<void> show(BuildContext context) => showModalBottomSheet(
Future<void> show(BuildContext context) => showAdaptiveBottomSheet(
context: context,
builder: (context) => this,
useRootNavigator: false,
isDismissible: false,
);

View File

@ -3,11 +3,11 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:email_validator/email_validator.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/matrix.dart';
import '../../utils/platform_infos.dart';
import 'login_view.dart';
@ -30,7 +30,7 @@ class LoginController extends State<Login> {
void toggleShowPassword() =>
setState(() => showPassword = !loading && !showPassword);
void login([_]) async {
void login() async {
final matrix = Matrix.of(context);
if (usernameController.text.isEmpty) {
setState(() => usernameError = L10n.of(context)!.pleaseEnterYourUsername);
@ -48,6 +48,9 @@ class LoginController extends State<Login> {
}
setState(() => loading = true);
_coolDown?.cancel();
try {
final username = usernameController.text;
AuthenticationIdentifier identifier;
@ -97,8 +100,8 @@ class LoginController extends State<Login> {
void _checkWellKnown(String userId) async {
if (mounted) setState(() => usernameError = null);
if (!userId.isValidMatrixId) return;
final oldHomeserver = Matrix.of(context).getLoginClient().homeserver;
try {
final oldHomeserver = Matrix.of(context).getLoginClient().homeserver;
var newDomain = Uri.https(userId.domain!, '');
Matrix.of(context).getLoginClient().homeserver = newDomain;
DiscoveryInformation? wellKnownInformation;
@ -112,14 +115,11 @@ class LoginController extends State<Login> {
// do nothing, newDomain is already set to a reasonable fallback
}
if (newDomain != oldHomeserver) {
await showFutureLoadingDialog(
context: context,
// do nothing if we error, we'll handle it below
future: () => Matrix.of(context)
.getLoginClient()
.checkHomeserver(newDomain)
.catchError((e) {}),
);
Matrix.of(context)
.getLoginClient()
.checkHomeserver(newDomain)
.catchError((e) {});
if (Matrix.of(context).getLoginClient().homeserver == null) {
Matrix.of(context).getLoginClient().homeserver = oldHomeserver;
// okay, the server we checked does not appear to be a matrix server
@ -140,15 +140,18 @@ class LoginController extends State<Login> {
return;
}
}
if (mounted) setState(() => usernameError = null);
usernameError = null;
if (mounted) setState(() {});
} else {
Matrix.of(context).getLoginClient().homeserver = oldHomeserver;
if (mounted) {
setState(() =>
Matrix.of(context).getLoginClient().homeserver = oldHomeserver);
setState(() {});
}
}
} catch (e) {
if (mounted) setState(() => usernameError = e.toString());
Matrix.of(context).getLoginClient().homeserver = oldHomeserver;
usernameError = e.toLocalizedString(context);
if (mounted) setState(() {});
}
}
@ -246,8 +249,9 @@ class LoginController extends State<Login> {
extension on String {
static final RegExp _phoneRegex =
RegExp(r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$');
static final RegExp _emailRegex = RegExp(r'(.+)@(.+)\.(.+)');
bool get isEmail => EmailValidator.validate(this);
bool get isEmail => _emailRegex.hasMatch(this);
bool get isPhoneNumber => _phoneRegex.hasMatch(this);
}

View File

@ -60,7 +60,7 @@ class LoginView extends StatelessWidget {
controller: controller.passwordController,
textInputAction: TextInputAction.go,
obscureText: !controller.showPassword,
onSubmitted: controller.login,
onSubmitted: (_) => controller.login(),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.lock_outlined),
errorText: controller.passwordError,
@ -87,9 +87,7 @@ class LoginView extends StatelessWidget {
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: controller.loading
? null
: () => controller.login(context),
onPressed: controller.loading ? null : controller.login,
icon: const Icon(Icons.login_outlined),
label: controller.loading
? const LinearProgressIndicator()

View File

@ -7,6 +7,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/new_private_chat/new_private_chat_view.dart';
import 'package:fluffychat/pages/new_private_chat/qr_scanner_modal.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/url_launcher.dart';
@ -75,10 +76,8 @@ class NewPrivateChatController extends State<NewPrivateChat> {
return;
}
}
await showModalBottomSheet(
await showAdaptiveBottomSheet(
context: context,
useRootNavigator: false,
//useSafeArea: false,
builder: (_) => const QrScannerModal(),
);
}

View File

@ -94,7 +94,7 @@ class NewPrivateChatView extends StatelessWidget {
horizontal: 12,
vertical: 6,
),
labelText: L10n.of(context)!.typeInInviteLinkManually,
labelText: L10n.of(context)!.enterInviteLinkOrMatrixId,
hintText: '@username',
prefixText: NewPrivateChatController.prefixNoProtocol,
suffixIcon: IconButton(

View File

@ -38,7 +38,7 @@ class NewSpaceController extends State<NewSpace> {
),
);
if (roomID.error == null) {
VRouter.of(context).toSegments(['rooms', roomID.result!, 'details']);
VRouter.of(context).toSegments(['spaces', roomID.result!]);
}
}

View File

@ -6,6 +6,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import '../../config/themes.dart';
import '../../widgets/content_banner.dart';
import 'settings.dart';
@ -38,12 +39,13 @@ class SettingsView extends StatelessWidget {
body: ListTileTheme(
iconColor: Theme.of(context).colorScheme.onBackground,
child: ListView(
key: const Key('SettingsListViewContent'),
children: <Widget>[
AnimatedContainer(
height: controller.showChatBackupBanner ? 54 : 0,
duration: const Duration(milliseconds: 300),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
clipBehavior: Clip.hardEdge,
curve: Curves.bounceInOut,
decoration: const BoxDecoration(),
child: ListTile(
leading: const Icon(Icons.backup_outlined),

View File

@ -13,6 +13,7 @@ import 'package:video_player/video_player.dart';
import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/story/story_view.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/client_stories_extension.dart';
@ -58,7 +59,7 @@ class StoryPageController extends State<StoryPage> {
void replyEmojiAction() async {
if (replyLoading) return;
_modalOpened = true;
await showModalBottomSheet(
await showAdaptiveBottomSheet(
context: context,
builder: (context) => EmojiPicker(
onEmojiSelected: (c, e) {
@ -123,7 +124,7 @@ class StoryPageController extends State<StoryPage> {
void displaySeenByUsers() async {
_modalOpened = true;
await showModalBottomSheet(
await showAdaptiveBottomSheet(
context: context,
builder: (context) => Scaffold(
appBar: AppBar(

View File

@ -15,6 +15,7 @@ import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/string_color.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/avatar.dart';
import '../../config/themes.dart';
import '../../widgets/m2_popup_menu_button.dart';
class StoryView extends StatelessWidget {
@ -247,7 +248,8 @@ class StoryView extends StatelessWidget {
onHorizontalDragStart: controller.hold,
onHorizontalDragEnd: controller.unhold,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 80,

View File

@ -10,6 +10,17 @@ import 'package:fluffychat/widgets/permission_slider_dialog.dart';
import '../../widgets/matrix.dart';
import 'user_bottom_sheet_view.dart';
enum UserBottomSheetAction {
report,
mention,
ban,
kick,
unban,
permission,
message,
ignore,
}
class UserBottomSheet extends StatefulWidget {
final User user;
final Function? onMention;
@ -27,7 +38,7 @@ class UserBottomSheet extends StatefulWidget {
}
class UserBottomSheetController extends State<UserBottomSheet> {
void participantAction(String action) async {
void participantAction(UserBottomSheetAction action) async {
// ignore: prefer_function_declarations_over_variables
final Function askConfirmation = () async => (await showOkCancelAlertDialog(
useRootNavigator: false,
@ -38,7 +49,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
) ==
OkCancelResult.ok);
switch (action) {
case 'report':
case UserBottomSheetAction.report:
final event = widget.user;
final score = await showConfirmationDialog<int>(
context: context,
@ -82,11 +93,11 @@ class UserBottomSheetController extends State<UserBottomSheet> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context)!.contentHasBeenReported)));
break;
case 'mention':
case UserBottomSheetAction.mention:
Navigator.of(context, rootNavigator: false).pop();
widget.onMention!();
break;
case 'ban':
case UserBottomSheetAction.ban:
if (await askConfirmation()) {
await showFutureLoadingDialog(
context: context,
@ -95,7 +106,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop();
}
break;
case 'unban':
case UserBottomSheetAction.unban:
if (await askConfirmation()) {
await showFutureLoadingDialog(
context: context,
@ -104,7 +115,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop();
}
break;
case 'kick':
case UserBottomSheetAction.kick:
if (await askConfirmation()) {
await showFutureLoadingDialog(
context: context,
@ -113,7 +124,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop();
}
break;
case 'permission':
case UserBottomSheetAction.permission:
final newPermission = await showPermissionChooser(
context,
currentLevel: widget.user.powerLevel,
@ -127,7 +138,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
Navigator.of(context, rootNavigator: false).pop();
}
break;
case 'message':
case UserBottomSheetAction.message:
final roomIdResult = await showFutureLoadingDialog(
context: context,
future: () => widget.user.startDirectChat(),
@ -137,7 +148,7 @@ class UserBottomSheetController extends State<UserBottomSheet> {
.toSegments(['rooms', roomIdResult.result!]);
Navigator.of(context, rootNavigator: false).pop();
break;
case 'ignore':
case UserBottomSheetAction.ignore:
if (await askConfirmation()) {
await showFutureLoadingDialog(
context: context,

View File

@ -1,15 +1,11 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/widgets/avatar.dart';
import '../../utils/matrix_sdk_extensions/presence_extension.dart';
import '../../widgets/content_banner.dart';
import '../../widgets/m2_popup_menu_button.dart';
import '../../widgets/matrix.dart';
import 'user_bottom_sheet.dart';
@ -23,155 +19,114 @@ class UserBottomSheetView extends StatelessWidget {
final user = controller.widget.user;
final client = Matrix.of(context).client;
final presence = client.presences[user.id];
return Center(
child: SizedBox(
width: min(
MediaQuery.of(context).size.width, FluffyThemes.columnWidth * 1.5),
child: Material(
elevation: 4,
child: SafeArea(
child: Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
elevation: 0,
backgroundColor:
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5),
leading: IconButton(
icon: const Icon(Icons.arrow_downward_outlined),
onPressed: Navigator.of(context, rootNavigator: false).pop,
tooltip: L10n.of(context)!.close,
),
title: Text(user.calcDisplayname()),
actions: [
if (user.id != client.userID)
M2PopupMenuButton(
itemBuilder: (_) => [
if (controller.widget.onMention != null)
PopupMenuItem(
value: 'mention',
child: _TextWithIcon(
L10n.of(context)!.mention,
Icons.alternate_email_outlined,
),
),
if (user.id != client.userID && !user.room.isDirectChat)
PopupMenuItem(
value: 'message',
child: _TextWithIcon(
L10n.of(context)!.sendAMessage,
Icons.send_outlined,
),
),
if (user.canChangePowerLevel)
PopupMenuItem(
value: 'permission',
child: _TextWithIcon(
L10n.of(context)!.setPermissionsLevel,
Icons.edit_attributes_outlined,
),
),
if (user.canKick)
PopupMenuItem(
value: 'kick',
child: _TextWithIcon(
L10n.of(context)!.kickFromChat,
Icons.exit_to_app_outlined,
),
),
if (user.canBan && user.membership != Membership.ban)
PopupMenuItem(
value: 'ban',
child: _TextWithIcon(
L10n.of(context)!.banFromChat,
Icons.warning_sharp,
),
)
else if (user.canBan &&
user.membership == Membership.ban)
PopupMenuItem(
value: 'unban',
child: _TextWithIcon(
L10n.of(context)!.unbanFromChat,
Icons.warning_outlined,
),
),
if (!client.ignoredUsers.contains(user.id))
PopupMenuItem(
value: 'ignore',
child: _TextWithIcon(
L10n.of(context)!.ignore,
Icons.block,
),
),
PopupMenuItem(
value: 'report',
child: _TextWithIcon(
L10n.of(context)!.reportUser,
Icons.shield_outlined,
),
),
],
onSelected: controller.participantAction,
),
],
),
body: Column(
children: [
Expanded(
child: ContentBanner(
mxContent: user.avatarUrl,
defaultIcon: Icons.account_circle_outlined,
client: client,
),
),
ListTile(
title: Text(L10n.of(context)!.username),
subtitle: Text(user.id),
trailing: Icon(Icons.adaptive.share_outlined),
onTap: () => FluffyShare.share(
user.id,
context,
),
),
if (presence != null)
ListTile(
title: Text(presence.getLocalizedStatusMessage(context)),
subtitle:
Text(presence.getLocalizedLastActiveAgo(context)),
trailing: Icon(Icons.circle,
color: presence.presence == PresenceType.online
? Colors.green
: Colors.grey),
),
],
),
),
return SafeArea(
child: Scaffold(
appBar: AppBar(
leading: CloseButton(
onPressed: Navigator.of(context, rootNavigator: false).pop,
),
title: Text(user.calcDisplayname()),
actions: [
if (user.id != client.userID)
Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton.icon(
onPressed: () => controller
.participantAction(UserBottomSheetAction.message),
icon: const Icon(Icons.chat_outlined),
label: Text(L10n.of(context)!.newChat),
),
),
],
),
body: ListView(
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Avatar(
mxContent: user.avatarUrl,
name: user.calcDisplayname(),
size: Avatar.defaultSize * 2,
fontSize: 24,
),
),
Expanded(
child: ListTile(
contentPadding: const EdgeInsets.only(right: 16.0),
title: Text(user.id),
subtitle: presence == null
? null
: Text(presence.getLocalizedLastActiveAgo(context)),
trailing: IconButton(
icon: Icon(Icons.adaptive.share),
onPressed: () => FluffyShare.share(
user.id,
context,
),
),
),
),
],
),
if (controller.widget.onMention != null)
ListTile(
trailing: const Icon(Icons.alternate_email_outlined),
title: Text(L10n.of(context)!.mention),
onTap: () =>
controller.participantAction(UserBottomSheetAction.mention),
),
if (user.canChangePowerLevel)
ListTile(
title: Text(L10n.of(context)!.setPermissionsLevel),
trailing: const Icon(Icons.edit_attributes_outlined),
onTap: () => controller
.participantAction(UserBottomSheetAction.permission),
),
if (user.canKick)
ListTile(
title: Text(L10n.of(context)!.kickFromChat),
trailing: const Icon(Icons.exit_to_app_outlined),
onTap: () =>
controller.participantAction(UserBottomSheetAction.kick),
),
if (user.canBan && user.membership != Membership.ban)
ListTile(
title: Text(L10n.of(context)!.banFromChat),
trailing: const Icon(Icons.warning_sharp),
onTap: () =>
controller.participantAction(UserBottomSheetAction.ban),
)
else if (user.canBan && user.membership == Membership.ban)
ListTile(
title: Text(L10n.of(context)!.unbanFromChat),
trailing: const Icon(Icons.warning_outlined),
onTap: () =>
controller.participantAction(UserBottomSheetAction.unban),
),
if (user.id != client.userID &&
!client.ignoredUsers.contains(user.id))
ListTile(
textColor: Theme.of(context).colorScheme.onErrorContainer,
iconColor: Theme.of(context).colorScheme.onErrorContainer,
title: Text(L10n.of(context)!.ignore),
trailing: const Icon(Icons.block),
onTap: () =>
controller.participantAction(UserBottomSheetAction.ignore),
),
if (user.id != client.userID)
ListTile(
textColor: Theme.of(context).colorScheme.error,
iconColor: Theme.of(context).colorScheme.error,
title: Text(L10n.of(context)!.reportUser),
trailing: const Icon(Icons.shield_outlined),
onTap: () =>
controller.participantAction(UserBottomSheetAction.report),
),
],
),
),
);
}
}
class _TextWithIcon extends StatelessWidget {
final String text;
final IconData iconData;
const _TextWithIcon(
this.text,
this.iconData, {
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(iconData),
const SizedBox(width: 16),
Text(text),
],
);
}
}

View File

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/utils/platform_infos.dart';
Future<T?> showAdaptiveBottomSheet<T>({
required BuildContext context,
required Widget Function(BuildContext) builder,
bool isDismissible = true,
bool isScrollControlled = false,
}) =>
showModalBottomSheet(
context: context,
builder: builder,
useRootNavigator: !PlatformInfos.isMobile,
isDismissible: isDismissible,
isScrollControlled: isScrollControlled,
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height - 128,
maxWidth: FluffyThemes.columnWidth * 1.5,
),
clipBehavior: Clip.hardEdge,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(AppConfig.borderRadius),
topRight: Radius.circular(AppConfig.borderRadius),
),
),
);

View File

@ -10,6 +10,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/profile_bottom_sheet.dart';
import 'package:fluffychat/widgets/public_room_bottom_sheet.dart';
@ -145,7 +146,7 @@ class UrlLauncher {
}
return;
} else {
await showModalBottomSheet(
await showAdaptiveBottomSheet(
context: context,
builder: (c) => PublicRoomBottomSheet(
roomAlias: identityParts.primaryIdentifier,
@ -182,7 +183,7 @@ class UrlLauncher {
}
}
} else if (identityParts.primaryIdentifier.sigil == '@') {
await showModalBottomSheet(
await showAdaptiveBottomSheet(
context: context,
builder: (c) => ProfileBottomSheet(
userId: identityParts.primaryIdentifier,

View File

@ -14,6 +14,7 @@ import 'package:vrouter/vrouter.dart';
import 'package:fluffychat/pages/chat/cupertino_widgets_bottom_sheet.dart';
import 'package:fluffychat/pages/chat/edit_widgets_dialog.dart';
import 'package:fluffychat/pages/chat/widgets_bottom_sheet.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'm2_popup_menu_button.dart';
import 'matrix.dart';
@ -185,7 +186,7 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
context: context,
builder: (context) => CupertinoWidgetsBottomSheet(room: widget.room),
)
: showModalBottomSheet(
: showAdaptiveBottomSheet(
context: context,
builder: (context) => WidgetsBottomSheet(room: widget.room),
);

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