Compare commits
No commits in common. "main" and "v1.7.0" have entirely different histories.
6
.gitignore
vendored
@ -10,10 +10,11 @@
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
lib/generated_plugin_registrant.dart
|
||||
prime
|
||||
|
||||
# libolm package
|
||||
/assets/js/package
|
||||
/assets/js/package/*
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
@ -37,6 +38,7 @@ prime
|
||||
/build/
|
||||
|
||||
# Web related
|
||||
lib/generated_plugin_registrant.dart
|
||||
docs/build/
|
||||
docs/.jekyll-cache/
|
||||
docs/_site/
|
||||
@ -60,4 +62,4 @@ ios/Podfile.lock
|
||||
/linux/out
|
||||
/macos/out
|
||||
.vs
|
||||
olm
|
||||
assets/js/package/olm.js
|
||||
|
||||
236
.gitlab-ci.yml
@ -1,7 +1,7 @@
|
||||
variables:
|
||||
FLUTTER_VERSION: 3.10.0
|
||||
FLUTTER_VERSION: 3.3.8
|
||||
|
||||
image: ghcr.io/cirruslabs/flutter:${FLUTTER_VERSION}
|
||||
image: cirrusci/flutter:${FLUTTER_VERSION}
|
||||
|
||||
.shared_windows_runners:
|
||||
tags:
|
||||
@ -16,15 +16,7 @@ stages:
|
||||
|
||||
code_analyze:
|
||||
stage: test
|
||||
script:
|
||||
- flutter pub get
|
||||
- dart run import_sorter:main --no-comments --exit-if-changed
|
||||
- dart format lib/ test/ --set-exit-if-changed
|
||||
- flutter analyze
|
||||
- git apply ./scripts/enable-android-google-services.patch
|
||||
- flutter pub get
|
||||
- flutter analyze
|
||||
- flutter pub run dart_code_metrics:metrics lib -r gitlab > code-quality-report.json || true
|
||||
script: [./scripts/code_analyze.sh]
|
||||
artifacts:
|
||||
reports:
|
||||
codequality: code-quality-report.json
|
||||
@ -40,150 +32,106 @@ widget_test:
|
||||
services:
|
||||
- name: docker:dind
|
||||
alias: docker
|
||||
parallel:
|
||||
matrix:
|
||||
- HOMESERVER_IMPLEMENTATION:
|
||||
- synapse
|
||||
- dendrite
|
||||
- conduit
|
||||
variables:
|
||||
# activate container-to-container networking
|
||||
FF_NETWORK_PER_BUILD: "true"
|
||||
# Tell docker CLI how to talk to Docker daemon.
|
||||
DOCKER_HOST: tcp://docker:2375/
|
||||
# Use the btrfs driver for improved performance.
|
||||
DOCKER_DRIVER: btrfs
|
||||
# Use the overlayfs driver for improved performance.
|
||||
DOCKER_DRIVER: overlay2
|
||||
# Disable TLS since we're running inside local network.
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
HOMESERVER: docker
|
||||
before_script:
|
||||
- scripts/integration-prepare-host.sh
|
||||
# create test user environment variables
|
||||
- source scripts/integration-create-environment-variables.sh
|
||||
# start AVD and keep running in background
|
||||
- scripts/integration-start-avd.sh &
|
||||
- scripts/integration-prepare-alpine.sh
|
||||
# create Synapse instance
|
||||
- scripts/integration-server-${HOMESERVER_IMPLEMENTATION}.sh
|
||||
- scripts/integration-server-synapse.sh
|
||||
# properly set the homeserver IP and create test users
|
||||
- scripts/integration-prepare-homeserver.sh
|
||||
# ensure the homeserver works
|
||||
- curl docker:8008/_matrix/static/ 2> /dev/null | grep "It works! Synapse is running"
|
||||
script:
|
||||
# start AVD and keep running in background
|
||||
- scripts/integration-start-avd.sh &
|
||||
- flutter pub get
|
||||
- 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
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- video.mp4
|
||||
- flutter test integration_test
|
||||
allow_failure: true
|
||||
tags:
|
||||
- docker
|
||||
- famedly
|
||||
|
||||
# integration tests for Linux builds
|
||||
### disabled because of Linux headless issues
|
||||
.integration_test_linux:
|
||||
extends: .integration_test
|
||||
parallel:
|
||||
matrix:
|
||||
- HOMESERVER_IMPLEMENTATION:
|
||||
- conduit
|
||||
script:
|
||||
- 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 --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:
|
||||
- android
|
||||
timeout: 20m
|
||||
|
||||
# extending the default tests to test the Google-flavored builds
|
||||
.integration_test_proprietary:
|
||||
.integration_test_google:
|
||||
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
|
||||
- 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 )
|
||||
- flutter test integration_test
|
||||
allow_failure: true
|
||||
|
||||
release_mode_launches:
|
||||
parallel:
|
||||
matrix:
|
||||
- FLAVOR:
|
||||
- floss
|
||||
- proprietary
|
||||
# extending the default tests to use Conduit as local homeserver
|
||||
.integration_test_conduit:
|
||||
extends: .integration_test
|
||||
before_script:
|
||||
# start AVD and keep running in background
|
||||
- scripts/integration-start-avd.sh &
|
||||
- scripts/integration-prepare-alpine.sh
|
||||
# create Conduit instance
|
||||
- scripts/integration-server-conduit.sh
|
||||
# properly set the homeserver IP and create test users
|
||||
- scripts/integration-prepare-homeserver.sh
|
||||
# ensure the homeserver works
|
||||
- curl docker:8008/_matrix/static/ 2> /dev/null | grep "M_NOT_FOUND" 1> /dev/null && echo "Conduit is running!"
|
||||
allow_failure: true
|
||||
|
||||
# extending the default tests to use Dendrite as local homeserver
|
||||
.integration_test_dendrite:
|
||||
extends: .integration_test
|
||||
before_script:
|
||||
# start AVD and keep running in background
|
||||
- scripts/integration-start-avd.sh &
|
||||
- scripts/integration-prepare-alpine.sh
|
||||
# create Dendrite instance
|
||||
- scripts/integration-server-dendrite.sh
|
||||
# properly set the homeserver IP and create test users
|
||||
- scripts/integration-prepare-homeserver.sh
|
||||
# ensure the homeserver works
|
||||
- curl docker:8008/_matrix/static/ 2> /dev/null | grep "404 page not found" 1> /dev/null && echo "Dendrite is running!"
|
||||
allow_failure: true
|
||||
|
||||
.release_mode_launches:
|
||||
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/integration/stable:${FLUTTER_VERSION}
|
||||
stage: test
|
||||
before_script:
|
||||
- |
|
||||
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 &
|
||||
# generate temporary release build configuration and ensure app launches
|
||||
- scripts/integration-check-release-build.sh
|
||||
timeout: 20m
|
||||
only:
|
||||
- tags
|
||||
allow_failure: true
|
||||
tags:
|
||||
- docker
|
||||
- famedly
|
||||
- android
|
||||
timeout: 20m
|
||||
|
||||
.release_mode_launches_google:
|
||||
extends: .release_mode_launches
|
||||
before_script:
|
||||
- git apply ./scripts/enable-android-google-services.patch
|
||||
allow_failure: true
|
||||
|
||||
build_web:
|
||||
stage: build
|
||||
before_script:
|
||||
[sudo apt update && sudo apt install curl -y, ./scripts/prepare-web.sh]
|
||||
script:
|
||||
- flutter build web --release --verbose --source-maps
|
||||
script: [./scripts/build-web.sh]
|
||||
artifacts:
|
||||
paths:
|
||||
- build/web/
|
||||
|
||||
# yes, we *do* build a Windows DLL on Linux. More reliable.
|
||||
build_olm_windows:
|
||||
image: archlinux:latest
|
||||
stage: test
|
||||
before_script:
|
||||
- pacman-key --init
|
||||
- pacman --noconfirm -Sy mingw-w64 cmake git base-devel
|
||||
script:
|
||||
- ./scripts/build-olm-windows.sh
|
||||
- mv olm/build/libolm.dll .
|
||||
artifacts:
|
||||
paths:
|
||||
- libolm.dll
|
||||
allow_failure: true
|
||||
only:
|
||||
- main
|
||||
- tags
|
||||
|
||||
build_windows:
|
||||
extends:
|
||||
- .shared_windows_runners
|
||||
stage: test
|
||||
before_script:
|
||||
- ./scripts/prepare-windows.ps1
|
||||
# workarounding artifacts download being broken
|
||||
- $response = Invoke-WebRequest -Uri "$CI_API_V4_URL/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/jobs" -UseBasicParsing
|
||||
- $jobs = $response | ConvertFrom-Json
|
||||
- $job = $jobs | where { $_.name -eq "build_olm_windows" }
|
||||
- $jobId = $job.id
|
||||
- Invoke-WebRequest -Uri "$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$jobId/artifacts/libolm.dll" -UseBasicParsing -OutFile libolm.dll
|
||||
script:
|
||||
- ./scripts/build-windows.ps1
|
||||
- Copy-Item -Path "libolm.dll" -Destination "build/windows/runner/Release"
|
||||
- ./scripts/package-windows.ps1
|
||||
stage: build
|
||||
before_script: [./scripts/prepare-windows.ps1]
|
||||
script: [./scripts/build-windows.ps1]
|
||||
artifacts:
|
||||
paths:
|
||||
- build/windows/runner/Release
|
||||
@ -194,14 +142,13 @@ build_windows:
|
||||
|
||||
build_android_debug:
|
||||
stage: build
|
||||
script: [flutter build apk --debug]
|
||||
script: [./scripts/build-android-debug.sh]
|
||||
tags:
|
||||
- android
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
- build/app/outputs/apk/debug/app-debug.apk
|
||||
tags:
|
||||
- docker
|
||||
- famedly
|
||||
except:
|
||||
- main
|
||||
- tags
|
||||
@ -211,14 +158,13 @@ build_android_apk:
|
||||
before_script:
|
||||
- git apply ./scripts/enable-android-google-services.patch
|
||||
- ./scripts/prepare-android-release.sh
|
||||
script: [flutter build apk --release]
|
||||
script: [./scripts/build-android-apk.sh]
|
||||
tags:
|
||||
- android
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
- build/app/outputs/apk/release/app-release.apk
|
||||
tags:
|
||||
- docker
|
||||
- famedly
|
||||
- build/android/app-release.apk
|
||||
only:
|
||||
- main
|
||||
- tags
|
||||
@ -229,14 +175,13 @@ deploy_playstore_internal:
|
||||
- git apply ./scripts/enable-android-google-services.patch
|
||||
- ./scripts/prepare-android-release.sh
|
||||
script: [./scripts/release-playstore-beta.sh]
|
||||
tags:
|
||||
- android
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
- build/android/app-release.aab
|
||||
resource_group: playstore_release
|
||||
tags:
|
||||
- docker
|
||||
- famedly
|
||||
only:
|
||||
- main
|
||||
|
||||
@ -274,7 +219,12 @@ pages:
|
||||
- cd ..
|
||||
- mv docs public
|
||||
- mv repo public || true
|
||||
- mv build/web/ public/web
|
||||
- mv build/web/ public/nightly
|
||||
# ensure the nightly deployment knows its location
|
||||
- sed -i "s/href=\"\/web\/\"/href=\"\/nightly\/\"/g" public/nightly/index.html
|
||||
- rm -rf build
|
||||
- ./scripts/download-web-stable.sh
|
||||
- mv stable public/web
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
@ -283,14 +233,11 @@ pages:
|
||||
|
||||
build_linux_x86:
|
||||
stage: build
|
||||
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/flutter-linux/stable:${FLUTTER_VERSION}
|
||||
before_script:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install curl clang cmake ninja-build pkg-config libgtk-3-dev libblkid-dev liblzma-dev libjsoncpp-dev cmake-data libsecret-1-dev libsecret-1-0 librhash0 -y
|
||||
script: [flutter build linux --release]
|
||||
tags:
|
||||
- docker
|
||||
- famedly
|
||||
[
|
||||
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]
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
@ -298,9 +245,8 @@ build_linux_x86:
|
||||
|
||||
build_linux_arm64:
|
||||
stage: build
|
||||
before_script:
|
||||
- flutter upgrade $FLUTTER_VERSION --force
|
||||
script: [flutter build linux --release]
|
||||
before_script: [flutter upgrade]
|
||||
script: [./scripts/build-linux.sh]
|
||||
tags: [docker_arm64]
|
||||
only:
|
||||
- main
|
||||
@ -314,6 +260,8 @@ build_linux_arm64:
|
||||
update_dependencies:
|
||||
stage: build
|
||||
needs: []
|
||||
tags:
|
||||
- docker
|
||||
only:
|
||||
- schedules
|
||||
variables:
|
||||
@ -350,29 +298,28 @@ upload_android:
|
||||
extends: .release
|
||||
script:
|
||||
- |
|
||||
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file build/app/outputs/apk/release/app-release.apk ${PACKAGE_REGISTRY_URL}/fluffychat.apk
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file build/android/app-release.apk ${PACKAGE_REGISTRY_URL}/fluffychat.apk
|
||||
|
||||
upload_web:
|
||||
extends: .release
|
||||
script:
|
||||
- tar czf package.tar.gz -C build/web/ .
|
||||
- |
|
||||
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-web.tar.gz
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-web.tar.gz
|
||||
|
||||
upload_linux_x86:
|
||||
extends: .release
|
||||
script:
|
||||
- tar czf package.tar.gz -C build/linux/x64/release/bundle/ .
|
||||
- |
|
||||
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-x86.tar.gz
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-x86.tar.gz
|
||||
|
||||
upload_linux_arm64:
|
||||
extends: .release
|
||||
script:
|
||||
- tar czf package.tar.gz -C build/linux/arm64/release/bundle/ .
|
||||
- |
|
||||
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-arm64.tar.gz
|
||||
allow_failure: true
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.tar.gz ${PACKAGE_REGISTRY_URL}/fluffychat-linux-arm64.tar.gz
|
||||
|
||||
upload_windows:
|
||||
extends: .release
|
||||
@ -382,9 +329,8 @@ upload_windows:
|
||||
- mv build/windows/runner/Release/fluffychat.msix fluffychat.msix
|
||||
- cd build/windows/runner/Release; zip -r ../../../../package.zip . ; cd -
|
||||
- |
|
||||
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.zip ${PACKAGE_REGISTRY_URL}/fluffychat-windows.zip
|
||||
curl --fail-with-body --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file fluffychat.msix ${PACKAGE_REGISTRY_URL}/fluffychat-windows.msix
|
||||
allow_failure: true
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file package.zip ${PACKAGE_REGISTRY_URL}/fluffychat-windows.zip
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file fluffychat.msix ${PACKAGE_REGISTRY_URL}/fluffychat-windows.msix
|
||||
|
||||
deploy_playstore:
|
||||
stage: deploy
|
||||
|
||||
12
.metadata
@ -4,7 +4,7 @@
|
||||
# This file should be version controlled.
|
||||
|
||||
version:
|
||||
revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
|
||||
revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
@ -13,11 +13,11 @@ project_type: app
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
|
||||
base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
|
||||
- platform: macos
|
||||
create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
|
||||
base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
- platform: windows
|
||||
create_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
base_revision: 85684f9300908116a78138ea4c6036c35c9a1236
|
||||
|
||||
# User provided section
|
||||
|
||||
|
||||
232
CHANGELOG.md
@ -1,235 +1,3 @@
|
||||
## v1.12.0
|
||||
- Added translation using Weblate (Toki Pona) (Mæve Rey)
|
||||
- Translated using Weblate (Arabic) (Rex_sa)
|
||||
- Translated using Weblate (Chinese (Simplified)) (Eric)
|
||||
- Translated using Weblate (Croatian) (Milo Ivir)
|
||||
- Translated using Weblate (Estonian) (Priit Jõerüüt)
|
||||
- Translated using Weblate (Galician) (josé m)
|
||||
- Translated using Weblate (Indonesian) (Linerly)
|
||||
- Translated using Weblate (Polish) (lauren n. liberda)
|
||||
- Translated using Weblate (Romanian) (Riley)
|
||||
- Translated using Weblate (Russian) (DarkCoder15)
|
||||
- Translated using Weblate (Spanish) (José Muñoz)
|
||||
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
|
||||
- build: Remove dependency overwrite for ffi (Krille)
|
||||
- build: Update dependencies (Krille)
|
||||
- builds: Change minsdkversion of Android from 16 to 19 (Krille)
|
||||
- builds: Do not allow failure for linux x86 (Krille)
|
||||
- builds: Do not use verbose mode on building linux (Krille)
|
||||
- builds: Linux with flutter 3.10 (Krille)
|
||||
- builds: Remove workaround for building linux arm64 (Krille)
|
||||
- builds: Update file_picker to 5.3.0 (Krille)
|
||||
- builds: Update flutter table html (Krille)
|
||||
- builds: Update flutter_html (Krille)
|
||||
- builds: migrate to dart 3.0/flutter 3.10 (lauren n. liberda)
|
||||
- chore: Add missing blockquote style (Krille)
|
||||
- chore: Allow failure in build linux for now (Krille)
|
||||
- chore: Ask for storage persistence (Krille)
|
||||
- chore: Clean unused translations (Malin Errenst)
|
||||
- chore: Enhance room pills (Krille)
|
||||
- chore: Minor code clean up (Krille)
|
||||
- chore: Update flutter webrtc (Krille)
|
||||
- chore: Upgrade to Flutter 3.10.1 (Malin Errenst)
|
||||
- chore: change release curl calls to use --fail-with-body (Tim Flink)
|
||||
- chore: update macOS icons and add build script (TheOneWithTheBraid)
|
||||
- design: Replace anime images with neutral cupertino icons (Krille)
|
||||
- feat: Add toggle to mute notifications from chat groups (fbievan)
|
||||
- feat: Allow ruby tags in html (Krille)
|
||||
- feat: Display progress value for initial sync (Krille)
|
||||
- feat: Implement new error reporting tool when critical features break like playing audio or video messages or opening a chat (Krille)
|
||||
- feat: clean up macOS build metadata (TheOneWithTheBraid)
|
||||
- feat: set display information correctly (TheOneWithTheBraid)
|
||||
- feat: update macOS build files (TheOneWithTheBraid)
|
||||
- feat: update macOS build information for macOS Ventura (TheOneWithTheBraid)
|
||||
- fix "Unhandled Exception: VRouter.of(context) was called with a context which does not contain a VRouter." (Lauren N. Liberda)
|
||||
- fix: Broken arb file (Krille)
|
||||
- fix: Do not unnecessary request all members in public rooms (Krille)
|
||||
- fix: Remove wrong rendered linebreak in html (Krille)
|
||||
- fix: Scroll down button (Krille)
|
||||
- fix: Scroll up and scroll down buttons in chat list (Krille)
|
||||
- fix: Scrolldown button (Krille)
|
||||
- fix: Too long file name cause a render overflow (Skying)
|
||||
- fix: Try to reload timeline on IOException (Krille)
|
||||
- fix: User pills (Krille)
|
||||
- fix: broken CI artifact uploads (TheOneWithTheBraid)
|
||||
- fix: custom emote placeholder (TheOneWithTheBraid)
|
||||
- fix: path of libolm (TheOneWithTheBraid)
|
||||
- fix: Quick account switching (JHansen)
|
||||
- fix: read reciepts (JHansen)
|
||||
- perf: Use valuenotifier to not rebuild chatlist (Krille)
|
||||
- refactor: Reimplement flutter matrix html locally (Krille)
|
||||
- refactor: Update Roboto and Noto Emoji (The one with the Braid)
|
||||
- refactor: Use AnimatedSize for FAB (Krille)
|
||||
- refactor: Use DateTime for weekday localization (Malin Errenst)
|
||||
|
||||
## v1.11.2
|
||||
- Translated using Weblate (Croatian) (Milo Ivir)
|
||||
- Translated using Weblate (Dutch) (Jelv)
|
||||
- Translated using Weblate (Estonian) (Priit Jõerüüt)
|
||||
- Translated using Weblate (Galician) (josé m)
|
||||
- Translated using Weblate (Polish) (Eryk Michalak)
|
||||
- Translated using Weblate (Turkish) (Oğuz Ersen)
|
||||
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
|
||||
- feat: Permission dialog before open link in browser (Krille)
|
||||
- fix: Chats do not load (Krille)
|
||||
|
||||
## v1.11.1 - 2023-04-20
|
||||
- fix: Download files on web and iOS with correct mimetype
|
||||
|
||||
## v1.11.0 - 2023-04-14
|
||||
- feat: Add visual read marker (Krille)
|
||||
- feat: Jump to last read event (Krille)
|
||||
- feat: Use fragmented timeline to jump to event (Krille)
|
||||
- feat: change to flutterwebauth2 (ShootingStarDragons)
|
||||
- fix: Join public room (Krille)
|
||||
- fix: Set fcm priority to max on android (Krille)
|
||||
- refactor: CI scripts and old workarounds for build scripts (Krille)
|
||||
- refactor: Client in ChatPage (Krille)
|
||||
- refactor: Not nullable room in ChatPage (Krille)
|
||||
- refactor: Switch to file_picker package and get rid of some dependency overrides (Krille)
|
||||
- refactor: Use correct Matrix instance (Krille)
|
||||
- style: Make emptypage logo bigger (Krille)
|
||||
- style: Minor adjustments for modal bottom sheets (Krille)
|
||||
- style: Move chats to top (Krille)
|
||||
- style: Use SliverList for chatlist (Krille)
|
||||
- refactor: Container -> SizedBox.shrink() (noob_tea)
|
||||
- Translated using Weblate (Chinese (Simplified)) (Eric)
|
||||
- Translated using Weblate (Dutch) (Jelv)
|
||||
- Translated using Weblate (Estonian) (Priit Jõerüüt)
|
||||
- Translated using Weblate (French) (Anne Onyme 017)
|
||||
- Translated using Weblate (Galician) (josé m)
|
||||
- Translated using Weblate (Indonesian) (Linerly)
|
||||
- Translated using Weblate (Persian) (Parsa)
|
||||
- Translated using Weblate (Persian) (Siavash)
|
||||
- Translated using Weblate (Polish) (Luna)
|
||||
- Translated using Weblate (Swedish) (Kristoffer Grundström)
|
||||
- Translated using Weblate (Turkish) (Oğuz Ersen)
|
||||
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
|
||||
|
||||
## v1.10.0 - 2023-02-25
|
||||
- Added translation using Weblate (Thai) (Wphaoka)
|
||||
- Added translation using Weblate (Tibetan) (Nathan Freitas)
|
||||
- Default hardcoded message when l10n is not available (fabienli)
|
||||
- Fix: The stable repo fingerprint (TODO the qr-code should be updated) (machiav3lli)
|
||||
- Translated using Weblate (Basque) (xabirequejo)
|
||||
- Translated using Weblate (Dutch) (Jelv)
|
||||
- Translated using Weblate (Estonian) (Priit Jõerüüt)
|
||||
- Translated using Weblate (French) (Anne Onyme 017)
|
||||
- Translated using Weblate (Galician) (josé m)
|
||||
- Translated using Weblate (Galician) (josé m)
|
||||
- Translated using Weblate (Indonesian) (Linerly)
|
||||
- Translated using Weblate (Japanese) (Suguru Hirahara)
|
||||
- Translated using Weblate (Persian) (Farooq Karimi Zadeh)
|
||||
- Translated using Weblate (Swedish) (Joaquim Homrighausen)
|
||||
- Translated using Weblate (Turkish) (Oğuz Ersen)
|
||||
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
|
||||
- chore: Disable stable for web until script is fixed (Krille)
|
||||
- chore: Display warning when logout without backup (Krille)
|
||||
- chore: Downgrade flutter CI version (Krille)
|
||||
- chore: Follow up audioplayer on linux (Krille)
|
||||
- chore: Follow up chat encryption desgin (Krille)
|
||||
- chore: Follow up fix audioplayer on android (Christian Pauly)
|
||||
- chore: Follow up formatting (Christian Pauly)
|
||||
- chore: Follow up formatting (Krille)
|
||||
- chore: Follow up remove hero animation (Krille)
|
||||
- chore: Follow up secrity settings design (Krille)
|
||||
- chore: Follow up settings page (Krille)
|
||||
- chore: Follow up settings page design (Christian Pauly)
|
||||
- chore: Follow up style adjustments (Krille)
|
||||
- chore: Lookup l10n in pushhelper if null (Krille)
|
||||
- chore: Update matrix package to 0.17.0 (Krille)
|
||||
- chore: Update to Flutter 3.7.1 (Krille)
|
||||
- docs/qr-stable.svg: update the QR code (Aminda Suomalainen)
|
||||
- feat: Enable audioplayer for web and linux (Christian Pauly)
|
||||
- fix: Display error when user tries to send too large file (Christian Pauly)
|
||||
- refactor: Do only instantiate AudioPlayer() object when in use (Christian Pauly)
|
||||
- refactor: Remove syncstatus verbose logs (Christian Pauly)
|
||||
- refactor: Store cached files in tmp directory so OS will clear file cache from time to time (Krille)
|
||||
- style: Adjust key verification dialog (Christian Pauly)
|
||||
- style: Bootstrap design adjustments (Christian Pauly)
|
||||
- style: Encryption page adjustments (Christian Pauly)
|
||||
- style: Enhance user device settings design (Krille)
|
||||
- style: Enhanced chat details design (Krille)
|
||||
- style: Give chat list list tiles rounded corners (Krille)
|
||||
- style: Link underline color (Christian Pauly)
|
||||
- style: Make adaptive bottom sheets scrollable by default (Krille)
|
||||
- style: Make invite page more pretty (Krille)
|
||||
- style: New settings design (Krille)
|
||||
- style: Nicer chips in encryption settings and icons showing device status (Krille)
|
||||
- style: Use emojis on web as well (Christian Pauly)
|
||||
- style: Use robotomono to display device keys (Christian Pauly)
|
||||
- utils/url_launcher: force opening http(s) links in external browser (Marcus Hoffmann)
|
||||
|
||||
## v1.9.0 - 2023-01-29
|
||||
- Translated using Weblate (Czech) (Michal Bedáň)
|
||||
- Translated using Weblate (Czech) (grreby)
|
||||
- Translated using Weblate (Dutch) (Jelv)
|
||||
- Translated using Weblate (Estonian) (Priit Jõerüüt)
|
||||
- Translated using Weblate (Galician) (josé m)
|
||||
- Translated using Weblate (German) (Christian)
|
||||
- Translated using Weblate (German) (Vri 🌈)
|
||||
- Translated using Weblate (Indonesian) (Linerly)
|
||||
- Translated using Weblate (Korean) (Youngbin Han)
|
||||
- Translated using Weblate (Polish) (Wiktor)
|
||||
- Translated using Weblate (Turkish) (Oğuz Ersen)
|
||||
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
|
||||
- chore: Change invite link textfield label (Krille)
|
||||
- chore: Remove unused dependency (Krille)
|
||||
- chore: Remove unused translations (Krille)
|
||||
- chore: Update Matrix SDK and refactor (Krille)
|
||||
- chore: Update dependencies (Krille)
|
||||
- chore: Update flutter_map (Krille)
|
||||
- chore: add integration tests (TheOneWithTheBraid)
|
||||
- chore: add integration tests for spaces (TheOneWithTheBraid)
|
||||
- design: More clear chat background and rounded popup menu (Krille)
|
||||
- design: Nicer navigationrail (Krille)
|
||||
- design: Upgrade to Flutter 3.7
|
||||
- feat: Bring back disabling the header bar on Linux desktop (q234rty)
|
||||
- feat: Nicer design for abandonded DM rooms (Christian Pauly)
|
||||
- fix: Archive (Krille)
|
||||
- fix: Shared preferences package for flutter 3.7 (Christian Pauly)
|
||||
- fix: permission of web builds (TheOneWithTheBraid)
|
||||
- fix: Notification Settings (Krille)
|
||||
- refactor: Migrate to Flutter 3.7.0 (Christian Pauly)
|
||||
- refactor: Same animations everywhere in app (Krille)
|
||||
- refactor: Stories header with futurebuilder (Krille)
|
||||
- refactor: disable some redundant tests (TheOneWithTheBraid)
|
||||
- style: Animate in out search results (Krille)
|
||||
- style: New modal bottom sheets (Krille)
|
||||
- style: Redesign public room bottomsheets (Krille)
|
||||
|
||||
## v1.8.0 2022-12-30
|
||||
- Added translation using Weblate (Yue (yue_HK)) (Raatty)
|
||||
- Translated using Weblate (Chinese (Simplified)) (Mike Evans)
|
||||
- Translated using Weblate (Estonian) (Priit Jõerüüt)
|
||||
- Translated using Weblate (French) (Anne Onyme 017)
|
||||
- Translated using Weblate (Indonesian) (Linerly)
|
||||
- Translated using Weblate (Turkish) (Oğuz Ersen)
|
||||
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
|
||||
- design: New encryption page (Krille Fear)
|
||||
- feat: Add audio message support to linux (Krille Fear)
|
||||
- feat: Use Android system accent color (Krille Fear)
|
||||
- feat: include olm to Windows builds (TheOneWithTheBraid)
|
||||
- feat: Store drafts (Krille)
|
||||
- fix: Android push notification follow-up (TheOneWithTheBraid)
|
||||
- fix: Content banner (Krille Fear)
|
||||
- fix: Correct redacted by username (Krille Fear)
|
||||
- fix: Do not setup push on every app resume (Krille Fear)
|
||||
- fix: Encryption button is orange in public rooms (Krille Fear)
|
||||
- fix: File event design (Krille Fear)
|
||||
- fix: Hide google services warning after marked (Krille Fear)
|
||||
- fix: Improve story page appearance (Reinhart Previano Koentjoro)
|
||||
- fix: Libhandy windows (Krille Fear)
|
||||
- fix: Monochromatic icon rendering for Android 13+ (Reinhart Previano Koentjoro)
|
||||
- fix: homeserver error text not visible in app bar (TheOneWithTheBraid)
|
||||
- fix: minor issues in room list (TheOneWithTheBraid)
|
||||
|
||||
## v1.7.2 2022-12-19
|
||||
Update dependencies and translations.
|
||||
|
||||
## v1.7.1 2022-11-23
|
||||
Minor bugfix release to retrigger build for FlatPak and Android. Fixes some style bugs and updates some translations
|
||||
|
||||
## v1.7.0 2022-11-17
|
||||
FluffyChat 1.7.0 features a new way to work with spaces via a bottom navigation bar. A lot of work has also been done under the hood to make the app faster and more stable. The main color has slightly changed and the design got some finetuning.
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM ghcr.io/cirruslabs/flutter as builder
|
||||
FROM cirrusci/flutter as builder
|
||||
RUN sudo apt update && sudo apt install curl -y
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
26
PRIVACY.md
@ -2,15 +2,15 @@
|
||||
|
||||
FluffyChat is available on Android, iOS and as a web version. Desktop versions for Windows, Linux and macOS may follow.
|
||||
|
||||
* [Matrix](#matrix)
|
||||
* Sentry
|
||||
* [Database](#database)
|
||||
* [Encryption](#encryption)
|
||||
* [App Permissions](#app-permissions)
|
||||
* [Push Notifications](#push-notifications)
|
||||
* [Stories](#stories)
|
||||
* [Matrix](#1)
|
||||
* [Sentry](#2)
|
||||
* [Database](#3)
|
||||
* [Encryption](#4)
|
||||
* [App Permissions](#5)
|
||||
* [Push Notifications](#6)
|
||||
* [Stories](#7)
|
||||
|
||||
## Matrix<a id="matrix"/>
|
||||
## Matrix<a id="1"/>
|
||||
FluffyChat uses the Matrix protocol. This means that FluffyChat is just a client that can be connected to any compatible matrix server. The respective data protection agreement of the server selected by the user then applies.
|
||||
|
||||
For convenience, one or more servers are set as default that the FluffyChat developers consider trustworthy. The developers of FluffyChat do not guarantee their trustworthiness. Before the first communication, users are informed which server they are connecting to.
|
||||
@ -19,17 +19,17 @@ FluffyChat only communicates with the selected server, with sentry.io if enabled
|
||||
|
||||
More information is available at: [https://matrix.org](https://matrix.org)
|
||||
|
||||
## Database<a id="database"/>
|
||||
## Database<a id="3"/>
|
||||
FluffyChat caches some data received from the server in a local database on the device of the user.
|
||||
|
||||
More information is available at: [https://pub.dev/packages/hive](https://pub.dev/packages/hive)
|
||||
|
||||
## Encryption<a id="encryption"/>
|
||||
## Encryption<a id="4"/>
|
||||
All communication of substantive content between Fluffychat and any server is done in secure way, using transport encryption to protect it.
|
||||
|
||||
FluffyChat is able to use End-To-End-Encryption as a tech preview.
|
||||
|
||||
## App Permissions<a id="app-permissions"/>
|
||||
## App Permissions<a id="5"/>
|
||||
|
||||
The permissions are the same on Android and iOS but may differ in the name. This are the Android Permissions:
|
||||
|
||||
@ -52,7 +52,7 @@ The user is able to send files from the device's file system.
|
||||
#### Location
|
||||
FluffyChat makes it possible to share the current location via the chat. When the user shares their location, FluffyChat uses the device location service and sends the geo-data via Matrix.
|
||||
|
||||
## Push Notifications<a id="push-notifications"/>
|
||||
## Push Notifications<a id="6"/>
|
||||
FluffyChat uses the Firebase Cloud Messaging service for push notifications on Android and iOS. This takes place in the following steps:
|
||||
1. The matrix server sends the push notification to the FluffyChat Push Gateway
|
||||
2. The FluffyChat Push Gateway forwards the message in a different format to Firebase Cloud Messaging
|
||||
@ -95,7 +95,7 @@ A typical push notification could look like this:
|
||||
|
||||
FluffyChat sets the `event_id_only` flag at the Matrix Server. This server is then responsible to send the correct data.
|
||||
|
||||
## Stories<a id="stories"/>
|
||||
## Stories<a id="7"/>
|
||||
|
||||
FluffyChat supports stories which is a feature similar to WhatsApp status or Instagram stories. However it is just a different GUI for the same room-related communication. More information about the feature can be found here:
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@ linter:
|
||||
- prefer_final_locals
|
||||
- prefer_final_in_for_each
|
||||
- sort_pub_dependencies
|
||||
- require_trailing_commas
|
||||
|
||||
analyzer:
|
||||
errors:
|
||||
|
||||
@ -44,8 +44,8 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "chat.fluffy.fluffychat"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 31
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@ -93,9 +93,8 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
android:exported="true">
|
||||
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity"
|
||||
android:exported="true">
|
||||
<intent-filter android:label="flutter_web_auth">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@ -118,8 +117,7 @@
|
||||
<service android:name="io.wazo.callkeep.VoiceConnectionService"
|
||||
android:label="Wazo"
|
||||
android:foregroundServiceType="camera|microphone|mediaProjection"
|
||||
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
|
||||
android:exported="true">
|
||||
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.telecom.ConnectionService" />
|
||||
</intent-filter>
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.8.0'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
@ -27,6 +27,6 @@ subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
tasks.register("clean", Delete) {
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
@ -5,17 +5,12 @@
|
||||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: update_fastlane" time="1.455419">
|
||||
<testcase classname="fastlane.lanes" name="0: update_fastlane" time="0.000202">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: default_platform" time="0.000127">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: google_play_track_version_codes" time="2.638619">
|
||||
<testcase classname="fastlane.lanes" name="1: default_platform" time="7.9e-05">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 37 KiB |
1
assets/js/package/olm.js
Normal file
@ -0,0 +1 @@
|
||||
// Dummy file :-)
|
||||
@ -1,25 +1,30 @@
|
||||
{
|
||||
"@@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": {}
|
||||
"@@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": {}
|
||||
},
|
||||
"accountInformation": "অ্যাকাউন্ট তথ্য",
|
||||
"@accountInformation": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
{}
|
||||
@ -1 +0,0 @@
|
||||
{}
|
||||
@ -1 +1 @@
|
||||
{}
|
||||
{}
|
||||
|
||||
1551
assets/l10n/intl_hy.arb
Normal file
@ -1,120 +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": {}
|
||||
},
|
||||
"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": {}
|
||||
},
|
||||
"logout": "Terminar sessão",
|
||||
"@logout": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"search": "Pesquisar",
|
||||
"@search": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"users": "Utilizadores",
|
||||
"@users": {},
|
||||
"close": "Fechar",
|
||||
"@close": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"dateWithoutYear": "{day}-{month}",
|
||||
"@dateWithoutYear": {
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"month": {},
|
||||
"day": {}
|
||||
}
|
||||
"@@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": {}
|
||||
}
|
||||
}
|
||||
|
||||
374
assets/l10n/intl_si.arb
Normal file
@ -0,0 +1,374 @@
|
||||
{
|
||||
"@@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": {}
|
||||
},
|
||||
"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": {}
|
||||
}
|
||||
},
|
||||
"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": {}
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,20 @@
|
||||
{
|
||||
"@@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": {}
|
||||
"@@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": {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
{}
|
||||
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 212 KiB |
BIN
assets/private_chat_wallpaper.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/Kofi_pixel_logo.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
@ -7,9 +7,11 @@ are also published on it.
|
||||
|
||||
Easiest way to add the Repository is to either **scan the QR-Code** or if you are on your phone **directly click it**.
|
||||
|
||||
<a href="fdroidrepos://fluffychat.im/repo/stable/repo/?fingerprint=5EDB5C4395B2F2D9BA682F6A1D275170CCE5365A6FA27D2220EA8D52A6D95F07" >
|
||||
{::nomarkdown}
|
||||
<a href="fdroidrepos://fluffychat.im/repo/stable/repo/?fingerprint=8E2637AEF6697CC6DD486AF044A6EE45B1A742AE3EF56566E748CDE8BC65C1FB" >
|
||||
<img src="qr-stable.svg" width="300" height="300"/>
|
||||
</a>
|
||||
{:/}
|
||||
|
||||
|
||||
### If the QR-Code doesn't work:
|
||||
@ -22,11 +24,11 @@ If this still isn't working follow the next steps:
|
||||
2. Go to the `Settings` Tab in the Bottom bar
|
||||
3. Click the `Repositories` Action
|
||||
4. Click on the plus sign at the top.
|
||||
5. Fill in `https://fluffychat.im/repo/stable/repo/` into the top field and `5EDB5C4395B2F2D9BA682F6A1D275170CCE5365A6FA27D2220EA8D52A6D95F07` in the bottom field.
|
||||
5. Fill in `https://fluffychat.im/repo/stable/repo/` into the top field and `8E2637AEF6697CC6DD486AF044A6EE45B1A742AE3EF56566E748CDE8BC65C1FB` in the bottom field.
|
||||
|
||||
## What is the fingerprint?
|
||||
|
||||
The fingerprint of the Repository is: `5EDB5C4395B2F2D9BA682F6A1D275170CCE5365A6FA27D2220EA8D52A6D95F07`
|
||||
The fingerprint of the Repository is: `8E2637AEF6697CC6DD486AF044A6EE45B1A742AE3EF56566E748CDE8BC65C1FB`
|
||||
|
||||
# Nightly Repository
|
||||
|
||||
@ -34,9 +36,11 @@ The fingerprint of the Repository is: `5EDB5C4395B2F2D9BA682F6A1D275170CCE5365A6
|
||||
|
||||
Easiest way to add the Repository is to either **scan the QR-Code** or if you are on your phone **directly click** it.
|
||||
|
||||
{::nomarkdown}
|
||||
<a href="fdroidrepos://fluffychat.im/repo/nightly/repo/?fingerprint=21A469657300576478B623DF99D8EB889A80BCD939ACA60A4074741BEAEC397D" >
|
||||
<img src="qr-nightly.svg" width="300" height="300"/>
|
||||
</a>
|
||||
{:/}
|
||||
|
||||
|
||||
### If the QR-Code doesn't work:
|
||||
|
||||
646
docs/index.html
@ -1,119 +1,565 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<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">
|
||||
<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-->
|
||||
<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" />
|
||||
|
||||
<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/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>
|
||||
<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://twitter.com/KrilleFear">
|
||||
<svg class="fill-current h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<path
|
||||
d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z">
|
||||
</path>
|
||||
</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="flex mb-8 justify-center content-center">
|
||||
<a rel="me"
|
||||
class="inline-block text-indigo-500 no-underline hover:text-indigo-900 hover:scale-105 transition-all text-center h-auto p-4"
|
||||
rel="me" href="https://mastodon.art/@krille">
|
||||
<svg class="fill-current h-6" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
|
||||
<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>
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 84 KiB |
BIN
fonts/NotoEmoji/NotoEmoji-Regular.ttf
Normal file
@ -1,193 +1,49 @@
|
||||
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 'dart:developer';
|
||||
|
||||
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',
|
||||
() {
|
||||
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 (_) {}
|
||||
},
|
||||
);
|
||||
group('Integration Test', () {
|
||||
testWidgets('Test if the app starts', (WidgetTester tester) async {
|
||||
app.main();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
testWidgets(
|
||||
'Start app, login and logout',
|
||||
(WidgetTester tester) async {
|
||||
app.main();
|
||||
await tester.ensureAppStartedHomescreen();
|
||||
await tester.ensureLoggedOut();
|
||||
},
|
||||
);
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
|
||||
testWidgets(
|
||||
'Login again',
|
||||
(WidgetTester tester) async {
|
||||
app.main();
|
||||
await tester.ensureAppStartedHomescreen();
|
||||
},
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
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();
|
||||
expect(find.text('Connect'), findsOneWidget);
|
||||
|
||||
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();
|
||||
final input = find.byType(TextField);
|
||||
|
||||
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);
|
||||
expect(input, findsOneWidget);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
await tester.enterText(input, homeserver);
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
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'));
|
||||
// in case registration is allowed
|
||||
try {
|
||||
await tester.tap(find.text('Login'));
|
||||
await tester.pumpAndSettle();
|
||||
} catch (e) {
|
||||
log('Registration is not allowed. Proceeding with login...');
|
||||
}
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.waitFor(find.byIcon(Icons.workspaces_outlined));
|
||||
await tester.tap(find.byIcon(Icons.workspaces_outlined));
|
||||
await tester.pumpAndSettle();
|
||||
final inputs = find.byType(TextField);
|
||||
|
||||
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);
|
||||
});
|
||||
},
|
||||
);
|
||||
await tester.enterText(inputs.first, Users.alice.name);
|
||||
await tester.enterText(inputs.last, Users.alice.password);
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,171 +0,0 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:fluffychat/pages/chat_list/chat_list_body.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.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('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();
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -297,7 +297,7 @@ listeners:
|
||||
# If you plan to use a reverse proxy, please see
|
||||
# https://matrix-org.github.io/synapse/latest/reverse_proxy.html.
|
||||
#
|
||||
- port: 80
|
||||
- port: 8008
|
||||
tls: false
|
||||
type: http
|
||||
x_forwarded: false
|
||||
|
||||
@ -1,26 +1,8 @@
|
||||
abstract class Users {
|
||||
const Users._();
|
||||
|
||||
static const user1 = User(
|
||||
String.fromEnvironment(
|
||||
'USER1_NAME',
|
||||
defaultValue: 'alice',
|
||||
),
|
||||
String.fromEnvironment(
|
||||
'USER1_PW',
|
||||
defaultValue: 'AliceInWonderland',
|
||||
),
|
||||
);
|
||||
static const user2 = User(
|
||||
String.fromEnvironment(
|
||||
'USER2_NAME',
|
||||
defaultValue: 'bob',
|
||||
),
|
||||
String.fromEnvironment(
|
||||
'USER2_PW',
|
||||
defaultValue: 'JoWirSchaffenDas',
|
||||
),
|
||||
);
|
||||
static const alice = User('alice', 'AliceInWonderland');
|
||||
static const bob = User('bob', 'JoWirSchaffenDas');
|
||||
static const trudy = User('trudy', 'HaveIBeenPwned');
|
||||
}
|
||||
|
||||
class User {
|
||||
@ -30,7 +12,5 @@ class User {
|
||||
const User(this.name, this.password);
|
||||
}
|
||||
|
||||
const homeserver = 'http://${const String.fromEnvironment(
|
||||
'HOMESERVER',
|
||||
defaultValue: 'localhost',
|
||||
)}';
|
||||
// https://stackoverflow.com/a/33088657
|
||||
const homeserver = 'http://10.0.2.2:8008';
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -286,12 +286,10 @@
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
@ -324,7 +322,6 @@
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
||||
@ -63,8 +63,6 @@
|
||||
<string>Share your location with your contacts in FluffyChat.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Share your location with your contacts in FluffyChat.</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Share your location with your contacts in FluffyChat.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Record voice message and share them with your contacts on FluffyChat.</string>
|
||||
<key>NSMotionUsageDescription</key>
|
||||
@ -110,7 +108,5 @@
|
||||
</dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
app_identifier("im.fluffychat.app") # The bundle identifier of your app
|
||||
apple_id("christian-kussowski@posteo.de") # Your Apple email address
|
||||
apple_id("christian.pauly@wtal.de") # Your Apple email address
|
||||
|
||||
itc_team_id("122628977") # App Store Connect Team ID
|
||||
team_id("4NXF6Z997G") # Developer Portal Team ID
|
||||
|
||||
@ -16,7 +16,7 @@ abstract class AppConfig {
|
||||
static const double messageFontSize = 15.75;
|
||||
static const bool allowOtherHomeservers = true;
|
||||
static const bool enableRegistration = true;
|
||||
static const Color primaryColor = Color(0xFF5625BA);
|
||||
static const Color primaryColor = Color.fromARGB(255, 135, 103, 172);
|
||||
static const Color primaryColorLight = Color(0xFFCCBDEA);
|
||||
static const Color secondaryColor = Color(0xFF41a2bc);
|
||||
static String _privacyUrl =
|
||||
@ -24,8 +24,6 @@ abstract class AppConfig {
|
||||
static String get privacyUrl => _privacyUrl;
|
||||
static const String enablePushTutorial =
|
||||
'https://gitlab.com/famedly/fluffychat/-/wikis/Push-Notifications-without-Google-Services';
|
||||
static const String encryptionTutorial =
|
||||
'https://gitlab.com/famedly/fluffychat/-/wikis/How-to-use-end-to-end-encryption-in-FluffyChat';
|
||||
static const String appId = 'im.fluffychat.FluffyChat';
|
||||
static const String appOpenUrlScheme = 'im.fluffychat';
|
||||
static String _webBaseUrl = 'https://fluffychat.im/web';
|
||||
@ -33,11 +31,6 @@ abstract class AppConfig {
|
||||
static const String sourceCodeUrl = 'https://gitlab.com/famedly/fluffychat';
|
||||
static const String supportUrl =
|
||||
'https://gitlab.com/famedly/fluffychat/issues';
|
||||
static final Uri newIssueUrl = Uri(
|
||||
scheme: 'https',
|
||||
host: 'gitlab.com',
|
||||
path: '/famedly/fluffychat/-/issues/new',
|
||||
);
|
||||
static const bool enableSentry = true;
|
||||
static const String sentryDns =
|
||||
'https://8591d0d863b646feb4f3dda7e5dcab38@o256755.ingest.sentry.io/5243143';
|
||||
@ -75,9 +68,8 @@ abstract class AppConfig {
|
||||
colorSchemeSeed = Color(json['chat_color']);
|
||||
} catch (e) {
|
||||
Logs().w(
|
||||
'Invalid color in config.json! Please make sure to define the color in this format: "0xffdd0000"',
|
||||
e,
|
||||
);
|
||||
'Invalid color in config.json! Please make sure to define the color in this format: "0xffdd0000"',
|
||||
e);
|
||||
}
|
||||
}
|
||||
if (json['application_name'] is String) {
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||
import 'package:fluffychat/pages/chat_encryption_settings/chat_encryption_settings.dart';
|
||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||
import 'package:fluffychat/pages/chat_permissions_settings/chat_permissions_settings.dart';
|
||||
import 'package:fluffychat/pages/connect/connect_page.dart';
|
||||
import 'package:fluffychat/pages/device_settings/device_settings.dart';
|
||||
import 'package:fluffychat/pages/homeserver_picker/homeserver_picker.dart';
|
||||
import 'package:fluffychat/pages/invitation_selection/invitation_selection.dart';
|
||||
@ -18,6 +19,7 @@ import 'package:fluffychat/pages/new_private_chat/new_private_chat.dart';
|
||||
import 'package:fluffychat/pages/new_space/new_space.dart';
|
||||
import 'package:fluffychat/pages/settings/settings.dart';
|
||||
import 'package:fluffychat/pages/settings_3pid/settings_3pid.dart';
|
||||
import 'package:fluffychat/pages/settings_account/settings_account.dart';
|
||||
import 'package:fluffychat/pages/settings_chat/settings_chat.dart';
|
||||
import 'package:fluffychat/pages/settings_emotes/settings_emotes.dart';
|
||||
import 'package:fluffychat/pages/settings_ignore_list/settings_ignore_list.dart';
|
||||
@ -26,6 +28,7 @@ import 'package:fluffychat/pages/settings_notifications/settings_notifications.d
|
||||
import 'package:fluffychat/pages/settings_security/settings_security.dart';
|
||||
import 'package:fluffychat/pages/settings_stories/settings_stories.dart';
|
||||
import 'package:fluffychat/pages/settings_style/settings_style.dart';
|
||||
import 'package:fluffychat/pages/sign_up/signup.dart';
|
||||
import 'package:fluffychat/pages/story/story_page.dart';
|
||||
import 'package:fluffychat/widgets/layouts/empty_page.dart';
|
||||
import 'package:fluffychat/widgets/layouts/loading_view.dart';
|
||||
@ -68,25 +71,21 @@ class AppRoutes {
|
||||
widget: const ChatDetails(),
|
||||
stackedRoutes: _chatDetailsRoutes,
|
||||
),
|
||||
VWidget(
|
||||
path: ':roomid',
|
||||
widget: const ChatPage(),
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'encryption',
|
||||
widget: const ChatEncryptionSettings(),
|
||||
),
|
||||
VWidget(
|
||||
path: 'invite',
|
||||
widget: const InvitationSelection(),
|
||||
),
|
||||
VWidget(
|
||||
path: 'details',
|
||||
widget: const ChatDetails(),
|
||||
stackedRoutes: _chatDetailsRoutes,
|
||||
),
|
||||
],
|
||||
),
|
||||
VWidget(path: ':roomid', widget: const Chat(), stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'encryption',
|
||||
widget: const ChatEncryptionSettings(),
|
||||
),
|
||||
VWidget(
|
||||
path: 'invite',
|
||||
widget: const InvitationSelection(),
|
||||
),
|
||||
VWidget(
|
||||
path: 'details',
|
||||
widget: const ChatDetails(),
|
||||
stackedRoutes: _chatDetailsRoutes,
|
||||
),
|
||||
]),
|
||||
VWidget(
|
||||
path: '/settings',
|
||||
widget: const Settings(),
|
||||
@ -95,13 +94,6 @@ class AppRoutes {
|
||||
VWidget(
|
||||
path: '/archive',
|
||||
widget: const Archive(),
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: ':roomid',
|
||||
widget: const ChatPage(),
|
||||
buildTransition: _dynamicTransition,
|
||||
),
|
||||
],
|
||||
),
|
||||
VWidget(
|
||||
path: '/newprivatechat',
|
||||
@ -172,14 +164,14 @@ class AppRoutes {
|
||||
VNester(
|
||||
path: ':roomid',
|
||||
widgetBuilder: (child) => SideViewLayout(
|
||||
mainView: const ChatPage(),
|
||||
mainView: const Chat(),
|
||||
sideView: child,
|
||||
),
|
||||
buildTransition: _fadeTransition,
|
||||
nestedRoutes: [
|
||||
VWidget(
|
||||
path: '',
|
||||
widget: const ChatPage(),
|
||||
widget: const Chat(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
VWidget(
|
||||
@ -228,25 +220,13 @@ class AppRoutes {
|
||||
),
|
||||
],
|
||||
),
|
||||
VNester(
|
||||
VWidget(
|
||||
path: '/archive',
|
||||
widgetBuilder: (child) => TwoColumnLayout(
|
||||
mainView: const Archive(),
|
||||
sideView: child,
|
||||
widget: const TwoColumnLayout(
|
||||
mainView: Archive(),
|
||||
sideView: EmptyPage(),
|
||||
),
|
||||
buildTransition: _fadeTransition,
|
||||
nestedRoutes: [
|
||||
VWidget(
|
||||
path: '',
|
||||
widget: const EmptyPage(),
|
||||
buildTransition: _dynamicTransition,
|
||||
),
|
||||
VWidget(
|
||||
path: ':roomid',
|
||||
widget: const ChatPage(),
|
||||
buildTransition: _dynamicTransition,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -264,6 +244,22 @@ class AppRoutes {
|
||||
widget: const Login(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
VWidget(
|
||||
path: 'connect',
|
||||
widget: const ConnectPage(),
|
||||
buildTransition: _fadeTransition,
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'login',
|
||||
widget: const Login(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
VWidget(
|
||||
path: 'signup',
|
||||
widget: const SignupPage(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
]),
|
||||
VWidget(
|
||||
path: 'logs',
|
||||
widget: const LogViewer(),
|
||||
@ -330,14 +326,37 @@ class AppRoutes {
|
||||
],
|
||||
),
|
||||
VWidget(
|
||||
path: 'addaccount',
|
||||
widget: const HomeserverPicker(),
|
||||
buildTransition: _fadeTransition,
|
||||
path: 'account',
|
||||
widget: const SettingsAccount(),
|
||||
buildTransition: _dynamicTransition,
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'login',
|
||||
widget: const Login(),
|
||||
path: 'add',
|
||||
widget: const HomeserverPicker(),
|
||||
buildTransition: _fadeTransition,
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'login',
|
||||
widget: const Login(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
VWidget(
|
||||
path: 'connect',
|
||||
widget: const ConnectPage(),
|
||||
buildTransition: _fadeTransition,
|
||||
stackedRoutes: [
|
||||
VWidget(
|
||||
path: 'login',
|
||||
widget: const Login(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
VWidget(
|
||||
path: 'signup',
|
||||
widget: const SignupPage(),
|
||||
buildTransition: _fadeTransition,
|
||||
),
|
||||
]),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -8,6 +8,7 @@ abstract class SettingKeys {
|
||||
static const String showDirectChatsInSpaces =
|
||||
'chat.fluffy.showDirectChatsInSpaces';
|
||||
static const String separateChatTypes = 'chat.fluffy.separateChatTypes';
|
||||
static const String chatColor = 'chat.fluffy.chat_color';
|
||||
static const String sentry = 'sentry';
|
||||
static const String theme = 'theme';
|
||||
static const String amoledEnabled = 'amoled_enabled';
|
||||
|
||||
@ -9,10 +9,7 @@ import 'app_config.dart';
|
||||
abstract class FluffyThemes {
|
||||
static const double columnWidth = 360.0;
|
||||
|
||||
static const double navRailWidth = 64.0;
|
||||
|
||||
static bool isColumnModeByWidth(double width) =>
|
||||
width > columnWidth * 2 + navRailWidth;
|
||||
static bool isColumnModeByWidth(double width) => width > columnWidth * 2 + 64;
|
||||
|
||||
static bool isColumnMode(BuildContext context) =>
|
||||
isColumnModeByWidth(MediaQuery.of(context).size.width);
|
||||
@ -26,47 +23,31 @@ abstract class FluffyThemes {
|
||||
);
|
||||
|
||||
static var fallbackTextTheme = const TextTheme(
|
||||
bodyLarge: fallbackTextStyle,
|
||||
bodyMedium: fallbackTextStyle,
|
||||
labelLarge: fallbackTextStyle,
|
||||
bodySmall: fallbackTextStyle,
|
||||
labelSmall: fallbackTextStyle,
|
||||
displayLarge: fallbackTextStyle,
|
||||
displayMedium: fallbackTextStyle,
|
||||
displaySmall: fallbackTextStyle,
|
||||
headlineMedium: fallbackTextStyle,
|
||||
headlineSmall: fallbackTextStyle,
|
||||
titleLarge: fallbackTextStyle,
|
||||
titleMedium: fallbackTextStyle,
|
||||
titleSmall: fallbackTextStyle,
|
||||
bodyText1: fallbackTextStyle,
|
||||
bodyText2: fallbackTextStyle,
|
||||
button: fallbackTextStyle,
|
||||
caption: fallbackTextStyle,
|
||||
overline: fallbackTextStyle,
|
||||
headline1: fallbackTextStyle,
|
||||
headline2: fallbackTextStyle,
|
||||
headline3: fallbackTextStyle,
|
||||
headline4: fallbackTextStyle,
|
||||
headline5: fallbackTextStyle,
|
||||
headline6: fallbackTextStyle,
|
||||
subtitle1: fallbackTextStyle,
|
||||
subtitle2: fallbackTextStyle,
|
||||
);
|
||||
|
||||
static LinearGradient backgroundGradient(
|
||||
BuildContext context,
|
||||
int alpha,
|
||||
) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
colors: [
|
||||
colorScheme.primaryContainer.withAlpha(alpha),
|
||||
colorScheme.secondaryContainer.withAlpha(alpha),
|
||||
colorScheme.tertiaryContainer.withAlpha(alpha),
|
||||
colorScheme.primaryContainer.withAlpha(alpha),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
static const Duration animationDuration = Duration(milliseconds: 250);
|
||||
static const Curve animationCurve = Curves.easeInOut;
|
||||
|
||||
static ThemeData buildTheme(Brightness brightness, [Color? seed]) =>
|
||||
static ThemeData buildTheme(Brightness brightness,
|
||||
[ColorScheme? colorScheme]) =>
|
||||
ThemeData(
|
||||
visualDensity: VisualDensity.standard,
|
||||
useMaterial3: true,
|
||||
brightness: brightness,
|
||||
colorSchemeSeed: seed ?? AppConfig.colorSchemeSeed,
|
||||
textTheme: PlatformInfos.isDesktop || PlatformInfos.isWeb
|
||||
colorSchemeSeed: AppConfig.colorSchemeSeed ??
|
||||
colorScheme?.primary ??
|
||||
AppConfig.chatColor,
|
||||
textTheme: PlatformInfos.isDesktop
|
||||
? brightness == Brightness.light
|
||||
? Typography.material2018().black.merge(fallbackTextTheme)
|
||||
: Typography.material2018().white.merge(fallbackTextTheme)
|
||||
@ -77,16 +58,8 @@ abstract class FluffyThemes {
|
||||
dividerColor: brightness == Brightness.light
|
||||
? Colors.blueGrey.shade50
|
||||
: Colors.blueGrey.shade900,
|
||||
popupMenuTheme: PopupMenuThemeData(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
border: UnderlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2),
|
||||
),
|
||||
inputDecorationTheme: const InputDecorationTheme(
|
||||
border: InputBorder.none,
|
||||
filled: true,
|
||||
),
|
||||
appBarTheme: AppBarTheme(
|
||||
@ -99,32 +72,10 @@ abstract class FluffyThemes {
|
||||
statusBarBrightness: brightness,
|
||||
),
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2),
|
||||
),
|
||||
),
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2),
|
||||
),
|
||||
),
|
||||
),
|
||||
dialogTheme: DialogTheme(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2),
|
||||
),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(16),
|
||||
textStyle: const TextStyle(fontSize: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -3,8 +3,7 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:file_picker_cross/file_picker_cross.dart';
|
||||
import 'package:future_loading_dialog/future_loading_dialog.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
@ -13,12 +12,12 @@ import 'package:vrouter/vrouter.dart';
|
||||
|
||||
import 'package:fluffychat/pages/add_story/add_story_view.dart';
|
||||
import 'package:fluffychat/pages/add_story/invite_story_page.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/matrix_file_extension.dart';
|
||||
import 'package:fluffychat/utils/resize_image.dart';
|
||||
import 'package:fluffychat/utils/story_theme_data.dart';
|
||||
import 'package:fluffychat/utils/string_color.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../../utils/matrix_sdk_extensions/client_stories_extension.dart';
|
||||
import '../../utils/matrix_sdk_extensions.dart/client_stories_extension.dart';
|
||||
|
||||
class AddStoryPage extends StatefulWidget {
|
||||
const AddStoryPage({Key? key}) : super(key: key);
|
||||
@ -69,15 +68,14 @@ class AddStoryController extends State<AddStoryPage> {
|
||||
}
|
||||
|
||||
void importMedia() async {
|
||||
final picked = await FilePicker.platform.pickFiles(
|
||||
type: FileType.image,
|
||||
withData: true,
|
||||
final picked = await FilePickerCross.importFromStorage(
|
||||
type: FileTypeCross.image,
|
||||
);
|
||||
final file = picked?.files.firstOrNull;
|
||||
if (file == null) return;
|
||||
final fileName = picked.fileName;
|
||||
if (fileName == null) return;
|
||||
final matrixFile = MatrixImageFile(
|
||||
bytes: file.bytes!,
|
||||
name: file.name,
|
||||
bytes: picked.toUint8List(),
|
||||
name: fileName,
|
||||
);
|
||||
setState(() {
|
||||
image = matrixFile;
|
||||
@ -90,15 +88,14 @@ class AddStoryController extends State<AddStoryPage> {
|
||||
);
|
||||
if (picked == null) return;
|
||||
final matrixFile = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () async {
|
||||
final bytes = await picked.readAsBytes();
|
||||
return MatrixImageFile(
|
||||
bytes: bytes,
|
||||
name: picked.name,
|
||||
);
|
||||
},
|
||||
);
|
||||
context: context,
|
||||
future: () async {
|
||||
final bytes = await picked.readAsBytes();
|
||||
return MatrixImageFile(
|
||||
bytes: bytes,
|
||||
name: picked.name,
|
||||
);
|
||||
});
|
||||
|
||||
setState(() {
|
||||
image = matrixFile.result;
|
||||
|
||||