Merge branch 'main' into add_typos_config

This commit is contained in:
Access 2025-08-14 22:20:20 +09:00 committed by GitHub
commit b3488c0159
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
132 changed files with 85879 additions and 87003 deletions

1
.github/CODEOWNERS vendored
View file

@ -1,2 +1,3 @@
* @krille-chan
pubspec.* @dependabot
lib/l10n/*.arb @weblate

View file

@ -9,6 +9,9 @@ updates:
commit-message:
prefix: "build: "
include: "scope"
assignees:
- "krille-chan"
open-pull-requests-limit: 5
- package-ecosystem: "github-actions"
directory: "/"
schedule:

View file

@ -1,24 +0,0 @@
name: Completed Issue Comment
on:
issues:
types: [labeled]
jobs:
completed_issue_comment:
if: github.event.label.name == 'status:completed'
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- run: |
gh issue comment ${{ github.event.issue.number }} --body "$(cat <<EOF
Thank you so much for reporting this issue and helping us improve FluffyChat! 💬💖
This project is built and maintained by volunteers in their free time.
If you enjoyed using FluffyChat and want to support the people behind it,
you can say thanks by buying us a coffee or chipping in:
☕ https://ko-fi.com/krille
💜 https://liberapay.com/KrilleChritzelius
EOF
)"

View file

@ -25,8 +25,8 @@ jobs:
- name: Check license compliance
run: dart run license_checker check-licenses -c licenses.yaml --problematic
- run: flutter analyze
- name: Apply google services patch
run: git apply ./scripts/enable-android-google-services.patch
- name: Add Firebase Messaging
run: ./scripts/add-firebase-messaging.sh
- run: flutter analyze
- run: flutter test
@ -67,7 +67,7 @@ jobs:
strategy:
matrix:
arch: [ x64, arm64 ]
runs-on: ${{ matrix.arch == 'arm64' && 'self-hosted' || 'ubuntu-latest'}}
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest'}}
steps:
- uses: actions/checkout@v4
- run: cat .github/workflows/versions.env >> $GITHUB_ENV
@ -82,7 +82,7 @@ jobs:
- run: ./flutter/bin/flutter build linux --target-platform linux-${{ matrix.arch }}
build_debug_ios:
runs-on: macos-15
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- run: cat .github/workflows/versions.env >> $GITHUB_ENV
@ -96,5 +96,9 @@ jobs:
xcode-version: latest
- run: brew install sqlcipher
- uses: moonrepo/setup-rust@v1
- name: Add Firebase Messaging
run: |
flutter pub add fcm_shared_isolate:0.1.0
sed -i '' 's,//<GOOGLE_SERVICES>,,g' lib/utils/background_push.dart
- run: flutter pub get
- run: flutter build ios --no-codesign

View file

@ -56,8 +56,10 @@ jobs:
- uses: moonrepo/setup-rust@v1
- name: Install Fastlane
run: gem install fastlane -NV
- name: Apply Google Services Patch
run: git apply ./scripts/enable-android-google-services.patch
- name: Add Firebase Messaging
run: |
echo '${{secrets.GOOGLE_SERVICES_JSON}}' | base64 -d > android/app/google-services.json
./scripts/add-firebase-messaging.sh
- run: flutter pub get
- name: Prepare Android Release Build
env:

View file

@ -82,8 +82,10 @@ jobs:
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Apply Google Services Patch
run: git apply ./scripts/enable-android-google-services.patch
- name: Add Firebase Messaging
run: |
echo '${{secrets.GOOGLE_SERVICES_JSON}}' | base64 -d > android/app/google-services.json
./scripts/add-firebase-messaging.sh
- uses: moonrepo/setup-rust@v1
- run: flutter pub get
- name: Prepare Android Release Build
@ -153,8 +155,10 @@ jobs:
- name: Install Fastlane
working-directory: android
run: gem install fastlane -NV
- name: Apply Google Services Patch
run: git apply ./scripts/enable-android-google-services.patch
- name: Add Firebase Messaging
run: |
echo '${{secrets.GOOGLE_SERVICES_JSON}}' | base64 -d > android/app/google-services.json
./scripts/add-firebase-messaging.sh
- run: flutter pub get
- name: Prepare Android Release Build
env:

View file

@ -1,2 +1,2 @@
FLUTTER_VERSION=3.32.4
FLUTTER_VERSION=3.32.8
JAVA_VERSION=17

1848
.gitignore vendored

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
revision: "abb292a07e20d696c4568099f918f6c5f330e6b0"
revision: "fcf2c11572af6f390246c056bc905eca609533a0"
channel: "stable"
project_type: app
@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
- platform: linux
create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
create_revision: fcf2c11572af6f390246c056bc905eca609533a0
base_revision: fcf2c11572af6f390246c056bc905eca609533a0
- platform: android
create_revision: fcf2c11572af6f390246c056bc905eca609533a0
base_revision: fcf2c11572af6f390246c056bc905eca609533a0
# User provided section

View file

@ -1,3 +1,112 @@
## v2.1.0
- feat: Collapse all state events by default (Christian Kußowski)
- feat(linux/notify): support avatar icon (ShootingStarDragons)
- build: (deps): bump archive from 3.6.1 to 4.0.7 (dependabot[bot])
- build: (deps): bump chewie from 1.11.3 to 1.12.1 (dependabot[bot])
- build: (deps): bump desktop_drop from 0.4.4 to 0.6.1 (dependabot[bot])
- build: (deps): bump device_info_plus from 10.1.2 to 11.5.0 (dependabot[bot])
- build: (deps): bump dynamic_color from 1.7.0 to 1.8.1 (dependabot[bot])
- build: (deps): bump file_picker from 10.2.0 to 10.2.1 (dependabot[bot])
- build: (deps): bump file_picker from 8.3.7 to 10.2.0 (dependabot[bot])
- build: (deps): bump flutter_foreground_task from 6.5.0 to 9.1.0 (dependabot[bot])
- build: (deps): bump flutter_local_notifications from 19.3.0 to 19.4.0 (dependabot[bot])
- build: (deps): bump flutter_map from 6.2.1 to 8.1.1 (dependabot[bot])
- build: (deps): bump flutter_map from 8.1.1 to 8.2.1 (dependabot[bot])
- build: (deps): bump flutter_native_splash from 2.4.4 to 2.4.6 (dependabot[bot])
- build: (deps): bump flutter_webrtc from 0.12.12+hotfix.1 to 1.0.0 (dependabot[bot])
- build: (deps): bump geolocator from 13.0.4 to 14.0.2 (dependabot[bot])
- build: (deps): bump go_router from 15.1.2 to 16.0.0 (dependabot[bot])
- build: (deps): bump go_router from 16.0.0 to 16.1.0 (dependabot[bot])
- build: (deps): bump just_audio from 0.9.46 to 0.10.4 (dependabot[bot])
- build: (deps): bump matrix from 1.0.1 to 1.1.0 (dependabot[bot])
- build: (deps): bump mime from 1.0.6 to 2.0.0 (dependabot[bot])
- build: (deps): bump msix from 3.16.9 to 3.16.10 (dependabot[bot])
- build: (deps): bump permission_handler from 11.4.0 to 12.0.1 (dependabot[bot])
- build: (deps): bump pretty_qr_code from 3.4.0 to 3.5.0 (dependabot[bot])
- build: (deps): bump share_plus from 10.1.4 to 11.0.0 (dependabot[bot])
- build: (deps): bump sqflite_common_ffi from 2.3.5 to 2.3.6 (dependabot[bot])
- build: (deps): bump sqlcipher_flutter_libs from 0.6.6 to 0.6.7 (dependabot[bot])
- build: (deps): bump unifiedpush from 5.0.2 to 6.0.2 (dependabot[bot])
- build: (deps): bump url_launcher from 6.3.1 to 6.3.2 (dependabot[bot])
- build: Update Flutter 3.32.8 (Christian Kußowski)
- build: Upgrade emoji picker flutter (Christian Kußowski)
- build: Use gradle in kotlin (Christian Kußowski)
- build: Use macos-latest for debug ios job (Christian Kußowski)
- chore: Add CI workflow for thank you message after issue got completed (Christian Kußowski)
- chore: Add dependabot to code owners for pubspec (Christian Kußowski)
- chore: Add ISC as compatible license to aGPLv3 (Christian Kußowski)
- chore: Better error handling for push notifications (Christian Kußowski)
- chore: Bump Flutter version in pubspec.lock (Rafał Hirsch)
- chore: do format (ShootingStarDragons)
- chore: Fix snapcraft build (krille-chan)
- chore: Nicer own reaction color design (Christian Kußowski)
- chore: Remove double quotes from screenshot filenames (Christian Kußowski)
- chore: Remove lifecyclestate logs (Christian Kußowski)
- chore: Remove unused workflow (krille-chan)
- chore: Set height for screenshots in readme (krille-chan)
- chore: Set text message max length to 16384 but make it configurable (Christian Kußowski)
- chore: Update height for screenshots in readme (krille-chan)
- chore: Update screenshots in readme (krille-chan)
- fix: Add flexible to file messages to prevent long name overflow (Kelrap)
- fix: Avoid using MediaQuery.of() (imnotlxy)
- fix: Config viewer not updating state (Christian Kußowski)
- fix: Delete database correctly after corruption (krille-chan)
- fix: Design glitches in sticker dialog (Christian Kußowski)
- fix: limit characters and lines so redact message can't be too long (avashilling)
- fix: LoadingSnackBar consistently remains visible until the upload is complete (JaWeee)
- fix: notification clicked still cannot jump (ShootingStarDragons)
- fix: open chat from notification (ShootingStarDragons)
- fix: Open database crashes on start (krille-chan)
- fix: Open external account management when trying to delete devices (Christian Kußowski)
- fix: Use retry http client (Christian Kußowski)
- fix: Workaround for reversed width and height of compressed videos sent from Android (Christian Kußowski)
- refactor: Add support for Room version 12 via matrix dart sdk update
- refactor: Better UX for accepting declining invite (krille-chan)
- refactor: ignore bubble gradient when using system high contrast mode (Christian Kußowski)
- refactor: Make notification avatars rounded (krille-chan)
- refactor: Remove unused dependencies (krille-chan)
- chore(translations): Translated using Weblate (Basque) (xabirequejo)
- chore(translations): Translated using Weblate (Belarusian) (Alex Katon)
- chore(translations): Translated using Weblate (German) (Christian)
- chore(translations): Translated using Weblate (Norwegian Bokmål) (Frank Paul Silye)
- chore(translations): Translated using Weblate (Portuguese (Brazil)) (LucasMZ)
- chore(translations): Translated using Weblate (Spanish) (Fuan200)
- chore(translations): Translated using Weblate (Tamil) (தமிழ்நேரம்)
- chore(translations): Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
- Translated using Weblate (Arabic) (LucasMZ)
- Translated using Weblate (Basque) (xabirequejo)
- Translated using Weblate (Chinese (Simplified Han script)) (大王叫我来巡山)
- Translated using Weblate (Chinese (Traditional Han script)) (miullu)
- Translated using Weblate (Czech) (LucasMZ)
- Translated using Weblate (Dutch) (Jelv)
- Translated using Weblate (English) (LucasMZ)
- Translated using Weblate (Estonian) (Priit Jõerüüt)
- Translated using Weblate (Galician) (josé m)
- Translated using Weblate (German) (nautilusx)
- Translated using Weblate (Hebrew) (LucasMZ)
- Translated using Weblate (Hungarian) (LucasMZ)
- Translated using Weblate (Indonesian) (Linerly)
- Translated using Weblate (Irish) (Aindriú Mac Giolla Eoin)
- Translated using Weblate (Irish) (LucasMZ)
- Translated using Weblate (Italian) (Angelo Schirinzi)
- Translated using Weblate (Italian) (LucasMZ)
- Translated using Weblate (Latvian) (Edgars Andersons)
- Translated using Weblate (Latvian) (LucasMZ)
- Translated using Weblate (Norwegian Bokmål) (Christian)
- Translated using Weblate (Norwegian Bokmål) (Frank Paul Silye)
- Translated using Weblate (Persian) (Alireza Rashidi)
- Translated using Weblate (Polish) (Piotr Orzechowski)
- Translated using Weblate (Portuguese (Brazil)) (LucasMZ)
- Translated using Weblate (Portuguese) (Ana Elisa Ramos)
- Translated using Weblate (Portuguese) (LucasMZ)
- Translated using Weblate (Russian) (LucasMZ)
- Translated using Weblate (Tamil) (தமிழ்நேரம்)
- Translated using Weblate (Tamil) (LucasMZ)
- Translated using Weblate (Telugu) (LucasMZ)
- Translated using Weblate (Ukrainian) (Ihor Hordiichuk)
- Translated using Weblate (Ukrainian) (LucasMZ)
- Translated using Weblate (Vietnamese) (LucasMZ)
## v2.0.0
This version migrates to Vodozemac and Matrix Dart SDK 1.0.0. This is a breaking

View file

@ -14,7 +14,8 @@
### Screenshots:
![Screenshot](https://github.com/krille-chan/fluffychat/blob/main/docs/screenshots/product.jpeg?raw=true)
<img src="https://github.com/krille-chan/fluffychat/blob/main/docs/screenshots/mobile.png?raw=true" height="300">
<img src="https://github.com/krille-chan/fluffychat/blob/main/docs/screenshots/desktop.png?raw=true" height="300">
# Features

View file

@ -1,107 +0,0 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
//id "com.google.gms.google-services"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdk = 35
namespace = "chat.fluffy.fluffychat"
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "chat.fluffy.fluffychat"
minSdkVersion 21
targetSdkVersion 35
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
signingConfigs {
release {
if (keystorePropertiesFile.exists()) {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
versionNameSuffix "-debug"
}
release {
minifyEnabled false
shrinkResources false
signingConfig signingConfigs.release
}
}
// https://stackoverflow.com/a/77494454/8222484
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled true
}
kotlinOptions {
jvmTarget = "17"
}
}
flutter {
source '../..'
}
dependencies {
//implementation 'com.google.firebase:firebase-messaging:19.0.1' // Workaround for https://github.com/microg/android_packages_apps_GmsCore/issues/313#issuecomment-617651698
implementation 'androidx.multidex:multidex:2.0.1'
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
}
configurations.all {
exclude group: 'com.google.android.gms'
}

View file

@ -0,0 +1,89 @@
import java.util.Properties
import java.io.FileInputStream
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
if (file("google-services.json").exists()) {
apply(plugin = "com.google.gms.google-services")
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") // For flutter_local_notifications // Workaround for: https://github.com/MaikuB/flutter_local_notifications/issues/2286
}
// Workaround for https://pub.dev/packages/unifiedpush#the-build-fails-because-of-duplicate-classes
configurations.all {
// Use the latest version published: https://central.sonatype.com/artifact/com.google.crypto.tink/tink-android
val tink = "com.google.crypto.tink:tink-android:1.17.0"
// You can also use the library declaration catalog
// val tink = libs.google.tink
resolutionStrategy {
force(tink)
dependencySubstitution {
substitute(module("com.google.crypto.tink:tink")).using(module(tink))
}
}
}
android {
namespace = "chat.fluffy.fluffychat"
compileSdk = flutter.compileSdkVersion
ndkVersion = "27.0.12077973"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
isCoreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
signingConfigs {
create("release") {
keyAlias = "dummyAlias"
keyPassword = "dummyPassword"
storeFile = file("dummy.keystore")
storePassword = "dummyStorePassword"
}
}
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
signingConfigs.getByName("release").apply {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
storePassword = keystoreProperties["storePassword"] as String
}
}
defaultConfig {
applicationId = "chat.fluffy.fluffychat"
minSdk = 21
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
}
}
flutter {
source = "../.."
}

View file

@ -1,46 +0,0 @@
{
"project_info": {
"project_number": "865731724731",
"project_id": "fluffychat-ef3e8",
"storage_bucket": "fluffychat-ef3e8.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:865731724731:android:ec427b3b1dcd4a1e64309e",
"android_client_info": {
"package_name": "chat.fluffy.fluffychat"
}
},
"oauth_client": [
{
"client_id": "865731724731-od6969v178ul9970elgacpt936v5t7qg.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBLdZpGSPjcinikB4lAU6awW_h88NG17Sg"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "865731724731-od6969v178ul9970elgacpt936v5t7qg.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "865731724731-ofdr7e6m04murgb1bvchlj9oaos0q5i3.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "im.fluffychat.app"
}
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -135,20 +135,6 @@
</intent-filter>
</service>
<receiver android:name="org.unifiedpush.flutter.connector.UnifiedPushReceiver"
tools:replace="android:enabled"
android:enabled="false">
</receiver>
<receiver android:exported="false" android:enabled="true" android:name=".UnifiedPushReceiver">
<intent-filter>
<action android:name="org.unifiedpush.flutter.connector.MESSAGE"/>
<action android:name="org.unifiedpush.flutter.connector.UNREGISTERED"/>
<action android:name="org.unifiedpush.flutter.connector.NEW_ENDPOINT"/>
<action android:name="org.unifiedpush.flutter.connector.REGISTRATION_FAILED" />
</intent-filter>
</receiver>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data

View file

@ -4,13 +4,11 @@ import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import android.content.Context
import androidx.multidex.MultiDex
class MainActivity : FlutterActivity() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}

View file

@ -1,23 +0,0 @@
package chat.fluffy.fluffychat
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.dart.DartExecutor
import org.unifiedpush.flutter.connector.UnifiedPushReceiver
import android.content.Context
class UnifiedPushReceiver : UnifiedPushReceiver() {
override fun getEngine(context: Context): FlutterEngine {
var engine = MainActivity.engine
if (engine == null) {
engine = MainActivity.provideEngine(context)
engine.localizationPlugin.sendLocalesToFlutter(
context.resources.configuration
)
engine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
}
return engine
}
}

View file

@ -1,17 +0,0 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

21
android/build.gradle.kts Normal file
View file

@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View file

@ -1 +1 @@
FluffyChat 2.0.0 now uses the Vodozemac encryption library and brings bugfixes and performance improvements, together with an improved user experience when interacting with messages.
FluffyChat 2.1.0 brings a lot of bugfixes, updated translations and performance improvements. Also chat state events are now collapsed by default.

View file

@ -1,26 +0,0 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.7.3" apply false
id "org.jetbrains.kotlin.android" version "2.1.10" apply false
// id "com.google.gms.google-services" version "4.3.8" apply false
}
include ":app"

View file

@ -0,0 +1,28 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
if (file("app/google-services.json").exists()) {
id("com.google.gms.google-services") version "4.3.8" apply false
}
}
include(":app")

View file

@ -6,7 +6,6 @@ import 'package:fluffychat/pages/invitation_selection/invitation_selection_view.
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;
@ -28,10 +27,6 @@ void main() {
SharedPreferences.setMockInitialValues({
SettingKeys.showNoGoogle: false,
});
try {
Hive.deleteFromDisk();
Hive.initFlutter();
} catch (_) {}
},
);

View file

@ -37,6 +37,7 @@ abstract class SettingKeys {
}
enum AppSettings<T> {
textMessageMaxLength<int>('textMessageMaxLength', 16384),
audioRecordingNumChannels<int>('audioRecordingNumChannels', 1),
audioRecordingAutoGain<bool>('audioRecordingAutoGain', true),
audioRecordingEchoCancel<bool>('audioRecordingEchoCancel', false),

View file

@ -14,10 +14,10 @@ abstract class FluffyThemes {
width > columnWidth * 2 + navRailWidth;
static bool isColumnMode(BuildContext context) =>
isColumnModeByWidth(MediaQuery.of(context).size.width);
isColumnModeByWidth(MediaQuery.sizeOf(context).width);
static bool isThreeColumnMode(BuildContext context) =>
MediaQuery.of(context).size.width > FluffyThemes.columnWidth * 3.5;
MediaQuery.sizeOf(context).width > FluffyThemes.columnWidth * 3.5;
static LinearGradient backgroundGradient(
BuildContext context,

File diff suppressed because it is too large Load diff

View file

@ -1 +1,443 @@
{}
{
"alwaysUse24HourFormat": "адключана",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
"repeatPassword": "Паўтарыце пароль",
"@repeatPassword": {},
"notAnImage": "Не файл выявы.",
"@notAnImage": {},
"setCustomPermissionLevel": "Задайце карыстальніцкі ўзровень дазволу",
"@setCustomPermissionLevel": {},
"setPermissionsLevelDescription": "Калі ласка, выберыце ролю ніжэй альбо ўвядзіце карыстальніцкі ўзровень дазволу паміж 0 і 100.",
"@setPermissionsLevelDescription": {},
"ignoreUser": "Ігнараваць карыстальніка",
"@ignoreUser": {},
"normalUser": "Звычайны карыстальнік",
"@normalUser": {},
"remove": "Прыбраць",
"@remove": {
"type": "String",
"placeholders": {}
},
"importNow": "Імпартаваць зараз",
"@importNow": {},
"importEmojis": "Імпартаваць эмодзі",
"@importEmojis": {},
"importFromZipFile": "Імпартаваць з файла .zip",
"@importFromZipFile": {},
"exportEmotePack": "Экспартаваць пак эмодзі як .zip",
"@exportEmotePack": {},
"replace": "Замяніць",
"@replace": {},
"about": "Пра праграму",
"@about": {},
"aboutHomeserver": "Пра {homeserver}",
"@aboutHomeserver": {
"type": "String",
"placeholders": {
"homeserver": {
"type": "String"
}
}
},
"accept": "Прыняць",
"@accept": {
"type": "String",
"placeholders": {}
},
"acceptedTheInvitation": "👍 {username} прыняў запрашэнне",
"@acceptedTheInvitation": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"account": "Уліковы запіс",
"@account": {
"type": "String",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐 {username} актывіраваў end to end шыфраванне",
"@activatedEndToEndEncryption": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"addEmail": "Дадаць email",
"@addEmail": {
"type": "String",
"placeholders": {}
},
"confirmMatrixId": "Калі ласка, спраўдзіце свой Matrix ID перад выдаленнем свайго ўліковага запісу.",
"@confirmMatrixId": {},
"supposedMxid": "Гэта павінна быць накшталт {mxid}",
"@supposedMxid": {
"type": "String",
"placeholders": {
"mxid": {
"type": "String"
}
}
},
"addChatDescription": "Дадайце апісанне чату...",
"@addChatDescription": {},
"addToSpace": "Дадаць прастору",
"@addToSpace": {},
"admin": "Адмін",
"@admin": {
"type": "String",
"placeholders": {}
},
"alias": "займенне",
"@alias": {
"type": "String",
"placeholders": {}
},
"all": "Усё",
"@all": {
"type": "String",
"placeholders": {}
},
"allChats": "Усе чаты",
"@allChats": {
"type": "String",
"placeholders": {}
},
"commandHint_roomupgrade": "Палепшыце гэты пакой да версіі дадзенага пакою",
"@commandHint_roomupgrade": {},
"commandHint_googly": "Дасылае смешныя вочы",
"@commandHint_googly": {},
"commandHint_cuddle": "Дасылае ўсмешку",
"@commandHint_cuddle": {},
"commandHint_hug": "Дасылае абдыманне",
"@commandHint_hug": {},
"googlyEyesContent": "{senderName} даслаў вам смешныя вочы",
"@googlyEyesContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"cuddleContent": "{senderName} усміхаецца вам",
"@cuddleContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"hugContent": "{senderName} абдымае вас",
"@hugContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"answeredTheCall": "{senderName} адказаў на выклік",
"@answeredTheCall": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"anyoneCanJoin": "Усе могуць далучыцца",
"@anyoneCanJoin": {
"type": "String",
"placeholders": {}
},
"appLock": "Код-пароль",
"@appLock": {
"type": "String",
"placeholders": {}
},
"appLockDescription": "Блакіруе праграму, пакуль вы не ўвядзеце пін-код",
"@appLockDescription": {},
"archive": "Архіў",
"@archive": {
"type": "String",
"placeholders": {}
},
"areGuestsAllowedToJoin": "Карыстальнікі-госці могуць далучыцца",
"@areGuestsAllowedToJoin": {
"type": "String",
"placeholders": {}
},
"areYouSure": "Вы ўпэўнены?",
"@areYouSure": {
"type": "String",
"placeholders": {}
},
"areYouSureYouWantToLogout": "Вы ўпэўнены, што хаціце выйсці?",
"@areYouSureYouWantToLogout": {
"type": "String",
"placeholders": {}
},
"askSSSSSign": "Каб увайсці як іншы чалавек, калі ласка, увядзіце ключавую фразу ці ключ аднаўлення.",
"@askSSSSSign": {
"type": "String",
"placeholders": {}
},
"askVerificationRequest": "Прыняць запрос на верыфікацыю ад {username}?",
"@askVerificationRequest": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"autoplayImages": "Аўтаматычна прайграваць аніміраваныя стыкеры і эмодзі",
"@autoplayImages": {
"type": "String",
"placeholder": {}
},
"badServerLoginTypesException": "Хатні сервер падтрымлівае наступныя метады ўваходу:\n{serverVersions}\nАле гэта праграма падтрымлівае толькі:\n{supportedVersions}",
"@badServerLoginTypesException": {
"type": "String",
"placeholders": {
"serverVersions": {
"type": "String"
},
"supportedVersions": {
"type": "String"
}
}
},
"sendTypingNotifications": "Дасылаць паведамленне пра друк",
"@sendTypingNotifications": {},
"swipeRightToLeftToReply": "Змахніце ўлева, каб адказаць",
"@swipeRightToLeftToReply": {},
"sendOnEnter": "Дасылаць на enter",
"@sendOnEnter": {},
"badServerVersionsException": "Хатні сервер падтрымлівае наступныя версіі спецыфікацыі:\n{serverVersions}\nАле гэьа праграма падтрымлівае толькі:\n{supportedVersions}",
"@badServerVersionsException": {
"type": "String",
"placeholders": {
"serverVersions": {
"type": "String"
},
"supportedVersions": {
"type": "String"
}
}
},
"countChatsAndCountParticipants": "{chats} чатаў і {participants} удзельнікаў",
"@countChatsAndCountParticipants": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
},
"participants": {
"type": "int"
}
}
},
"noMoreChatsFound": "Болей чатаў не знойдзена...",
"@noMoreChatsFound": {},
"noChatsFoundHere": "Здаецца, тут пуств. Пачніце новы чат з кімсьці праз кнопку ніжэй. ⤵️",
"@noChatsFoundHere": {},
"joinedChats": "Чаты, да якіх далучыўся",
"@joinedChats": {},
"unread": "Непрачытана",
"@unread": {},
"space": "Прастора",
"@space": {},
"spaces": "Прасторы",
"@spaces": {},
"banFromChat": "Заблакіраваць ў чаце",
"@banFromChat": {
"type": "String",
"placeholders": {}
},
"banned": "Заблакіраваны",
"@banned": {
"type": "String",
"placeholders": {}
},
"bannedUser": "{username} заюлакіраваў {targetName}",
"@bannedUser": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"targetName": {
"type": "String"
}
}
},
"blockDevice": "Заблакіраваць прыладу",
"@blockDevice": {
"type": "String",
"placeholders": {}
},
"blocked": "Заблакіравана",
"@blocked": {
"type": "String",
"placeholders": {}
},
"botMessages": "Паведамленні бота",
"@botMessages": {
"type": "String",
"placeholders": {}
},
"cancel": "Скасаваць",
"@cancel": {
"type": "String",
"placeholders": {}
},
"cantOpenUri": "Немагчыма адкрыць URI {uri}",
"@cantOpenUri": {
"type": "String",
"placeholders": {
"uri": {
"type": "String"
}
}
},
"changeDeviceName": "Змяніць назву прылады",
"@changeDeviceName": {
"type": "String",
"placeholders": {}
},
"changedTheChatAvatar": "{username} змяніў выяву чата",
"@changedTheChatAvatar": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"changedTheChatDescriptionTo": "{username} змяніў апісанне чата на :'{description}'",
"@changedTheChatDescriptionTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"description": {
"type": "String"
}
}
},
"changedTheChatNameTo": "{username} змяніў назву чата на '{chatname}'",
"@changedTheChatNameTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"chatname": {
"type": "String"
}
}
},
"changedTheChatPermissions": "{username} змяніў дазволы чата",
"@changedTheChatPermissions": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"changedTheDisplaynameTo": "{username} змяніў адлюстроўваемае імя на: '{displayname}'",
"@changedTheDisplaynameTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"displayname": {
"type": "String"
}
}
},
"changedTheGuestAccessRules": "{username} змяніў правілы гасцявога доступу",
"@changedTheGuestAccessRules": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"changedTheGuestAccessRulesTo": "{username} змяніў правілы гасцявога доступу на: {rules}",
"@changedTheGuestAccessRulesTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"rules": {
"type": "String"
}
}
},
"changedTheHistoryVisibility": "{username} змяніў бачнасць гісторыі",
"@changedTheHistoryVisibility": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"changedTheHistoryVisibilityTo": "{username} змяніў бачнасць гісторыі на: {rules}",
"@changedTheHistoryVisibilityTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"rules": {
"type": "String"
}
}
},
"changedTheJoinRules": "{username} змяніў правілы падлучэння",
"@changedTheJoinRules": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"changedTheJoinRulesTo": "{username} змяніў правілы падлучэння на: {joinRules}",
"@changedTheJoinRulesTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"joinRules": {
"type": "String"
}
}
},
"changedTheProfileAvatar": "{username} змяніў свой аватар",
"@changedTheProfileAvatar": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3355,7 +3355,7 @@
"@notificationRuleServerAcl": {},
"notificationRuleMemberEventDescription": "Unterdrückt Benachrichtigungen zu Mitgliedschaftsereignissen.",
"@notificationRuleMemberEventDescription": {},
"sentVoiceMessage": "🎙️ {duration} - {sender}",
"sentVoiceMessage": "🎙️ {duration} - Sprachnachricht von {sender}",
"@sentVoiceMessage": {
"type": "String",
"placeholders": {
@ -3380,5 +3380,17 @@
"pleaseWaitUntilInvited": "Bitte warte nun, bis dich jemand aus dem Raum auffordert.",
"@pleaseWaitUntilInvited": {},
"notificationRuleTombstone": "Tombstone",
"@notificationRuleTombstone": {}
"@notificationRuleTombstone": {},
"commandHint_logout": "Aktuelles Gerät abmelden",
"@commandHint_logout": {},
"commandHint_logoutall": "Alle aktiven Geräte abmelden",
"@commandHint_logoutall": {},
"displayNavigationRail": "Navigationsleiste auf dem Smartphone anzeigen",
"@displayNavigationRail": {},
"customReaction": "Benutzerdefinierte Reaktion",
"@customReaction": {},
"moreEvents": "Weitere Ereignisse",
"@moreEvents": {},
"declineInvitation": "Einladung ablehnen",
"@declineInvitation": {}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3386,5 +3386,11 @@
"approve": "Aprobar",
"@approve": {},
"youHaveKnocked": "Has sido golpeado",
"@youHaveKnocked": {}
"@youHaveKnocked": {},
"customReaction": "Reacción personalizada",
"@customReaction": {},
"moreEvents": "Más eventos",
"@moreEvents": {},
"declineInvitation": "Rechazar invitación",
"@declineInvitation": {}
}

View file

@ -2592,7 +2592,7 @@
}
}
},
"inviteGroupChat": "📨 Kutsu vestlusrühma",
"inviteGroupChat": "📨 Kutse vestlusrühma",
"@inviteGroupChat": {},
"invitePrivateChat": "📨 Kutsu omavahelisele vestlusele",
"@invitePrivateChat": {},
@ -3377,5 +3377,13 @@
"commandHint_logoutall": "Logi kõikidest aktiivsetest seadmetest välja",
"@commandHint_logoutall": {},
"commandHint_logout": "Logi oma praegusest seadmest välja",
"@commandHint_logout": {}
"@commandHint_logout": {},
"displayNavigationRail": "Näita mobiilis külgmist tööriistariba",
"@displayNavigationRail": {},
"customReaction": "Kohandatud reaktsioon",
"@customReaction": {},
"moreEvents": "Veel sündmusi",
"@moreEvents": {},
"declineInvitation": "Keeldu kutsest",
"@declineInvitation": {}
}

View file

@ -1911,7 +1911,7 @@
"type": "String",
"description": "Usage hint for the command /invite"
},
"commandHint_join": "Batu gelara",
"commandHint_join": "Batu adierazitako gelara",
"@commandHint_join": {
"type": "String",
"description": "Usage hint for the command /join"
@ -2608,9 +2608,9 @@
"@invite": {},
"invalidInput": "Sartu duzunak ez du balio!",
"@invalidInput": {},
"inviteGroupChat": "📨 Gonbidatu taldeko txatera",
"inviteGroupChat": "📨 Taldeko txatera gonbidapena",
"@inviteGroupChat": {},
"invitePrivateChat": "📨 Gonbidatu txat pribatura",
"invitePrivateChat": "📨 Txat pribatura gonbidapena",
"@invitePrivateChat": {},
"banUserDescription": "Erabiltzailea txatetik kanporatu eta berriro sartzeko debekua ezarriko zaio; ezingo da berriro sartu debekua kendu arte.",
"@banUserDescription": {},
@ -3362,7 +3362,7 @@
}
}
},
"sentVoiceMessage": "🎙️ {duration} - {sender}",
"sentVoiceMessage": "🎙️ {duration} - {sender}(r)en ahots-mezua",
"@sentVoiceMessage": {
"type": "String",
"placeholders": {
@ -3373,5 +3373,17 @@
"type": "String"
}
}
}
},
"commandHint_logout": "Amaitu saioa gailu honetan",
"@commandHint_logout": {},
"commandHint_logoutall": "Amaitu saioa aktibo dauden gailu guztietan",
"@commandHint_logoutall": {},
"moreEvents": "Gertaera gehiago",
"@moreEvents": {},
"displayNavigationRail": "Erakutsi nabigazio-barra mugikorrean",
"@displayNavigationRail": {},
"customReaction": "Erreakzio pertsonalizatua",
"@customReaction": {},
"declineInvitation": "Uko egin gonbidapenari",
"@declineInvitation": {}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2146,7 +2146,7 @@
"@noOtherDevicesFound": {},
"profileNotFound": "Níorbh fhéidir an t-úsáideoir a aimsiú ar an bhfreastalaí. B'fhéidir go bhfuil fadhb nasctha ann nó nach bhfuil an t-úsáideoir ann.",
"@profileNotFound": {},
"inviteGroupChat": "📨 Tabhair cuireadh comhrá grúpa",
"inviteGroupChat": "📨 Cuireadh chuig comhrá grúpa",
"@inviteGroupChat": {},
"knocking": "Cnagadh",
"@knocking": {},
@ -2491,7 +2491,7 @@
}
}
},
"invitePrivateChat": "📨 Tabhair cuireadh comhrá príobháideach",
"invitePrivateChat": "📨 Cuireadh chuig comhrá príobháideach",
"@invitePrivateChat": {},
"wrongPinEntered": "Tháinig biorán mícheart isteach! Bain triail eile as i {seconds} soicind...",
"@wrongPinEntered": {
@ -3384,5 +3384,11 @@
"commandHint_logout": "Logáil amach as do ghléas reatha",
"@commandHint_logout": {},
"commandHint_logoutall": "Logáil amach gach gléas gníomhach",
"@commandHint_logoutall": {}
"@commandHint_logoutall": {},
"customReaction": "Imoibriú saincheaptha",
"@customReaction": {},
"moreEvents": "Tuilleadh imeachtaí",
"@moreEvents": {},
"declineInvitation": "Diúltaigh don chuireadh",
"@declineInvitation": {}
}

View file

@ -3375,5 +3375,11 @@
"commandHint_logoutall": "Fechar a sesión en todos os dispositivos activos",
"@commandHint_logoutall": {},
"commandHint_logout": "Fechar a sesión no dispositivo actual",
"@commandHint_logout": {}
"@commandHint_logout": {},
"moreEvents": "Máis eventos",
"@moreEvents": {},
"customReaction": "Reacción personalizada",
"@customReaction": {},
"declineInvitation": "Rexeitar o convite",
"@declineInvitation": {}
}

View file

@ -1428,7 +1428,7 @@
},
"notAnImage": "הקובץ אינו תמונה.",
"@notAnImage": {},
"alwaysUse24HourFormat": "שגוי",
"alwaysUse24HourFormat": "",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3055,7 +3055,7 @@
"@changeTheDescriptionOfTheGroup": {},
"swipeRightToLeftToReply": "Húzza balra a válaszoláshoz",
"@swipeRightToLeftToReply": {},
"alwaysUse24HourFormat": "hamis",
"alwaysUse24HourFormat": "",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},

View file

@ -1,60 +1,60 @@
{
"repeatPassword": "Repeter le contrasigno",
"@repeatPassword": {},
"notAnImage": "Non es un file de imagine.",
"@notAnImage": {},
"remove": "Remover",
"@remove": {
"type": "String",
"placeholders": {}
},
"importEmojis": "Importar emojis",
"@importEmojis": {},
"importFromZipFile": "Importar ab un file .zip",
"@importFromZipFile": {},
"importNow": "Importar ora",
"@importNow": {},
"exportEmotePack": "Exportar pacchetto de emotes como un .zip",
"@exportEmotePack": {},
"replace": "Reimplaciar",
"@replace": {},
"about": "A proposito de",
"@about": {
"type": "String",
"placeholders": {}
},
"accept": "Acceptar",
"@accept": {
"type": "String",
"placeholders": {}
},
"acceptedTheInvitation": "👍 {username} acceptava tu invitation",
"@acceptedTheInvitation": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"account": "Conto",
"@account": {
"type": "String",
"placeholders": {}
},
"addEmail": "Adder email",
"@addEmail": {
"type": "String",
"placeholders": {}
},
"supposedMxid": "Isto deberea esser {mxid}",
"@supposedMxid": {
"type": "String",
"placeholders": {
"mxid": {
"type": "String"
}
}
},
"@custom": {}
}
"repeatPassword": "Repeter le contrasigno",
"@repeatPassword": {},
"notAnImage": "Non es un file de imagine.",
"@notAnImage": {},
"remove": "Remover",
"@remove": {
"type": "String",
"placeholders": {}
},
"importEmojis": "Importar emojis",
"@importEmojis": {},
"importFromZipFile": "Importar ab un file .zip",
"@importFromZipFile": {},
"importNow": "Importar ora",
"@importNow": {},
"exportEmotePack": "Exportar pacchetto de emotes como un .zip",
"@exportEmotePack": {},
"replace": "Reimplaciar",
"@replace": {},
"about": "A proposito de",
"@about": {
"type": "String",
"placeholders": {}
},
"accept": "Acceptar",
"@accept": {
"type": "String",
"placeholders": {}
},
"acceptedTheInvitation": "👍 {username} acceptava tu invitation",
"@acceptedTheInvitation": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"account": "Conto",
"@account": {
"type": "String",
"placeholders": {}
},
"addEmail": "Adder email",
"@addEmail": {
"type": "String",
"placeholders": {}
},
"supposedMxid": "Isto deberea esser {mxid}",
"@supposedMxid": {
"type": "String",
"placeholders": {
"mxid": {
"type": "String"
}
}
},
"@custom": {}
}

View file

@ -3378,5 +3378,9 @@
"commandHint_logoutall": "Keluarkan semua perangkat aktif",
"@commandHint_logoutall": {},
"displayNavigationRail": "Tampilkan jalur navigasi pada ponsel",
"@displayNavigationRail": {}
"@displayNavigationRail": {},
"customReaction": "Reaksi khusus",
"@customReaction": {},
"moreEvents": "Peristiwa tambahan",
"@moreEvents": {}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1250,7 +1250,7 @@
}
}
},
"waitingPartnerEmoji": "Gaida, līdz biedrs apstiprinās emocijzīmi…",
"waitingPartnerEmoji": "Gaida, līdz biedrs apstiprinās emocijzīmes…",
"@waitingPartnerEmoji": {
"type": "String",
"placeholders": {}
@ -1941,11 +1941,11 @@
"type": "String",
"placeholders": {}
},
"inviteGroupChat": "📨 Uzaicināt kopas tērzēšanu",
"inviteGroupChat": "📨 Uzaicinājums uz kopas tērzēšanu",
"@inviteGroupChat": {},
"appearOnTop": "Parādīt virspusē",
"@appearOnTop": {},
"invitePrivateChat": "📨 Uzaicināt privātu tērzēšanu",
"invitePrivateChat": "📨 Uzaicinājums uz privātu tērzēšanu",
"@invitePrivateChat": {},
"verifyTitle": "Apliecina citu kontu",
"@verifyTitle": {
@ -2256,7 +2256,7 @@
"type": "String",
"placeholders": {}
},
"noGoogleServicesWarning": "Izskatās, ka Firebase mākoņziņojumapmaiņa nav pieejama šajā ierīcē. Lai joprojām saņemtu pašpiegādes paziņojumus, mēs iesakām uzstādīt ntfy. Ar ntfy vai citu Vienotās pašpiegādes nodrošinātāju ir iespējams saņemt pašpiegādes paziņojumus drošā veidā. ntfy var lejupielādēt no PlayStore vai F-Droid.",
"noGoogleServicesWarning": "Izskatās, ka Firebase mākoņziņojumapmaiņa nav pieejama šajā ierīcē. Lai joprojām saņemtu pašpiegādes paziņojumus, mēs iesakām uzstādīt ntfy. Ar ntfy vai citu UnifiedPush nodrošinātāju ir iespējams saņemt pašpiegādes paziņojumus drošā veidā. ntfy var lejupielādēt no Play Store vai F-Droid.",
"@noGoogleServicesWarning": {
"type": "String",
"placeholders": {}
@ -3362,5 +3362,11 @@
"commandHint_logoutall": "Atteikties visās izmantotajās ierīcēs",
"@commandHint_logoutall": {},
"displayNavigationRail": "Rādīt pārvietošanās sliedi viedierīcēs",
"@displayNavigationRail": {}
"@displayNavigationRail": {},
"customReaction": "Pielāgota reakcija",
"@customReaction": {},
"moreEvents": "Vairāk notikumu",
"@moreEvents": {},
"declineInvitation": "Noraidīt uzaicinājumu",
"@declineInvitation": {}
}

File diff suppressed because it is too large Load diff

View file

@ -1208,7 +1208,7 @@
"type": "String",
"placeholders": {}
},
"noGoogleServicesWarning": "Firebase Cloud Messaging lijkt niet beschikbaar op je apparaat. Om nog steeds pushmeldingen te krijgen, adviseren we om ntfy te installeren. Met ntfy of een andere Unified Push provider kun je pushmeldingen ontvangen op een veilige manier. Je kunt ntfy downloaden van de PlayStore of van F-Droid.",
"noGoogleServicesWarning": "Firebase Cloud Messaging lijkt niet beschikbaar op je apparaat. Om pushmeldingen te krijgen, adviseren we om ntfy te installeren. Met ntfy of een andere Unified Push-provider kun je pushmeldingen ontvangen op een veilige manier. Je kunt ntfy downloaden in de PlayStore of F-Droid.",
"@noGoogleServicesWarning": {
"type": "String",
"placeholders": {}
@ -2195,7 +2195,7 @@
"@placeCall": {},
"unsupportedAndroidVersion": "Niet-ondersteunde Android-versie",
"@unsupportedAndroidVersion": {},
"unsupportedAndroidVersionLong": "Voor deze functie is een nieuwere Android-versie vereist. Controleer op updates of Lineage OS-ondersteuning.",
"unsupportedAndroidVersionLong": "Voor deze functie is een nieuwe Android-versie verplicht. Controleer je updates of Lineage OS-ondersteuning.",
"@unsupportedAndroidVersionLong": {},
"videoCallsBetaWarning": "Houd er rekening mee dat videogesprekken momenteel in bèta zijn. Ze werken misschien niet zoals je verwacht of werken niet op alle platformen.",
"@videoCallsBetaWarning": {},
@ -2394,7 +2394,7 @@
"@callingAccountDetails": {},
"appearOnTop": "Bovenaan verschijnen",
"@appearOnTop": {},
"appearOnTopDetails": "Laat de app bovenaan verschijnen (niet nodig als je FluffyChat al hebt ingesteld als een belaccount)",
"appearOnTopDetails": "Laat de app bovenaan verschijnen (niet nodig als je FluffyChat al hebt ingesteld als een bel-account)",
"@appearOnTopDetails": {},
"otherCallingPermissions": "Microfoon, camera en andere FluffyChat-rechten",
"@otherCallingPermissions": {},
@ -3350,7 +3350,7 @@
"@approve": {},
"youHaveKnocked": "Je hebt geklopt",
"@youHaveKnocked": {},
"sentVoiceMessage": "🎙️ {duration} - {sender}",
"sentVoiceMessage": "🎙️ {duration} - Spraakbericht van {sender}",
"@sentVoiceMessage": {
"type": "String",
"placeholders": {
@ -3372,5 +3372,17 @@
}
},
"checkList": "Checklist",
"@checkList": {}
"@checkList": {},
"commandHint_logout": "Uw huidige apparaat uitloggen",
"@commandHint_logout": {},
"commandHint_logoutall": "Alle actieve apparaten uitloggen",
"@commandHint_logoutall": {},
"displayNavigationRail": "Navigatiebalk op mobiel tonen",
"@displayNavigationRail": {},
"moreEvents": "Meer gebeurtenissen",
"@moreEvents": {},
"customReaction": "Aangepaste reactie",
"@customReaction": {},
"declineInvitation": "Uitnodiging afwijzen",
"@declineInvitation": {}
}

View file

@ -3373,5 +3373,15 @@
"youHaveKnocked": "Zapukałeś/-aś",
"@youHaveKnocked": {},
"pleaseWaitUntilInvited": "Proszę zaczekać na zaproszenie przez kogoś z pokoju.",
"@pleaseWaitUntilInvited": {}
"@pleaseWaitUntilInvited": {},
"commandHint_logout": "Wyloguj bieżące urządzenie",
"@commandHint_logout": {},
"commandHint_logoutall": "Wyloguj wszystkie aktywne urządzenia",
"@commandHint_logoutall": {},
"displayNavigationRail": "Pokazuj pasek nawigacyjny na urządzeniach mobilnych",
"@displayNavigationRail": {},
"customReaction": "Własna reakcja",
"@customReaction": {},
"moreEvents": "Więcej zdarzeń",
"@moreEvents": {}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,15 @@
{
"alwaysUse24HourFormat": "తప్పుడు",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
"notAnImage": "ఇమేజ్ ఫైల్ కాదు.",
"@notAnImage": {},
"repeatPassword": "పాస్‌వర్డ్‌ను పునరావృతం చేయండి",
"@repeatPassword": {},
"remove": "తొలగించు",
"@remove": {
"type": "String",
"placeholders": {}
}
}
"alwaysUse24HourFormat": "",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
"notAnImage": "ఇమేజ్ ఫైల్ కాదు.",
"@notAnImage": {},
"repeatPassword": "పాస్‌వర్డ్‌ను పునరావృతం చేయండి",
"@repeatPassword": {},
"remove": "తొలగించు",
"@remove": {
"type": "String",
"placeholders": {}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2592,9 +2592,9 @@
"@redactMessageDescription": {},
"setChatDescription": "Налаштувати опис бесіди",
"@setChatDescription": {},
"inviteGroupChat": "📨 Запросити до групової бесіди",
"inviteGroupChat": "📨 Запрошення до групової бесіди",
"@inviteGroupChat": {},
"invitePrivateChat": "📨 Запросити до приватної бесіди",
"invitePrivateChat": "📨 Запрошення до приватної бесіди",
"@invitePrivateChat": {},
"emoteKeyboardNoRecents": "Тут з'являться нещодавно використані смайлики...",
"@emoteKeyboardNoRecents": {
@ -3022,7 +3022,7 @@
},
"markAsUnread": "Позначити непрочитаним",
"@markAsUnread": {},
"alwaysUse24HourFormat": "ні",
"alwaysUse24HourFormat": "false",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
@ -3377,5 +3377,13 @@
"commandHint_logout": "Вийти на цьому пристрої",
"@commandHint_logout": {},
"commandHint_logoutall": "Вийти на всіх активних пристроях",
"@commandHint_logoutall": {}
"@commandHint_logoutall": {},
"displayNavigationRail": "Показати навігаційну карту на мобільному",
"@displayNavigationRail": {},
"customReaction": "Власні реакції",
"@customReaction": {},
"moreEvents": "Інші події",
"@moreEvents": {},
"declineInvitation": "Відхилити запрошення",
"@declineInvitation": {}
}

File diff suppressed because it is too large Load diff

View file

@ -1,337 +1,337 @@
{
"@@locale": "yue",
"normalUser": "正常用家",
"@normalUser": {},
"areYouSureYouWantToLogout": "係咪確定要 log out",
"@areYouSureYouWantToLogout": {
"type": "String",
"placeholders": {}
},
"areGuestsAllowedToJoin": "畀唔畀陌生人 Join",
"@areGuestsAllowedToJoin": {
"type": "String",
"placeholders": {}
},
"askSSSSSign": "要向其他人簽名,請輸入你 Keep 好咗嘅密碼或者恢復密鑰。",
"@askSSSSSign": {
"type": "String",
"placeholders": {}
},
"badServerLoginTypesException": "呢個 Homeserver 支持嘅登錄類型有:\n{serverVersions}\n但係呢個 App 淨係支援:\n{supportedVersions}",
"@badServerLoginTypesException": {
"type": "String",
"placeholders": {
"serverVersions": {
"type": "String"
},
"supportedVersions": {
"type": "String"
}
}
},
"cantOpenUri": "打唔開嘅 URI {uri}",
"@cantOpenUri": {
"type": "String",
"placeholders": {
"uri": {
"type": "String"
}
}
},
"badServerVersionsException": "呢個 Homeserver 支持以下 Spec 版本:\n{serverVersions}\n但係個 App 淨係支持 {supoortedVersions} 版本",
"@badServerVersionsException": {
"type": "String",
"placeholders": {
"serverVersions": {
"type": "String"
},
"supportedVersions": {
"type": "String"
}
}
},
"banFromChat": "喺傾偈入面 Ban 咗佢",
"@banFromChat": {
"type": "String",
"placeholders": {}
},
"noChatsFoundHere": "暫時未有偈傾。撳下面粒掣同人開始傾偈 ⤵️",
"@noChatsFoundHere": {},
"bannedUser": "{username} Ban 咗 {targetName}",
"@bannedUser": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"targetName": {
"type": "String"
}
}
},
"changedTheChatDescriptionTo": "{username} 改咗呢個偈嘅介紹: 「'{description}'」",
"@changedTheChatDescriptionTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"description": {
"type": "String"
}
}
},
"addEmail": "加 Email",
"@addEmail": {
"type": "String",
"placeholders": {}
},
"alwaysUse24HourFormat": "false",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
"importEmojis": "導入 Emoji",
"@importEmojis": {},
"hugContent": "{senderName} 抱咗你",
"@hugContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"commandHint_hug": "Send 個 Hug",
"@commandHint_hug": {},
"anyoneCanJoin": "任何人都可以 Join",
"@anyoneCanJoin": {
"type": "String",
"placeholders": {}
},
"repeatPassword": "輸入多一次密碼",
"@repeatPassword": {},
"notAnImage": "唔係圖檔。",
"@notAnImage": {},
"remove": "刪走",
"@remove": {
"type": "String",
"placeholders": {}
},
"importNow": "即刻導入",
"@importNow": {},
"exportEmotePack": "將表情符號導出成 .zip 檔案",
"@exportEmotePack": {},
"replace": "換走",
"@replace": {},
"about": "關於",
"@about": {},
"aboutHomeserver": "關於{homeserver}",
"@aboutHomeserver": {
"type": "String",
"placeholders": {
"homeserver": {
"type": "String"
}
}
},
"accept": "同意",
"@accept": {
"type": "String",
"placeholders": {}
},
"acceptedTheInvitation": "👍 {username} 同意咗邀请",
"@acceptedTheInvitation": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"account": "Account",
"@account": {
"type": "String",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐 {username} 開咗點對點加密",
"@activatedEndToEndEncryption": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"supposedMxid": "呢度應該係 {mxid}",
"@supposedMxid": {
"type": "String",
"placeholders": {
"mxid": {
"type": "String"
}
}
},
"addChatDescription": "講下關於呢個偈係傾嘅乜嘢……",
"@addChatDescription": {},
"addToSpace": "加落去空間嗰度",
"@addToSpace": {},
"admin": "Admin",
"@admin": {
"type": "String",
"placeholders": {}
},
"alias": "花名",
"@alias": {
"type": "String",
"placeholders": {}
},
"all": "全部",
"@all": {
"type": "String",
"placeholders": {}
},
"allChats": "所有傾嘅偈仔",
"@allChats": {
"type": "String",
"placeholders": {}
},
"commandHint_roomupgrade": "將呢間房升級到指定版本",
"@commandHint_roomupgrade": {},
"commandHint_googly": "送啲古靈精怪表情過去",
"@commandHint_googly": {},
"commandHint_cuddle": "Send 個攬攬",
"@commandHint_cuddle": {},
"googlyEyesContent": "{senderName} Send 咗你一個咕嚕眼",
"@googlyEyesContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"cuddleContent": "{senderName} 攬咗你",
"@cuddleContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"answeredTheCall": "{senderName} 聽咗你嘅電話",
"@answeredTheCall": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"appLock": "App 鎖",
"@appLock": {
"type": "String",
"placeholders": {}
},
"appLockDescription": "無人用嘅時候用密碼鎖住個App",
"@appLockDescription": {},
"archive": "存檔",
"@archive": {
"type": "String",
"placeholders": {}
},
"areYouSure": "咪住先?",
"@areYouSure": {
"type": "String",
"placeholders": {}
},
"askVerificationRequest": "係咪要 Accept 來自 {username} 嘅驗證申請?",
"@askVerificationRequest": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"autoplayImages": "自動播放動畫貼紙同表情",
"@autoplayImages": {
"type": "String",
"placeholder": {}
},
"sendTypingNotifications": "通知人地打緊字",
"@sendTypingNotifications": {},
"swipeRightToLeftToReply": "向左滑嚟回覆",
"@swipeRightToLeftToReply": {},
"sendOnEnter": "撳 Enter 即 Send",
"@sendOnEnter": {},
"countChatsAndCountParticipants": "{chats} 間房同 {participants} 條友",
"@countChatsAndCountParticipants": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
},
"participants": {
"type": "int"
}
}
},
"noMoreChatsFound": "搵唔到更多偈傾啦…",
"@noMoreChatsFound": {},
"joinedChats": "入咗嘅房間",
"@joinedChats": {},
"unread": "未讀",
"@unread": {},
"space": "空間",
"@space": {},
"spaces": "空間",
"@spaces": {},
"banned": "Block 咗",
"@banned": {
"type": "String",
"placeholders": {}
},
"blockDevice": "Block 咗嘅裝置",
"@blockDevice": {
"type": "String",
"placeholders": {}
},
"blocked": "Block 咗",
"@blocked": {
"type": "String",
"placeholders": {}
},
"botMessages": "機械人訊息",
"@botMessages": {
"type": "String",
"placeholders": {}
},
"cancel": "取消",
"@cancel": {
"type": "String",
"placeholders": {}
},
"changeDeviceName": "改裝置名",
"@changeDeviceName": {
"type": "String",
"placeholders": {}
},
"changedTheChatAvatar": "{username}轉咗個大頭貼",
"@changedTheChatAvatar": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"confirmMatrixId": "Confirm 你嘅 Matrix ID ,我哋先至可以刪除你嘅 Account。",
"@confirmMatrixId": {},
"setCustomPermissionLevel": "自訂權限級別",
"@setCustomPermissionLevel": {},
"importFromZipFile": "喺 .zip 檔案導入",
"@importFromZipFile": {},
"setPermissionsLevelDescription": "請喺下面選擇一個預定義嘅角色或輸入介乎0同100之間嘅自定義權限級別。",
"@setPermissionsLevelDescription": {}
}
"@@locale": "yue",
"normalUser": "正常用家",
"@normalUser": {},
"areYouSureYouWantToLogout": "係咪確定要 log out",
"@areYouSureYouWantToLogout": {
"type": "String",
"placeholders": {}
},
"areGuestsAllowedToJoin": "畀唔畀陌生人 Join",
"@areGuestsAllowedToJoin": {
"type": "String",
"placeholders": {}
},
"askSSSSSign": "要向其他人簽名,請輸入你 Keep 好咗嘅密碼或者恢復密鑰。",
"@askSSSSSign": {
"type": "String",
"placeholders": {}
},
"badServerLoginTypesException": "呢個 Homeserver 支持嘅登錄類型有:\n{serverVersions}\n但係呢個 App 淨係支援:\n{supportedVersions}",
"@badServerLoginTypesException": {
"type": "String",
"placeholders": {
"serverVersions": {
"type": "String"
},
"supportedVersions": {
"type": "String"
}
}
},
"cantOpenUri": "打唔開嘅 URI {uri}",
"@cantOpenUri": {
"type": "String",
"placeholders": {
"uri": {
"type": "String"
}
}
},
"badServerVersionsException": "呢個 Homeserver 支持以下 Spec 版本:\n{serverVersions}\n但係個 App 淨係支持 {supoortedVersions} 版本",
"@badServerVersionsException": {
"type": "String",
"placeholders": {
"serverVersions": {
"type": "String"
},
"supportedVersions": {
"type": "String"
}
}
},
"banFromChat": "喺傾偈入面 Ban 咗佢",
"@banFromChat": {
"type": "String",
"placeholders": {}
},
"noChatsFoundHere": "暫時未有偈傾。撳下面粒掣同人開始傾偈 ⤵️",
"@noChatsFoundHere": {},
"bannedUser": "{username} Ban 咗 {targetName}",
"@bannedUser": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"targetName": {
"type": "String"
}
}
},
"changedTheChatDescriptionTo": "{username} 改咗呢個偈嘅介紹: 「'{description}'」",
"@changedTheChatDescriptionTo": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
},
"description": {
"type": "String"
}
}
},
"addEmail": "加 Email",
"@addEmail": {
"type": "String",
"placeholders": {}
},
"alwaysUse24HourFormat": "false",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
"importEmojis": "導入 Emoji",
"@importEmojis": {},
"hugContent": "{senderName} 抱咗你",
"@hugContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"commandHint_hug": "Send 個 Hug",
"@commandHint_hug": {},
"anyoneCanJoin": "任何人都可以 Join",
"@anyoneCanJoin": {
"type": "String",
"placeholders": {}
},
"repeatPassword": "輸入多一次密碼",
"@repeatPassword": {},
"notAnImage": "唔係圖檔。",
"@notAnImage": {},
"remove": "刪走",
"@remove": {
"type": "String",
"placeholders": {}
},
"importNow": "即刻導入",
"@importNow": {},
"exportEmotePack": "將表情符號導出成 .zip 檔案",
"@exportEmotePack": {},
"replace": "換走",
"@replace": {},
"about": "關於",
"@about": {},
"aboutHomeserver": "關於{homeserver}",
"@aboutHomeserver": {
"type": "String",
"placeholders": {
"homeserver": {
"type": "String"
}
}
},
"accept": "同意",
"@accept": {
"type": "String",
"placeholders": {}
},
"acceptedTheInvitation": "👍 {username} 同意咗邀请",
"@acceptedTheInvitation": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"account": "Account",
"@account": {
"type": "String",
"placeholders": {}
},
"activatedEndToEndEncryption": "🔐 {username} 開咗點對點加密",
"@activatedEndToEndEncryption": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"supposedMxid": "呢度應該係 {mxid}",
"@supposedMxid": {
"type": "String",
"placeholders": {
"mxid": {
"type": "String"
}
}
},
"addChatDescription": "講下關於呢個偈係傾嘅乜嘢……",
"@addChatDescription": {},
"addToSpace": "加落去空間嗰度",
"@addToSpace": {},
"admin": "Admin",
"@admin": {
"type": "String",
"placeholders": {}
},
"alias": "花名",
"@alias": {
"type": "String",
"placeholders": {}
},
"all": "全部",
"@all": {
"type": "String",
"placeholders": {}
},
"allChats": "所有傾嘅偈仔",
"@allChats": {
"type": "String",
"placeholders": {}
},
"commandHint_roomupgrade": "將呢間房升級到指定版本",
"@commandHint_roomupgrade": {},
"commandHint_googly": "送啲古靈精怪表情過去",
"@commandHint_googly": {},
"commandHint_cuddle": "Send 個攬攬",
"@commandHint_cuddle": {},
"googlyEyesContent": "{senderName} Send 咗你一個咕嚕眼",
"@googlyEyesContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"cuddleContent": "{senderName} 攬咗你",
"@cuddleContent": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"answeredTheCall": "{senderName} 聽咗你嘅電話",
"@answeredTheCall": {
"type": "String",
"placeholders": {
"senderName": {
"type": "String"
}
}
},
"appLock": "App 鎖",
"@appLock": {
"type": "String",
"placeholders": {}
},
"appLockDescription": "無人用嘅時候用密碼鎖住個App",
"@appLockDescription": {},
"archive": "存檔",
"@archive": {
"type": "String",
"placeholders": {}
},
"areYouSure": "咪住先?",
"@areYouSure": {
"type": "String",
"placeholders": {}
},
"askVerificationRequest": "係咪要 Accept 來自 {username} 嘅驗證申請?",
"@askVerificationRequest": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"autoplayImages": "自動播放動畫貼紙同表情",
"@autoplayImages": {
"type": "String",
"placeholder": {}
},
"sendTypingNotifications": "通知人地打緊字",
"@sendTypingNotifications": {},
"swipeRightToLeftToReply": "向左滑嚟回覆",
"@swipeRightToLeftToReply": {},
"sendOnEnter": "撳 Enter 即 Send",
"@sendOnEnter": {},
"countChatsAndCountParticipants": "{chats} 間房同 {participants} 條友",
"@countChatsAndCountParticipants": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
},
"participants": {
"type": "int"
}
}
},
"noMoreChatsFound": "搵唔到更多偈傾啦…",
"@noMoreChatsFound": {},
"joinedChats": "入咗嘅房間",
"@joinedChats": {},
"unread": "未讀",
"@unread": {},
"space": "空間",
"@space": {},
"spaces": "空間",
"@spaces": {},
"banned": "Block 咗",
"@banned": {
"type": "String",
"placeholders": {}
},
"blockDevice": "Block 咗嘅裝置",
"@blockDevice": {
"type": "String",
"placeholders": {}
},
"blocked": "Block 咗",
"@blocked": {
"type": "String",
"placeholders": {}
},
"botMessages": "機械人訊息",
"@botMessages": {
"type": "String",
"placeholders": {}
},
"cancel": "取消",
"@cancel": {
"type": "String",
"placeholders": {}
},
"changeDeviceName": "改裝置名",
"@changeDeviceName": {
"type": "String",
"placeholders": {}
},
"changedTheChatAvatar": "{username}轉咗個大頭貼",
"@changedTheChatAvatar": {
"type": "String",
"placeholders": {
"username": {
"type": "String"
}
}
},
"confirmMatrixId": "Confirm 你嘅 Matrix ID ,我哋先至可以刪除你嘅 Account。",
"@confirmMatrixId": {},
"setCustomPermissionLevel": "自訂權限級別",
"@setCustomPermissionLevel": {},
"importFromZipFile": "喺 .zip 檔案導入",
"@importFromZipFile": {},
"setPermissionsLevelDescription": "請喺下面選擇一個預定義嘅角色或輸入介乎0同100之間嘅自定義權限級別。",
"@setPermissionsLevelDescription": {}
}

View file

@ -2592,9 +2592,9 @@
}
}
},
"inviteGroupChat": "📨 邀请至群聊",
"inviteGroupChat": "📨 群聊邀请",
"@inviteGroupChat": {},
"invitePrivateChat": "📨 邀请至私聊",
"invitePrivateChat": "📨 私聊邀请",
"@invitePrivateChat": {},
"emoteKeyboardNoRecents": "最近使用过的表情会出现在这里...",
"@emoteKeyboardNoRecents": {
@ -3379,5 +3379,11 @@
"commandHint_logoutall": "注销所有活动设备",
"@commandHint_logoutall": {},
"displayNavigationRail": "在移动设备上显示导航栏",
"@displayNavigationRail": {}
"@displayNavigationRail": {},
"customReaction": "自定义回应",
"@customReaction": {},
"moreEvents": "更多事件",
"@moreEvents": {},
"declineInvitation": "拒绝邀请",
"@declineInvitation": {}
}

File diff suppressed because it is too large Load diff

View file

@ -843,6 +843,9 @@ class ChatController extends State<ChatPageWithRoom>
message: L10n.of(context).redactMessageDescription,
isDestructive: true,
hintText: L10n.of(context).optionalRedactReason,
maxLength: 255,
maxLines: 3,
minLines: 1,
okLabel: L10n.of(context).remove,
cancelLabel: L10n.of(context).cancel,
)

View file

@ -21,7 +21,7 @@ class ChatEmojiPicker extends StatelessWidget {
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
height: controller.showEmojiPicker
? MediaQuery.of(context).size.height / 2
? MediaQuery.sizeOf(context).height / 2
: 0,
child: controller.showEmojiPicker
? DefaultTabController(

View file

@ -289,6 +289,7 @@ class ChatInputRow extends StatelessWidget {
bottom: 6.0,
top: 3.0,
),
counter: const SizedBox.shrink(),
hintText: L10n.of(context).writeAMessage,
hintMaxLines: 1,
border: InputBorder.none,

View file

@ -274,8 +274,8 @@ class ChatView extends StatelessWidget {
cacheKey: accountConfig.wallpaperUrl.toString(),
uri: accountConfig.wallpaperUrl,
fit: BoxFit.cover,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
height: MediaQuery.sizeOf(context).height,
width: MediaQuery.sizeOf(context).width,
isThumbnail: false,
placeholder: (_) => Container(),
),

View file

@ -461,8 +461,11 @@ class Message extends StatelessWidget {
clipBehavior: Clip.antiAlias,
child: BubbleBackground(
colors: colors,
ignore:
noBubble || !ownMessage,
ignore: noBubble ||
!ownMessage ||
MediaQuery.highContrastOf(
context,
),
scrollController:
scrollController,
child: Container(

View file

@ -53,26 +53,28 @@ class MessageDownloadContent extends StatelessWidget {
backgroundColor: textColor.withAlpha(32),
child: Icon(Icons.file_download_outlined, color: textColor),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
filename,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: textColor,
fontWeight: FontWeight.w500,
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
filename,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: textColor,
fontWeight: FontWeight.w500,
),
),
),
Text(
'$sizeString | $filetype',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: textColor, fontSize: 10),
),
],
Text(
'$sizeString | $filetype',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: textColor, fontSize: 10),
),
],
),
),
],
),

View file

@ -6,6 +6,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:matrix/matrix.dart';
import 'package:slugify/slugify.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/utils/markdown_context_builder.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
@ -23,7 +24,7 @@ class InputBar extends StatelessWidget {
final ValueChanged<Uint8List?>? onSubmitImage;
final FocusNode? focusNode;
final TextEditingController? controller;
final InputDecoration? decoration;
final InputDecoration decoration;
final ValueChanged<String>? onChanged;
final bool? autofocus;
final bool readOnly;
@ -37,7 +38,7 @@ class InputBar extends StatelessWidget {
this.onSubmitImage,
this.focusNode,
this.controller,
this.decoration,
required this.decoration,
this.onChanged,
this.autofocus,
this.textInputAction,
@ -437,7 +438,9 @@ class InputBar extends StatelessWidget {
// it sets the types for the callback incorrectly
onSubmitted!(text);
},
decoration: decoration!,
maxLength:
AppSettings.textMessageMaxLength.getItem(Matrix.of(context).store),
decoration: decoration,
onChanged: (text) {
// fix for the library for now
// it sets the types for the callback incorrectly
@ -445,6 +448,7 @@ class InputBar extends StatelessWidget {
},
textCapitalization: TextCapitalization.sentences,
),
suggestionsCallback: getSuggestions,
itemBuilder: (c, s) => buildSuggestion(c, s, Matrix.of(context).client),
onSelected: (Map<String, String?> suggestion) =>

View file

@ -98,8 +98,6 @@ class SendFileDialogState extends State<SendFileDialog> {
widget.files.length,
),
);
} else {
scaffoldMessenger.clearSnackBars();
}
final label = _labelTextController.text.trim();

View file

@ -73,26 +73,29 @@ class StickerPickerDialogState extends State<StickerPickerDialog> {
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int imageIndex) {
final image = pack.images[imageKeys[imageIndex]]!;
return InkWell(
radius: AppConfig.borderRadius,
key: ValueKey(image.url.toString()),
onTap: () {
// copy the image
final imageCopy =
ImagePackImageContent.fromJson(image.toJson().copy());
// set the body, if it doesn't exist, to the key
imageCopy.body ??= imageKeys[imageIndex];
widget.onSelected(imageCopy);
},
child: AbsorbPointer(
absorbing: true,
child: MxcImage(
uri: image.url,
fit: BoxFit.contain,
width: 128,
height: 128,
animated: true,
isThumbnail: false,
return Tooltip(
message: image.body ?? imageKeys[imageIndex],
child: InkWell(
radius: AppConfig.borderRadius,
key: ValueKey(image.url.toString()),
onTap: () {
// copy the image
final imageCopy =
ImagePackImageContent.fromJson(image.toJson().copy());
// set the body, if it doesn't exist, to the key
imageCopy.body ??= imageKeys[imageIndex];
widget.onSelected(imageCopy);
},
child: AbsorbPointer(
absorbing: true,
child: MxcImage(
uri: image.url,
fit: BoxFit.contain,
width: 128,
height: 128,
animated: true,
isThumbnail: false,
),
),
),
);
@ -111,6 +114,7 @@ class StickerPickerDialogState extends State<StickerPickerDialog> {
SliverAppBar(
floating: true,
pinned: true,
scrolledUnderElevation: 0,
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
title: SizedBox(
@ -118,6 +122,7 @@ class StickerPickerDialogState extends State<StickerPickerDialog> {
child: TextField(
autofocus: false,
decoration: InputDecoration(
filled: true,
hintText: L10n.of(context).search,
prefixIcon: const Icon(Icons.search_outlined),
contentPadding: EdgeInsets.zero,

View file

@ -15,12 +15,12 @@ import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat_list/chat_list_view.dart';
import 'package:fluffychat/utils/error_reporter.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/show_scaffold_dialog.dart';
import 'package:fluffychat/utils/show_update_snackbar.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart';
@ -114,82 +114,6 @@ class ChatListController extends State<ChatList>
void onChatTap(Room room) async {
if (room.membership == Membership.invite) {
final theme = Theme.of(context);
final inviteEvent = room.getState(
EventTypes.RoomMember,
room.client.userID!,
);
final matrixLocals = MatrixLocals(L10n.of(context));
final action = await showAdaptiveDialog<InviteAction>(
context: context,
builder: (context) => AlertDialog.adaptive(
title: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256),
child: Center(
child: Text(
room.getLocalizedDisplayname(matrixLocals),
textAlign: TextAlign.center,
),
),
),
content: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256),
child: Text(
inviteEvent == null
? L10n.of(context).inviteForMe
: inviteEvent.content.tryGet<String>('reason') ??
L10n.of(context).youInvitedBy(
room
.unsafeGetUserFromMemoryOrFallback(
inviteEvent.senderId,
)
.calcDisplayname(i18n: matrixLocals),
),
textAlign: TextAlign.center,
),
),
actions: [
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(InviteAction.accept),
bigButtons: true,
child: Text(L10n.of(context).accept),
),
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(InviteAction.decline),
bigButtons: true,
child: Text(
L10n.of(context).decline,
style: TextStyle(color: theme.colorScheme.error),
),
),
AdaptiveDialogAction(
onPressed: () => Navigator.of(context).pop(InviteAction.block),
bigButtons: true,
child: Text(
L10n.of(context).block,
style: TextStyle(color: theme.colorScheme.error),
),
),
],
),
);
switch (action) {
case null:
return;
case InviteAction.accept:
break;
case InviteAction.decline:
await showFutureLoadingDialog(
context: context,
future: () => room.leave(),
);
return;
case InviteAction.block:
final userId = inviteEvent?.senderId;
context.go('/rooms/settings/security/ignorelist', extra: userId);
return;
}
if (!mounted) return;
final joinResult = await showFutureLoadingDialog(
context: context,
future: () async {
@ -497,6 +421,8 @@ class ChatListController extends State<ChatList>
_checkTorBrowser();
ErrorReporter(context).consumeTemporaryErrorLogFile();
super.initState();
}
@ -680,6 +606,26 @@ class ChatListController extends State<ChatList>
],
),
),
if (room.membership == Membership.invite)
PopupMenuItem(
value: ChatContextAction.block,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.block_outlined,
color: Theme.of(context).colorScheme.onErrorContainer,
),
const SizedBox(width: 12),
Text(
L10n.of(context).block,
style: TextStyle(
color: Theme.of(context).colorScheme.onErrorContainer,
),
),
],
),
),
],
);
@ -715,6 +661,15 @@ class ChatListController extends State<ChatList>
),
);
return;
case ChatContextAction.block:
final inviteEvent = room.getState(
EventTypes.RoomMember,
room.client.userID!,
);
context.go(
'/rooms/settings/security/ignorelist',
extra: inviteEvent?.senderId,
);
case ChatContextAction.leave:
final confirmed = await showOkCancelAlertDialog(
context: context,
@ -981,6 +936,5 @@ enum ChatContextAction {
mute,
leave,
addToSpace,
block,
}
enum InviteAction { accept, decline, block }

View file

@ -35,32 +35,6 @@ class ChatListItem extends StatelessWidget {
super.key,
});
Future<bool> archiveAction(BuildContext context) async {
{
if ([Membership.leave, Membership.ban].contains(room.membership)) {
final forgetResult = await showFutureLoadingDialog(
context: context,
future: () => room.forget(),
);
return forgetResult.isValue;
}
final confirmed = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).areYouSure,
okLabel: L10n.of(context).leave,
cancelLabel: L10n.of(context).cancel,
message: L10n.of(context).archiveRoomDescription,
isDestructive: true,
);
if (confirmed != OkCancelResult.ok) return false;
final leaveResult = await showFutureLoadingDialog(
context: context,
future: () => room.leave(),
);
return leaveResult.isValue;
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@ -69,7 +43,7 @@ class ChatListItem extends StatelessWidget {
final typingText = room.getLocalizedTypingText(context);
final lastEvent = room.lastEvent;
final ownMessage = lastEvent?.senderId == room.client.userID;
final unread = room.isUnread || room.membership == Membership.invite;
final unread = room.isUnread;
final directChatMatrixId = room.directChatMatrixID;
final isDirectChat = directChatMatrixId != null;
final unreadBubbleSize = unread || room.hasNewMessages
@ -357,8 +331,7 @@ class ChatListItem extends StatelessWidget {
room.notificationCount.toString().length +
9,
decoration: BoxDecoration(
color: room.highlightCount > 0 ||
room.membership == Membership.invite
color: room.highlightCount > 0
? theme.colorScheme.error
: hasNotifications || room.markedUnread
? theme.colorScheme.primary
@ -369,8 +342,7 @@ class ChatListItem extends StatelessWidget {
? Text(
room.notificationCount.toString(),
style: TextStyle(
color: room.highlightCount > 0 ||
room.membership == Membership.invite
color: room.highlightCount > 0
? theme.colorScheme.onError
: hasNotifications
? theme.colorScheme.onPrimary
@ -386,7 +358,28 @@ class ChatListItem extends StatelessWidget {
),
onTap: onTap,
trailing: onForget == null
? null
? room.membership == Membership.invite
? IconButton(
tooltip: L10n.of(context).declineInvitation,
icon: const Icon(Icons.delete_forever_outlined),
color: theme.colorScheme.error,
onPressed: () async {
final consent = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).declineInvitation,
message: L10n.of(context).areYouSure,
okLabel: L10n.of(context).yes,
isDestructive: true,
);
if (consent != OkCancelResult.ok) return;
if (!context.mounted) return;
await showFutureLoadingDialog(
context: context,
future: room.leave,
);
},
)
: null
: IconButton(
icon: const Icon(Icons.delete_outlined),
onPressed: onForget,

View file

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:matrix/encryption/utils/key_verification.dart';
import 'package:matrix/matrix.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/device_settings/device_settings_view.dart';
@ -52,6 +53,18 @@ class DevicesSettingsController extends State<DevicesSettings> {
}
void removeDevicesAction(List<Device> devices) async {
final client = Matrix.of(context).client;
final accountManageUrl = client.wellKnown?.additionalProperties
.tryGetMap<String, Object?>('org.matrix.msc2965.authentication')
?.tryGet<String>('account');
if (accountManageUrl != null) {
launchUrlString(
accountManageUrl,
mode: LaunchMode.inAppBrowserView,
);
return;
}
if (await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).areYouSure,

View file

@ -238,18 +238,18 @@ class MyCallingPage extends State<Calling> {
void _resizeLocalVideo(Orientation orientation) {
final shortSide = min(
MediaQuery.of(widget.context).size.width,
MediaQuery.of(widget.context).size.height,
MediaQuery.sizeOf(widget.context).width,
MediaQuery.sizeOf(widget.context).height,
);
_localVideoMargin = remoteStream != null
? const EdgeInsets.only(top: 20.0, right: 20.0)
: EdgeInsets.zero;
_localVideoWidth = remoteStream != null
? shortSide / 3
: MediaQuery.of(widget.context).size.width;
: MediaQuery.sizeOf(widget.context).width;
_localVideoHeight = remoteStream != null
? shortSide / 4
: MediaQuery.of(widget.context).size.height;
: MediaQuery.sizeOf(widget.context).height;
}
void _handleCallState(CallState state) {
@ -299,7 +299,9 @@ class MyCallingPage extends State<Calling> {
L10n.of(widget.context).foregroundServiceRunning,
),
iosNotificationOptions: const IOSNotificationOptions(),
foregroundTaskOptions: const ForegroundTaskOptions(),
foregroundTaskOptions: ForegroundTaskOptions(
eventAction: ForegroundTaskEventAction.nothing(),
),
);
FlutterForegroundTask.startService(
notificationTitle: L10n.of(widget.context).screenSharingTitle,

View file

@ -138,10 +138,9 @@ class PIPViewState extends State<PIPView> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
var windowPadding = mediaQuery.padding;
var windowPadding = MediaQuery.paddingOf(context);
if (widget.avoidKeyboard) {
windowPadding += mediaQuery.viewInsets;
windowPadding += MediaQuery.viewInsetsOf(context);
}
final isFloating = _floating;

View file

@ -6,7 +6,6 @@ import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
import 'package:go_router/go_router.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:matrix/matrix.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher_string.dart';
@ -45,17 +44,6 @@ class HomeserverPickerController extends State<HomeserverPicker> {
Future<void> _checkTorBrowser() async {
if (!kIsWeb) return;
Hive.openBox('test').then((value) => null).catchError(
(e, s) async {
await showOkAlertDialog(
context: context,
title: L10n.of(context).indexedDbErrorTitle,
message: L10n.of(context).indexedDbErrorLong,
);
_checkTorBrowser();
},
);
final isTor = await TorBrowserDetector.isTorBrowser;
isTorBrowser = isTor;
}

View file

@ -111,7 +111,7 @@ class ImageViewerController extends State<ImageViewer> {
void onInteractionEnds(ScaleEndDetails endDetails) {
if (PlatformInfos.usesTouchscreen == false) {
if (endDetails.velocity.pixelsPerSecond.dy >
MediaQuery.of(context).size.height * maxScaleFactor) {
MediaQuery.sizeOf(context).height * maxScaleFactor) {
Navigator.of(context, rootNavigator: false).pop();
}
}

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