2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-31 22:25:08 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Albert Vaca Cintora
36636406b0 Require Android 6 (API 32) 2024-05-12 16:25:11 +02:00
175 changed files with 4749 additions and 6219 deletions

View File

@@ -8,18 +8,12 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:versionCode="13202"
android:versionName="1.32.2">
android:versionCode="13001"
android:versionName="1.30.1">
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.INTERNET" />
@@ -62,7 +56,6 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/kde_connect"
android:banner="@mipmap/ic_launcher_banner"
android:supportsRtl="true"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -117,12 +110,6 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
<meta-data android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
android:name="org.kde.kdeconnect.UserInterface.PluginSettingsActivity"

View File

@@ -1,15 +1,8 @@
import com.android.build.api.instrumentation.AsmClassVisitorFactory
import com.android.build.api.instrumentation.ClassContext
import com.android.build.api.instrumentation.ClassData
import com.android.build.api.instrumentation.InstrumentationParameters
import com.android.build.api.instrumentation.InstrumentationScope
import com.github.jk1.license.LicenseReportExtension
import com.github.jk1.license.render.ReportRenderer
import com.github.jk1.license.render.TextReportRenderer
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes.CHECKCAST
import org.objectweb.asm.Opcodes.INVOKESTATIC
import java.io.FileNotFoundException
import java.util.Properties
buildscript {
dependencies {
@@ -18,12 +11,12 @@ buildscript {
}
}
@Suppress("DSL_SCOPE_VIOLATION") // TODO: remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.dependencyLicenseReport)
alias(libs.plugins.compose.compiler)
}
val licenseResDir = File("$projectDir/build/dependency-license-res")
@@ -50,7 +43,7 @@ android {
namespace = "org.kde.kdeconnect_tp"
compileSdk = 34
defaultConfig {
minSdk = 21
minSdk = 23
targetSdk = 33
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
@@ -60,6 +53,10 @@ android {
buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_9
targetCompatibility = JavaVersion.VERSION_1_9
@@ -102,10 +99,22 @@ android {
}
buildTypes {
getByName("debug") {
isMinifyEnabled = false
isShrinkResources = false
// We minify by default even on debug builds. This has helped us catch issues where minification would remove files that were actually used (eg: via reflection).
// If you want to locally disable this behavior to speed-up the build, add a line `disableMinifyDebug=true` to your `local.properties` file.
val reader = try {
rootProject.file("local.properties").reader()
} catch (e: FileNotFoundException) {
null
}
val properties = reader?.use { Properties().apply { load(it) } }
val disableMinifyDebug = properties?.getProperty("disableMinifyDebug")?.toBoolean() ?: false
isMinifyEnabled = !disableMinifyDebug
isShrinkResources = !disableMinifyDebug
signingConfig = signingConfigs.getByName("debug")
}
// keep minifyEnabled false above for faster builds; set to 'true'
// when testing to make sure ProGuard/R8 is not deleting important stuff
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
@@ -116,6 +125,19 @@ android {
checkReleaseBuilds = false
}
testOptions {
unitTests.all {
it.jvmArgs = it.jvmArgs.orEmpty() + listOf(
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.security=ALL-UNNAMED",
"--add-opens=java.base/sun.security.rsa=ALL-UNNAMED",
"--add-opens=java.base/sun.security.x509=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"--add-opens=java.base/java.lang.reflect=ALL-UNNAMED"
)
}
}
applicationVariants.all {
val variant = this
logger.quiet("Found a variant called ${variant.name}")
@@ -129,7 +151,7 @@ android {
try {
val hash = "git rev-parse --short HEAD".runCommand(workingDir = rootDir)
val newName = "${project.name}-${variant.name}-${hash}.apk"
logger.quiet(" Found an output file ${output.outputFile.name}, renaming to $newName")
logger.quiet(" Found an output file ${output.outputFile.name}, renaming to ${newName}")
output.outputFileName = newName
} catch (ignored: Exception) {
logger.warn("Could not make use of the 'git' command-line tool. Output filenames will not be customized.")
@@ -140,139 +162,8 @@ android {
}
}
/**
* Fix PosixFilePermission class type check issue.
*
* It fixed the class cast exception when lib desugar enabled and minSdk < 26.
*/
abstract class FixPosixFilePermissionClassVisitorFactory :
AsmClassVisitorFactory<FixPosixFilePermissionClassVisitorFactory.Params> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor
): ClassVisitor {
return object : ClassVisitor(instrumentationContext.apiVersion.get(), nextClassVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
if (name == "attributesToPermissions") { // org.apache.sshd.sftp.common.SftpHelper.attributesToPermissions
return object : MethodVisitor(
instrumentationContext.apiVersion.get(),
super.visitMethod(access, name, descriptor, signature, exceptions)
) {
override fun visitTypeInsn(opcode: Int, type: String?) {
// We need to prevent Android Desugar modifying the `PosixFilePermission` classname.
//
// Android Desugar will replace `CHECKCAST java/nio/file/attribute/PosixFilePermission`
// to `CHECKCAST j$/nio/file/attribute/PosixFilePermission`.
// We need to replace it with `CHECKCAST java/lang/Enum` to prevent Android Desugar from modifying it.
if (opcode == CHECKCAST && type == "java/nio/file/attribute/PosixFilePermission") {
println("Bypass PosixFilePermission type check success.")
// `Enum` is the superclass of `PosixFilePermission`.
// Due to `Object` is not the superclass of `Enum`, we need to use `Enum` instead of `Object`.
super.visitTypeInsn(opcode, "java/lang/Enum")
} else {
super.visitTypeInsn(opcode, type)
}
}
}
}
return super.visitMethod(access, name, descriptor, signature, exceptions)
}
}
}
override fun isInstrumentable(classData: ClassData): Boolean {
return (classData.className == "org.apache.sshd.sftp.common.SftpHelper").also {
if (it) println("SftpHelper Found! Instrumenting...")
}
}
interface Params : InstrumentationParameters
}
/**
* Collections.unmodifiableXXX is not exist when Android API level is lower than 26.
* So we replace the call to Collections.unmodifiableXXX with the original collection by removing the call.
*/
abstract class FixCollectionsClassVisitorFactory :
AsmClassVisitorFactory<FixCollectionsClassVisitorFactory.Params> {
override fun createClassVisitor(
classContext: ClassContext,
nextClassVisitor: ClassVisitor
): ClassVisitor {
return object : ClassVisitor(instrumentationContext.apiVersion.get(), nextClassVisitor) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
return object : MethodVisitor(
instrumentationContext.apiVersion.get(),
super.visitMethod(access, name, descriptor, signature, exceptions)
) {
override fun visitMethodInsn(
opcode: Int,
type: String?,
name: String?,
descriptor: String?,
isInterface: Boolean
) {
val backportClass = "org/kde/kdeconnect/Helpers/CollectionsBackport"
if (opcode == INVOKESTATIC && type == "java/util/Collections") {
val replaceRules = mapOf(
"unmodifiableNavigableSet" to "(Ljava/util/NavigableSet;)Ljava/util/NavigableSet;",
"unmodifiableSet" to "(Ljava/util/Set;)Ljava/util/Set;",
"unmodifiableNavigableMap" to "(Ljava/util/NavigableMap;)Ljava/util/NavigableMap;",
"emptyNavigableMap" to "()Ljava/util/NavigableMap;")
if (name in replaceRules && descriptor == replaceRules[name]) {
super.visitMethodInsn(opcode, backportClass, name, descriptor, isInterface)
val calleeClass = classContext.currentClassData.className
println("Replace Collections.$name call with CollectionsBackport.$name from $calleeClass success.")
return
}
}
super.visitMethodInsn(opcode, type, name, descriptor, isInterface)
}
}
}
}
}
override fun isInstrumentable(classData: ClassData): Boolean {
return classData.className.startsWith("org.apache.sshd") // We only need to fix the Apache SSHD library
}
interface Params : InstrumentationParameters
}
androidComponents {
onVariants { variant ->
variant.instrumentation.transformClassesWith(
FixPosixFilePermissionClassVisitorFactory::class.java,
InstrumentationScope.ALL
) { }
variant.instrumentation.transformClassesWith(
FixCollectionsClassVisitorFactory::class.java,
InstrumentationScope.ALL
) { }
}
}
dependencies {
// It has a bug that causes a crash when using PosixFilePermission and minSdk < 26.
// It has been used in SSHD Core.
// We have taken a workaround to fix it.
// See `FixPosixFilePermissionClassVisitorFactory` for more details.
coreLibraryDesugaring(libs.android.desugarJdkLibsNio)
coreLibraryDesugaring(libs.android.desugarJdkLibs)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.ui.tooling.preview)
@@ -299,10 +190,7 @@ dependencies {
implementation(libs.slf4j.handroid)
implementation(libs.apache.sshd.core)
implementation(libs.apache.sshd.sftp)
implementation(libs.apache.sshd.scp)
implementation(libs.apache.sshd.mina)
implementation(libs.apache.mina.core)
implementation(libs.apache.mina.core) //For some reason, makes sshd-core:0.14.0 work without NIO, which isn't available until Android 8 (api 26)
//implementation("com.github.bright:slf4android:0.1.6") { transitive = true } // For org.apache.sshd debugging
implementation(libs.bcpkix.jdk15on) //For SSL certificate generation
@@ -331,7 +219,10 @@ dependencies {
// Testing
testImplementation(libs.junit)
testImplementation(libs.mockito.core)
testImplementation(libs.powermock.core)
testImplementation(libs.powermock.module.junit4)
testImplementation(libs.powermock.api.mockito2)
testImplementation(libs.mockito.core) // powermock isn't compatible with mockito 4
testImplementation(libs.jsonassert)
// For device controls

View File

@@ -1,21 +0,0 @@
KDE Connect предоставя набор от функции за интегриране на вашия работен процес на различни устройства:
- Прехвърляйте файлове между вашите устройства.
- Осъществявайте достъп до файлове на телефона си от компютъра си, без кабели.
- Споделен клипборд: копирайте и поставяйте между вашите устройства.
- Получавайте известия за входящи обаждания и съобщения на вашия компютър.
- Виртуален тъчпад: Използвайте екрана на телефона си като тъчпад на компютъра.
- Синхронизиране на известия: Достъп до известията на телефона ви от вашия компютър и отговаряне на съобщения.
- Мултимедийно дистанционно управление: Използвайте телефона си като дистанционно за Linux медийни плейъри.
- WiFi връзка: не е необходим USB кабел или bluetooth.
- TLS криптиране от край до край: информацията ви е в безопасност.
Моля, имайте предвид, че ще трябва да инсталирате KDE Connect на вашия компютър, за да работи това приложение, и поддържайте версията за настолен компютър актуална с версията за Android, за да работят най-новите функции.
Поверителна информация за разрешения:
* Разрешение за достъпност: Изисква се за получаване на вход от друго устройство за управление на вашия телефон с Android, ако използвате функцията за отдалечено въвеждане.
* Разрешение за местоположение във фонов режим: Изисква се, за да знаете към коя WiFi мрежа сте свързани, ако използвате функцията Trusted Networks.
KDE Connect никога не изпраща никаква информация на KDE или на трета страна. KDE Connect изпраща данни от едно устройство на друго директно чрез локалната мрежа, никога през интернет, и чрез криптиране от край до край.
Това приложение е част от проект с отворен код и съществува благодарение на всички хора, които са допринесли за него. Посетете уебсайта, за да вземете изходния код.

View File

@@ -1 +0,0 @@
KDE Connect интегрира вашия смартфон и компютър

View File

@@ -1 +0,0 @@
KDE Connect

View File

@@ -1,11 +0,0 @@
1.31
* Allow sharing URLs to disconnected devices, to be opened when they become available later
* Show a notification to continue playing media on this device after stopping it on another device
* Display a shortened version of the pairing verification key
* Tweaks to the app theme
1.30
* Added Bluetooth support (beta)
* Improved device controls
* Added scroll sensitivity option to remote input
* Accessibility improvements

View File

@@ -1,10 +0,0 @@
1.32
* Rewrite the remote file browsing
* Add Direct Share targets
* Send album art from phone to PC
1.31
* Allow sharing URLs to disconnected devices, to be opened when they become available later
* Show a notification to continue playing media on this device after stopping it on another device
* Display a shortened version of the pairing verification key
* Tweaks to the app theme

View File

@@ -1,13 +0,0 @@
1.32.1
* Fixed a crash when opening the presentation remote
1.32
* Rewrite the remote file browsing
* Add Direct Share targets
* Send album art from phone to PC
1.31
* Allow sharing URLs to disconnected devices, to be opened when they become available later
* Show a notification to continue playing media on this device after stopping it on another device
* Display a shortened version of the pairing verification key
* Tweaks to the app theme

View File

@@ -1,11 +0,0 @@
1.32.2
* Handle expired certificates
* Support doubletap drag in remote mouse
1.32.1
* Fixed a crash when opening the presentation remote
1.32
* Rewrite the remote file browsing
* Add Direct Share targets
* Send album art from phone to PC

View File

@@ -1,21 +1,14 @@
KDE Connect provides a set of features to integrate your workflow across devices:
- Transfer files between your devices.
- Access files on your phone from your computer, without wires.
- Shared clipboard: copy and paste between your devices.
- Get notifications for incoming calls and messages on your computer.
- Share files and URLs to your computer from any app.
- Get notifications for incoming calls and SMS messages on your PC.
- Virtual touchpad: Use your phone screen as your computer's touchpad.
- Notifications sync: Access your phone notifications from your computer and reply to messages.
- Notifications sync: Read your Android notifications from the desktop.
- Multimedia remote control: Use your phone as a remote for Linux media players.
- WiFi connection: no USB wire or bluetooth needed.
- End-to-end TLS encryption: your information is safe.
Please note you will need to install KDE Connect on your computer for this app to work, and keep the desktop version up-to-date with the Android version for the latest features to work.
Sensitive permissions information:
* Accessibility permission: Required to receive input from another device to control your Android phone, if you use the Remote Input feature.
* Background location permission: Required to know to which WiFi network you are connected to, if you use the Trusted Networks feature.
KDE Connect never sends any information to KDE nor to any third party. KDE Connect sends data from one device to the other directly using the local network, never through the internet, and using end to end encryption.
This app is part of an open source project and it exists thanks to all the people who contributed to it. Visit the website to grab the source code.

View File

@@ -6,7 +6,7 @@ KDEConnect fournit un ensemble de fonctionnalités pour intégrer votre flux de
- Apparition de notifications pour les appels et les messages entrants sur votre ordinateur.
- Pavé tactile virtuel : utilisation de l'écran de votre téléphone comme pavé tactile pour votre ordinateur.
- Synchronisation de vos notifications : accès à vos notifications téléphoniques depuis votre ordinateur et réponses aux messages.
- Télé-commande multimédia : utilisation de votre téléphone comme télécommande pour les lecteurs de média sous Linux.
- Télé-commande multimédia : utilisation de votre téléphone comme télécommande pour les lecteurs de médias sous Linux.
- Connexion au Wifi : aucun connexion USB ou Bluetooth nécessaire.
- Chiffrement « TLS » de bout en bout : vos informations sont en sécurité.
@@ -18,4 +18,4 @@ Informations sur les permissions sensibles :
KDEConnect n'envoie jamais d'informations à KDE ni à aucun tiers. KDEConnect envoie des données d'un périphérique à un autre à l'aide du réseau local, mais jamais par Internet et en utilisant le chiffrement de bout en bout.
Cette application fait partie d'un projet « Open source ». Il existe grâce à toutes les personnes qui y ont contribué. Veuillez visiter le site Internet pour accéder au code source.
Cette application fait partie d'un projet « Open source ». Il existe grâce à toutes les personnes qui y ont contribué.Visitez le site Internet pour accéder au code source.

View File

@@ -1,21 +0,0 @@
KDE Connect tilbyr eit sett funksjonar som lèt deg enkelt arbeida på tvers av einingar:
Overfør filer mellom einingane
Få trådlaus tilgang til filer på telefonen frå datamaskina
Del utklippsbilete: kopier og lim inn mellom einingane
Vert varsla på datamaskina om innkommande samtalar og tekstmeldingar
Virtuell styreplate: bruk telefon­skjermen som styreplate for datamaskina
Synkronisering av varslingar: få tilgang til telefon­varslingar frå datamaskina og svar på meldingar
Fjernkontroll av medieavspeling: bruk telefonen til å styra Linux-baserte mediespelarar
Wi-Fi-tilkopling: du treng ikkje USB- eller Bluetooth-tilkopling
Ende-til-ende-kryptering: informasjonen din er trygg
Merk at du må installera KDE Connect på datamaskina for å kunna bruka appen. Hugs å halda PC-versjonen oppdatert med Android-versjonen for tilgang til dei nyaste funksjonane.
Informasjon om sensitive løyve:
Tilgjenge-løyve: Trengst for å kunna ta imot tastetrykk frå PC for å styra Android-eininga om du brukar funksjonen «Fjernstyring»
Bakgrunns­løyve til å sjå geografiske posisjon: Trengst for å veta kva Wi-Fi-nettverk du er tilkopla om du brukar funksjonen «Tiltrudde nettverk»
KDE Connect sender aldri informasjon til KDE eller nokon tredjepart. Programmet sender data direkte mellom dei to einingane via lokalnettet, aldri via Internett og alltid med ende-til-ende-kryptering.
Appen er ein del av eit fri programvare-prosjekt og er blitt til takka vera mange bidragsytarar. Gå til heimesida for å sjå kjeldekoden.

View File

@@ -1 +0,0 @@
KDE Connect koplar telefonen din saman med datamaskina

View File

@@ -1 +0,0 @@
KDE Connect

View File

@@ -1,21 +1,20 @@
O KDE Connect fornece um conjunto de recursos para integrar seu fluxo de trabalho entre dispositivos:
- Transfira arquivos entre seus dispositivos.
- Acesse arquivos do seu computador no seu telefone, sem fios.
- Área de transferência compartilhada: copie e cole entre seus dispositivos.
- Compartilhe arquivos e URLs em seu computador a partir de qualquer app.
- Receba notificações de chamadas recebidas e mensagens SMS no seu PC.
- Touchpad virtual: use a tela do telefone como touchpad do computador.
- Sincronização de notificações: acesse as notificações do seu telefone no seu computador e responda as mensagens.
- Controle remoto multimídia: use seu telefone como controle remoto para reprodutores de mídia no Linux.
- Sincronização de notificações: leia as notificações do seu Android na área de trabalho.
- Controle remoto multimídia: use seu telefone como controle remoto para reprodutores de mídia Linux.
- Conexão Wi-Fi: sem necessidade de cabos USB ou bluetooth.
- Criptografia TLS de ponta a ponta: suas informações estão seguras.
Observe que você precisará instalar o KDE Connect no seu computador para que este aplicativo funcione e mantenha a versão para desktop atualizada com a versão do Android para que os recursos mais recentes funcionem.
Informações sobre permissões sensíveis:
Informações a respeito de permissões especiais :
* Permissão de acessibilidade: necessária para receber entrada de outro dispositivo para controlar seu telefone Android, se você usar o recurso de entrada remota.
* Permissão de localização em segundo plano: necessária para saber a qual rede Wi-Fi você está conectado, se você usar o recurso de redes confiáveis.
O KDE Connect nunca envia nenhuma informação ao KDE ou a terceiros. O KDE Connect envia dados de um dispositivo para outro diretamente usando a rede local, nunca pela Internet e usando criptografia de ponta a ponta.
O KDE Connect nunca envia nenhuma informação ao KDE nem a terceiros. O KDE Connect envia dados de um dispositivo para outro diretamente usando a rede local, nunca pela Internet e usando criptografia de ponta a ponta.
Este aplicativo faz parte de um projeto de código aberto e existe graças a todas as pessoas que contribuíram para ele. Visite o site para obter o código-fonte.

View File

@@ -1,7 +1,3 @@
android.enableJetifier=false
android.useAndroidX=true
org.gradle.jvmargs=-Xmx4096m
org.gradle.caching=true
org.gradle.parallel=true
# License report doesn't allow us to enable configuration caching
#org.gradle.configuration-cache=true

View File

@@ -1,44 +1,47 @@
[versions]
activityCompose = "1.9.1"
androidDesugarJdkLibs = "2.1.1"
androidGradlePlugin = "8.6.0"
activityCompose = "1.8.2"
androidDesugarJdkLibs = "2.0.4"
androidGradlePlugin = "8.4.0"
androidSmsmms = "kdeconnect-1-21-0"
appcompat = "1.7.0"
appcompat = "1.6.1"
bcpkixJdk15on = "1.70"
classindex = "3.13"
commonsCollections4 = "4.4"
commonsIo = "2.16.1"
commonsLang3 = "3.17.0"
commonsLang3 = "3.14.0"
constraintlayoutCompose = "1.0.1"
coreKtx = "1.13.1"
dependencyLicenseReport = "2.7"
compose-compiler = "1.5.11"
coreKtx = "1.12.0"
disklrucache = "2.0.2"
documentfile = "1.0.1"
gradle = "8.4.0"
gridlayout = "1.0.0"
jsonassert = "1.5.3"
jsonassert = "1.5.1"
junit = "4.13.2"
kotlin = "2.0.20"
kotlinxCoroutinesCore = "1.8.1"
dependencyLicenseReport = "1.16"
kotlin = "1.9.23"
kotlinxCoroutinesCore = "1.8.0"
lifecycleExtensions = "2.2.0"
lifecycleRuntimeKtx = "2.8.4"
lifecycleRuntimeKtx = "2.7.0"
logger = "1.0.3"
material = "1.12.0"
material = "1.11.0"
material3 = "1.2.1"
media = "1.7.0"
minaCore = "2.2.3"
mockitoCore = "5.13.0"
minaCore = "2.0.19"
mockitoCore = "3.12.4"
powermockModuleJunit4 = "2.0.9"
preferenceKtx = "1.2.1"
reactiveStreams = "1.0.4"
recyclerview = "1.3.2"
rxjava = "2.2.21"
sl4j = "2.0.13"
sshdCore = "2.13.2"
sshdCore = "0.14.0"
swiperefreshlayout = "1.1.0"
uiToolingPreview = "1.6.8"
uiToolingPreview = "1.6.5"
univocityParsers = "2.9.1"
sl4j = "2.0.4"
[libraries]
android-desugarJdkLibsNio = { module = "com.android.tools:desugar_jdk_libs_nio", version.ref = "androidDesugarJdkLibs" }
android-desugarJdkLibs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" }
android-smsmms = { module = "org.kde.invent.sredman:android-smsmms", version.ref = "androidSmsmms" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
@@ -63,9 +66,9 @@ commons-collections4 = { module = "org.apache.commons:commons-collections4", ver
commons-io = { module = "commons-io:commons-io", version.ref = "commonsIo" }
commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang3" }
disklrucache = { module = "com.jakewharton:disklrucache", version.ref = "disklrucache" }
android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "gradle" }
jsonassert = { module = "org.skyscreamer:jsonassert", version.ref = "jsonassert" }
junit = { module = "junit:junit", version.ref = "junit" }
android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" }
kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesCore" }
@@ -74,10 +77,10 @@ logger = { module = "com.klinkerapps:logger", version.ref = "logger" }
material = { module = "com.google.android.material:material", version.ref = "material" }
apache-mina-core = { module = "org.apache.mina:mina-core", version.ref = "minaCore" }
apache-sshd-core = { module = "org.apache.sshd:sshd-core", version.ref = "sshdCore" }
apache-sshd-sftp = { module = "org.apache.sshd:sshd-sftp", version.ref = "sshdCore" }
apache-sshd-scp = { module = "org.apache.sshd:sshd-scp", version.ref = "sshdCore" }
apache-sshd-mina = { module = "org.apache.sshd:sshd-mina", version.ref = "sshdCore" }
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockitoCore" }
powermock-api-mockito2 = { module = "org.powermock:powermock-api-mockito2", version.ref = "powermockModuleJunit4" }
powermock-core = { module = "org.powermock:powermock-core", version.ref = "powermockModuleJunit4" }
powermock-module-junit4 = { module = "org.powermock:powermock-module-junit4", version.ref = "powermockModuleJunit4" }
reactive-streams = { module = "org.reactivestreams:reactive-streams", version.ref = "reactiveStreams" }
rxjava = { module = "io.reactivex.rxjava2:rxjava", version.ref = "rxjava" }
univocity-parsers = { module = "com.univocity:univocity-parsers", version.ref = "univocityParsers" }
@@ -85,7 +88,6 @@ slf4j-handroid = { group = "com.gitlab.mvysny.slf4j", name = "slf4j-handroid", v
[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-android = { id ="org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
dependencyLicenseReport = { id = "com.github.jk1.dependency-license-report", version.ref = "dependencyLicenseReport" }

View File

@@ -1,6 +1,6 @@
#Sat Mar 02 00:26:28 CET 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,85 +0,0 @@
# SPDX-FileCopyrightText: 2024 Mincho Kondarev <mkondarev@yahoo.de>
#. extracted from ./metadata/android/en-US/full_description.txt
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-05 12:31+0000\n"
"PO-Revision-Date: 2024-07-28 18:31+0200\n"
"Last-Translator: Mincho Kondarev <mkondarev@yahoo.de>\n"
"Language-Team: Bulgarian <kde-i18n-doc@kde.org>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 24.07.70\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
msgid ""
"KDE Connect provides a set of features to integrate your workflow across "
"devices:\n"
"\n"
"- Transfer files between your devices.\n"
"- Access files on your phone from your computer, without wires.\n"
"- Shared clipboard: copy and paste between your devices.\n"
"- Get notifications for incoming calls and messages on your computer.\n"
"- Virtual touchpad: Use your phone screen as your computer's touchpad.\n"
"- Notifications sync: Access your phone notifications from your computer and "
"reply to messages.\n"
"- Multimedia remote control: Use your phone as a remote for Linux media "
"players.\n"
"- WiFi connection: no USB wire or bluetooth needed.\n"
"- End-to-end TLS encryption: your information is safe.\n"
"\n"
"Please note you will need to install KDE Connect on your computer for this "
"app to work, and keep the desktop version up-to-date with the Android "
"version for the latest features to work.\n"
"\n"
"Sensitive permissions information:\n"
"* Accessibility permission: Required to receive input from another device to "
"control your Android phone, if you use the Remote Input feature.\n"
"* Background location permission: Required to know to which WiFi network you "
"are connected to, if you use the Trusted Networks feature.\n"
"\n"
"KDE Connect never sends any information to KDE nor to any third party. KDE "
"Connect sends data from one device to the other directly using the local "
"network, never through the internet, and using end to end encryption.\n"
"\n"
"This app is part of an open source project and it exists thanks to all the "
"people who contributed to it. Visit the website to grab the source code.\n"
msgstr ""
"KDE Connect предоставя набор от функции за интегриране на вашия работен "
"процес на различни устройства:\n"
"\n"
"- Прехвърляйте файлове между вашите устройства.\n"
"- Осъществявайте достъп до файлове на телефона си от компютъра си, без "
"кабели.\n"
"- Споделен клипборд: копирайте и поставяйте между вашите устройства.\n"
"- Получавайте известия за входящи обаждания и съобщения на вашия компютър.\n"
"- Виртуален тъчпад: Използвайте екрана на телефона си като тъчпад на "
"компютъра.\n"
"- Синхронизиране на известия: Достъп до известията на телефона ви от вашия "
"компютър и отговаряне на съобщения.\n"
"- Мултимедийно дистанционно управление: Използвайте телефона си като "
"дистанционно за Linux медийни плейъри.\n"
"- WiFi връзка: не е необходим USB кабел или bluetooth.\n"
"- TLS криптиране от край до край: информацията ви е в безопасност.\n"
"\n"
"Моля, имайте предвид, че ще трябва да инсталирате KDE Connect на вашия "
"компютър, за да работи това приложение, и поддържайте версията за настолен "
"компютър актуална с версията за Android, за да работят най-новите функции.\n"
"\n"
"Поверителна информация за разрешения:\n"
"* Разрешение за достъпност: Изисква се за получаване на вход от друго "
"устройство за управление на вашия телефон с Android, ако използвате "
"функцията за отдалечено въвеждане.\n"
"* Разрешение за местоположение във фонов режим: Изисква се, за да знаете към "
"коя WiFi мрежа сте свързани, ако използвате функцията Trusted Networks.\n"
"\n"
"KDE Connect никога не изпраща никаква информация на KDE или на трета страна. "
"KDE Connect изпраща данни от едно устройство на друго директно чрез "
"локалната мрежа, никога през интернет, и чрез криптиране от край до край.\n"
"\n"
"Това приложение е част от проект с отворен код и съществува благодарение на "
"всички хора, които са допринесли за него. Посетете уебсайта, за да вземете "
"изходния код.\n"

View File

@@ -1,19 +0,0 @@
# SPDX-FileCopyrightText: 2024 Mincho Kondarev <mkondarev@yahoo.de>
#. extracted from ./metadata/android/en-US/short_description.txt
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-05 12:31+0000\n"
"PO-Revision-Date: 2024-07-28 18:32+0200\n"
"Last-Translator: Mincho Kondarev <mkondarev@yahoo.de>\n"
"Language-Team: Bulgarian <kde-i18n-doc@kde.org>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 24.07.70\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
msgid "KDE Connect integrates your smartphone and computer"
msgstr "KDE Connect интегрира вашия смартфон и компютър"

View File

@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2024 Vit Pelcak <vit@pelcak.org>
# SPDX-FileCopyrightText: 2024 Vit Pelcak <vpelcak@suse.cz>
#. extracted from ./metadata/android/en-US/short_description.txt
msgid ""
msgstr ""

View File

@@ -1,20 +1,42 @@
# SPDX-FileCopyrightText: 2023, 2024 Steve Allewell <steve.allewell@gmail.com>
# Steve Allewell <steve.allewell@gmail.com>, 2023.
#. extracted from ./metadata/android/en-US/full_description.txt
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-05 12:31+0000\n"
"PO-Revision-Date: 2024-05-24 19:25+0100\n"
"PO-Revision-Date: 2023-06-17 12:11+0100\n"
"Last-Translator: Steve Allewell <steve.allewell@gmail.com>\n"
"Language-Team: British English\n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 24.02.2\n"
"X-Generator: Lokalize 23.03.70\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, fuzzy
#| msgid ""
#| "KDE Connect provides a set of features to integrate your workflow across "
#| "devices:\n"
#| "\n"
#| "- Shared clipboard: copy and paste between your devices.\n"
#| "- Share files and URLs to your computer from any app.\n"
#| "- Get notifications for incoming calls and SMS messages on your PC.\n"
#| "- Virtual touchpad: Use your phone screen as your computer's touchpad.\n"
#| "- Notifications sync: Read your Android notifications from the desktop.\n"
#| "- Multimedia remote control: Use your phone as a remote for Linux media "
#| "players.\n"
#| "- WiFi connection: no USB wire or bluetooth needed.\n"
#| "- End-to-end TLS encryption: your information is safe.\n"
#| "\n"
#| "Please note you will need to install KDE Connect on your computer for "
#| "this app to work, and keep the desktop version up-to-date with the "
#| "Android version for the latest features to work.\n"
#| "\n"
#| "This app is part of an open source project and it exists thanks to all "
#| "the people who contributed to it. Visit the website to grab the source "
#| "code."
msgid ""
"KDE Connect provides a set of features to integrate your workflow across "
"devices:\n"
@@ -51,13 +73,11 @@ msgstr ""
"KDE Connect provides a set of features to integrate your workflow across "
"devices:\n"
"\n"
"- Transfer files between your devices.\n"
"- Access files on your phone from your computer, without wires.\n"
"- Shared clipboard: copy and paste between your devices.\n"
"- Get notifications for incoming calls and messages on your computer.\n"
"- Share files and URLs to your computer from any app.\n"
"- Get notifications for incoming calls and SMS messages on your PC.\n"
"- Virtual touchpad: Use your phone screen as your computer's touchpad.\n"
"- Notifications sync: Access your phone notifications from your computer and "
"reply to messages.\n"
"- Notifications sync: Read your Android notifications from the desktop.\n"
"- Multimedia remote control: Use your phone as a remote for Linux media "
"players.\n"
"- WiFi connection: no USB wire or bluetooth needed.\n"
@@ -67,15 +87,5 @@ msgstr ""
"app to work, and keep the desktop version up-to-date with the Android "
"version for the latest features to work.\n"
"\n"
"Sensitive permissions information:\n"
"* Accessibility permission: Required to receive input from another device to "
"control your Android phone, if you use the Remote Input feature.\n"
"* Background location permission: Required to know to which WiFi network you "
"are connected to, if you use the Trusted Networks feature.\n"
"\n"
"KDE Connect never sends any information to KDE nor to any third party. KDE "
"Connect sends data from one device to the other directly using the local "
"network, never through the internet, and using end to end encryption.\n"
"\n"
"This app is part of an open source project and it exists thanks to all the "
"people who contributed to it. Visit the website to grab the source code.\n"
"people who contributed to it. Visit the website to grab the source code."

View File

@@ -1,20 +1,20 @@
#
# SPDX-FileCopyrightText: 2023, 2024 Xavier Besnard <xavier.besnard@kde.org>
# SPDX-FileCopyrightText: 2023 Xavier Besnard <xavier.besnard@kde.org>
#. extracted from ./metadata/android/en-US/full_description.txt
msgid ""
msgstr ""
"Project-Id-Version: kdeconnect-android-store-full\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-05 12:31+0000\n"
"PO-Revision-Date: 2024-08-09 22:07+0200\n"
"Last-Translator: Xavier Besnard <xavier.besnard@kde.org>\n"
"Language-Team: French <French <kde-francophone@kde.org>>\n"
"PO-Revision-Date: 2023-09-28 18:06+0200\n"
"Last-Translator: Xavier BESNARD <xavier.besnard@neuf.fr>\n"
"Language-Team: French <kde-francophone@kde.org>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Lokalize 23.08.5\n"
"X-Generator: Lokalize 23.08.1\n"
msgid ""
"KDE Connect provides a set of features to integrate your workflow across "
@@ -62,7 +62,7 @@ msgstr ""
"- Synchronisation de vos notifications : accès à vos notifications "
"téléphoniques depuis votre ordinateur et réponses aux messages.\n"
"- Télé-commande multimédia : utilisation de votre téléphone comme "
"télécommande pour les lecteurs de média sous Linux.\n"
"télécommande pour les lecteurs de médias sous Linux.\n"
"- Connexion au Wifi : aucun connexion USB ou Bluetooth nécessaire.\n"
"- Chiffrement « TLS » de bout en bout : vos informations sont en sécurité.\n"
"\n"
@@ -83,5 +83,5 @@ msgstr ""
"mais jamais par Internet et en utilisant le chiffrement de bout en bout.\n"
"\n"
"Cette application fait partie d'un projet « Open source ». Il existe grâce à "
"toutes les personnes qui y ont contribué. Veuillez visiter le site Internet "
"pour accéder au code source.\n"
"toutes les personnes qui y ont contribué.Visitez le site Internet pour "
"accéder au code source.\n"

View File

@@ -1,85 +0,0 @@
# Translation of kdeconnect-android-store-full to Norwegian Nynorsk
#
#. extracted from ./metadata/android/en-US/full_description.txt
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-05 12:31+0000\n"
"PO-Revision-Date: 2024-07-10 20:18+0200\n"
"Last-Translator: Karl Ove Hufthammer <karl@huftis.org>\n"
"Language-Team: Norwegian Nynorsk <l10n-no@lister.huftis.org>\n"
"Language: nn\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 24.05.1\n"
"X-Environment: kde\n"
"X-Accelerator-Marker: &\n"
"X-Text-Markup: kde4\n"
msgid ""
"KDE Connect provides a set of features to integrate your workflow across "
"devices:\n"
"\n"
"- Transfer files between your devices.\n"
"- Access files on your phone from your computer, without wires.\n"
"- Shared clipboard: copy and paste between your devices.\n"
"- Get notifications for incoming calls and messages on your computer.\n"
"- Virtual touchpad: Use your phone screen as your computer's touchpad.\n"
"- Notifications sync: Access your phone notifications from your computer and "
"reply to messages.\n"
"- Multimedia remote control: Use your phone as a remote for Linux media "
"players.\n"
"- WiFi connection: no USB wire or bluetooth needed.\n"
"- End-to-end TLS encryption: your information is safe.\n"
"\n"
"Please note you will need to install KDE Connect on your computer for this "
"app to work, and keep the desktop version up-to-date with the Android "
"version for the latest features to work.\n"
"\n"
"Sensitive permissions information:\n"
"* Accessibility permission: Required to receive input from another device to "
"control your Android phone, if you use the Remote Input feature.\n"
"* Background location permission: Required to know to which WiFi network you "
"are connected to, if you use the Trusted Networks feature.\n"
"\n"
"KDE Connect never sends any information to KDE nor to any third party. KDE "
"Connect sends data from one device to the other directly using the local "
"network, never through the internet, and using end to end encryption.\n"
"\n"
"This app is part of an open source project and it exists thanks to all the "
"people who contributed to it. Visit the website to grab the source code.\n"
msgstr ""
"KDE Connect tilbyr eit sett funksjonar som lèt deg enkelt arbeida på tvers "
"av einingar:\n"
"\n"
" Overfør filer mellom einingane\n"
" Få trådlaus tilgang til filer på telefonen frå datamaskina\n"
" Del utklippsbilete: kopier og lim inn mellom einingane\n"
" Vert varsla på datamaskina om innkommande samtalar og tekstmeldingar\n"
" Virtuell styreplate: bruk telefon­skjermen som styreplate for datamaskina\n"
" Synkronisering av varslingar: få tilgang til telefon­varslingar frå "
"datamaskina og svar på meldingar\n"
" Fjernkontroll av medieavspeling: bruk telefonen til å styra Linux-baserte "
"mediespelarar\n"
" Wi-Fi-tilkopling: du treng ikkje USB- eller Bluetooth-tilkopling\n"
" Ende-til-ende-kryptering: informasjonen din er trygg\n"
"\n"
"Merk at du må installera KDE Connect på datamaskina for å kunna bruka appen. "
"Hugs å halda PC-versjonen oppdatert med Android-versjonen for tilgang til "
"dei nyaste funksjonane.\n"
"\n"
"Informasjon om sensitive løyve:\n"
" Tilgjenge-løyve: Trengst for å kunna ta imot tastetrykk frå PC for å styra "
"Android-eininga om du brukar funksjonen «Fjernstyring»\n"
" Bakgrunns­løyve til å sjå geografiske posisjon: Trengst for å veta kva Wi-"
"Fi-nettverk du er tilkopla om du brukar funksjonen «Tiltrudde nettverk»\n"
"\n"
"KDE Connect sender aldri informasjon til KDE eller nokon tredjepart. "
"Programmet sender data direkte mellom dei to einingane via lokalnettet, "
"aldri via Internett og alltid med ende-til-ende-kryptering.\n"
"\n"
"Appen er ein del av eit fri programvare-prosjekt og er blitt til takka vera "
"mange bidragsytarar. Gå til heimesida for å sjå kjeldekoden.\n"

View File

@@ -12,6 +12,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 23.04.3\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"

View File

@@ -12,6 +12,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 23.04.3\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"

View File

@@ -1,21 +1,53 @@
# Geraldo Simiao <geraldosimiao@fedoraproject.org>, 2023.
# Frederico Goncalves Guimaraes <frederico@teia.bio.br>, 2024.
#. extracted from ./metadata/android/en-US/full_description.txt
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-05 12:31+0000\n"
"PO-Revision-Date: 2024-08-28 17:37-0300\n"
"Last-Translator: Frederico Goncalves Guimaraes <frederico@teia.bio.br>\n"
"PO-Revision-Date: 2023-08-04 01:33-0300\n"
"Last-Translator: Geraldo Simiao <geraldosimiao@fedoraproject.org>\n"
"Language-Team: Brazilian Portuguese <kde-i18n-pt_BR@kde.org>\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 22.12.3\n"
"X-Generator: Lokalize 23.04.3\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#, fuzzy
#| msgid ""
#| "KDE Connect provides a set of features to integrate your workflow across "
#| "devices:\n"
#| "\n"
#| "- Shared clipboard: copy and paste between your devices.\n"
#| "- Share files and URLs to your computer from any app.\n"
#| "- Get notifications for incoming calls and SMS messages on your PC.\n"
#| "- Virtual touchpad: Use your phone screen as your computer's touchpad.\n"
#| "- Notifications sync: Read your Android notifications from the desktop.\n"
#| "- Multimedia remote control: Use your phone as a remote for Linux media "
#| "players.\n"
#| "- WiFi connection: no USB wire or bluetooth needed.\n"
#| "- End-to-end TLS encryption: your information is safe.\n"
#| "\n"
#| "Please note you will need to install KDE Connect on your computer for "
#| "this app to work, and keep the desktop version up-to-date with the "
#| "Android version for the latest features to work.\n"
#| "\n"
#| "Sensitive permissions information:\n"
#| "* Accessibility permission: Required to receive input from another device "
#| "to control your Android phone, if you use the Remote Input feature.\n"
#| "* Background location permission: Required to know to which WiFi network "
#| "you are connected to, if you use the Trusted Networks feature.\n"
#| "\n"
#| "KDE Connect never sends any information to KDE nor to any third party. "
#| "KDE Connect sends data from one device to the other directly using the "
#| "local network, never through the internet, and using end to end "
#| "encryption.\n"
#| "\n"
#| "This app is part of an open source project and it exists thanks to all "
#| "the people who contributed to it. Visit the website to grab the source "
#| "code.\n"
msgid ""
"KDE Connect provides a set of features to integrate your workflow across "
"devices:\n"
@@ -52,16 +84,15 @@ msgstr ""
"O KDE Connect fornece um conjunto de recursos para integrar seu fluxo de "
"trabalho entre dispositivos:\n"
"\n"
"- Transfira arquivos entre seus dispositivos.\n"
"- Acesse arquivos do seu computador no seu telefone, sem fios.\n"
"- Área de transferência compartilhada: copie e cole entre seus "
"dispositivos.\n"
"- Compartilhe arquivos e URLs em seu computador a partir de qualquer app.\n"
"- Receba notificações de chamadas recebidas e mensagens SMS no seu PC.\n"
"- Touchpad virtual: use a tela do telefone como touchpad do computador.\n"
"- Sincronização de notificações: acesse as notificações do seu telefone no "
"seu computador e responda as mensagens.\n"
"- Sincronização de notificações: leia as notificações do seu Android na área "
"de trabalho.\n"
"- Controle remoto multimídia: use seu telefone como controle remoto para "
"reprodutores de mídia no Linux.\n"
"reprodutores de mídia Linux.\n"
"- Conexão Wi-Fi: sem necessidade de cabos USB ou bluetooth.\n"
"- Criptografia TLS de ponta a ponta: suas informações estão seguras.\n"
"\n"
@@ -69,14 +100,14 @@ msgstr ""
"este aplicativo funcione e mantenha a versão para desktop atualizada com a "
"versão do Android para que os recursos mais recentes funcionem.\n"
"\n"
"Informações sobre permissões sensíveis:\n"
"Informações a respeito de permissões especiais :\n"
"* Permissão de acessibilidade: necessária para receber entrada de outro "
"dispositivo para controlar seu telefone Android, se você usar o recurso de "
"entrada remota.\n"
"* Permissão de localização em segundo plano: necessária para saber a qual "
"rede Wi-Fi você está conectado, se você usar o recurso de redes confiáveis.\n"
"\n"
"O KDE Connect nunca envia nenhuma informação ao KDE ou a terceiros. O KDE "
"O KDE Connect nunca envia nenhuma informação ao KDE nem a terceiros. O KDE "
"Connect envia dados de um dispositivo para outro diretamente usando a rede "
"local, nunca pela Internet e usando criptografia de ponta a ponta.\n"
"\n"

View File

@@ -7,4 +7,20 @@
<path
android:pathData="m0,0h108v108h-108z"
android:fillColor="@color/launcher_background"/>
<path
android:pathData="m0,0h108v108h-108z"
android:strokeAlpha="0.2"
android:fillAlpha="0.2">
<aapt:attr name="android:fillColor">
<gradient
android:startY="0"
android:endY="108"
android:startX="0"
android:endX="0"
android:type="linear">
<item android:offset="0" android:color="#FFFFFFFF"/>
<item android:offset="1" android:color="#00FFFFFF"/>
</gradient>
</aapt:attr>
</path>
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="320dp"
android:height="180dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:pathData="m0,0h320v108h-320z"
android:fillColor="@color/launcher_background"/>
</vector>

View File

@@ -1,104 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="320dp"
android:height="180dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.6666667"
android:scaleY="0.6666667"
android:translateX="18"
android:translateY="18">
<group android:scaleX="0.6525"
android:scaleY="1.16"
android:translateX="-10.395"
android:translateY="-8.64">
<group android:scaleX="0.8"
android:scaleY="0.8"
android:translateX="10.8"
android:translateY="10.8">
<path
android:pathData="M40,27L68,27A2,2 0,0 1,70 29L70,79A2,2 0,0 1,68 81L40,81A2,2 0,0 1,38 79L38,29A2,2 0,0 1,40 27z"
android:strokeWidth="1.73436">
<aapt:attr name="android:fillColor">
<gradient
android:startY="27"
android:startX="38"
android:endY="81"
android:endX="38"
android:type="linear">
<item android:offset="0" android:color="#FFF5F5F5"/>
<item android:offset="1" android:color="#FFF0F0F0"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m41,30h26v48h-26z"
android:strokeWidth="1.00241"
android:fillColor="#2d2d2d"/>
<path
android:pathData="M50.25,28.25L57.75,28.25A0.25,0.25 0,0 1,58 28.5L58,28.5A0.25,0.25 0,0 1,57.75 28.75L50.25,28.75A0.25,0.25 0,0 1,50 28.5L50,28.5A0.25,0.25 0,0 1,50.25 28.25z"
android:strokeWidth=".632455"
android:fillColor="#2d2d2d"/>
<path
android:pathData="m47.694,47.379c-0.04,0.004 -0.083,0.015 -0.113,0.045 0,0 -1.381,1.381 -1.381,1.381 -0.058,0.058 -0.065,0.147 -0.023,0.218 0,0 1.614,2.665 1.614,2.665 -0.287,0.482 -0.519,0.999 -0.683,1.547 0,0 -2.965,0.616 -2.965,0.616 -0.083,0.017 -0.143,0.096 -0.143,0.18v1.952c0,0.083 0.063,0.153 0.143,0.173 0,0 2.875,0.698 2.875,0.698 0.154,0.634 0.391,1.241 0.706,1.794 0,0 -1.667,2.538 -1.667,2.538 -0.046,0.071 -0.037,0.165 0.023,0.225 0,0 1.381,1.381 1.381,1.381 0.058,0.058 0.147,0.065 0.218,0.023 0,0 2.613,-1.584 2.613,-1.584 0.512,0.296 1.067,0.533 1.652,0.691 0,0 0.608,2.928 0.608,2.928 0.017,0.083 0.088,0.143 0.173,0.143h1.952c0.082,0 0.153,-0.055 0.173,-0.135 0,0 0.721,-2.943 0.721,-2.943 0.603,-0.163 1.171,-0.404 1.697,-0.713 0,0 2.575,1.689 2.575,1.689 0.071,0.046 0.165,0.037 0.225,-0.023 0,0 1.374,-1.381 1.374,-1.381 0.058,-0.058 0.073,-0.147 0.03,-0.218 0,0 -0.938,-1.547 -0.938,-1.547s-0.308,0.098 -0.308,0.098c-0.044,0.014 -0.094,-0.006 -0.12,-0.045 0,0 -0.593,-0.872 -1.366,-2.005 -0.925,1.81 -2.812,3.048 -4.985,3.048 -3.088,0 -5.593,-2.505 -5.593,-5.593 0,-2.271 1.358,-4.222 3.303,-5.098v-1.441c-0.354,0.124 -0.696,0.273 -1.021,0.45 -0.001,-0 0.001,-0.007 0,-0.007 0,0 -2.635,-1.727 -2.635,-1.727 -0.035,-0.023 -0.073,-0.027 -0.113,-0.023 0,0 0,0 0,-0zM55.659,43.85s-3.514,0.338 -3.514,0.338v14.475s3.476,-0.526 3.476,-0.526v-6.171s4.677,6.847 4.677,6.847 3.664,-1.164 3.664,-1.164 -4.79,-6.584 -4.79,-6.584 4.827,-6.209 4.827,-6.209 -3.739,-0.856 -3.739,-0.856 -4.64,6.209 -4.64,6.209 0.038,-6.359 0.038,-6.359z"
android:fillColor="#f2f2f2"/>
<path
android:pathData="m41,30h22l-18,45h-4z"
android:strokeAlpha="0.1"
android:fillAlpha="0.1">
<aapt:attr name="android:fillColor">
<gradient
android:startY="30"
android:startX="41"
android:endY="70"
android:endX="60"
android:type="linear">
<item android:offset="0" android:color="#FFFFFFFD"/>
<item android:offset="1" android:color="#00FFFFFD"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FF000000"
android:pathData="m38,78v1c0,1.108 0.892,2 2,2h28c1.108,0 2,-0.892 2,-2v-1c0,1.108 -0.892,2 -2,2h-28c-1.108,0 -2,-0.892 -2,-2z"
android:strokeAlpha="0.1"
android:strokeWidth="1.73436"
android:fillAlpha="0.1"/>
<path
android:pathData="m70,30v-1c0,-1.108 -0.892,-2 -2,-2h-28c-1.108,0 -2,0.892 -2,2v1c0,-1.108 0.892,-2 2,-2h28c1.108,0 2,0.892 2,2z"
android:strokeAlpha="0.5"
android:strokeWidth="1.73436"
android:fillColor="#fffff8"
android:fillAlpha="0.5"/>
</group>
</group>
<group android:scaleX="0.075"
android:scaleY="0.16"
android:translateX="40"
android:translateY="36">
<group android:translateY="153.93605">
<path android:pathData="M83.375,-0L58.03125,-0L39.453125,-40.609375L32.546875,-35.421875L32.546875,-0L9.796875,-0L9.796875,-102.8125L32.546875,-102.8125L32.546875,-56.734375Q33.546875,-59.765625,35.34375,-63Q37.15625,-66.234375,39.171875,-69.984375L58.75,-102.8125L83.375,-102.8125L55.734375,-56.875L83.375,-0Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M165.9375,-53.28125Q165.9375,-27.359375,153.84375,-13.671875Q141.75,0,119.859375,0L92.796875,0L92.796875,-102.8125L121.734375,-102.8125Q142.76562,-102.8125,154.34375,-90.0625Q165.9375,-77.328125,165.9375,-53.28125ZM142.46875,-52.421875Q142.46875,-68.6875,137.20312,-76.09375Q131.95312,-83.515625,121.734375,-83.515625L115.546875,-83.515625L115.546875,-19.4375L120.15625,-19.4375Q131.67188,-19.4375,137.0625,-27.578125Q142.46875,-35.71875,142.46875,-52.421875Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M234.34375,0L182.79688,0L182.79688,-102.8125L234.34375,-102.8125L234.34375,-83.8125L205.54688,-83.8125L205.54688,-62.78125L232.1875,-62.78125L232.1875,-43.78125L205.54688,-43.78125L205.54688,-19.296875L234.34375,-19.296875L234.34375,0Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M318.67188,-84.953125Q309.59375,-84.953125,304.84375,-75.671875Q300.09375,-66.390625,300.09375,-51.125Q300.09375,-34.84375,304.98438,-26.421875Q309.89062,-18,319.6875,-18Q325.01562,-18,330.04688,-19.65625Q335.09375,-21.3125,340.26562,-23.90625L340.26562,-4.03125Q329.76562,1.4375,316.51562,1.4375Q296.78125,1.4375,286.625,-12.453125Q276.48438,-26.359375,276.48438,-51.265625Q276.48438,-66.8125,281.29688,-78.765625Q286.125,-90.71875,295.26562,-97.484375Q304.42188,-104.25,317.51562,-104.25Q331.34375,-104.25,343.73438,-97.34375L337.25,-78.90625Q332.78125,-81.5,328.25,-83.21875Q323.71875,-84.953125,318.67188,-84.953125Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M420.14062,-39.75Q420.14062,-28.375,416.6875,-19Q413.23438,-9.640625,405.8125,-4.09375Q398.40625,1.4375,386.59375,1.4375Q375.79688,1.4375,368.375,-4.03125Q360.95312,-9.5,357.14062,-18.859375Q353.32812,-28.21875,353.32812,-39.75Q353.32812,-51.84375,357,-61.046875Q360.67188,-70.265625,368.07812,-75.453125Q375.5,-80.640625,387.03125,-80.640625Q401.85938,-80.640625,411,-70.046875Q420.14062,-59.46875,420.14062,-39.75ZM375.5,-39.59375Q375.5,-28.21875,378.15625,-22.3125Q380.82812,-16.421875,386.875,-16.421875Q392.78125,-16.421875,395.375,-22.25Q397.96875,-28.078125,397.96875,-39.75Q397.96875,-51.265625,395.375,-56.953125Q392.78125,-62.640625,386.73438,-62.640625Q380.82812,-62.640625,378.15625,-56.953125Q375.5,-51.265625,375.5,-39.59375Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M474.95312,-80.640625Q485.76562,-80.640625,491.95312,-73.359375Q498.14062,-66.09375,498.14062,-51.84375L498.14062,0L476.25,0L476.25,-45.359375Q476.25,-53.421875,474.375,-57.59375Q472.51562,-61.78125,467.60938,-61.78125Q461.14062,-61.78125,458.76562,-55.9375Q456.39062,-50.109375,456.39062,-36.859375L456.39062,0L434.5,0L434.5,-79.203125L451.48438,-79.203125L454.07812,-69.125L455.23438,-69.125Q461.28125,-80.640625,474.95312,-80.640625Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M555.9531,-80.640625Q566.7656,-80.640625,572.9531,-73.359375Q579.1406,-66.09375,579.1406,-51.84375L579.1406,0L557.25,0L557.25,-45.359375Q557.25,-53.421875,555.375,-57.59375Q553.5156,-61.78125,548.6094,-61.78125Q542.1406,-61.78125,539.7656,-55.9375Q537.3906,-50.109375,537.3906,-36.859375L537.3906,0L515.5,0L515.5,-79.203125L532.4844,-79.203125L535.0781,-69.125L536.2344,-69.125Q542.28125,-80.640625,555.9531,-80.640625Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M625.4375,-80.5Q640.125,-80.5,648.2656,-71.0625Q656.40625,-61.625,656.40625,-44.5L656.40625,-33.265625L615.0781,-33.265625Q615.3594,-15.546875,630.625,-15.546875Q636.53125,-15.546875,641.6406,-16.984375Q646.75,-18.4375,652.375,-21.59375L652.375,-4.171875Q642.28125,1.4375,627.8906,1.4375Q610.75,1.4375,602.03125,-9Q593.3281,-19.4375,593.3281,-39.171875Q593.3281,-59.328125,601.6719,-69.90625Q610.03125,-80.5,625.4375,-80.5ZM626.0156,-64.078125Q621.40625,-64.078125,618.4531,-60.40625Q615.5,-56.734375,615.21875,-48.390625L636.2344,-48.390625Q636.2344,-55.875,633.5625,-59.96875Q630.90625,-64.078125,626.0156,-64.078125Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M699.15625,1.4375Q683.03125,1.4375,674.6719,-8.421875Q666.3281,-18.28125,666.3281,-39.171875Q666.3281,-58.03125,674.8906,-69.328125Q683.46875,-80.640625,700.03125,-80.640625Q706.6406,-80.640625,712.0469,-79.125Q717.4531,-77.609375,722.0625,-75.03125L715.8594,-57.890625Q711.96875,-59.90625,708.375,-61.046875Q704.78125,-62.203125,701.1719,-62.203125Q695.125,-62.203125,691.8125,-56.375Q688.5,-50.546875,688.5,-39.3125Q688.5,-27.9375,691.875,-22.390625Q695.2656,-16.84375,701.46875,-16.84375Q710.96875,-16.84375,720.0469,-23.46875L720.0469,-5.046875Q711.40625,1.4375,699.15625,1.4375Z"
android:fillColor="@android:color/primary_text_light"/>
<path android:pathData="M765.1719,-16.984375Q767.7656,-16.984375,770.34375,-17.625Q772.9375,-18.28125,775.8281,-19.578125L775.8281,-2.59375Q772.21875,-0.71875,767.8906,0.359375Q763.5781,1.4375,758.40625,1.4375Q747.4531,1.4375,741.9844,-4.75Q736.5156,-10.9375,736.5156,-24.90625L736.5156,-61.625L728.0156,-61.625L728.0156,-72.4375L738.2344,-78.625L743.71875,-95.46875L758.40625,-95.46875L758.40625,-79.203125L774.8125,-79.203125L774.8125,-61.625L758.40625,-61.625L758.40625,-25.484375Q758.40625,-16.984375,765.1719,-16.984375Z"
android:fillColor="@android:color/primary_text_light"/>
</group>
</group>
</group>
</vector>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<group android:pivotX="12" android:pivotY="12" android:scaleX="0.66" android:scaleY="0.66">
<path
android:fillColor="@android:color/white"
android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L8,20v2h8v-2h-2v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,4h18v12z" />
</group>
</vector>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:pivotX="12"
android:pivotY="12"
android:scaleX="0.66"
android:scaleY="0.66">
<path
android:fillColor="@android:color/white"
android:pathData="M20,18c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2H4C2.9,4 2,4.9 2,6v10c0,1.1 0.9,2 2,2H0v2h24v-2H20zM4,6h16v10H4V6z" />
</group>
</vector>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:pivotX="12"
android:pivotY="12"
android:scaleX="0.66"
android:scaleY="0.66">
<path
android:fillColor="@android:color/white"
android:pathData="M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM14,21h-4v-1h4v1zM17.25,18L6.75,18L6.75,4h10.5v14z" />
</group>
</vector>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:pivotX="12"
android:pivotY="12"
android:scaleX="0.66"
android:scaleY="0.66">
<path
android:fillColor="@android:color/white"
android:pathData="M21,4L3,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h18c1.1,0 1.99,-0.9 1.99,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM19,18L5,18L5,6h14v12z" />
</group>
</vector>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:pivotX="12"
android:pivotY="12"
android:scaleX="0.66"
android:scaleY="0.66">
<path
android:fillColor="@android:color/white"
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z" />
</group>
</vector>

View File

@@ -40,6 +40,7 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
android:drawablePadding="5dp"
android:layout_marginBottom="8dip"
android:importantForAccessibility="no"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceMedium"
app:drawableStartCompat="@drawable/ic_key" />

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_banner_background"/>
<foreground android:drawable="@drawable/ic_launcher_banner_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -83,7 +83,9 @@
<string name="error_canceled_by_user">ألغاه المستخدم</string>
<string name="error_canceled_by_other_peer">ألغاه ندّ آخر</string>
<string name="encryption_info_title">معلومات التّعمية</string>
<string name="encryption_info_msg_no_ssl">لا يستخدم الجهاز الآخر إصدارة حديثة من «كِيدِي المتّصل»، ستُستخدم طريقة التّعمية القديمة.</string>
<string name="pair_requested">طُلب الاقتران</string>
<string name="pairing_request_from">طلب اقتران من %1s</string>
<string name="tap_to_open">اطرق لتفتح</string>
<string name="received_file_text">المس لفتح \'%1s\'</string>
<string name="tap_to_answer">المس للإجابة</string>

View File

@@ -115,9 +115,11 @@
<string name="error_canceled_by_user">İstifadəçi ləğv etdi</string>
<string name="error_canceled_by_other_peer">Digər istifadəçi ləğv etdi</string>
<string name="encryption_info_title">Şifrələmə məlumatı</string>
<string name="encryption_info_msg_no_ssl">Digər cihaz köhnə şifrələmə metodu istifadə edən KDE Connect\'in sonuncu versiyasını istifadə etmir.</string>
<string name="my_device_fingerprint">Cihazınızın sertifikatının SHA256 şifrə izi:</string>
<string name="remote_device_fingerprint">Uzaq cihaz sertifikatının SHA256 şifrə izi:</string>
<string name="pair_requested">Qoşulma soruşuldu</string>
<string name="pairing_request_from">%1s tərəfindən qoşulma sorğusu</string>
<plurals name="incoming_file_title">
<item quantity="one">%1$d fayl %2$s\'dn alınır</item>
<item quantity="other">%1$d fayl %2$s\'dn alınır</item>

View File

@@ -118,6 +118,7 @@
<string name="error_canceled_by_user">Отхвърлена от потребителя</string>
<string name="error_canceled_by_other_peer">Отказана от другата страна</string>
<string name="encryption_info_title">Информация за криптиране</string>
<string name="encryption_info_msg_no_ssl">Другото устройство не използва последна версия на KDE Connect, като използва остарял метод на криптиране.</string>
<string name="my_device_fingerprint">SHA256 отпечатък на сертификата на вашето устройство е:</string>
<string name="remote_device_fingerprint">SHA256 отпечатък на сертификата на отдалеченото устройство е:</string>
<string name="pair_requested">Заявено е сдвояване</string>
@@ -403,7 +404,6 @@
<string name="maxim_leshchenko_task">Подобрения на потребителския интерфейс и тази страница за</string>
<string name="holger_kaelberer_task">Плъгин за отдалечена клавиатура и поправки на грешки</string>
<string name="saikrishna_arcot_task">Поддръжка за използване на клавиатура в плъгина за отдалечено въвеждане, поправки на грешки и общи подобрения</string>
<string name="shellwen_chen_task">Внедряване на SFTP, подобряване на възможностите за поддръжка на този проект, поправки на грешки и общи подобрения</string>
<string name="everyone_else">Всички останали, които са допринесли за KDE Connect през годините</string>
<string name="send_clipboard">Изпращане на клипборд</string>
<string name="tap_to_execute">Докоснете, за да се изпълни</string>

View File

@@ -46,6 +46,7 @@
<string name="error_canceled_by_user">Prekinuo korisnik</string>
<string name="error_canceled_by_other_peer">Prekinuo drugi korisnik</string>
<string name="pair_requested">Uparivanje zatraženo</string>
<string name="pairing_request_from">Uparivanje zatraženo od %1s</string>
<string name="received_file_text">Kucni za otvaranje \'%1s\'</string>
<string name="tap_to_answer">Kucni za odgovor</string>
<string name="right_click">Pošalji Desni Klik</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Cancel·lat per l\'usuari</string>
<string name="error_canceled_by_other_peer">Cancel·lat per l\'altre parell</string>
<string name="encryption_info_title">Informació de l\'encriptatge</string>
<string name="encryption_info_msg_no_ssl">L\'altre dispositiu no usa una versió recent del KDE Connect, s\'utilitzarà el mètode d\'encriptatge antic.</string>
<string name="my_device_fingerprint">L\'empremta digital SHA256 del certificat del vostre dispositiu és:</string>
<string name="remote_device_fingerprint">L\'empremta digital SHA256 del certificat del dispositiu remot és:</string>
<string name="pair_requested">S\'ha demanat aparellar</string>
<string name="pair_succeeded">S\'ha aparellat correctament</string>
<string name="pairing_request_from">S\'ha demanat aparellar des de «%1s»</string>
<string name="pairing_request_from">S\'ha demanat aparellar des de %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">S\'està rebent %1$d fitxer des de %2$s</item>
<item quantity="other">S\'estan rebent %1$d fitxers des de %2$s</item>
@@ -366,7 +367,7 @@
<item>Clar</item>
<item>Fosc</item>
</string-array>
<string name="report_bug">Informeu d\'un error</string>
<string name="report_bug">Informa d\'un error</string>
<string name="donate">Donació de diners</string>
<string name="source_code">Codi font</string>
<string name="licenses">Llicències</string>
@@ -389,10 +390,8 @@
<string name="send_compose">Envia</string>
<string name="compose_send_title">Títol de l\'enviament</string>
<string name="open_compose_send">Redacta text</string>
<string name="double_tap_to_drag">Dos tocs per a arrossegar</string>
<string name="hold_to_drag">Mantenir premut per a arrossegar</string>
<string name="about_kde_about">&lt;h1&gt;Quant al&lt;/h1&gt; &lt;p&gt;El KDE és una comunitat mundial d\'enginyers, artistes, escriptors, traductors i creadors de programari compromesos amb el desenvolupament de &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;programari lliure&lt;/a&gt;. El KDE produeix l\'entorn d\'escriptori Plasma, centenars d\'aplicacions i moltes biblioteques de programari que els donen suport.&lt;/p&gt; &lt;p&gt;El KDE és una empresa en cooperativa: cap entitat controla la seva direcció o els productes. En el seu lloc, treballem junts per a aconseguir l\'objectiu comú de construir el millor programari lliure del món. Tothom hi és benvingut a &lt;a href=https://community.kde.org/Get_Involved&gt;unir-se i contribuir&lt;/a&gt; al KDE, inclosos vosaltres.&lt;/p&gt; Visiteu &lt;a href=https://www.kde.org/ca/&gt;https://www.kde.org/ca/&lt;/a&gt; per a obtenir més informació sobre la comunitat KDE i el programari que produïm.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Informeu dels errors o desitjos&lt;/h1&gt; &lt;p&gt;El programari sempre es pot millorar, i l\'equip del KDE està a punt per a fer-ho. No obstant això, l\'usuari, ha de dir-nos quan alguna cosa no funciona com s\'esperava o si podria fer-se millor.&lt;/p&gt; &lt;p&gt;El KDE té un sistema de seguiment d\'errors. Per a informar-ne d\'un, visiteu &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; o useu el botó «Informeu d\'un error» des de la pantalla Quant al.&lt;/p&gt; Si teniu un suggeriment de millora, podeu usar el sistema de seguiment d\'errors per a enregistrar el vostre desig. Assegureu-vos d\'usar la severitat anomenada «Llista de desitjos» (Wishlist).</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Informeu dels errors o desitjos&lt;/h1&gt; &lt;p&gt;El programari sempre es pot millorar, i l\'equip del KDE està a punt per a fer-ho. No obstant això, l\'usuari, ha de dir-nos quan alguna cosa no funciona com s\'esperava o si podria fer-se millor.&lt;/p&gt; &lt;p&gt;El KDE té un sistema de seguiment d\'errors. Per a informar-ne d\'un, visiteu &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; o useu el botó \"Informa d\'un error\" des de la pantalla Quant al.&lt;/p&gt; Si teniu un suggeriment de millora, podeu usar el sistema de seguiment d\'errors per a enregistrar el vostre desig. Assegureu-vos d\'usar la severitat anomenada \"Llista de desitjos\" (Wishlist).</string>
<string name="about_kde_join_kde">&lt;h1&gt;Uniu-vos al KDE&lt;/h1&gt; &lt;p&gt;No cal ser un desenvolupador de programari per a ser membre de l\'equip KDE. Podeu unir-vos als equips d\'idiomes que tradueixen la interfície dels programes. Podeu proporcionar gràfics, temes, sons i documentació millorada. Vosaltres decidiu!&lt;/p&gt; &lt;p&gt;Visiteu &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; per a obtenir informació sobre alguns projectes en què podeu participar-hi.&lt;/p&gt; Si us cal més informació o documentació, una visita a &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; us proporcionarà el que necessiteu.</string>
<string name="about_kde_support_kde">&lt;h1&gt;Contribució al KDE&lt;/h1&gt; &lt;p&gt;El programari KDE està i sempre estarà disponible de forma gratuïta, però la creació no està lliure de càrrecs.&lt;/p&gt; &lt;p&gt;Per a donar suport al desenvolupament, la comunitat KDE ha format la KDE e.V., una organització sense ànim de lucre legalment fundada a Alemanya. La KDE e.V. representa a la comunitat KDE en els assumptes legals i financers. Per a obtenir informació sobre la KDE e.V., vegeu &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt;.El KDE es beneficia de molts tipus de contribucions, inclosa la financera. Usem els fons per a reemborsar als membres i altra gent per les despeses que incorren col·laborant-hi. S\'usen més fons per al suport legal i l\'organització de les conferències i reunions.&lt;/p&gt; &lt;p&gt;Us animem a ajudar al KDE mitjançant donacions monetàries, usant un dels mitjans descrits a &lt;a href=https://kde.org/ca/community/donations/&gt;https://kde.org/ca/community/donations/&lt;/a&gt;.&lt;/p&gt;. Moltes gràcies per endavant per la vostra ajuda.</string>
<string name="maintainer_and_developer">Mantenidor i desenvolupador</string>
@@ -405,7 +404,6 @@
<string name="maxim_leshchenko_task">Millores en la IU i ha creat aquesta pàgina</string>
<string name="holger_kaelberer_task">Connector de teclat remot i esmenes d\'errors</string>
<string name="saikrishna_arcot_task">Suport per a usar el teclat en el connector d\'entrada remota, esmenes d\'errors i millores generals</string>
<string name="shellwen_chen_task">Millorar la seguretat d\'SFTP, millorar la mantenibilitat d\'aquest projecte, esmenes d\'errors i millores generals</string>
<string name="everyone_else">Tothom qui ha contribuït al KDE Connect al llarg dels anys</string>
<string name="send_clipboard">Envia el porta-retalls</string>
<string name="tap_to_execute">Toqueu per a executar</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Přerušeno uživatelem</string>
<string name="error_canceled_by_other_peer">Přerušeno druhým uživatelem</string>
<string name="encryption_info_title">Informace o šifrování</string>
<string name="encryption_info_msg_no_ssl">Druhé zařízení nepoužívá poslední verzi KDE Connect. Bude použita stará metoda šifrování.</string>
<string name="my_device_fingerprint">Otisk SHA256 certifikátu vašeho zařízení je:</string>
<string name="remote_device_fingerprint">Otisk certifikátu SHA256 vzdáleného zařízení je:</string>
<string name="pair_requested">Bylo vyžádáno párování</string>
<string name="pair_succeeded">Párování bylo úspěšné</string>
<string name="pairing_request_from">Požadavek o párování z \'%1s\'</string>
<string name="pairing_request_from">Požadavek o párování z %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Přijímám %1$d soubor z %2$s</item>
<item quantity="few">Přijímám %1$d soubory z %2$s</item>
@@ -202,12 +203,10 @@
<item>1 minuta</item>
<item>2 minuty</item>
</string-array>
<string name="mpris_notifications_explanation">Oprávnění k upozorněním je potřeba pro zobrazení vzdálených médií v upozorněních</string>
<string name="mpris_notification_settings_title">Obrazit oznámení pro ovládání médií</string>
<string name="mpris_notification_settings_summary">Umožnit ovládání přehrávače médií bez otevření KDE Connect</string>
<string name="share_to">Sdílet s...</string>
<string name="unreachable_device">%s (nedostupná)</string>
<string name="unreachable_device_url_share_text">URL sdílená s nedostupným zařízením budou zaslána jakmile se stane dostupným.\n\n</string>
<string name="protocol_version_newer">Toto zařízení používá novější verzi protokolu</string>
<string name="plugin_settings_with_name">Nastavení %s</string>
<string name="invalid_device_name">Neplatný název zařízení</string>
@@ -274,12 +273,10 @@
<string name="optional_permission_explanation">Pro zpřístupnění všech funkcí potřebujete další oprávnění</string>
<string name="plugins_need_optional_permission">Některé moduly mají vypnuté vlastnosti, kvůli nedostatečným oprávněním (ťukněte pro více informací):</string>
<string name="share_optional_permission_explanation">Pro příjem souborů je potřeba povolit přístup k úložišti</string>
<string name="share_notifications_explanation">Abyste mohli vidět průběh odesílání nebo přijímání souborů, potřebujete povolit upozornění</string>
<string name="telepathy_permission_explanation">Pro čtení a psaní SMS z počítače musíte udělit oprávnění k SMS</string>
<string name="telephony_permission_explanation">Pro zobrazení telefonátů v počítači musíte udělit oprávnění k záznamům telefonování a stavu telefonu</string>
<string name="telephony_optional_permission_explanation">Pro zobrazení jména kontaktu u telefonního čísla je potřeba udělit oprávnění ke kontaktům v telefonu</string>
<string name="contacts_permission_explanation">Pro sdílení knihy kontaktů s pracovním prostředím, musíte udělit přístup ke kontaktům</string>
<string name="contacts_per_device_confirmation">Kontakty vašeho zařízení budou zkopírovány do tohoto zařízení aby je bylo možné použít pro připojení aplikací pro SMS a dalších.</string>
<string name="select_ringtone">Vybrat vyzváněcí tón</string>
<string name="telephony_pref_blocked_title">Blokovaná čísla</string>
<string name="telephony_pref_blocked_dialog_desc">Nezobrazovat volání a SMS z těchto čísel. Prosím, zadejte pouze jedno slovo na řádek.</string>
@@ -309,7 +306,6 @@
<string name="runcommand_nosuchdevice">Není zde žádné takové zařízení</string>
<string name="runcommand_noruncommandplugin">Toto zařízení nemá povolený modul pro spouštění příkazů</string>
<string name="runcommand_category_device_controls_title">Ovládání zařízení</string>
<string name="runcommand_device_controls_summary">Pokud vaše zařízení podporuje Ovládání zařízení, zobrazí se zde příkazy, které jste nastavili.</string>
<string name="runcommand_name_as_title_title">Zobrazit název jako popisek</string>
<string name="pref_plugin_findremotedevice">Najít vzdálené zařízení</string>
<string name="pref_plugin_findremotedevice_desc">Prozvonit vzdálené zařízení</string>
@@ -401,8 +397,6 @@
<string name="clear_compose">Vyprázdnit</string>
<string name="send_compose">Odeslat</string>
<string name="open_compose_send">Napsat text</string>
<string name="double_tap_to_drag">Přetáhnout dvojitým ťuknutím</string>
<string name="hold_to_drag">Přetáhnout podržením</string>
<string name="about_kde_about">&lt;h1&gt;O KDE&lt;/h1&gt; &lt;p&gt;KDE je celosvětová komunita softwarových inženýrů, výtvarníků, překladatelů a jiných přispěvatelů, kteří se odevzdali vývoji &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Svobodného Softwaru&lt;/a&gt;. KDE vytvořilo pracovní prostředí Plasma, stovky aplikací a spousty knihoven, jenž je podporují. &lt;/p&gt; &lt;p&gt;KDE je společné úsilí, kde žádná společnost neřídí jeho směr nebo produkty. Namísto toho spolupracujeme na společném cíli jímž je vytvoření nejlepšího Free Softwaru. Každý je vítán aby &lt;a href=https://community.kde.org/Get_Involved&gt;se zapojil a přispíval&lt;/a&gt; do KDE, včetně vás. Více informací o komunitě KDE a softwaru, na kterém pracujeme najdete na &lt;/a&gt;$3&lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt;.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Hlaste chyby a návrhy&lt;/h1&gt; &lt;p&gt;Software je možno neustále vylepšovat a tým KDE je k tomu připraven. Avšak vy, uživatel, nám musíte sdělit, když něco nefunguje tak, jak by se očekávalo nebo by mělo být uděláno lépe.&lt;/p&gt; &lt;p&gt;KDE má systém sledování chyb. Chcete-li tedy nahlásit chybu, navštivte &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; nebo použijte dialog \"Nahlásit chybu...\".&lt;/p&gt; Máte-li náměty na vylepšení, budeme rádi, pošlete-li nám svoje přání. Ujistěte se však, že jste označili chybové hlášení jako \"Přání\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Přidejte se ke KDE&lt;/h1&gt; &lt;p&gt;K tomu, abyste se stali členem týmu KDE, není zapotřebí být vývojářem softwaru. Můžete se připojit k překladatelským týmům, které překládají programy. Můžete vytvářet grafiku, motivy, zvuky a lepší dokumentaci. Vy se rozhodněte!&lt;/p&gt; &lt;p&gt;Navštivte &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; kde naleznete informace o některých projektech, kterých se můžete zúčastnit.&lt;/p&gt; Potřebujete-li více informací nebo dokumentace, pak návštěva na &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; vám poskytne, co potřebujete.&lt;/p&gt;České stránky o KDE se nacházejí na adrese &lt;a href=\"http://czechia.kde.org/\"&gt;http://czechia.kde.org/&lt;/a&gt; . Přidejte se k nám!</string>
@@ -417,17 +411,10 @@
<string name="maxim_leshchenko_task">Vylepšení prostředí a tato stránka o aplikaci</string>
<string name="holger_kaelberer_task">Vzdálené modul klávesnice a opravy chyb</string>
<string name="saikrishna_arcot_task">Podpora použití klávesnice na vzdáleném vstupním modulu, opravy chyb a obecná zlepšení</string>
<string name="shellwen_chen_task">Vylepšení zabezpečení SFTP, zlepšení udržovatelnosti projektu, opravy chyb a obecná vylepšení</string>
<string name="everyone_else">Každý kdo přispěl do KDE Connect během let</string>
<string name="send_clipboard">Poslat schránku</string>
<string name="tap_to_execute">Pro spuštění ťukněte sem</string>
<string name="plugin_stats">Statistiky modulů</string>
<string name="enable_udp_broadcast">Povolit prohledávání sítě UDP</string>
<string name="receive_notifications_permission_explanation">Je potřeba povolit oznámení aby e šlo přijímat z ostatních zařízení</string>
<string name="findmyphone_notifications_explanation">Oprávnění k upozorněním je potřeba aby telefon mohl zvonit když je aplikace na pozadí</string>
<string name="no_notifications">Upozornění jsou zakázána. Neuvidíte upozornění na párování.</string>
<string name="mpris_keepwatching">Pokračovat v přehrávání</string>
<string name="mpris_keepwatching_settings_title">Pokračovat v přehrávání</string>
<string name="mpris_keepwatching_settings_summary">Zobrazit tiché upozornění pro pokračování přehrávání na tomto zařízení po zavření médií</string>
<string name="notification_channel_keepwatching">Pokračovat v přehrávání</string>
</resources>

View File

@@ -67,7 +67,9 @@
<string name="error_canceled_by_user">Annulleret af brugeren</string>
<string name="error_canceled_by_other_peer">Annulleret af modpart</string>
<string name="encryption_info_title">Krypteringsinfo</string>
<string name="encryption_info_msg_no_ssl">Den anden enhed bruger ikke en nylig version af KDE Connect, og bruger dermed den forældede krypteringsmetode.</string>
<string name="pair_requested">Anmodet om parring</string>
<string name="pairing_request_from">Parringsanmodning fra %1s</string>
<string name="received_file_text">Tap for at åbne \"%1s\"</string>
<string name="tap_to_answer">Tap for at svare</string>
<string name="right_click">Send højreklik</string>

View File

@@ -112,9 +112,11 @@
<string name="error_canceled_by_user">Abbruch durch Benutzer</string>
<string name="error_canceled_by_other_peer">Abbruch durch Gegenstelle</string>
<string name="encryption_info_title">Verschlüsselungsinformationen</string>
<string name="encryption_info_msg_no_ssl">Das andere Gerät verwendet eine ältere Version von KDE Connect. Daher muss eine veraltete Verschlüsselungsmethode verwendet werden</string>
<string name="my_device_fingerprint">Der SHA256-Fingerabdruck Ihres Gerätezertifikats lautet:</string>
<string name="remote_device_fingerprint">Der SHA256-Fingerabdruck des Gerätezertifikats der Gegenstelle lautet:</string>
<string name="pair_requested">Verbindung angefordert</string>
<string name="pairing_request_from">Kopplungsanfrage von %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">%1$d Datei von %2$s wird empfangen</item>
<item quantity="other">%1$d Dateien von %2$s werden empfangen</item>

View File

@@ -100,9 +100,11 @@
<string name="error_canceled_by_user">Ακυρώθηκε από τον χρήστη</string>
<string name="error_canceled_by_other_peer">Ακυρώθηκε από άλλον χρήστη</string>
<string name="encryption_info_title">Πληροφορίες κρυπτογράφησης</string>
<string name="encryption_info_msg_no_ssl">Η άλλη συσκευή δεν χρησιμοποιεί μια πρόσφατη έκδοση του KDE Connect, θα χρησιμοποιηθεί η παλαιά μέθοδος κρυπτογράφησης.</string>
<string name="my_device_fingerprint">Το ίχνος SHA256 του πιστοποιητικού της συσκευής σας είναι:</string>
<string name="remote_device_fingerprint">Το ίχνος SHA256 του πιστοποιητικού της απομακρυσμένης συσκευής είναι:</string>
<string name="pair_requested">Ζητήθηκε σύζευξη</string>
<string name="pairing_request_from">Αίτημα σύζευξης από %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Ελήφθη %1$d αρχείο από %2$s`</item>
<item quantity="other">Ελήφθησαν %1$d αρχεία από %2$s</item>

View File

@@ -18,7 +18,6 @@
<string name="pref_plugin_clipboard_sent">Clipboard Sent</string>
<string name="pref_plugin_mousepad">Remote input</string>
<string name="pref_plugin_mousepad_desc">Use your phone or tablet as a touchpad and keyboard</string>
<string name="pref_plugin_presenter">Presentation remote</string>
<string name="pref_plugin_presenter_desc">Use your device to change slides in a presentation</string>
<string name="pref_plugin_remotekeyboard">Receive remote keypresses</string>
<string name="pref_plugin_remotekeyboard_desc">Receive keypress events from remote devices</string>
@@ -52,7 +51,6 @@
<string name="remotekeyboard_multiple_connections">There is more than one remote keyboard connection, select the device to configure</string>
<string name="open_mousepad">Remote input</string>
<string name="mousepad_info">Move a finger on the screen to move the mouse cursor. Tap for a click, and use two/three fingers for right and middle buttons. Use 2 fingers to scroll. Use a long press to drag and drop. Gyro mouse functionality can be enabled from plugin preferences</string>
<string name="mousepad_info_no_gestures">Move a finger on the screen to move the mouse cursor, tap for a click.</string>
<string name="mousepad_keyboard_input_not_supported">Keyboard input not supported by the paired device</string>
<string name="mousepad_single_tap_settings_title">Set one finger tap action</string>
<string name="mousepad_double_tap_settings_title">Set two finger tap action</string>
@@ -61,7 +59,6 @@
<string name="mousepad_mouse_buttons_title">Show mouse buttons</string>
<string name="mousepad_acceleration_profile_settings_title">Set pointer acceleration</string>
<string name="mousepad_scroll_direction_title">Reverse Scrolling Direction</string>
<string name="mousepad_scroll_sensitivity_title">Scroll sensitivity</string>
<string name="gyro_mouse_enabled_title">Enable gyroscope mouse</string>
<string name="gyro_mouse_sensitivity_title">Gyroscope sensitivity</string>
<string-array name="mousepad_tap_entries">
@@ -99,7 +96,6 @@
<string name="pref_plugin_mousepad_send_keystrokes">Send as keystrokes</string>
<string name="mouse_receiver_plugin_description">Receive remote mouse movement</string>
<string name="mouse_receiver_plugin_name">Mouse receiver</string>
<string name="mouse_receiver_no_permissions">To receive touch inputs remotely you need to grant Accessibility permissions to fully control your device</string>
<string name="view_status_title">Status</string>
<string name="battery_status_format">Battery: %d%%</string>
<string name="battery_status_low_format">Battery: %d%% Low Battery</string>
@@ -118,11 +114,11 @@
<string name="error_canceled_by_user">Cancelled by user</string>
<string name="error_canceled_by_other_peer">Cancelled by other peer</string>
<string name="encryption_info_title">Encryption Info</string>
<string name="encryption_info_msg_no_ssl">The other device doesn\'t use a recent version of KDE Connect, using the legacy encryption method.</string>
<string name="my_device_fingerprint">SHA256 fingerprint of your device certificate is:</string>
<string name="remote_device_fingerprint">SHA256 fingerprint of remote device certificate is:</string>
<string name="pair_requested">Pair requested</string>
<string name="pair_succeeded">Pair succeeded</string>
<string name="pairing_request_from">Pairing request from \'%1s\'</string>
<string name="pairing_request_from">Pairing request from %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Receiving %1$d file from %2$s</item>
<item quantity="other">Receiving %1$d files from %2$s</item>
@@ -159,7 +155,6 @@
<string name="received_file_text">Tap to open \'%1s\'</string>
<string name="cannot_create_file">Cannot create file %s</string>
<string name="tap_to_answer">Tap to answer</string>
<string name="left_click">Send Left Click</string>
<string name="right_click">Send Right Click</string>
<string name="middle_click">Send Middle Click</string>
<string name="show_keyboard">Show Keyboard</string>
@@ -186,12 +181,8 @@
<item>1 minute</item>
<item>2 minutes</item>
</string-array>
<string name="mpris_notifications_explanation">The notifications permission is needed to show remote media in the notifications drawer</string>
<string name="mpris_notification_settings_title">Show media control notification</string>
<string name="mpris_notification_settings_summary">Allow controlling your media players without opening KDE Connect</string>
<string name="share_to">Share to…</string>
<string name="unreachable_device">%s (Unreachable)</string>
<string name="unreachable_device_url_share_text">URLs shared to an unreachable device will be delivered to it once it becomes reachable.\n\n</string>
<string name="protocol_version_newer">This device uses a newer protocol version</string>
<string name="plugin_settings_with_name">%s settings</string>
<string name="invalid_device_name">Invalid device name</string>
@@ -258,12 +249,10 @@
<string name="optional_permission_explanation">You need to grant extra permissions to enable all functions</string>
<string name="plugins_need_optional_permission">Some plugins have features disabled because of lack of permission (tap for more info):</string>
<string name="share_optional_permission_explanation">To receive files you need to allow storage access</string>
<string name="share_notifications_explanation">To see the progress when sending and receiving files you need to allow notifications</string>
<string name="telepathy_permission_explanation">To read and write SMS from your desktop you need to give permission to SMS</string>
<string name="telephony_permission_explanation">To see phone calls on the desktop you need to give permission to phone call logs and phone state</string>
<string name="telephony_optional_permission_explanation">To see a contact name instead of a phone number you need to give access to the phone\'s contacts</string>
<string name="contacts_permission_explanation">To share your contacts book with the desktop, you need to give contacts permission</string>
<string name="contacts_per_device_confirmation">Your phone contacts will be copied over to this device, so they can be used by the KDE Connect SMS app and other apps.</string>
<string name="select_ringtone">Select a ringtone</string>
<string name="telephony_pref_blocked_title">Blocked numbers</string>
<string name="telephony_pref_blocked_dialog_desc">Don\'t show calls and SMS from these numbers. Please specify one number per line</string>
@@ -281,9 +270,6 @@
<string name="notification_channel_default">Other notifications</string>
<string name="notification_channel_persistent">Persistent indicator</string>
<string name="notification_channel_media_control">Media control</string>
<string name="notification_channel_filetransfer">Incoming file transfer</string>
<string name="notification_channel_filetransfer_upload">Outgoing file transfer</string>
<string name="notification_channel_filetransfer_error">File transfer error</string>
<string name="notification_channel_high_priority">High priority</string>
<string name="mpris_stop">Stop the current player</string>
<string name="copy_url_to_clipboard">Copy URL to clipboard</string>
@@ -292,10 +278,6 @@
<string name="runcommand_notpaired">Device is not paired</string>
<string name="runcommand_nosuchdevice">There is no such device</string>
<string name="runcommand_noruncommandplugin">This device does not have the Run Command Plugin enabled</string>
<string name="runcommand_category_device_controls_title">Device Controls</string>
<string name="runcommand_device_controls_summary">If your device supports Device Controls, commands you have configured will appear there.</string>
<string name="set_runcommand_name_as_title">set_runcommand_name_as_title</string>
<string name="runcommand_name_as_title_title">Show name as title</string>
<string name="pref_plugin_findremotedevice">Find remote device</string>
<string name="pref_plugin_findremotedevice_desc">Ring your remote device</string>
<string name="ring">Ring</string>
@@ -389,11 +371,8 @@
<string name="send_compose">Send</string>
<string name="compose_send_title">Compose send</string>
<string name="open_compose_send">Compose text</string>
<string name="double_tap_to_drag">Double tap to drag</string>
<string name="hold_to_drag">Hold to drag</string>
<string name="about_kde_about">&lt;h1&gt;About&lt;/h1&gt; &lt;p&gt;KDE is a world-wide community of software engineers, artists, writers, translators and creators who are committed to &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Free Software&lt;/a&gt; development. KDE produces the Plasma desktop environment, hundreds of applications, and the many software libraries that support them.&lt;/p&gt; &lt;p&gt;KDE is a cooperative enterprise: no single entity controls its direction or products. Instead, we work together to achieve the common goal of building the world\'s finest Free Software. Everyone is welcome to &lt;a href=https://community.kde.org/Get_Involved&gt;join and contribute&lt;/a&gt; to KDE, including you.&lt;/p&gt; Visit &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; for more information about the KDE community and the software we produce.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Report Bugs or Wishes&lt;/h1&gt; &lt;p&gt;Software can always be improved, and the KDE team is ready to do so. However, you - the user - must tell us when something does not work as expected or could be done better.&lt;/p&gt; &lt;p&gt;KDE has a bug tracking system. Visit &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; or use the \"Report Bug\" button from the about screen to report bugs.&lt;/p&gt; If you have a suggestion for improvement then you are welcome to use the bug tracking system to register your wish. Make sure you use the severity called \"Wishlist\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Join KDE&lt;/h1&gt; &lt;p&gt;You do not have to be a software developer to be a member of the KDE team. You can join the language teams that translate program interfaces. You can provide graphics, themes, sounds, and improved documentation. You decide!&lt;/p&gt; &lt;p&gt;Visit &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; for information on some projects in which you can participate.&lt;/p&gt; If you need more information or documentation, then a visit to &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; will provide you with what you need.</string>
<string name="about_kde_support_kde">&lt;h1&gt;Support KDE&lt;/h1&gt; &lt;p&gt;KDE software is and will always be available free of charge, however creating it is not free.&lt;/p&gt; &lt;p&gt;To support development the KDE community has formed the KDE e.V., a non-profit organisation legally founded in Germany. KDE e.V. represents the KDE community in legal and financial matters. See &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; for information on KDE e.V.&lt;/p&gt; &lt;p&gt;KDE benefits from many kinds of contributions, including financial. We use the funds to reimburse members and others for expenses they incur when contributing. Further funds are used for legal support and organising conferences and meetings.&lt;/p&gt; &lt;p&gt;We would like to encourage you to support our efforts with a financial donation, using one of the ways described at &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt;.&lt;/p&gt; Thank you very much in advance for your support.</string>
<string name="maintainer_and_developer">Maintainer and developer</string>
<string name="developer">Developer</string>
@@ -405,17 +384,8 @@
<string name="maxim_leshchenko_task">UI improvements and this about page</string>
<string name="holger_kaelberer_task">Remote keyboard plugin and bug fixes</string>
<string name="saikrishna_arcot_task">Support for using the keyboard in the remote input plugin, bug fixes and general improvements</string>
<string name="shellwen_chen_task">Improve the security of SFTP, improve the maintainability of this project, bug fixes and general improvements</string>
<string name="everyone_else">Everyone else who has contributed to KDE Connect over the years</string>
<string name="send_clipboard">Send clipboard</string>
<string name="tap_to_execute">Tap to execute</string>
<string name="plugin_stats">Plugin stats</string>
<string name="enable_udp_broadcast">Enable UDP device discovery</string>
<string name="receive_notifications_permission_explanation">Notifications need to be allowed to receive them from other devices</string>
<string name="findmyphone_notifications_explanation">The notifications permission is needed so the phone can ring when the app is in the background</string>
<string name="no_notifications">Notifications are disabled, you won\'t receive incoming pair notifications.</string>
<string name="mpris_keepwatching">Continue playing</string>
<string name="mpris_keepwatching_settings_title">Continue playing</string>
<string name="mpris_keepwatching_settings_summary">Show a silent notification to continue playing on this device after closing media</string>
<string name="notification_channel_keepwatching">Continue playing</string>
</resources>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Nuligite de uzanto</string>
<string name="error_canceled_by_other_peer">Nuligite de alia kunulo</string>
<string name="encryption_info_title">Ĉifrada Informo</string>
<string name="encryption_info_msg_no_ssl">La alia aparato ne uzas lastatempan version de KDE Connect, uzante la heredan ĉifradan metodon.</string>
<string name="my_device_fingerprint">SHA256-fingrospuro de via aparato-atestilo estas:</string>
<string name="remote_device_fingerprint">SHA256-fingrospuro de atestilo de fora aparato estas:</string>
<string name="pair_requested">Parigo alpetiĝis</string>
<string name="pair_succeeded">Parigo sukcesis</string>
<string name="pairing_request_from">Pariga alpeto de \'%1s\'</string>
<string name="pairing_request_from">Pariga alpeto de %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Ricevante %1$d dosieron de %2$s</item>
<item quantity="other">Ricevante %1$d dosierojn de %2$s</item>
@@ -311,7 +312,7 @@
<string name="setting_persistent_notification">Montri konstantan sciigon</string>
<string name="setting_persistent_notification_oreo">Konstanta sciigo</string>
<string name="setting_persistent_notification_description">Frapi por aktivigi/malŝalti en Sciigaj agordoj</string>
<string name="extra_options">Kromaj elektebloj</string>
<string name="extra_options">Kromaj opcioj</string>
<string name="privacy_options">Privatecaj elektoj</string>
<string name="set_privacy_options">Agordu viajn privatecajn elektojn</string>
<string name="block_contents">Bloki enhavon de sciigoj</string>
@@ -390,9 +391,6 @@
<string name="compose_send_title">Verki sendon</string>
<string name="open_compose_send">Verki tekston</string>
<string name="about_kde_about">&lt;h1&gt;Pri&lt;/h1&gt; &lt;p&gt;KDE estas tutmonda komunumo de softvar-inĝenieroj, artistoj, verkistoj, tradukistoj kaj kreintoj kiuj engaĝiĝas al &lt;a href=https://www.gnu.org/philosophy/free -sw.html&gt;Disvolvado de Libera Programaro&lt;/a&gt;. KDE produktas la Plasma labortablan medion, centojn da aplikaĵoj, kaj la multajn programarajn bibliotekojn kiuj subtenas ilin.&lt;/p&gt; &lt;/p&gt;KDE estas kunlabora entrepreno: neniu unuopa ento stiras ĝian direkton aŭ produktojn. Anstataŭe, ni kunlaboras por atingi la komunan celon konstrui la plej bonan Liberan Programaron de la mondo. Ĉiuj bonvenas &lt;a href=https://community.kde.org/Get_Involved&gt;aliiĝi kaj kontribui&lt;/a&gt; al KDE, inkluzive de vi.&lt;/p&gt; Vizitu &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; por pliaj informoj pri la KDE-komunumo kaj la programaro, kiun ni produktas.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Raporti Cimojn aŭ Dezirojn&lt;/h1&gt; &lt;p&gt;Softvaro ĉiam povas esti plibonigita kaj la KDE-teamo pretas fari tion. Tamen, vi - la uzanto - devas diri al ni se io ne funkcias kiel atendite aŭ povus esti farata pli bone.&lt;/p&gt; &lt;p&gt;KDE havas cimraportan sistemon. Vizitu &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; aŭ uzu la butonon \"Raporti Cimon\" el la Pri-ekrano por raporti cimojn.&lt;/p&gt; Se vi havas sugeston por plibonigo, vi estas bonvena uzi la cimtrakan sistemon pro registri vian deziron. Certigu, ke vi uzas la severecon nomita \"Wishlist\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Kuniĝu al KDE&lt;/h1&gt; &lt;p&gt;Vi ne devas esti programisto por esti membro de la teamo KDE. Vi povas aliĝi al la lingvoteamoj kiuj tradukas program-interfacojn. Vi povas provizi grafikaĵojn, etosojn, sonojn, kaj plibonigitan dokumentadon. Vi decidas!&lt;/p&gt; &lt;p&gt;Vizitu &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; por informo pri iuj projektoj en kiuj vi povas partopreni.&lt;/p&gt; Se vi bezonas plian informon aŭ dorkmentadon, vizito al &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; provizos al vi kion vi bezonas.</string>
<string name="about_kde_support_kde">&lt;h1&gt;Subtenu KDE&lt;/h1&gt; &lt;p&gt;KDE-programaro estas kaj ĉiam estos senpage disponebla, tamen krei ĝin ne estas senpaga.&lt;/p&gt; &lt;p&gt;Por subteni evoluon, la KDE-komunumo formis la KDE e.V., neprofitcela organizaĵo laŭleĝe fondita en Germanio. KDE e.V. reprezentas la KDE-komunumon en juraj kaj financaj aferoj. Vidu &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; por informoj pri KDE e.V.&lt;/p&gt; &lt;p&gt;KDE profitas de multaj specoj de kontribuoj, inkluzive financajn. Ni uzas la financon por repagi membrojn kaj aliajn por elspezoj, kiujn ili faras kiam ili kontribuas. Pliaj monrimedoj estas uzataj por jura subteno kaj organizado de konferencoj kaj renkontiĝoj.&lt;/p&gt; &lt;p&gt; Ni ŝatus instigi vin subteni niajn klopodojn per financa donaco, uzante unu el la manieroj priskribitaj ĉe &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt;.&lt;/p&gt; Multan dankon anticipe pro via subteno.</string>
<string name="maintainer_and_developer">Prizorganto kaj programisto</string>
<string name="developer">Ellaboranto</string>
<string name="apple_support">subteno de macOS. Laborante pri iOS-subteno</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Cancelado por el usuario</string>
<string name="error_canceled_by_other_peer">Cancelado por la otra parte</string>
<string name="encryption_info_title">Información de cifrado</string>
<string name="encryption_info_msg_no_ssl">El otro dispositivo no dispone de una versión reciente de KDE Connect, se usará un método de cifrado antiguo.</string>
<string name="my_device_fingerprint">La huella digital SHA256 del certificado de su dispositivo es:</string>
<string name="remote_device_fingerprint">La huella digital SHA256 del certificado del dispositivo remoto es:</string>
<string name="pair_requested">Vinculación solicitada</string>
<string name="pair_succeeded">Vinculación exitosa</string>
<string name="pairing_request_from">Solicitud de vinculación de «%1s»</string>
<string name="pairing_request_from">Solicitud de vinculación de %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Recibiendo %1$d archivo desde %2$s</item>
<item quantity="other">Recibiendo %1$d archivos desde %2$s</item>
@@ -389,8 +390,6 @@
<string name="send_compose">Enviar</string>
<string name="compose_send_title">Componer envío</string>
<string name="open_compose_send">Componer texto</string>
<string name="double_tap_to_drag">Doble pulsación para arrastrar</string>
<string name="hold_to_drag">Mantener para arrastrar</string>
<string name="about_kde_about">&lt;h1&gt;Acerca de&lt;/h1&gt; &lt;p&gt;KDE es una comunidad global de ingenieros software, artistas, escritores, traductores y creadores que siguen el desarrollo de &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Software Libre&lt;/a&gt;. KDE produce el entorno de escritorio Plasma, cientos de aplicaciones y todas las librerías en las que se basan.&lt;/p&gt; &lt;p&gt;KDE es una empresa colaborativa: no hay una entidad única que controla sus productos o su dirección. En su lugar, trabajamos de manera conjunta para conseguir la meta común de construir el mejor software libre posible. Todo el mundo es bienvenido a &lt;a href=https://community.kde.org/Get_Involved&gt;unirse y contribuir&lt;/a&gt; a KDE, incluido usted.&lt;/p&gt; Visite &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; para más información sobre la comunidad KDE y el software que creamos.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Reporte errores o deseos&lt;/h1&gt; &lt;p&gt;El software siempre puede ser mejorado y el equipo de KDE está preparado para ello. Sin embargo, usted - el usuario - debe comunicarnos cuando algo no funciona como es esperado o que puede ser mejorado. &lt;/p&gt; &lt;p&gt; KDE tiene un sistema de traqueo de errores. Visite &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; o use el botón «Informar de fallo» en la ventana «Acerca de» para reportar errores.&lt;/p&gt; Si tiene una sugerencia de mejora entonces use el sistema de traqueo de errores para registrar su sugerencia. Asegúrese de que usa la severidad «Lista de deseos».</string>
<string name="about_kde_join_kde">&lt;h1&gt;Unirse a KDE&lt;/h1&gt; &lt;p&gt;No tiene por que ser un desarrollador de software para ser miembro del equipo KDE. Se puede unir a los equipos de traducción que traducen las interfaces de los programas. Puede proporcionar gráficos, temas, sonidos y mejorar la documentación. ¡Tú decides!&lt;/p&gt; &lt;p&gt;Visite &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; para más información sobre los proyectos en los que puede participar.&lt;/p&gt; Si necesita más información o documentación, entonces una visita a &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; le proporcionará la información que necesite.</string>
@@ -405,7 +404,6 @@
<string name="maxim_leshchenko_task">Mejoras en la UI y la página «Acerca de»</string>
<string name="holger_kaelberer_task">Complemento del teclado remoto y arreglos</string>
<string name="saikrishna_arcot_task">Soporte para usar el teclado en el complemento de entrada remota, arreglos y mejoras generales</string>
<string name="shellwen_chen_task">Mejoras en la seguridad de SFTP, mejoras en la mantenibilidad del proyecto, arreglos de fallos y mejoras generales.</string>
<string name="everyone_else">Todos los demás que han contribuido a KDE Connect a lo largo de su historia</string>
<string name="send_clipboard">Enviar al portapapeles</string>
<string name="tap_to_execute">Pulse para ejecutar</string>

View File

@@ -80,7 +80,9 @@
<string name="error_canceled_by_user">Kasutaja katkestas</string>
<string name="error_canceled_by_other_peer">Teine pool katkestas</string>
<string name="encryption_info_title">Krüptimise teave</string>
<string name="encryption_info_msg_no_ssl">Teine seade ei kasuta KDE Connecti uusimat versiooni ja tarvitab krüptimisel pärandmeetodit.</string>
<string name="pair_requested">Paardumise soov</string>
<string name="pairing_request_from">Paardumise soov seadmest %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Saadi %1$d fail seadmest %2$s</item>
<item quantity="other">Saadi %1$d faili seadmest %2$s</item>

View File

@@ -18,7 +18,6 @@
<string name="pref_plugin_clipboard_sent">Arbelekoa bidali da</string>
<string name="pref_plugin_mousepad">Urrutiko sarrera</string>
<string name="pref_plugin_mousepad_desc">Erabili zure telefonoa edo tableta ukimen-sagu eta teklatu gisa</string>
<string name="pref_plugin_presenter">Aurkezpenetarako urruneko agintea</string>
<string name="pref_plugin_presenter_desc">Erabili zure gailua aurkezpen bateko diapositibak aldatzeko</string>
<string name="pref_plugin_remotekeyboard">Jaso urruneko tekla-sakatzeak</string>
<string name="pref_plugin_remotekeyboard_desc">Jaso tekla-sakatze gertaerak urruneko gailuetatik</string>
@@ -52,7 +51,6 @@
<string name="remotekeyboard_multiple_connections">Urruneko teklatuekin konexio bat baino gehiago dago, hautatu konfiguratu beharreko gailua</string>
<string name="open_mousepad">Urruneko sarrera</string>
<string name="mousepad_info">Mugitu hatz bat pantailan zehar saguaren erakuslea mugitzeko. Egin tak klik baterako, eta erabili bi/hiru hatz eskuin eta erdiko botoietarako. Erabili 2 hatz kiribiltzeko. Erabili sakatze luze bat arrastatu eta jaregiteko. Saguaren giroskopio funtzionalitatea pluginen hobespenetatik gaitu daiteke.</string>
<string name="mousepad_info_no_gestures">Mugitu hatz bat pantailan kurtsorea mugitzeko, egin tak klik egiteko.</string>
<string name="mousepad_keyboard_input_not_supported">Parekatutako gailuak ez du teklatuko sarreraren euskarririk</string>
<string name="mousepad_single_tap_settings_title">Ezarri hatz bakarrarekin tak egitearen ekintza</string>
<string name="mousepad_double_tap_settings_title">Ezarri bi hatzez tak egitearen ekintza</string>
@@ -118,11 +116,11 @@
<string name="error_canceled_by_user">Erabiltzaileak utzita</string>
<string name="error_canceled_by_other_peer">Beste kideak utzita</string>
<string name="encryption_info_title">Zifratze informazioa</string>
<string name="encryption_info_msg_no_ssl">Beste gailuak ez du oraintsuko KDE Connect bertsio bat erabiltzen, erabili aurreko bertsioetako metodoa.</string>
<string name="my_device_fingerprint">Zure gailuaren ziurtagiriaren SHA256 hatz-marka:</string>
<string name="remote_device_fingerprint">Urruneko gailuaren ziurtagiriaren SHA256 hatz-marka hau da:</string>
<string name="pair_requested">Parekatzea eskatu da</string>
<string name="pair_succeeded">Parekatze arrakastatsua</string>
<string name="pairing_request_from">\'%1s\'(e)ren parekatzeko eskaria</string>
<string name="pairing_request_from">Parekatzeko eskaria %1s-tik</string>
<plurals name="incoming_file_title">
<item quantity="one">%2$s(e)tik fitxategi %1$d jasotzen</item>
<item quantity="other">%2$s(e)tik %1$d fitxategi jasotzen</item>
@@ -159,7 +157,6 @@
<string name="received_file_text">Tak egin \'%1s\' irekitzeko</string>
<string name="cannot_create_file">Ezin da sortu %s fitxategia</string>
<string name="tap_to_answer">Tak egin erantzuteko</string>
<string name="left_click">Bidali ezkerreko klik</string>
<string name="right_click">Bidali eskumako klik</string>
<string name="middle_click">Bidali erdiko klik</string>
<string name="show_keyboard">Erakutsi teklatua</string>
@@ -189,9 +186,6 @@
<string name="mpris_notifications_explanation">Urruneko euskarria jakinarazpen tiraderan erakusteko jakinarazpen-baimena behar da</string>
<string name="mpris_notification_settings_title">Erakutsi euskarri kontrolaren jakinarazpena</string>
<string name="mpris_notification_settings_summary">Utzi zure euskarri-jotzaileak kontrolatzen KDE Connect ireki gabe</string>
<string name="share_to">Partekatu honekin...</string>
<string name="unreachable_device">%s (eskuraezin)</string>
<string name="unreachable_device_url_share_text">Gailu eskuraezinekin partekatutako URLak, hartara bidaliko dira eskuragarri dagoenean.\n\n</string>
<string name="protocol_version_newer">Gailu honek protokoloaren bertsio berriago bat erabiltzen du</string>
<string name="plugin_settings_with_name">%s ezarpenak</string>
<string name="invalid_device_name">Gailuaren izen baliogabea</string>
@@ -389,8 +383,6 @@
<string name="send_compose">Bidali</string>
<string name="compose_send_title">Bidalketa osatu</string>
<string name="open_compose_send">Konposatu testua</string>
<string name="double_tap_to_drag">Tak bikoitza arrastatzeko</string>
<string name="hold_to_drag">Eutsi arrastatzeko</string>
<string name="about_kde_about">"&lt;h1&gt;Honi buruz&lt;/h1&gt; &lt;p&gt;KDE &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Software Askearen&lt;/a&gt; garapenarekin engaiatutako mundu osoko software ingeniari, artista, idazle, itzultzaile eta sortzaile elkarte bat da. KDEk Plasma mahaigain ingurunea, ehunka aplikazio, eta haiei euskarria ematen dieten liburutegi ugariak ekoizten ditu. &lt;/p&gt; &lt;p&gt;KDE ekimen kooperatibo bat da: ez dago bere norabidea eta produktuak kontrolatzen dituen erakunderik. Aldiz, elkarrekin lan egiten dugu guztiok partekatzen dugun helburu bera lortzeko, munduko Software Aske bikainena eraikitzearena alegia. Jende oro ongi etorria da KDErekin &lt;a href=https://community.kde.org/Get_Involved&gt;elkartu eta laguntza ematera&lt;/a&gt;, zu barne. &lt;/p&gt; Bisitatu &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; , KDE elkartearen eta ekoizten dugun softwarearen gaineko informazio zabalagoa eskuratzeko."</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Akatsen edo nahien berri ematea&lt;/h1&gt; &lt;p&gt;Softwarea beti hobetu daiteke, eta KDE taldea horretarako prest dago. Hala ere, zuk - erabiltzailea zaren horrek - zerbait behar bezala ez dabilenean edo hobeto egin daitekeenean esan egin behar diguzu.&lt;/p&gt; &lt;p&gt;KDEk programa-akatsen gaineko jarraipena egiteko sistema bat du. Bisitatu &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; edo erabili Honi buruz pantailako «Akatsa jakinarazi» botoia.&lt;/p&gt; Hobetzeko iradokizunik baduzu, akatsen jarraipen sisteman zure nahia erregistratzera gonbidatzen zaitugu. Larritasun maila bezala \"Wishlist\" (nahien zerrenda) erabil ezazu horretarako.</string>
<string name="about_kde_join_kde">"&lt;h1&gt;Zatoz KDEra&lt;/h1&gt; &lt;p&gt;Ez duzu software garatzailea izan behar KDEren taldeko kide izateko. Programen interfazeak itzultzen dituzten hizkuntzen taldeetara batu zaitezke. Grafikoak, gaiak, soinuak, eta dokumentazio hobetua eskain ditzakezu. Zeuk erabaki!&lt;/p&gt; &lt;p&gt;Bisitatu &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; parte hartu dezakezun proiektuen informazioa eskuratzeko.&lt;/p&gt; Informazio edo dokumentazio gehiago behar baduzu, &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; bisitatuz behar duzuna eskuratuko duzu."</string>
@@ -405,7 +397,6 @@
<string name="maxim_leshchenko_task">Erabiltzaile-interfazean hobekuntzak eta Honi buru orria hau</string>
<string name="holger_kaelberer_task">Urruneko teklatuaren plugina eta akatsen konponketa</string>
<string name="saikrishna_arcot_task">Urruneko sarrerako pluginean teklatua erabiltzeko euskarria, akatsen konponketa eta hobekuntza orokorrak</string>
<string name="shellwen_chen_task">SFTPren segurtasuna hobetu, proiektu honen mantentze-gaitasuna hobetu, akatsak konpondu eta hobekuntza orokorrak</string>
<string name="everyone_else">Urteetan KDE Connect-ekin lagundu duten gainerako guztiak</string>
<string name="send_clipboard">Bidali arbelekoa</string>
<string name="tap_to_execute">Tak egin exekutatzeko</string>
@@ -414,8 +405,4 @@
<string name="receive_notifications_permission_explanation">Jakinarazpenak baimendu behar dira beste gailuetatik haiek jasotzeko</string>
<string name="findmyphone_notifications_explanation">Aplikazioa atzeko planoan dagoenean telefonoak jo dezan jakinarazpen-baimena behar da</string>
<string name="no_notifications">Jakinarazpenak ezgaituta daude, ez duzu jasoko parekatzeko sarrerako jakinarazpenik.</string>
<string name="mpris_keepwatching">Jarraitu jotzen</string>
<string name="mpris_keepwatching_settings_title">Jarraitu jotzen</string>
<string name="mpris_keepwatching_settings_summary">Hedabidea itxi ondoren, gailu honetan jotzen jarraitzeko jakinarazpen ixil bat erakutsi.</string>
<string name="notification_channel_keepwatching">Jarraitu jotzen</string>
</resources>

View File

@@ -18,7 +18,6 @@
<string name="pref_plugin_clipboard_sent">Leikepöytä lähetetty</string>
<string name="pref_plugin_mousepad">Kauko-ohjaus</string>
<string name="pref_plugin_mousepad_desc">Käytä puhelinta tai tablettia hiirenä ja näppäimistönä</string>
<string name="pref_plugin_presenter">Esityskaukosäädin</string>
<string name="pref_plugin_presenter_desc">Käytä laitettasi esitysdiojen vaihtamiseen</string>
<string name="pref_plugin_remotekeyboard">Vastaanota etänäppäinpainallukset</string>
<string name="pref_plugin_remotekeyboard_desc">Vastaanottaa etälaitteiden näppäinpainallustapahtumat</string>
@@ -52,7 +51,6 @@
<string name="remotekeyboard_multiple_connections">Etänäppäimistöyhteyksiä on useampia: valitse asetettava laite</string>
<string name="open_mousepad">Kauko-ohjaus</string>
<string name="mousepad_info">Siirrä hiirikohdistinta liikuttamalla sormea näytöllä. Tee hiirenpainallus napauttamalla, ja käytä kahta tai kolmea sormea oikealle ja keskipainikkeelle. Vieritä kahdella sormella. Pitkällä painalluksella voit vetää ja pudottaa. Gyrohiiritoiminnon voi ottaa käyttää liitännäisen asetuksista</string>
<string name="mousepad_info_no_gestures">Siirrä hiiriosoitinta liikuttamalla sormea näytöllä, napautus napsauttaa.</string>
<string name="mousepad_keyboard_input_not_supported">Paritettu laite ei tue näppäimistösyötettä</string>
<string name="mousepad_single_tap_settings_title">Aseta yhden sormen napautuksen toiminto</string>
<string name="mousepad_double_tap_settings_title">Aseta kahden sormen napautuksen toiminto</string>
@@ -118,10 +116,11 @@
<string name="error_canceled_by_user">Käyttäjä perui</string>
<string name="error_canceled_by_other_peer">Vertaiskäyttäjä perui</string>
<string name="encryption_info_title">Salaustiedot</string>
<string name="encryption_info_msg_no_ssl">Toinen laite ei käytä KDE Connectin uudehkoa versiota, joten käytetään vanhaa salausmenetelmää.</string>
<string name="my_device_fingerprint">Laitevarmenteen SHA256-sormenjälki on:</string>
<string name="remote_device_fingerprint">Etälaitteen varmenteen SHA256-sormenjälki on:</string>
<string name="pair_requested">Paripyyntö</string>
<string name="pair_succeeded">Paritus onnistui</string>
<string name="pairing_request_from">Paripyyntö laitteesta %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Vastaanotetaan %1$d tiedosto lähettäjältä %2$s</item>
<item quantity="other">Vastaanotetaan %1$d tiedostoa lähettäjältä %2$s</item>
@@ -158,7 +157,6 @@
<string name="received_file_text">Avaa ”%1s” napauttamalla</string>
<string name="cannot_create_file">Ei voida luoda tiedostoa %s</string>
<string name="tap_to_answer">Vastaa napauttamalla</string>
<string name="left_click">Lähetä vasemman painikkeen napsautus</string>
<string name="right_click">Lähetä oikean painikkeen napsautus</string>
<string name="middle_click">Lähetä keskipainikkeen napsautus</string>
<string name="show_keyboard">Näytä näppäimistö</string>
@@ -387,7 +385,6 @@
<string name="open_compose_send">Kirjoita teksti</string>
<string name="about_kde_about">&lt;h1&gt;Tietoa&lt;/h1&gt; &lt;p&gt;KDE on ohjelmoijien, taiteilijoiden, kirjoittajien, kääntäjien ja muiden sisällönluojien kansainvälinen yhteisö, joka on sitoutunut &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;vapaiden ohjelmien&lt;/a&gt; kehitykseen. KDE tuottaa Plasma-työpöytäympäristöä, satoja sovelluksia ja monia niitä tukevia ohjelmakirjastoja.&lt;/p&gt; &lt;p&gt;KDE pyrkii yhteistyöhön: mikään yksittäinen toimija ei hallitse sen suuntaa tai tuotteita, vaan teemme yhdessä työtä yhteisen päämäärän hyväksi: tuottaaksemme maailman hienointa vapaata ohjelmistoa. Kaikki ovat tervetulleita &lt;a href=https://community.kde.org/Get_Involved&gt;liittymään ja avustamaan&lt;/a&gt; KDE:ta myös sinä.&lt;/p&gt; Sivulta &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; löytyy KDE-yhteisöstä ja tuottamistamme ohjelmista lisätietoa.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Ilmoita ohjelmavirheistä tai -toiveista&lt;/h1&gt; &lt;p&gt;Ohjelmia voi aina parantaa, ja KDE-yhteisö on siihen valmis. Sinun käyttäjän on kuitenkin kerrottava meille, kun jokin ei toimi odotetusti tai voisi toimia paremmin.&lt;/p&gt; &lt;p&gt;KDE:lla on virheenseurantajärjestelmä. Käy sivulla &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; tai käytä Tietoa-sivun painiketta ”Ilmoita ohjelmavirheestä”.&lt;/p&gt; Parannusehdotuksissakin olet tervetullut käyttämään virheenseurantajärjestelmää kirjataksesi toiveesi. Varmista, että käytät vakavuustasoa ”Wishlist”.</string>
<string name="about_kde_join_kde">&lt;h1&gt;Liity KDE:hen&lt;/h1&gt; &lt;p&gt;KDE-työryhmän jäseneksi tullakseen ei tarvitse olla ohjelmoija. Ohjelmien käyttöliittymien kääntämiseksi voi liittyä johonkin kansalliseen ryhmään, tuottaa grafiikkaa, teemoja tai ääniä tai parantaa ohjeistusta. Sinä päätät!&lt;/p&gt; &lt;p&gt;Sivulta &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; löytyy tietoa projekteista, joihin osallistua.&lt;/p&gt; Kaikki tarvittava lisätieto ja ohjeet löytyvät sivulta &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;.</string>
<string name="about_kde_support_kde">&lt;h1&gt;Tue KDE:tä&lt;/h1&gt; &lt;p&gt;KDE-ohjelmat ovat ja tulevat aina olemaan ilmaisia, mutta niiden luominen ei ole ilmaista.&lt;/p&gt; &lt;p&gt;Kehitystyön tukemiseksi KDE-yhteisö on muodostanut KDE e.V:n, voittoa tuottamattoman yhteisön, joka lain kannalta sijaitsee Saksassa. KDE e.V. edustaa KDE-yhteisöä laki- ja talousasioissa. Osoitteesta &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; löytyy KDE e.V:stä lisätietoa.&lt;/p&gt; &lt;p&gt;KDE voi hyötyä monenlaisista lahjoituksia, myös rahallisista. Varoja käytetään jäsenten ja muiden avustamiskulujen hyvittämiseen, lakitukeen ja konferenssien ja kokousten järjestämiseen.&lt;/p&gt; &lt;p&gt;Rohkaisemme sinua tukemaan pyrkimyksiämme rahalahjoituksella jollakin tavoista, jotka kuvataan osoitteessa &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt;.&lt;/p&gt; Kiitoksia tuestasi etukäteen!</string>
<string name="maintainer_and_developer">Ylläpitäjä ja kehittäjä</string>
<string name="developer">Kehittäjä</string>

View File

@@ -53,7 +53,7 @@
<string name="open_mousepad">Contrôle distant</string>
<string name="mousepad_info">Faites glisser votre doigt sur l\'écran pour déplacer le pointeur de la souris. Tapotez pour cliquer et utilisez deux / trois doigts pour les clics droit et centre. Utilisez 2 doigts pour faire un défilement. Faites un appui prolongé pour réaliser un glisser-déposer. La fonctionnalité de gyroscope de souris peut être activée à partir des préférences de module externe.</string>
<string name="mousepad_info_no_gestures">Faites glisser un doigt sur l\'écran pour déplacer le pointeur de souris. Tapotez sur l\'écran pour effectuer un clic.</string>
<string name="mousepad_keyboard_input_not_supported">La saisie par le clavier n\'est pas pris en charge par le périphérique associé.</string>
<string name="mousepad_keyboard_input_not_supported">La saisie par le clavier n\'est pas pris en charge par le périphérique appairée.</string>
<string name="mousepad_single_tap_settings_title">Définir une action pour tapotage avec un doigt</string>
<string name="mousepad_double_tap_settings_title">Action pour l\'appui à deux doigts</string>
<string name="mousepad_triple_tap_settings_title">Action pour l\'appui à trois doigts</string>
@@ -99,7 +99,7 @@
<string name="pref_plugin_mousepad_send_keystrokes">Envoyez comme appuis de touches</string>
<string name="mouse_receiver_plugin_description">Recevoir les mouvements de la souri distante</string>
<string name="mouse_receiver_plugin_name">Récepteur de souris</string>
<string name="mouse_receiver_no_permissions">Pour recevoir des entrées tactiles à distance, vous devez accorder des autorisations d\'accessibilité pour contrôler entièrement votre périphérique</string>
<string name="mouse_receiver_no_permissions">Pour recevoir des entrées tactiles à distance, vous devez accorder des autorisations daccessibilité pour contrôler entièrement votre périphérique</string>
<string name="view_status_title">État</string>
<string name="battery_status_format">Batterie : %d %%</string>
<string name="battery_status_low_format">Batterie : %d %% Batterie faible</string>
@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Annulé par l\'utilisateur</string>
<string name="error_canceled_by_other_peer">Annulé par un autre homologue</string>
<string name="encryption_info_title">Informations de chiffrement</string>
<string name="encryption_info_msg_no_ssl">Ce périphérique n\'utilise pas une version récente de KDEConnect qui utilise l\'ancienne méthode de chiffrement.</string>
<string name="my_device_fingerprint">L\'empreinte SHA256 du certificat de votre périphérique est :</string>
<string name="remote_device_fingerprint">L\'empreinte « SHA256 » du certificat du périphérique distant est :</string>
<string name="pair_requested">Paire demandée</string>
<string name="pair_succeeded">Appairage effectué avec succès</string>
<string name="pairing_request_from">Demande d\'association provenant de « %1s »</string>
<string name="pairing_request_from">Demande d\'association provenant de %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">%1$d fichier reçu de %2$s</item>
<item quantity="other">%1$d fichiers reçus de %2$s</item>
@@ -186,12 +187,12 @@
<item>1 minute</item>
<item>2 minutes</item>
</string-array>
<string name="mpris_notifications_explanation">Les permissions pour les notifications sont nécessaires pour afficher des média distants dans le panneau des notifications.</string>
<string name="mpris_notifications_explanation">Les permissions pour les notifications sont nécessaires pour afficher des supports distants dans le panneau des notifications</string>
<string name="mpris_notification_settings_title">Afficher la notification de contrôle du lecteur multimédia</string>
<string name="mpris_notification_settings_summary">Vous permet de contrôler vos lecteurs multimédia sans ouvrir KDEConnect.</string>
<string name="share_to">Partager vers…</string>
<string name="unreachable_device">%s (Inaccessible)</string>
<string name="unreachable_device_url_share_text">Les URL partagées vers un appareil inaccessible lui seront transmises une fois qu\'il re-deviendra accessible.\n\n</string>
<string name="unreachable_device_url_share_text">Les URL partagées vers un appareil inaccessible lui seront transmises une fois quil re-deviendra accessible.\n\n</string>
<string name="protocol_version_newer">Le périphérique utilise une version plus récente du protocole</string>
<string name="plugin_settings_with_name">Configuration %s</string>
<string name="invalid_device_name">Nom de périphérique non valable</string>
@@ -389,8 +390,6 @@
<string name="send_compose">Envoyer</string>
<string name="compose_send_title">Préparer l\'envoi</string>
<string name="open_compose_send">Composer du texte</string>
<string name="double_tap_to_drag">Tapotement double pour un glisser</string>
<string name="hold_to_drag">Maintenir pour faire glisser</string>
<string name="about_kde_about">&lt;h1&gt;A propos&lt;/h1&gt; &lt;p&gt;KDE est une communauté mondiale d\'ingénieurs en logiciel, d\'artistes d\'ingénieurs logiciels, d\'artistes, d\'écrivains, de traducteurs et de créateurs s\'engageant pour le développement de &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt; Logiciels libres &lt;/a &gt;. KDE développe l\'environnement de bureau Plasma, des centaines d\'applications, et les nombreuses bibliothèques logicielles les prenant en charge. KDE est une entreprise coopérative : aucune entité centrale ne contrôle sa direction ou ses produits. Au contraire, nous travaillons tous ensemble pour atteindre un objectif commun : construire le meilleur logiciel libre au monde. Tout le monde est est le bienvenu pour &lt;a href=https://community.kde.org/Get_Involved&gt;rejoindre et contribuer&lt;/a&gt; à KDE, y compris vous. &lt;/p&gt; Visitez &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; pour de plus amples informations sur la communauté KDE et les logiciels que nous développons.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Signaler des bogues ou des souhaits&lt;/h1&gt; &lt;p&gt; Les logiciels peuvent toujours être améliorés et l\'équipe KDE est prête à le faire. Cependant, vous - la personne utilisatrice - devez nous dire quand quelque chose ne fonctionne pas comme prévu ou pourrait être mieux fait. KDE dispose d\'un système de suivi des bogues. Visitez &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; ou utilisez le bouton bouton « Signaler un bogue » de la page « A propos » pour signaler les bogues. Si vous avez une suggestion d\'amélioration, vous pouvez aussi utiliser le système de suivi des bogues pour enregistrer votre souhait. Veuillez vous assurer de bien utiliser le niveau de gravité appelée « Liste de souhaits ».</string>
<string name="about_kde_join_kde">&lt;h1&gt;Rejoignez KDE&lt;/h1&gt; &lt;p&gt;Vous n\'avez pas besoin d\'être un développeur de logiciels pour être membre de l\'équipe de KDE. Vous pouvez rejoindre les équipes nationales qui traduisent les interfaces des programmes. Vous pouvez fournir des illustrations, des thèmes, des sons, et de la documentation améliorée. À vous de décider ! &lt;/p&gt; &lt;p&gt;Visitez la page &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; pour obtenir des informations sur certains projets auxquels vous pouvez participer.&lt;/p&gt; Si vous avez besoin de plus d\'informations ou de documentation, veuillez visitez la page &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;, qui vous fournira ce dont vous avez besoin.</string>
@@ -405,8 +404,7 @@
<string name="maxim_leshchenko_task">Améliorations de l\'interface utilisateur et de cette page d\'à propos</string>
<string name="holger_kaelberer_task">Corrections du module externe de clavier sans fil et de bogues</string>
<string name="saikrishna_arcot_task">Prise en charge de l\'utilisation du clavier dans le module d\'entrée à distance, corrections de bogues et améliorations générales</string>
<string name="shellwen_chen_task">Implémentation de la sécurité de SFTP, amélioration de la maintenabilité de ce projet, corrections de bogues et améliorations générales</string>
<string name="everyone_else">Toutes les autres personnes ayant contribué à KDEConnect depuis plusieurs années</string>
<string name="everyone_else">"Toutes les autres personnes ayant contribué KDEConnect depuis plusieurs années"</string>
<string name="send_clipboard">Envoyer le presse-papier</string>
<string name="tap_to_execute">Tapotez pour lancer</string>
<string name="plugin_stats">Statistiques des modules externes</string>
@@ -414,8 +412,4 @@
<string name="receive_notifications_permission_explanation">Les notifications doivent être autorisées pour en recevoir d\'autres périphériques</string>
<string name="findmyphone_notifications_explanation">Les permissions pour les notifications sont nécessaires pour que le téléphone puisse sonner lorsque l\'application s\'exécute en tâche de fond</string>
<string name="no_notifications">Les notifications sont désactivées,. Vous ne recevrez pas de notifications d\'appairages entrants.</string>
<string name="mpris_keepwatching">Continuer la lecture</string>
<string name="mpris_keepwatching_settings_title">Continuer la lecture</string>
<string name="mpris_keepwatching_settings_summary">Afficher une notification silencieuse pour continuer à jouer sur ce périphérique après la fermeture du média.</string>
<string name="notification_channel_keepwatching">Continuer la lecture</string>
</resources>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Cancelouno a persoa usuaria.</string>
<string name="error_canceled_by_other_peer">Cancelouse remotamente</string>
<string name="encryption_info_title">Información do cifrado</string>
<string name="encryption_info_msg_no_ssl">O outro dispositivo non usa unha versión recente de KDE Connect, usarase un método obsoleto de cifrado.</string>
<string name="my_device_fingerprint">A pegada SHA256 do certificado do seu dispositivo é:</string>
<string name="remote_device_fingerprint">A pegada SHA256 do certificado do dispositivo remoto é:</string>
<string name="pair_requested">Solicitude de emparellamento</string>
<string name="pair_succeeded">Emparellouse</string>
<string name="pairing_request_from">Solicitude de emparellamento de «%1s».</string>
<string name="pairing_request_from">Solicitude de emparellamento de %1s.</string>
<plurals name="incoming_file_title">
<item quantity="one">Recibindo %1$d ficheiro de %2$s</item>
<item quantity="other">Recibindo %1$d ficheiros de %2$s</item>
@@ -389,8 +390,6 @@
<string name="send_compose">Enviar</string>
<string name="compose_send_title">Preparar un envío</string>
<string name="open_compose_send">Escribir texto</string>
<string name="double_tap_to_drag">Toque dúas veces para arrastrar</string>
<string name="hold_to_drag">Manteña para arrastrar</string>
<string name="about_kde_about">"&lt;h1&gt;Sobre&lt;/h1&gt; &lt;p&gt;KDE é unha comunidade internacional de persoas dedicadas á enxeñaría de soporte lóxico, á arte, á documentación, á tradución e á creación, todas elas comprometidas co desenvolvemento de &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;soporte lóxico libre&lt;/a&gt;. KDE produce o contorno de escritorio Plasma, centos de aplicacións, e as moitas bibliotecas de soporte lóxico sobre as que estas están construídas.&lt;/p&gt; &lt;p&gt;KDE é un esforzo cooperativo: non hai unha única entidade que controle a súa dirección ou os seus produtos. No seu lugar, xuntámonos para traballar no obxectivo común de construír o mellor soporte lóxico libre do mundo. Todas as persoas son benvidas a &lt;a href=https://community.kde.org/Get_Involved&gt;unirse e colaborar&lt;/a&gt; en KDE, incluída vostede.&lt;/p&gt; Visite &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; para máis información sobre a comunidade KDE e o soporte lóxico que produce."</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Informe de fallos ou pida melloras&lt;/h1&gt; &lt;p&gt;O software sempre pode mellorarse, e o equipo de KDE está preparado para facelo. Porén, vostede, a persoa usuaria, ten que avisarnos cando algo non funciona como espera ou podería mellorarse.&lt;/p&gt; &lt;p&gt;KDE ten un sistema de seguimento de fallos. Visite &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; ou use o botón de «Informar dun fallo» da pantalla de información para informar dun fallo.&lt;/p&gt; Se ten unha suxestión de mellora tamén pode usar o sistema de seguimento de fallos para rexistrala. Asegúrese nese caso de usar a severidade «Lista de desexos».</string>
<string name="about_kde_join_kde">&lt;h1&gt;Únase a KDE&lt;/h1&gt; &lt;p&gt;Non necesita saber desenvolver software para formar parte do equipo de KDE. Pode unirse aos equipos de idiomas que traducen as interfaces dos programas. Pode fornecer imaxes, temas, sons, e mellorar a documentación. Vostede decide!&lt;/p&gt; &lt;p&gt;Visite &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; para informarse sobre os proxectos nos que pode participar.&lt;/p&gt; Se necesita máis información ou documentación, ten o que necesita en &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;.</string>
@@ -405,7 +404,6 @@
<string name="maxim_leshchenko_task">Melloras na UI e nesta páxina de información</string>
<string name="holger_kaelberer_task">Complemento de teclado remoto e correccións de fallos</string>
<string name="saikrishna_arcot_task">Posibilidade de usar o teclado no complemento de entrada remota, correccións de fallos e melloras xerais</string>
<string name="shellwen_chen_task">Mellorar a seguridade de SFTP, facilitar o mantemento do proxecto, correccións de fallos e melloras xerais.</string>
<string name="everyone_else">O resto de xente que colaborou en KDE Connect ao longo dos anos</string>
<string name="send_clipboard">Enviar o portapapeis</string>
<string name="tap_to_execute">Toque para executar</string>

View File

@@ -108,9 +108,11 @@
<string name="error_canceled_by_user">Megszakítva a felhasználó által</string>
<string name="error_canceled_by_other_peer">A másik partner megszakította</string>
<string name="encryption_info_title">Titkosítási információk</string>
<string name="encryption_info_msg_no_ssl">A másik eszköz nem használja a KDE Connect legújabb verzióját, régi titkosítási módszert lesz használva.</string>
<string name="my_device_fingerprint">Az eszköz tanúsítványának SHA256 ujjlenyomata:</string>
<string name="remote_device_fingerprint">A távoli eszköz tanúsítványának SHA256 ujjlenyomata:</string>
<string name="pair_requested">Párosítás kérve</string>
<string name="pairing_request_from">Párosítási kérés innen: %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">%1$d fájl fogadása innen: %2$s</item>
<item quantity="other">%1$d fájl fogadása innen: %2$s</item>

View File

@@ -201,7 +201,4 @@
<string name="receive_notifications_permission_explanation">Notificationes necessita esser permettite a reciper los ex altere dispositivos</string>
<string name="findmyphone_notifications_explanation">Le permission de notificationes es necessari assi que le telephono pote sonar quando le app es in le fundo</string>
<string name="no_notifications">Notificatione es dishabilitate, tu nonrecipera notificatioones de association in arrivata.</string>
<string name="mpris_keepwatching">"Continua a executar "</string>
<string name="mpris_keepwatching_settings_title">Continua a executar</string>
<string name="notification_channel_keepwatching">Continua a executar</string>
</resources>

View File

@@ -108,9 +108,11 @@
<string name="error_canceled_by_user">Dibatalkan oleh pengguna</string>
<string name="error_canceled_by_other_peer">Dibatalkan oleh kawan lain</string>
<string name="encryption_info_title">Info Enkripsi</string>
<string name="encryption_info_msg_no_ssl">Perangkat lain tidaklah menggunakan KDE Connect yang berversi saat ini, menggunakan metode enkripsi kuno.</string>
<string name="my_device_fingerprint">Sidik jari SHA256 pada sertifikat peranti adalah:</string>
<string name="remote_device_fingerprint">Sidik jari SHA256 pada sertifikat peranti jarak jauh adalah:</string>
<string name="pair_requested">Meminta sanding</string>
<string name="pairing_request_from">Minta penyandingan dari %1s</string>
<plurals name="incoming_file_title">
<item quantity="other">Menerima %1$d file dari %2$s</item>
</plurals>

View File

@@ -112,9 +112,11 @@
<string name="error_canceled_by_user">Hætt við af notanda</string>
<string name="error_canceled_by_other_peer">Hætt við af hinum notandanum</string>
<string name="encryption_info_title">Upplýsingar um dulritun</string>
<string name="encryption_info_msg_no_ssl">Hitt tækið notar ekki nýlega útgáfu af KDE-tengingar, notast við eldri dulritunaraðferð.</string>
<string name="my_device_fingerprint">SHA256-fingrafar af skilríki tækisins þíns er:</string>
<string name="remote_device_fingerprint">SHA256-fingrafar af skilríki fjartengda tækisins er:</string>
<string name="pair_requested">Beðið um pörun</string>
<string name="pairing_request_from">Beiðni um pörun frá %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Tek á móti %1$d skrá frá %2$s</item>
<item quantity="other">Tek á móti %1$d skrám frá %2$s</item>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Annullata dall\'utente</string>
<string name="error_canceled_by_other_peer">Annullata dal dispositivo remoto</string>
<string name="encryption_info_title">Informazioni di cifratura</string>
<string name="encryption_info_msg_no_ssl">L\'altro dispositivo non utilizza una versione recente di KDE Connect, utilizzando il metodo di cifratura precedente.</string>
<string name="my_device_fingerprint">L\'impronta digitale SHA256 del certificato di dispositivo è:</string>
<string name="remote_device_fingerprint">L\'impronta digitale SHA256 del certificato del dispositivo remoto è:</string>
<string name="pair_requested">Richiesta di associazione</string>
<string name="pair_succeeded">Associazione riuscita</string>
<string name="pairing_request_from">Richiesta di associazione da «%1s»</string>
<string name="pairing_request_from">Richiesta associazione da %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Ricezione di %1$d file da %2$s</item>
<item quantity="other">Ricezione di %1$d file da %2$s</item>
@@ -307,7 +308,7 @@
<string name="settings_rename">Nome dispositivo</string>
<string name="settings_dark_mode">Tema scuro</string>
<string name="settings_more_settings_title">Altre impostazioni</string>
<string name="settings_more_settings_text">Le impostazioni per dispositivo sono disponibili sotto «Impostazioni estensioni» dall\'interno del dispositivo.</string>
<string name="settings_more_settings_text">Le impostazioni per dispositivo sono disponibili sotto «Impostazione estensioni» dall\'interno del dispositivo.</string>
<string name="setting_persistent_notification">Mostra notifica persistente</string>
<string name="setting_persistent_notification_oreo">Notifica persistente</string>
<string name="setting_persistent_notification_description">Tocca per abilitare/disabilitare nelle impostazioni delle notifiche</string>
@@ -389,8 +390,6 @@
<string name="send_compose">Invia</string>
<string name="compose_send_title">Invio scorciatoia composita</string>
<string name="open_compose_send">Componi il testo</string>
<string name="double_tap_to_drag">Doppio tocco per trascinare</string>
<string name="hold_to_drag">Tieni premuto per trascinare</string>
<string name="about_kde_about">&lt;h1&gt;Informazioni&lt;/h1&gt; &lt;p&gt;KDE è una comunità mondiale di ingegneri del software, artisti, scrittori, traduttori e creatori che si impegnano a sviluppare &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;software libero&lt;/a&gt;. KDE produce l\'ambiente desktop Plasma, centinaia di applicazioni e le numerose librerie software che le supportano.&lt;/p&gt; &lt;p&gt;KDE è un\'impresa cooperativa: nessuna singola entità ne controlla la direzione o i prodotti. Invece, lavoriamo insieme per raggiungere l\'obiettivo comune di costruire il miglior software libero del mondo. Tutti sono invitati a &lt;a href=https://community.kde.org/Get_Involved&gt;unirsi e contribuire&lt;/a&gt; a KDE, incluso te.&lt;/p&gt; Visita &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; per ulteriori informazioni sulla comunità KDE e sul software che produciamo.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Segnala bug o desideri&lt;/h1&gt; &lt;p&gt;Il software può sempre essere migliorato e il team di KDE è pronto a farlo. Tuttavia, tu - l\'utente - devi dirci quando qualcosa non funziona come previsto o potrebbe essere fatto meglio.&lt;/p&gt; &lt;p&gt;KDE ha un sistema di tracciamento dei bug. Visita &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; oppure utilizza il pulsante «Segnala bug» dalla schermata delle informazioni per segnalare i bug.&lt;/p&gt; Se hai un suggerimento per il miglioramento, puoi utilizzare il sistema di tracciamento dei bug per registrare il tuo desiderio. Assicurati di utilizzare «Wishlist» per il campo Severity.</string>
<string name="about_kde_join_kde">&lt;h1&gt;Unisciti a KDE&lt;/h1&gt; &lt;p&gt;Non devi essere uno sviluppatore di software per essere un membro della squadra di KDE. Puoi unirti ai gruppi linguistici che traducono le interfacce dei programmi. Puoi fornire grafica, temi, suoni e documentazione migliorata. Decidi tu!&lt;/p&gt; &lt;p&gt;Visita &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; per informazioni su alcuni progetti a cui puoi partecipare.&lt;/p&gt; Se hai bisogno di ulteriori informazioni o di documentazione, visita &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; ti fornirà quello che ti serve.</string>
@@ -405,7 +404,6 @@
<string name="maxim_leshchenko_task">Miglioramenti all\'interfaccia utente e questa pagina informativa</string>
<string name="holger_kaelberer_task">Estensione della tastiera remota e correzioni di bug</string>
<string name="saikrishna_arcot_task">Supporto per l\'utilizzo della tastiera nell\'estensione di inserimento remoto, correzioni di bug e miglioramenti generali</string>
<string name="shellwen_chen_task">Migliora la sicurezza di SFTP, migliora la manutenibilità di questo progetto, correzioni di bug e miglioramenti generali</string>
<string name="everyone_else">Tutti gli altri che hanno contribuito a KDE Connect nel corso degli anni</string>
<string name="send_clipboard">Invia gli appunti</string>
<string name="tap_to_execute">Tocca per eseguire</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">בוטל על ידי המשתמש</string>
<string name="error_canceled_by_other_peer">בוטל מהצד השני</string>
<string name="encryption_info_title">פרטי הצפנה</string>
<string name="encryption_info_msg_no_ssl">המכשיר השני לא משתמש בגרסה עדכנית של KDE Connect, ייעשה שימוש בשיטת ההצפנה המיושנת.</string>
<string name="my_device_fingerprint">טביעת אצבע ב־SHA256 של אישור המכשיר שלך היא:</string>
<string name="remote_device_fingerprint">טביעת אצבע ב־SHA256 של אישור המכשיר המרוחק היא:</string>
<string name="pair_requested">התקבלה בקשת צימוד</string>
<string name="pair_succeeded">הצימוד הצליח</string>
<string name="pairing_request_from">בקשת צימוד מאת %1s</string>
<string name="pairing_request_from">בקשת צימוד מאת %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">התקבל קובץ %1$d מהמכשיר %2$s</item>
<item quantity="two">התקבלו %1$d קבצים מהמכשיר %2$s</item>
@@ -405,8 +406,6 @@
<string name="send_compose">שליחה</string>
<string name="compose_send_title">שליחה מחיבור</string>
<string name="open_compose_send">טקסט חיבור</string>
<string name="double_tap_to_drag">נקישה כפולה לגרירה</string>
<string name="hold_to_drag">החזקה לגרירה</string>
<string name="about_kde_about">&lt;h1&gt;על אודות&lt;/h1&gt; &lt;p&gt;KDE היא קהילה בינלאומית של מהנדסי תוכנה, כותבים, מתרגמים ויוצרים שמחויבים לפיתוח &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;תוכנה חופשית&lt;/a&gt;. מיזם KDE מפיק את סביבת שולחן העבודה פלזמה, מאות יישומים ומגוון רחב של ספריות תוכנה כדי לתמוך בהם.&lt;/p&gt; &lt;p&gt;KDE הוא תאגיד חברתי: אף ישות יחידה לא שולטת בכיוון או במוצרים. במקום, אנו פעולים יחד כדי להגיע ליעדנו המשותף: לבנות את התוכנה החופשית הטובה בעולם. כולם מוזמנים &lt;a href=https://community.kde.org/Get_Involved&gt;להצטרף ולתרום&lt;/a&gt; ל־KDE, כולל אותך.&lt;/p&gt; כדאי לבקר באתר &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; למידע נוסף על קהילת KDE ועל התוכנה שאנו מפיקים.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;דיווח על תקלות או משאלות&lt;/h1&gt; &lt;p&gt;תוכנות תמיד יכולות להשתפר וצוות KDE ערוך לכך. עם זאת, אנו זקוקים לך - המשתמש או המשתמשת - כדי לספר לנו מתי משהו לא עובד כצפוי או עשוי לעבוד טוב יותר.&lt;/p&gt; &lt;p&gt;ל־KDE יש מערכת מעקב אחר תקלות. יש לבקר ב־&lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; או להשתמש בכפתור „דיווח על תקלה” ממסך על אודות כדי לדווח על תקלות.&lt;/p&gt; אם יש לך הצעה לשיפור, אנו מזמינים אותך להשתמש במערכת מעקב התקלות כדי לתעד את המשאלה שלך, חשוב לזכור לסמן אותה בדרגת חומרה (severity) בשם „Wishlist” (רשימת משאלות).</string>
<string name="about_kde_join_kde">&lt;h1&gt;הצטרפות ל־KDE&lt;/h1&gt; &lt;p&gt;לא צריך להיות מפתחי תוכנה כדי להצטרף לחברות ב־KDE. אפשר להצטרף לצוותים המקומיים שמתרגמים את ממשקי התוכנות. אפשר לספק גרפיקה, ערכות עיצוב, צלילי ושיפור התיעוד. הבחירה היא רק שלך!&lt;/p&gt; &lt;p&gt;יש לבקר ב־&lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; למידע על חלק מהמיזמים בהם ניתן לקחת חלק.&lt;/p&gt; כדי לקבל מידע או תיעוד נוספים, ביקור ב־&lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; יספק לך את מה שדרוש לך.</string>
@@ -421,7 +420,6 @@
<string name="maxim_leshchenko_task">שיפורי ממשק משתמש ועמוד על אודות הזה</string>
<string name="holger_kaelberer_task">תוסף מקלדת מרוחקת ותיקוני תקלות</string>
<string name="saikrishna_arcot_task">תמיכה בשימוש במקלדת בתוסף הקלט המרוחק, תיקוני תקלות ושיפורים כלליים</string>
<string name="shellwen_chen_task">שיפור האבטחה ב־SFTP, שיפור תחזוקתיות המיזם הזה, תיקוני תקלות ושיפורים כלליים</string>
<string name="everyone_else">כל מי שתרם ל־KDE Connect לאורך השנים</string>
<string name="send_clipboard">שליחת לוח גזירים</string>
<string name="tap_to_execute">נגיעה תפעיל</string>

View File

@@ -116,9 +116,11 @@
<string name="error_canceled_by_user">ユーザにキャンセルされました</string>
<string name="error_canceled_by_other_peer">他のピアにキャンセルされました</string>
<string name="encryption_info_title">暗号化情報</string>
<string name="encryption_info_msg_no_ssl">他のデバイスは最近のバージョンの KDE Connect を利用していません。古い暗号化方式を使用しています。</string>
<string name="my_device_fingerprint">このデバイスの証明書の SHA256 フィンガープリント:</string>
<string name="remote_device_fingerprint">リモートデバイスの証明書の SHA256 フィンガープリント:</string>
<string name="pair_requested">ペアリング要求済み</string>
<string name="pairing_request_from">%1s からペアリングを要求されました</string>
<plurals name="incoming_file_title">
<item quantity="other">%1$d ファイルを %2$s から受信しています</item>
</plurals>

View File

@@ -18,7 +18,6 @@
<string name="pref_plugin_clipboard_sent">ბუფერი გაგზავნილია</string>
<string name="pref_plugin_mousepad">დაშორებული შეყვანა</string>
<string name="pref_plugin_mousepad_desc">გამოიყენეთ თქვენი ტელეფონი ან ტაბლეტი როგორც თაჩპედი და კლავიატურა</string>
<string name="pref_plugin_presenter">დაშორებული პრეზენტაცია</string>
<string name="pref_plugin_presenter_desc">გამოიყენეთ თქვენი მოწყობილობა სლაიდშოუს სამართავად</string>
<string name="pref_plugin_remotekeyboard">დაშორებული ღილაკების მიღება</string>
<string name="pref_plugin_mpris">მულტიმედიის მართვა</string>
@@ -93,7 +92,6 @@
<string name="error_canceled_by_other_peer">გაუქმებულია პარტნიორის მიერ</string>
<string name="encryption_info_title">დაშიფვრის ინფორმაცია</string>
<string name="pair_requested">დაწყვილების მოთხოვნა</string>
<string name="pair_succeeded">დაწყვილება წარმატებულია</string>
<plurals name="incoming_files_text">
<item quantity="one">File: %1s</item>
<item quantity="other">(File %2$d of %3$d) : %1$s</item>
@@ -106,7 +104,6 @@
<string name="received_file_text">\'%1s\'-ის გასახსნელად დაატყაპუნეთ</string>
<string name="cannot_create_file">ფაილის (%s) შექმნის შეცდომა</string>
<string name="tap_to_answer">საპასუხოდ დაატყაპუნეთ</string>
<string name="left_click">მარჯვენა წკაპის გაგზავნა</string>
<string name="right_click">მარჯვენა წკაპის გაგზავნა</string>
<string name="middle_click">შუა წკაპის გაგზავნა</string>
<string name="show_keyboard">კლავიატურის ჩვენება</string>
@@ -132,8 +129,6 @@
<item>1 წუთი</item>
<item>2 წუთი</item>
</string-array>
<string name="share_to">გაზიარება…</string>
<string name="unreachable_device">%s (მიუწვდომელია)</string>
<string name="protocol_version_newer">მოწყობილობა პროტოკოლის უფრო ახალ ვერსიას იყენებს</string>
<string name="plugin_settings_with_name">%s-ის მორგება</string>
<string name="invalid_device_name">მოწყობილობის არასწორი სახელი</string>

View File

@@ -18,7 +18,6 @@
<string name="pref_plugin_clipboard_sent">클립보드 보냄</string>
<string name="pref_plugin_mousepad">원격 입력</string>
<string name="pref_plugin_mousepad_desc">내 휴대폰이나 태블릿을 터치패드와 키보드로 사용하기</string>
<string name="pref_plugin_presenter">프레젠테이션 리모콘</string>
<string name="pref_plugin_presenter_desc">내 장치로 프레젠테이션 슬라이드 전환하기</string>
<string name="pref_plugin_remotekeyboard">원격 키 입력 받기</string>
<string name="pref_plugin_remotekeyboard_desc">원격 장치의 키 입력 이벤트 받기</string>
@@ -52,7 +51,6 @@
<string name="remotekeyboard_multiple_connections">원격 키보드 연결이 여러 개 있습니다. 설정할 장치를 선택하십시오</string>
<string name="open_mousepad">원격 입력</string>
<string name="mousepad_info">화면에서 손가락을 움직이면 마우스 커서를 움직입니다. 화면을 누르면 왼쪽 단추를 누르고, 두 손가락과 세 손가락으로 누르면 오른쪽/가운데 단추를 누릅니다. 두 손가락을 사용하여 스크롤할 수 있습니다. 드래그 앤 드롭을 사용하려면 길게 누르십시오. 플러그인 설정에서 자이로 마우스를 활성화할 수 있습니다</string>
<string name="mousepad_info_no_gestures">화면에서 손가락을 움직이면 마우스 커서를 움직이며, 탭하면 클릭합니다.</string>
<string name="mousepad_keyboard_input_not_supported">페어링된 장치에서 키보드 입력을 지원하지 않음</string>
<string name="mousepad_single_tap_settings_title">한 손가락으로 눌렀을 때 동작 설정</string>
<string name="mousepad_double_tap_settings_title">두 손가락으로 눌렀을 때 동작 설정</string>
@@ -118,11 +116,11 @@
<string name="error_canceled_by_user">사용자가 취소함</string>
<string name="error_canceled_by_other_peer">다른 쪽에서 취소함</string>
<string name="encryption_info_title">암호화 정보</string>
<string name="encryption_info_msg_no_ssl">다른 장치에서 KDE Connect의 최근 버전을 실행하고 있지 않아서 레거시 암호화를 사용합니다.</string>
<string name="my_device_fingerprint">내 장치 인증서의 SHA256 지문:</string>
<string name="remote_device_fingerprint">원격 장치 인증서의 SHA256 지문:</string>
<string name="pair_requested">연결 요청됨</string>
<string name="pair_succeeded">연결 성공</string>
<string name="pairing_request_from">\'%1s\'에서 연결 요청</string>
<string name="pairing_request_from">%1s에서 연결 요청</string>
<plurals name="incoming_file_title">
<item quantity="other">%2$s에서 보낸 파일 %1$d개 받음</item>
</plurals>
@@ -151,7 +149,6 @@
<string name="received_file_text">\'%1s\'을(를) 열려면 누르십시오</string>
<string name="cannot_create_file">파일 %s을(를) 만들 수 없음</string>
<string name="tap_to_answer">눌러서 응답하기</string>
<string name="left_click">왼쪽 단추 클릭 신호 보내기</string>
<string name="right_click">오른쪽 단추 클릭 신호 보내기</string>
<string name="middle_click">가운데 단추 클릭 신호 보내기</string>
<string name="show_keyboard">키보드 표시</string>
@@ -181,9 +178,6 @@
<string name="mpris_notifications_explanation">알림 서랍에 원격 미디어를 표시하려면 알림 권한이 필요합니다</string>
<string name="mpris_notification_settings_title">미디어 제어 알림 표시</string>
<string name="mpris_notification_settings_summary">KDE Connect를 열지 않고 미디어 재생기 제어</string>
<string name="share_to">다음으로 공유…</string>
<string name="unreachable_device">%s(접근할 수 없음)</string>
<string name="unreachable_device_url_share_text">접근할 수 없는 장치와 공유한 URL은 장치에 다시 접근할 수 있게 될 때 전달됩니다.\n\n</string>
<string name="protocol_version_newer">이 장치의 프로토콜 버전이 더 새롭습니다</string>
<string name="plugin_settings_with_name">%s 설정</string>
<string name="invalid_device_name">잘못된 장치 이름</string>
@@ -395,7 +389,6 @@
<string name="maxim_leshchenko_task">UI 개선과 정보 페이지</string>
<string name="holger_kaelberer_task">원격 키보드 플러그인과 버그 수정</string>
<string name="saikrishna_arcot_task">원격 입력 플러그인에서 키보드 사용 지원, 버그 수정과 개선</string>
<string name="shellwen_chen_task">SFTP 보안 개선, 프로젝트 관리 편의성 개선, 버그 수정과 개선</string>
<string name="everyone_else">그 외 오랫동안 KDE Connect에 기여한 사람들</string>
<string name="send_clipboard">클립보드 보내기</string>
<string name="tap_to_execute">실행하려면 누르십시오</string>
@@ -404,8 +397,4 @@
<string name="receive_notifications_permission_explanation">다른 장치에서 알림을 받으려면 알림을 허용해야 합니다</string>
<string name="findmyphone_notifications_explanation">앱이 백그라운드에서 실행 중일 때 장치를 울리게 하려면 알림 권한이 필요합니다</string>
<string name="no_notifications">알림이 비활성화되어 있습니다. 들어오는 페어링 알림을 받을 수 없습니다</string>
<string name="mpris_keepwatching">계속 재생</string>
<string name="mpris_keepwatching_settings_title">계속 재생</string>
<string name="mpris_keepwatching_settings_summary">미디어를 닫은 후 이 장치에서 계속 재생할 수 있는 조용한 알림 표시</string>
<string name="notification_channel_keepwatching">계속 재생</string>
</resources>

View File

@@ -109,9 +109,11 @@
<string name="error_canceled_by_user">Naudotojas atsisakė</string>
<string name="error_canceled_by_other_peer">Lygiarangis atsisakė</string>
<string name="encryption_info_title">Šifravimo informacija</string>
<string name="encryption_info_msg_no_ssl">Kitas įrenginys nenaudoja paskiausios KDE Connect versijos, naudojamas pasenęs šifravimo metodas.</string>
<string name="my_device_fingerprint">Jūsų įrenginio liudijimo SHA256 kontrolinis kodas yra:</string>
<string name="remote_device_fingerprint">Nuotolinio įrenginio liudijimo SHA256 kontrolinis kodas yra:</string>
<string name="pair_requested">Užklaustas suporavimas</string>
<string name="pairing_request_from">Suporavimo užklausa iš %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Gaunamas %1$d failas iš %2$s</item>
<item quantity="few">Gaunami %1$d failai iš %2$s</item>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Geannuleerd door gebruiker</string>
<string name="error_canceled_by_other_peer">Geannuleerd door andere kant</string>
<string name="encryption_info_title">Versleutelde informatie</string>
<string name="encryption_info_msg_no_ssl">Het andere apparaat gebruikt geen recente versie van KDE Connect, de verouderde versleutelingsmethode zal worden gebruikt.</string>
<string name="my_device_fingerprint">De SHA256 vingerafdruk van het certificaat van uw apparaat is:</string>
<string name="remote_device_fingerprint">De SHA256 vingerafdruk van het certificaat van het apparaat op afstand is:</string>
<string name="pair_requested">Paarvorming gevraagd</string>
<string name="pair_succeeded">Paarvorming is gelukt</string>
<string name="pairing_request_from">Verzoek om een paar te maken van \'%1s\'</string>
<string name="pairing_request_from">Verzoek om een paar te maken van %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">%1$d bestand wordt ontvangen vanaf %2$s</item>
<item quantity="other">%1$d bestanden worden ontvangen vanaf %2$s</item>
@@ -389,8 +390,6 @@
<string name="send_compose">Verzenden</string>
<string name="compose_send_title">Opstellen van verzending</string>
<string name="open_compose_send">Tekst opstellen</string>
<string name="double_tap_to_drag">Dubbel tikken om te slepen</string>
<string name="hold_to_drag">Ingedrukt houden om te slepen</string>
<string name="about_kde_about">&lt;h1&gt;Info over&lt;/h1&gt; &lt;p&gt;KDE is een wereldwijde gemeenschap van software ingenieurs, artiesten, schrijvers, vertalers en makers die toegewijd zijn aan &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Vrije software&lt;/a&gt; ontwikkeling. KDE produceert de Plasma bureaubladomgeving, honderden toepassingen en de vele software bibliotheken die deze ondersteunen.&lt;/p&gt; &lt;p&gt;KDE is een coöperatieve onderneming: geen enkele entiteit controleert zijn richting of producten. In plaats daarvan werken we samen om het gemeenschappelijke doel te bereiken van het bouwen van de \'s werelds mooiste Vrije software. Iedereen is welkom om &lt;a href=https://community.kde.org/Get_Involved&gt;mee te doen en bij te dragen&lt;/a&gt; aan KDE, inclusief u.&lt;/p&gt; Bezoek &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; voor meer informatie over de KDE gemeenschap en de software die we produceren.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Bugs of wensen rapporteren&lt;/h1&gt; &lt;p&gt;Software kan altijd verbeterd worden en het KDE team is gereed om dat te doen. Echter, u - de gebruiker - moet ons vertellen wanneer iets niet werkt zoals verwacht of beter gedaan kan worden.&lt;/p&gt; &lt;p&gt;KDE heeft een bugvolgsysteem. Bezoek &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; of gebruik de knop \"Bug rapporteren\" uit het Info over scherm om bugs te rapporteren.&lt;/p&gt; Als u een suggestie voor verbetering dan bent u welkom om het bugvolgsysteem te gebruiken om uw wens te registreren. Ga na dat u de ernst genaamd \"Wishlist\" gebruikt.</string>
<string name="about_kde_join_kde">&lt;h1&gt;Mee doen met KDE&lt;/h1&gt; &lt;p&gt;U hoeft geen software ontwerper te zijn om een lid van het KDE-team te worden. U kunt meedoen met een vertaalteam dat interfaces van programma\'s vertaalt. U kunt illustraties, thema\'s, geluiden en verbeterde documentatie leveren. U beslist!&lt;/p&gt; &lt;p&gt;Bezoek &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; voor informatie over projecten waarin u kunt participeren.&lt;/p&gt; Als u meer informatie of documentatie nodig hebt, dan kan een bezoek aan &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; u alles wat u nodig hebt leveren.</string>
@@ -405,7 +404,6 @@
<string name="maxim_leshchenko_task">Verbeteringen aan UI en deze info over pagina</string>
<string name="holger_kaelberer_task">"Plug-in voor toetsenbord op afstand en reparaties"</string>
<string name="saikrishna_arcot_task">Ondersteuning voor gebruik van toetsenbord in de plug-in voor invoer op afstand, bugreparaties en algemene verbeteringen</string>
<string name="shellwen_chen_task">Verbeter de beveiliging van SFTP, verbeter de onderhoudbaarheid van dit project, reparaties van bugs en algemene verbeteringen</string>
<string name="everyone_else">Ieder ander die over de jaren heeft bijgedragen aan KDE Connect</string>
<string name="send_clipboard">Klembord verzenden</string>
<string name="tap_to_execute">Tik om uit te voeren</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Avbroten av brukar</string>
<string name="error_canceled_by_other_peer">Avbroten av den andre eininga</string>
<string name="encryption_info_title">Krypteringsinfo</string>
<string name="encryption_info_msg_no_ssl">Den andre eininga brukar ein gammal versjon av KDE Connect, med ein utdatert krypteringsmetode.</string>
<string name="my_device_fingerprint">SHA-256-fingeravtrykket til einingssertifikatet er:</string>
<string name="remote_device_fingerprint">SHA-256-fingeravtrykket til fjerneiningssertifikatet er:</string>
<string name="pair_requested">Paringsførespurnad</string>
<string name="pair_succeeded">Paring fullført</string>
<string name="pairing_request_from">Paringsførespurnad frå «%1s»</string>
<string name="pairing_request_from">Paringsførespurnad frå %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Fekk %1$d fil frå %2$s</item>
<item quantity="other">Fekk %1$d filer frå %2$s</item>
@@ -186,12 +187,10 @@
<item>1 minutt</item>
<item>2 minutt</item>
</string-array>
<string name="mpris_notifications_explanation">Varslingsløyvet trengst for å visa medieavspeling i varslingssenteret</string>
<string name="mpris_notification_settings_title">Vis varsling med avspelingskontrollar</string>
<string name="mpris_notification_settings_summary">Tillat å kontrollera mediespelarar utan å opna KDE Connect</string>
<string name="share_to">Del til </string>
<string name="unreachable_device">%s (får ikkje kontakt med)</string>
<string name="unreachable_device_url_share_text">Adresser delte til ei utilgjengeleg eining vert leverte når eininga vert tilgjengeleg att.\n\n</string>
<string name="protocol_version_newer">Denne eininga brukar ein nyare protokollversjon</string>
<string name="plugin_settings_with_name">%s-innstillingar</string>
<string name="invalid_device_name">Ugyldig einingsnamn</string>
@@ -258,12 +257,10 @@
<string name="optional_permission_explanation">Du må gje utvida løyve for at alle funksjonane skal fungera</string>
<string name="plugins_need_optional_permission">På grunn av manglande løyve vil desse funksjonane ikkje verka (trykk på dei for meir informasjon):</string>
<string name="share_optional_permission_explanation">For å kunna ta imot filer må du gje tilgangsløyve til lagringsområdet</string>
<string name="share_notifications_explanation">For å kunna sjå framdrift ved sending og mottak av filer må du gje appen varslingsløyve</string>
<string name="telepathy_permission_explanation">For å kunna lesa og skriva tekstmeldingar frå datamaskina må du gje appen tilgang til SMS</string>
<string name="telephony_permission_explanation">For å kunna sjå telefonsamtalar på datamaskina må du gje appen tilgang til samtaleloggar og telefonstatus</string>
<string name="telephony_optional_permission_explanation">For å kunna sjå namn på kontaktar i staden for berre telefonnummeret må du gje appen tilgang til kontaktlista di</string>
<string name="contacts_permission_explanation">For å kunna dela adresseboka di med datamaskina må du gje appen lese- og skriveløyve til adresseboka</string>
<string name="contacts_per_device_confirmation">Telefonkontaktane dine vert kopiert over til denne eininga, slik at dei kan brukast av KDE Connect SMS-appen og andre appar.</string>
<string name="select_ringtone">Vel ringjetone</string>
<string name="telephony_pref_blocked_title">Blokkerte nummer</string>
<string name="telephony_pref_blocked_dialog_desc">Ikkje vis oppringingar eller SMS-ar frå desse telefonnummera. Skriv inn eitt telefonnummer per linje.</string>
@@ -292,9 +289,6 @@
<string name="runcommand_notpaired">Eininga er ikkje para</string>
<string name="runcommand_nosuchdevice">Eininga finst ikkje</string>
<string name="runcommand_noruncommandplugin">Eininga har ikkje «Køyr kommando»-tillegget slått på</string>
<string name="runcommand_category_device_controls_title">Einingsstyring</string>
<string name="runcommand_device_controls_summary">Vis eininga støttar einingsstyring, vil kommandoar du har sette opp, visast her.</string>
<string name="set_runcommand_name_as_title">set_runcommand_name_as_title</string>
<string name="runcommand_name_as_title_title">Vis namn som tittel</string>
<string name="pref_plugin_findremotedevice">Finn ekstern eining</string>
<string name="pref_plugin_findremotedevice_desc">Ring til ekstern eining</string>
@@ -389,8 +383,6 @@
<string name="send_compose">Send</string>
<string name="compose_send_title">Send tekst</string>
<string name="open_compose_send">Skriv tekst</string>
<string name="double_tap_to_drag">Dobbelttrykk for å dra</string>
<string name="hold_to_drag">Hald for å dra</string>
<string name="about_kde_about">&lt;h1&gt;Om&lt;/h1&gt; &lt;p&gt;KDE er eit verdsfemnande fellesskap av eldsjeler som programmerer, teiknar, komponerer, dokumenterer, set om eller hjelper til på andre måtar med utvikling av &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;fri programvare&lt;/a&gt;. Me har laga brukarflata Plasma, hundrevis av program og dei mange programbiblioteka desse byggjer på.&lt;/p&gt; &lt;p&gt;KDE er eit fellesskap der inga einskild gruppe, firma eller organisasjon har eigarskap til produkta eller styrer retninga den vidare utviklinga skal gå i. Derimot arbeider me saman om å oppnå vårt felles mål om å laga fri programvare i verdsklasse. Alle er &lt;a href=https://community.kde.org/Get_Involved&gt;velkomne til å bidra&lt;/a&gt;  du òg.&lt;/p&gt;Du finn meir informasjon om KDE og programma me utviklar på &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt;.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Meld frå om feil eller ønskje&lt;/h1&gt; &lt;p&gt;Ein kan alltid forbetra programvare, og KDE-gruppa arbeider heile tida for det. Men du, som brukar, må melda frå til oss når noko ikkje verkar slik du forventar, eller når noko kunne vore gjort betre.&lt;/p&gt; &lt;p&gt;KDE har eit feilsporingssystem. Gå til &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; eller vel «Meld frå om feil» på «Om»-sida for å melda frå om feil.&lt;/p&gt; Om du har framlegg til forbetringar, kan du gjerne registrera òg desse i feilsporingssystemet. Sjå då til at du har markert feilrapporten med «Wishlist».</string>
<string name="about_kde_join_kde">&lt;h1&gt;Vert med i KDE&lt;/h1&gt; &lt;p&gt;Du treng ikkje vera programutviklar for å hjelpa til med KDE. Du kan arbeida med omsetjingar, laga grafikk, tema, lydar eller betre hjelpetekstar. Her er noko for alle!&lt;/p&gt; &lt;p&gt;&lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; finn du informasjon om nokre prosjekt du kan delta i.&lt;/p&gt; Om du vil ha meir informasjon eller dokumentasjon, finn du det du treng på &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;.</string>
@@ -405,17 +397,12 @@
<string name="maxim_leshchenko_task">Forbetringar av brukarflata og denne «om»-sida</string>
<string name="holger_kaelberer_task">Fjerntastatur-tillegget og feilrettingar</string>
<string name="saikrishna_arcot_task">Støtte for bruk av tastaturet i fjernstyrings­tillegget, feilrettingar og generelle forbetringar</string>
<string name="shellwen_chen_task">Forbetra tryggleiken til SFTP, gjort prosjektet lettare å vedlikehalda, feilrettingar og generelle forbetringar</string>
<string name="everyone_else">Alle andre som har hjelpt til med utviklinga av KDE Connect opp gjennom åra</string>
<string name="send_clipboard">Send utklippstavla</string>
<string name="tap_to_execute">Tapp for å utføra handlinga</string>
<string name="plugin_stats">Programtillegg-statistikk</string>
<string name="enable_udp_broadcast">Slå på einingsoppdaging via UDP</string>
<string name="receive_notifications_permission_explanation">Du må tillata varslingar for å kunna frå varslingar frå andre einingar</string>
<string name="findmyphone_notifications_explanation">Varslingsløyvet trengst for at telefonen skal kunna ringja når appen er i bakgrunnsmodus</string>
<string name="no_notifications">Varslingar er slåtte av, så du vil ikkje få varsling om parings­førespurnadar.</string>
<string name="mpris_keepwatching">Hald fram avspeling</string>
<string name="mpris_keepwatching_settings_title">Hald fram avspeling</string>
<string name="mpris_keepwatching_settings_summary">Vis ei stille varsling om framhald av medie­avspeling på eininga etter avspelingsstopp</string>
<string name="notification_channel_keepwatching">Hald fram avspeling</string>
</resources>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Użytkownik zaniechał</string>
<string name="error_canceled_by_other_peer">Inny uczestnik zaniechał</string>
<string name="encryption_info_title">Dane o szyfrowaniu</string>
<string name="encryption_info_msg_no_ssl">Drugie urządzenie nie używa ostatniej wersji KDE Connect, użyto przestarzałego szyfrowania.</string>
<string name="my_device_fingerprint">Odcisk palca SHA256 certyfikatu twojego urządzenia to:</string>
<string name="remote_device_fingerprint">Odcisk palca SHA256 certyfikatu twojego zdalnego urządzenia to:</string>
<string name="pair_requested">Poproszono o sparowanie</string>
<string name="pair_succeeded">Parowanie udane</string>
<string name="pairing_request_from">Prośba o sparowanie od \'%1s\'</string>
<string name="pairing_request_from">Prośba o sparowanie z %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Pobieranie %1$d pliku z %2$s</item>
<item quantity="few">Pobieranie %1$d plików z %2$s</item>
@@ -205,9 +206,6 @@
<string name="mpris_notifications_explanation">Uprawnienia powiadomień są potrzebne, aby móc pokazywać zdalne odtwarzacze na belce powiadomień</string>
<string name="mpris_notification_settings_title">Pokaż powiadomienia sterowania mediami</string>
<string name="mpris_notification_settings_summary">Steruje odtwarzaczami bez otwierania KDE Connect</string>
<string name="share_to">Udostępnij urządzeniu...</string>
<string name="unreachable_device">%s (nieosiągalne)</string>
<string name="unreachable_device_url_share_text">Adres URL udostępniony nieosiągalnemu urządzeniu zostanie do niego dostarczony zaraz po tym jak stanie się osiągalne.\n\n</string>
<string name="protocol_version_newer">Urządzenie to używa nowszej wersji protokołu</string>
<string name="plugin_settings_with_name">Ustawienia %s</string>
<string name="invalid_device_name">Nieprawidłowa nazwa urządzenia</string>
@@ -405,8 +403,6 @@
<string name="send_compose">Wyślij</string>
<string name="compose_send_title">Napisz do wysłania</string>
<string name="open_compose_send">Napisz tekst</string>
<string name="double_tap_to_drag">Stuknij dwukrotnie, aby przeciągnąć</string>
<string name="hold_to_drag">Przytrzymaj, aby przeciągnąć</string>
<string name="about_kde_about">"&lt;h1&gt;O programie&lt;/h1&gt; &lt;p&gt;KDE to światowa społeczność inżynierów oprogramowania, artystów, pisarzy, tłumaczy i twórców, którzy są częścią rozwoju &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Wolnego Oprogramowania&lt;/a&gt;. KDE tworzy środowisko pulpitu Plazmy, setki aplikacji i wiele bibliotek programistycznych, aby je wspierać.&lt;/p&gt; &lt;p&gt;KDE jest przedsięwzięciem istniejącym ze współpracy; jego ruchami, czy produktami, nie steruje żaden pojedynczy byt. Pracujemy razem, aby osiągnąć wspólny cel, czyli budowę najlepszego Wolnego Oprogramowania na świecie. Każdy jest mile wiedziany, żeby &lt;a href=https://community.kde.org/Get_Involved&gt;dołączył i zaczął współtworzyć&lt;/a&gt; KDE, włączając w to ciebie.&lt;/p&gt; Odwiedź &lt; href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; po więcej szczegółów nt. społeczności KDE i oprogramowania, które tworzymy."</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Zgłaszaj błędy lub życzenia&lt;/h1&gt; &lt;p&gt;Oprogramowanie zawsze można ulepszyć, a zespół KDE jest gotowy, aby to robić. Jednakże ty - użytkownik - musisz nam powiedzieć o tym, co nie działa jak powinno lub co można zrobić lepiej.&lt;/p&gt; &lt;p&gt;KDE ma system obsługi błędów. Odwiedź &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; lub użyj przycisku \"Zgłoś błąd\" z ekranu o programie do zgłaszania błędów.&lt;/p&gt; Jeśli masz sugestie nt. usprawnień, to także możesz ją zarejestrować w naszym systemie obsługi błędów. Upewnij się, że użyjesz ważności o nazwie \"Lista życzeń\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Dołącz do KDE&lt;/h1&gt; &lt;p&gt;Nie musisz być programistą, aby być członkiem zespołu KDE. Możesz dołączyć do zespołów językowych, które tłumaczą oprogramowanie. Możesz dostarczać grafikę, zestawy wyglądu, dźwięki i ulepszać dokumentację. To ty decydujesz!&lt;/p&gt; &lt;p&gt;odwiedź &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; po szczegóły nt. projektów, w których możesz wziąć udział .&lt;/p&gt; Jeśli potrzebujesz więcej szczegółów lub dokumentacji, to odwiedziny na &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; dadzą ci to, czego chcesz.</string>
@@ -421,7 +417,6 @@
<string name="maxim_leshchenko_task">Usprawnienia do interfejsu i strony o programie</string>
<string name="holger_kaelberer_task">Wtyczka zdalnej klawiatury i usuwanie błędów</string>
<string name="saikrishna_arcot_task">Wsparcie do obsługi klawiatury we wtyczce zdalnego wprowadzania, usuwanie błędów i ogólne usprawnienia</string>
<string name="shellwen_chen_task">Polepszenie bezpieczeństwa SFTP, polepszenie łatwości w utrzymaniu tego projektu, poprawki błędów oraz ogólne ulepszenia</string>
<string name="everyone_else">Inni którzy współtworzyli KDE Connect na przestrzeni lat</string>
<string name="send_clipboard">Wysyłanie schowka</string>
<string name="tap_to_execute">Stuknij, aby wykonać</string>
@@ -430,8 +425,4 @@
<string name="receive_notifications_permission_explanation">Należy zezwolić na powiadomienia, aby móc je otrzymywać z innych urządzeń</string>
<string name="findmyphone_notifications_explanation">Uprawnienia powiadomień są potrzebne, aby telefon mógł dzwonić, gdy aplikacja działa w tle</string>
<string name="no_notifications">Powiadomienia są wyłączone, więc nie otrzymasz żadnych próśb o sparowanie.</string>
<string name="mpris_keepwatching">Kontynuuj odtwarzanie</string>
<string name="mpris_keepwatching_settings_title">Kontynuuj odtwarzanie</string>
<string name="mpris_keepwatching_settings_summary">Pokaż ciche powiadomienie, aby kontynuować odtwarzanie na tym urządzeniu po zamknięciu mediów</string>
<string name="notification_channel_keepwatching">Kontynuuj odtwarzanie</string>
</resources>

View File

@@ -18,7 +18,6 @@
<string name="pref_plugin_clipboard_sent">Área de transferência enviada</string>
<string name="pref_plugin_mousepad">Introdução de dados remota</string>
<string name="pref_plugin_mousepad_desc">Use seu celular ou tablet como mouse e teclado</string>
<string name="pref_plugin_presenter">Controle remoto para apresentações</string>
<string name="pref_plugin_presenter_desc">Use o seu dispositivo para mudar os slides de uma apresentação</string>
<string name="pref_plugin_remotekeyboard">Receber pressionamento de teclas remoto</string>
<string name="pref_plugin_remotekeyboard_desc">Recebe os eventos de pressionamento de teclas dos dispositivos remotos</string>
@@ -52,7 +51,6 @@
<string name="remotekeyboard_multiple_connections">Existe mais que uma conexão a teclados remotos. Selecione o dispositivo a configurar</string>
<string name="open_mousepad">Introdução de dados remota</string>
<string name="mousepad_info">Mova um dedo pela tela para mover o ponteiro do mouse. Dê um toque para clicar e use dois/três dedos para os botões da direita e do meio. Use dois dedos para rolar a tela. Use uma pressão longa para arrastar e soltar. A funcionalidade do mouse giroscópio pode ser habilitada nas preferências do plugin.</string>
<string name="mousepad_info_no_gestures">Mova o dedo na tela para mover o cursor do mouse, toque para um clique.</string>
<string name="mousepad_keyboard_input_not_supported">Entrada de teclado não suportada pelo dispositivo emparelhado</string>
<string name="mousepad_single_tap_settings_title">Definir ação do toque com um dedo</string>
<string name="mousepad_double_tap_settings_title">Definir ação do toque com dois dedos</string>
@@ -61,7 +59,6 @@
<string name="mousepad_mouse_buttons_title">Mostrar botões do mouse</string>
<string name="mousepad_acceleration_profile_settings_title">Definir aceleração do ponteiro</string>
<string name="mousepad_scroll_direction_title">Direção de rolagem inversa</string>
<string name="mousepad_scroll_sensitivity_title">Sensibilidade da rolagem</string>
<string name="gyro_mouse_enabled_title">Ativar mouse giroscópio</string>
<string name="gyro_mouse_sensitivity_title">Sensibilidade do giroscópio</string>
<string-array name="mousepad_tap_entries">
@@ -118,10 +115,10 @@
<string name="error_canceled_by_user">Cancelado pelo usuário</string>
<string name="error_canceled_by_other_peer">Cancelado pelo outro dispositivo</string>
<string name="encryption_info_title">Informação de criptografia</string>
<string name="encryption_info_msg_no_ssl">O outro dispositivo não usa uma versão recente do KDE Connect. Será utilizado o método antigo de criptografia.</string>
<string name="my_device_fingerprint">A impressão digital SHA256 do certificado do seu dispositivo é:</string>
<string name="remote_device_fingerprint">A impressão digital SHA256 do certificado do dispositivo remoto é:</string>
<string name="pair_requested">Solicitação de emparelhamento</string>
<string name="pair_succeeded">Emparelhado com sucesso</string>
<string name="pairing_request_from">Emparelhamento solicitado por %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Recebendo %1$d arquivo de %2$s</item>
@@ -159,7 +156,6 @@
<string name="received_file_text">Toque para abrir o \'%1s\'</string>
<string name="cannot_create_file">Não foi possível criar o arquivo %s</string>
<string name="tap_to_answer">Toque para responder</string>
<string name="left_click">Enviar um clique de botão esquerdo</string>
<string name="right_click">Enviar um Botão Direito</string>
<string name="middle_click">Enviar um Botão do Meio</string>
<string name="show_keyboard">Mostrar teclado</string>
@@ -186,12 +182,8 @@
<item>1 minuto</item>
<item>2 minutos</item>
</string-array>
<string name="mpris_notifications_explanation">A permissão de notificações é necessária para exibir a mídia remotas na gaveta de notificações</string>
<string name="mpris_notification_settings_title">Mostrar a notificação do controle multimídia</string>
<string name="mpris_notification_settings_summary">Permite controlar os seus reprodutores de mídias sem abrir o KDE Connect</string>
<string name="share_to">Compartilhar com...</string>
<string name="unreachable_device">%s (Inalcançável)</string>
<string name="unreachable_device_url_share_text">URLs compartilhadas com um dispositivo inalcançável serão enviadas para ele assim que ele voltar a ficar disponível.\n\n</string>
<string name="protocol_version_newer">Este dispositivo usa uma versão mais recente do protocolo</string>
<string name="plugin_settings_with_name">Configurações de %s</string>
<string name="invalid_device_name">Nome do dispositivo inválido</string>
@@ -258,12 +250,10 @@
<string name="optional_permission_explanation">Você precisa conceder permissões extras para ativar todas as funções</string>
<string name="plugins_need_optional_permission">Alguns plugins possuem recursos desativados devido à falta de permissões (toque para obter mais informações):</string>
<string name="share_optional_permission_explanation">Para receber arquivos você precisa permitir o acesso ao armazenamento</string>
<string name="share_notifications_explanation">Para acompanhar o progresso ao enviar e receber arquivos, você precisa permitir as notificações</string>
<string name="telepathy_permission_explanation">Para ler e gravar SMS a partir do seu ambiente de trabalho é necessário conceder permissão para SMS</string>
<string name="telephony_permission_explanation">Para ver as chamadas telefônicas no seu ambiente de trabalho é preciso dar permissões para registro de chamadas telefônicas e do estado do celular</string>
<string name="telephony_optional_permission_explanation">Para ver o nome de um contato em vez do seu número de telefone é necessário conceder acesso aos contatos do celular</string>
<string name="contacts_permission_explanation">Para compartilhar o seu livro de endereços com o ambiente de trabalho é necessário conceder permissão para os contatos</string>
<string name="contacts_per_device_confirmation">Os contatos do seu telefone serão copiados para este dispositivo, dessa forma eles poderão ser utilizados pelo aplicativo de SMS do KDE Connect e por outros.</string>
<string name="select_ringtone">Selecionar um toque de chamada</string>
<string name="telephony_pref_blocked_title">Números bloqueados</string>
<string name="telephony_pref_blocked_dialog_desc">Não mostrar as chamadas e SMS destes números. Indique um número por linha.</string>
@@ -281,9 +271,6 @@
<string name="notification_channel_default">Outras notificações</string>
<string name="notification_channel_persistent">Indicador persistente</string>
<string name="notification_channel_media_control">Controle multimídia</string>
<string name="notification_channel_filetransfer">Chegada de arquivo via transferência</string>
<string name="notification_channel_filetransfer_upload">Saída de arquivo via transferência</string>
<string name="notification_channel_filetransfer_error">Erro na transferência de arquivo</string>
<string name="notification_channel_high_priority">Prioridade alta</string>
<string name="mpris_stop">Parar o reprodutor atual</string>
<string name="copy_url_to_clipboard">Copiar URL para a área de transferência</string>
@@ -292,10 +279,6 @@
<string name="runcommand_notpaired">Dispositivo não emparelhado</string>
<string name="runcommand_nosuchdevice">Este dispositivo não existe</string>
<string name="runcommand_noruncommandplugin">Este dispositivo não tem o plugin \'Executar comando\' ativo</string>
<string name="runcommand_category_device_controls_title">Controles do dispositivo</string>
<string name="runcommand_device_controls_summary">Caso o seu dispositivo suporte \"controles de dispositivo\", os comandos que você configurou aparecerão aqui.</string>
<string name="set_runcommand_name_as_title">set_runcommand_name_as_title</string>
<string name="runcommand_name_as_title_title">Exibir o nome como título</string>
<string name="pref_plugin_findremotedevice">Procurar dispositivo remoto</string>
<string name="pref_plugin_findremotedevice_desc">Fazer tocar o seu dispositivo remoto</string>
<string name="ring">Toque</string>
@@ -378,7 +361,7 @@
<string name="email_contributor">E-mail do colaborador\n%s</string>
<string name="visit_contributors_homepage">Visite o site do colaborador\n%s</string>
<string name="version">Versão %s</string>
<string name="about_kde">Sobre a KDE</string>
<string name="about_kde">Sobre o KDE</string>
<string name="kde_be_free">KDE - Seja livre!</string>
<string name="kde">KDE</string>
<string name="konqi">Konqi</string>
@@ -389,12 +372,9 @@
<string name="send_compose">Enviar</string>
<string name="compose_send_title">Enviar composto</string>
<string name="open_compose_send">Compor texto</string>
<string name="double_tap_to_drag">Toque duplo para arrastar</string>
<string name="hold_to_drag">Segurar para arrastar</string>
<string name="about_kde_about">&lt;h1&gt;About&lt;/h1&gt; &lt;p&gt;A KDE é uma comunidade mundial de engenheiros de software, artistas, escritores, tradutores e criadores comprometidos com o desenvolvimento de &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Software Livre.&lt;/a&gt; A KDE produz o ambiente de desktop Plasma, centenas de aplicativos e muitas bibliotecas de software que os suportam.&lt;/p&gt; &lt;p&gt;A KDE é uma empresa cooperativa: nenhuma entidade controla sua direção ou produtos. Em vez disso, trabalhamos juntos para alcançar o objetivo comum de construir o melhor software livre do mundo. Todos são bem-vindos para &lt;a href=https://community.kde.org/Get_Involved&gt;participar e contribuir com a KDE&lt;/a&gt; , inclusive você.&lt;/p&gt; Visite &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; para obter mais informações sobre a comunidade KDE e o software que produzimos.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Reportar bugs ou sugestões&lt;/h1&gt; &lt;p&gt; Software sempre pode ser melhorado e a equipe do KDE está pronta para isso. No entanto, você - o usuário - deve nos informar quando algo não funcionar conforme o esperado ou puder ser feito melhor.&lt;/p&gt; &lt;p&gt;A KDE possui um sistema de rastreamento de bugs. Visite &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; ou use o botão \"Relatar erro\" na tela \"sobre\" para relatar bugs.&lt;/p&gt; Se você tiver uma sugestão de melhoria, poderá usar o sistema de rastreamento de bugs para registrar sua solicitação. Certifique-se de usar a opção \"wishlist\" no campo \"severity\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Junte-se à KDE&lt;/h1&gt; &lt;p&gt; Você não precisa ser um desenvolvedor de software para ser membro da equipe KDE. Você pode se juntar às equipes de idioma que traduzem interfaces de programas. Você pode fornecer imagens, temas, sons e documentação aprimorada. Você decide!&lt;/p&gt; &lt;p&gt;Visite &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; para obter informações sobre alguns projetos dos quais você pode participar.&lt;/p&gt; Caso você precise de mais informações ou documentação, visite &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; talvez você encontre o que procura.</string>
<string name="about_kde_support_kde">&lt;h1&gt;Apoie a KDE&lt;/h1&gt; &lt;p&gt;O software da KDE está e sempre estará disponível gratuitamente, mas criá-lo não é gratuito.&lt;/p&gt; &lt;p&gt;Para apoiar o desenvolvimento, a comunidade KDE formou a KDE e.V., uma organização sem fins lucrativos fundada legalmente na Alemanha. KDE e.V. representa a comunidade KDE em questões legais e financeiras. Veja &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; para obter informações sobre o KDE e.V.&lt;/p&gt; &lt;p&gt;A KDE se beneficia de muitos tipos de contribuições, inclusive financeiras. Usamos os fundos para reembolsar os membros e outros pelas despesas em que incorrem ao contribuir. Outros fundos são usados para apoio jurídico e organização de conferências e reuniões.&lt;/p&gt; &lt;p&gt;Gostaríamos de incentivar você a apoiar nossos esforços com uma doação financeira, usando uma das formas descritas em &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt;.&lt;/p&gt; Agradecemos, antecipadamente, o seu apoio.</string>
<string name="about_kde_about">"&lt;h1&gt;About&lt;/h1&gt; &lt;p&gt;O KDE é uma comunidade mundial de engenheiros de software, artistas, escritores, tradutores e criadores comprometidos com o desenvolvimento de &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Software Livre.&lt;/a&gt; O KDE produz o ambiente de desktop Plasma, centenas de aplicativos e muitas bibliotecas de software que os suportam.&lt;/p&gt; &lt;p&gt;KDE é uma empresa cooperativa: nenhuma entidade controla sua direção ou produtos. Em vez disso, trabalhamos juntos para alcançar o objetivo comum de construir o melhor software livre do mundo. Todos são bem-vindos para &lt;a href=https://community.kde.org/Get_Involved&gt;participar e contribuir com o KDE&lt;/a&gt; , inclusive você.&lt;/p&gt; Visite &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; para obter mais informações sobre a comunidade KDE e o software que produzimos."</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Reportar bugs ou sugestões&lt;/h1&gt; &lt;p&gt; Software sempre pode ser melhorado e a equipe do KDE está pronta para isso. No entanto, você - o usuário - deve nos informar quando algo não funcionar conforme o esperado ou puder ser feito melhor.&lt;/p&gt; &lt;p&gt;KDE possui um sistema de rastreamento de bugs. Visite &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; ou use o botão \"Relatar erro\" na tela \"sobre\" para relatar bugs.&lt;/p&gt; Se você tiver uma sugestão de melhoria, poderá usar o sistema de rastreamento de bugs para registrar sua solicitação. Certifique-se de usar a opção \"wishlist\" no campo \"severity\".</string>
<string name="about_kde_support_kde">&lt;h1&gt;Apoie o KDE&lt;/h1&gt; &lt;p&gt;O software do KDE está e sempre estará disponível gratuitamente, mas criá-lo não é gratuito.&lt;/p&gt; &lt;p&gt;Para apoiar o desenvolvimento, a comunidade KDE formou o KDE e.V., uma organização sem fins lucrativos fundada legalmente na Alemanha. KDE e.V. representa a comunidade KDE em questões legais e financeiras. Veja &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; para obter informações sobre o KDE e.V.&lt;/p&gt; &lt;p&gt;O KDE se beneficia de muitos tipos de contribuições, inclusive financeiras. Usamos os fundos para reembolsar os membros e outros pelas despesas em que incorrem ao contribuir. Outros fundos são usados para apoio jurídico e organização de conferências e reuniões.&lt;/p&gt; &lt;p&gt;Gostaríamos de incentivá-lo a apoiar nossos esforços com uma doação financeira, usando uma das formas descritas em &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt;.&lt;/p&gt; Muito obrigado antecipadamente por seu apoio.</string>
<string name="maintainer_and_developer">Mantenedor e desenvolvedor</string>
<string name="developer">Desenvolvedor</string>
<string name="apple_support">Suporte ao macOS. Trabalhando no suporte ao iOS</string>
@@ -405,17 +385,8 @@
<string name="maxim_leshchenko_task">Melhorias na interface e nesta página Sobre</string>
<string name="holger_kaelberer_task">Plugin de teclado remoto e correções de erros</string>
<string name="saikrishna_arcot_task">Suporte para usar o teclado no plugin de entrada remoto, correções de erros e melhorias em geral</string>
<string name="shellwen_chen_task">Melhorar a segurança do SFTP, melhorar a capacidade de manutenção deste projeto, correções de erros e melhorias em geral</string>
<string name="everyone_else">Todo mundo que contribuiu para o KDE Connect ao longo dos anos</string>
<string name="everyone_else">Todos os outros que contribuíram para o KDE Connect ao longo dos anos</string>
<string name="send_clipboard">Enviar para área de transferência</string>
<string name="tap_to_execute">Toque para executar</string>
<string name="plugin_stats">Estatísticas do plugin</string>
<string name="enable_udp_broadcast">Habilitar a descoberta de dispositivo via UDP</string>
<string name="receive_notifications_permission_explanation">Notificações devem ser permitidas para receber notificações dos outros dispositivos</string>
<string name="findmyphone_notifications_explanation">A permissão de notificação é necessária para que o telefone possa tocar quando o app estiver em segudo plano</string>
<string name="no_notifications">As notificações estão desabilitadas, você não receberá notificações de solicitação de pareamento.</string>
<string name="mpris_keepwatching">Continuar a execução</string>
<string name="mpris_keepwatching_settings_title">Continuar a execução</string>
<string name="mpris_keepwatching_settings_summary">Exibe uma notificação silenciosa para continuar a execução neste dispositivo após o fechamento da mídia.</string>
<string name="notification_channel_keepwatching">Continuar a execução</string>
</resources>

View File

@@ -114,9 +114,11 @@
<string name="error_canceled_by_user">Cancelado pelo utilizador</string>
<string name="error_canceled_by_other_peer">Cancelado pela outra máquina</string>
<string name="encryption_info_title">Dados de Encriptação</string>
<string name="encryption_info_msg_no_ssl">O outro dispositivo não usa uma versão recente do KDE Connect; será usado o método antigo de encriptação.</string>
<string name="my_device_fingerprint">A impressão digital SHA256 do certificado do seu dispositivo é:</string>
<string name="remote_device_fingerprint">A impressão digital SHA256 do certificado do dispositivo remoto é:</string>
<string name="pair_requested">Emparelhamento pedido</string>
<string name="pairing_request_from">Pedido de emparelhamento de %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">A receber %1$d ficheiro de %2$s</item>
<item quantity="other">A receber %1$d ficheiros de %2$s</item>

View File

@@ -116,9 +116,11 @@
<string name="error_canceled_by_user">Anulat de către utilizator</string>
<string name="error_canceled_by_other_peer">Anulat de către partener</string>
<string name="encryption_info_title">Informații despre criptare</string>
<string name="encryption_info_msg_no_ssl">Celălalt dispozitiv nu folosește o versiune recentă de KDE Connect, se va folosi metoda de criptare moștenită.</string>
<string name="my_device_fingerprint">Amprenta SHA256 a certificatului acestui dispozitiv e:</string>
<string name="remote_device_fingerprint">Amprenta SHA256 a certificatului dispozitivului distant e:</string>
<string name="pair_requested">Asociere cerută</string>
<string name="pairing_request_from">Cerere de asociere de la %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Se primește %1$d fișier de la %2$s</item>
<item quantity="few">Se primesc %1$d fișiere de la %2$s</item>

File diff suppressed because one or more lines are too long

View File

@@ -99,9 +99,11 @@
<string name="error_canceled_by_user">Zrušené používateľom</string>
<string name="error_canceled_by_other_peer">Zrušené druhým účastníkom</string>
<string name="encryption_info_title">Informácie o šifrovaní</string>
<string name="encryption_info_msg_no_ssl">Druhé zariadenie nepoužíva najnovšiu verziu aplikácie KDE Connect. Použije sa zastaralý spôsob šifrovania.</string>
<string name="my_device_fingerprint">Odtlačok SHA256 certifikátu vášho zariadenia je:</string>
<string name="remote_device_fingerprint">Odtlačok SHA256 certifikátu vzdialeného zariadenia je:</string>
<string name="pair_requested">Spárovanie vyžiadané</string>
<string name="pairing_request_from">Požiadavka na spárovanie zo zariadenia %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Prijíma sa %1$d súbor z %2$s</item>
<item quantity="few">Prijímajú sa %1$d súbory z %2$s</item>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Preklical uporabnik</string>
<string name="error_canceled_by_other_peer">Preklican od drugega vrstnika</string>
<string name="encryption_info_title">Informacija o šifriranju</string>
<string name="encryption_info_msg_no_ssl">Druga naprava ne uporablja najnovejše različice KDE Connect, uporablja podedovano metodo šifriranja.</string>
<string name="my_device_fingerprint">Prstni odtis SHA256 certifikata vaše naprave je:</string>
<string name="remote_device_fingerprint">Prstni odtis SHA256 certifikata oddaljene naprave je:</string>
<string name="pair_requested">Zahtevan je par</string>
<string name="pair_succeeded">Uparjanje je uspelo</string>
<string name="pairing_request_from">Zahtevek za uparjanje od \'%1s\'</string>
<string name="pairing_request_from">Zahtevek za uparjanje od %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Prejemanje %1$d datoteke od %2$s</item>
<item quantity="two">Prejemanje %1$d datotek od %2$s</item>
@@ -405,8 +406,6 @@
<string name="send_compose">Pošlji</string>
<string name="compose_send_title">Sestavite besedilo</string>
<string name="open_compose_send">Sestavite besedilo</string>
<string name="double_tap_to_drag">Dvakrat tapnite za povlek</string>
<string name="hold_to_drag">Držite za povlek</string>
<string name="about_kde_about">&lt;h1&gt;O programu&lt;/h1&gt; &lt;p&gt;KDE je svetovna skupnost programskih inženirjev, umetnikov, piscev, prevajalcev in ustvarjalcev, ki so podporniki razvoja &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Prostega programja&lt;/a&gt;. KDE izdeluje Namizno okolje Plasma, stotine aplikacij in veliko programskih knjižnic, ki jih podpirajo. &lt;/p&gt; &lt;p&gt;KDE je zadružno podjetje: noben deležnik posamično ne obvladuje smeri razvoja ali izdelka. Namesto tega delamo skupaj, da bi dosegli skupni cilj razvoja, da bi prišli do najboljšega prostega programja na svetu. Vsakdo je dobrodošel v skupnost &lt;a href=https://community.kde.org/Get_Involved&gt;da se pridruži in prispeva &lt;/a&gt; v KDE vključno z vami. &lt;/p&gt; Obiščite &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; za več informacij o skupnosti KDE community in programju, ki ga razvijamo.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Poročajte o napakah in željah&lt;/h1&gt; &lt;p&gt;Programje je vedno mogoče izboljšati in skupina KDE je vedno pripravljena na izboljšave. Vendar, vi - kot uporabnica ali uporabnik - nam morate povedati, kadar nekaj ne deluje kot pričakujete ali bi bilo lahko izdelano bolje. &lt;/p&gt; &lt;p&gt;KDE ima sistem sledenja napak. Obiščite &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; ali uporabite gumb \"Poročaj o napaki\" na zaslonu O programu za poročanje napak.&lt;/p&gt; Če imate sugestijo za izboljšanje ste povabljeni, da uporabite sistem za sledenje napakam in zabeležite vašo željo. Zagotovite, da boste resnost napake označili kot \"Seznam želja - Wishlist\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Pridružite se KDE&lt;/h1&gt; &lt;p&gt;Ni treba, da ste razvijalci programov, da bi bili člani skupnosti KDE. Lahko se pridružite jezikovnim skupinam za prevajanje uporabniških vmesnikov. Lahko prispevate risbe, teme, zvoke in izboljšano dokumentacijo. Sami se odločite!&lt;/p&gt; &lt;p&gt;Obiščite &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; za informacije o projektih, katerim lahko prispevate.&lt;/p&gt; Če potrebujete več informacij ali dokumentacije, potem obiščite &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;, kjer boste dobili potrebna navodila.</string>
@@ -421,7 +420,6 @@
<string name="maxim_leshchenko_task">Izboljšave uporabniškega vmesnika in ta stran o programu</string>
<string name="holger_kaelberer_task">Vtičnik za oddaljeno tipkovnico in popravki napak</string>
<string name="saikrishna_arcot_task">Podpora za uporabo tipkovnice vtičnika za oddaljen vnos, popravki napak in splošne izboljšave</string>
<string name="shellwen_chen_task">Izboljšanje varnosti SFTP, izboljšanje vzdržljivosti tega projekta, popravki napak in splošne izboljšave</string>
<string name="everyone_else">Vsi ostali, ki so prispevali za KDE Connect v letih razvoja</string>
<string name="send_clipboard">Pošlji odložišče</string>
<string name="tap_to_execute">Tapkajte za izvedbo</string>

View File

@@ -53,7 +53,7 @@
<string name="open_mousepad">Extern inmatning</string>
<string name="mousepad_info">Flytta fingret på skärmen för att röra muspekaren. Rör för att klicka, och använd två eller tre fingrar för höger- och mittenknapparna. Använd två fingrar för att panorera. Använd en längre beröring för drag och släpp. Musens gyroskopiska funktion kan aktiveras från insticksprogrammets inställningar.</string>
<string name="mousepad_info_no_gestures">Flytta ett finger på skärmen för att flytta muspekaren, rör för att klicka.</string>
<string name="mousepad_keyboard_input_not_supported">Tangentbordsinmatning stöds inte av den parkopplade apparaten</string>
<string name="mousepad_keyboard_input_not_supported">Tangentbordsinmatning stöds inte av den ihopparade apparaten</string>
<string name="mousepad_single_tap_settings_title">Ställ in åtgärd vid en fingerberöring</string>
<string name="mousepad_double_tap_settings_title">Ställ in åtgärd vid två fingerberöringar</string>
<string name="mousepad_triple_tap_settings_title">Ställ in åtgärd vid tre fingerberöringar</string>
@@ -108,21 +108,22 @@
<string name="category_not_paired_devices">Tillgängliga apparater</string>
<string name="category_remembered_devices">Ihågkomna apparater</string>
<string name="device_menu_plugins">Inställningar av insticksprogram</string>
<string name="device_menu_unpair">Ta bort parkoppling</string>
<string name="device_menu_unpair">Ta bort ihopparning</string>
<string name="pair_new_device">Para ihop ny apparat</string>
<string name="cancel_pairing">Avbryt parkoppling</string>
<string name="cancel_pairing">Avbryt ihopparning</string>
<string name="unknown_device">Okänd apparat</string>
<string name="error_not_reachable">Apparaten kan inte nås</string>
<string name="error_already_paired">Apparat redan parkopplad</string>
<string name="error_already_paired">Apparat redan ihopparad</string>
<string name="error_timed_out">Tidsgräns överskriden</string>
<string name="error_canceled_by_user">Avbruten av användaren</string>
<string name="error_canceled_by_other_peer">Avbruten av motparten</string>
<string name="encryption_info_title">Krypteringsinformation</string>
<string name="encryption_info_msg_no_ssl">Den andra apparaten använder inte en aktuell version av KDE-anslut. Använder den föråldrade krypteringsmetoden.</string>
<string name="my_device_fingerprint">SHA256-fingeravtryck för din apparats certifikat är:</string>
<string name="remote_device_fingerprint">SHA256-fingeravtryck för den andra apparatens certifikat är:</string>
<string name="pair_requested">Parkoppling begärd</string>
<string name="pair_succeeded">Parkoppling lyckades</string>
<string name="pairing_request_from">Parkopplingsförfrågan från \'%1s\'</string>
<string name="pair_requested">Ihopparning begärd</string>
<string name="pair_succeeded">Ihopparning lyckades</string>
<string name="pairing_request_from">Begäran om ihopparning från %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Tar emot %1$d fil från %2$s</item>
<item quantity="other">Tar emot %1$d filer från %2$s</item>
@@ -163,8 +164,8 @@
<string name="right_click">Skicka högerklick</string>
<string name="middle_click">Skicka mittenklick</string>
<string name="show_keyboard">Visa tangentbord</string>
<string name="device_not_paired">Apparat inte parkopplad</string>
<string name="request_pairing">Begär parkoppling</string>
<string name="device_not_paired">Apparat inte ihopparad</string>
<string name="request_pairing">Begära ihopparning</string>
<string name="pairing_accept">Acceptera</string>
<string name="pairing_reject">Avslå</string>
<string name="settings">Inställningar</string>
@@ -237,7 +238,7 @@
<string name="device_rename_title">Byt namn på apparat</string>
<string name="device_rename_confirm">Byt namn</string>
<string name="refresh">Uppdatera</string>
<string name="unreachable_description">Den här parkopplade apparaten kan inte nås. Försäkra dig om att den är ansluten till samma nätverk.</string>
<string name="unreachable_description">Den här ihopparade apparaten kan inte nås. Försäkra dig om att den är ansluten till samma nätverk.</string>
<string name="no_wifi">Du är inte ansluten till ett WIFI-nätverk, så du kanske inte kan se alla apparater. Klicka här för att aktivera WIFI.</string>
<string name="on_non_trusted_message">Använder inte ett pålitligt nätverk: automatisk upptäckt är inaktiverad.</string>
<string name="no_file_browser">Det finns inga filbläddrare installerade.</string>
@@ -289,7 +290,7 @@
<string name="copy_url_to_clipboard">Kopiera webbadress till klippbordet</string>
<string name="clipboard_toast">Kopierad till klippbordet</string>
<string name="runcommand_notreachable">Apparaten kan inte nås</string>
<string name="runcommand_notpaired">Apparat inte parkopplad</string>
<string name="runcommand_notpaired">Apparat inte ihopparad</string>
<string name="runcommand_nosuchdevice">Det finns ingen sådan apparat</string>
<string name="runcommand_noruncommandplugin">Apparaten har inte insticksprogrammet Kör kommando aktiverat</string>
<string name="runcommand_category_device_controls_title">Apparatkontroller</string>
@@ -389,8 +390,6 @@
<string name="send_compose">Skicka</string>
<string name="compose_send_title">Skriv och skicka</string>
<string name="open_compose_send">Skriv text</string>
<string name="double_tap_to_drag">Dubbeltryck för att dra</string>
<string name="hold_to_drag">Håll för att dra</string>
<string name="about_kde_about">&lt;h1&gt;Om&lt;/h1&gt; &lt;p&gt;KDE är ett världsomspännande nätverk av programvaruingenjörer, grafiker, författare, översättare och kreatörer som är engagerade i utveckling av &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;fri programvara&lt;/a&gt;. KDE producerar skrivbordsmiljön Plasma, hundratals program, och de talrika programvarubibliotek som stöder dem.&lt;/p&gt; &lt;p&gt;KDE är ett kooperativ, där ingen enskild person styr inriktningen eller produkterna. Istället arbetar vi tillsammans för att uppnå det gemensamma målet att skapa värdens finaste fria programvara. Alla är välkomna att &lt;a href=https://community.kde.org/Get_Involved&gt;gå med och bidra&lt;/a&gt; till KDE, inklusive du själv.&lt;/p&gt; Besök &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; för ytterligare information om KDE-gemenskapen och programvaran vi skapar.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Rapportera fel eller önskemål&lt;/h1&gt; &lt;p&gt;Programvara kan alltid förbättras, och KDE-gruppen är beredd att göra det. Men du - användaren - måste berätta för oss om något inte fungerar som förväntat eller kunde ha gjorts bättre.&lt;/p&gt; &lt;p&gt;KDE har ett felrapporteringssystem. Besök &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; eller använd dialogrutan \"Rapportera fel...\" från om-skärmen för att rapportera fel.&lt;/p&gt; Om du har ett förslag på en förbättring kan du använda felrapporteringssystemet för att registrera din önskan. Se då till att du använder allvarlighetsgraden \"Önskan\".</string>
<string name="about_kde_join_kde">&lt;h1&gt;Gå med i KDE&lt;/h1&gt; &lt;p&gt;Du behöver inte vara en programutvecklare för att bli medlem i KDE-gruppen. Du kan gå med i de nationella grupperna som översätter programmens gränssnitt. Du kan bidra med grafik, teman, ljud och förbättrad dokumentation. Det är upp till dig!&lt;/p&gt; &lt;p&gt;Besök &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; för information om några projekt som du kan delta i.&lt;/p&gt;Om du behöver mer information eller dokumentation kommer ett besök på &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; att ge dig det du behöver.</string>
@@ -405,7 +404,6 @@
<string name="maxim_leshchenko_task">Förbättringar av användargränssnitt och den här om-sidan</string>
<string name="holger_kaelberer_task">Insticksprogram för fjärrtangentbord och felrättningar</string>
<string name="saikrishna_arcot_task">Stöd för användning av tangentbordet i insticksprogrammet för fjärrinmatning, felrättningar och allmänna förbättringar</string>
<string name="shellwen_chen_task">Förbättra säkerheten för SFTP, förbättra projektets underhållbarhet, felrättningar och allmänna förbättringar</string>
<string name="everyone_else">Alla andra som har bidragit till KDE-anslut under alla år</string>
<string name="send_clipboard">Skicka klippbord</string>
<string name="tap_to_execute">Rör för att köra</string>

View File

@@ -116,9 +116,11 @@
<string name="error_canceled_by_user">பயனரால் ரத்து செய்யப்பட்டது</string>
<string name="error_canceled_by_other_peer">மறு சாதனத்தால் ரத்து செய்யப்பட்டது</string>
<string name="encryption_info_title">மறையாக்க விவரங்கள்</string>
<string name="encryption_info_msg_no_ssl">மறு சாதனம் கே.டீ.யீ. கனெக்டின் சமீபமான பதிப்பை பயன்படுத்தவில்லை. பழைய மறையாக்க முறை பயன்படுத்தப்படுகிறது.</string>
<string name="my_device_fingerprint">உங்கள் சாதனச் சான்றிதழின் SHA256 சரிகாண்தொகை:</string>
<string name="remote_device_fingerprint">தொலை சாதனச் சான்றிதழின் SHA256 சரிகாண்தொகை:</string>
<string name="pair_requested">இணைப்பு கோரப்பட்டது</string>
<string name="pairing_request_from">%1s இலிருந்து இணைப்பு கோரிக்கை</string>
<plurals name="incoming_file_title">
<item quantity="one">%2$s இலிருந்து %1$d கோப்பு பெறப்படுகிறது</item>
<item quantity="other">%2$s இருந்து %1$d கோப்புகள் பெறப்படுகின்றன</item>

View File

@@ -35,7 +35,7 @@
<string name="pref_plugin_receive_notifications">Bildirimleri al</string>
<string name="pref_plugin_receive_notifications_desc">Bildirimleri diğer aygıtlardan al ve Android üzerinde göster</string>
<string name="pref_plugin_sharereceiver">Paylaş ve al</string>
<string name="pref_plugin_sharereceiver_desc">Dosyaları ve URLleri aygıtlar arasında paylaş</string>
<string name="pref_plugin_sharereceiver_desc">Dosyaları ve URL\'leri aygıtlar arasında paylaş</string>
<string name="device_list_empty">Aygıt yok</string>
<string name="ok">Tamam</string>
<string name="sad_ok">Tamam :(</string>
@@ -43,7 +43,7 @@
<string name="open_settings">Ayarları</string>
<string name="no_permissions">Bildirimler erişebilmek için izine gereksiniminiz var</string>
<string name="no_permission_mprisreceiver">Ortam oynatıcılarınızı denelemek için bildirimlere erişim izni vermeniz gerekir</string>
<string name="no_permissions_remotekeyboard">Düğmelere basmak için KDE Bağlan Uzak Klavyeyi etkinleştirmeniz gerekir</string>
<string name="no_permissions_remotekeyboard">Düğmelere basmak için KDE Bağlan Uzak Klavye\'yi etkinleştirmeniz gerekir</string>
<string name="send_ping">Ping gönder</string>
<string name="open_mpris_controls">Çoklu ortam denetimi</string>
<string name="remotekeyboard_editing_only_title">Yalnızca düzenlerken uzaktan düğmeleri işle</string>
@@ -87,13 +87,13 @@
</string-array>
<string name="sendkeystrokes_send_to">Düğme basımlarını gönder</string>
<string name="sendkeystrokes_textbox_hint">Ana makineye düğme basımlarını gönder</string>
<string name="sendkeystrokes_disabled_toast">Düğme basımlarını gönderme devre dışı ayarlarda etkinleştirin</string>
<string name="sendkeystrokes_wrong_data">Geçersiz MIME türü — “text/x-keystrokes olmalı</string>
<string name="sendkeystrokes_disabled_toast">Düğme basımlarını gönderme devre dışı - ayarlarda etkinleştirin</string>
<string name="sendkeystrokes_wrong_data">Geçersiz MIME türü - \'text/x-keystrokes\' olmalı</string>
<string name="sendkeystrokes_sent_text">%2$s aygıtına %1$s gönderildi</string>
<string name="sendkeystrokes_pref_category_summary">Bu modül, diğer uygulamaların metin segmentlerini düğme basımları olarak bağlı olan makineye göndermelerine izin verir.</string>
<string name="sendkeystrokes_pref_category_title">Düğme Basımları Gönder</string>
<string name="sendkeystrokes_pref_enabled">Düğme basımı göndermeyi etkinleştir</string>
<string name="sendkeystrokes_pref_enabled_summary">text/x-keystrokes MIME türlü veriyi dinle</string>
<string name="sendkeystrokes_pref_enabled_summary">\'text/x-keystrokes\' MIME türlü veriyi dinle</string>
<string name="sendkeystrokes_safe_text_enabled">Güvenli metni anında gönder</string>
<string name="sendkeystrokes_safe_text_enabled_summary">Onay olmadan yalnızca sayısal kısa diziler gönder</string>
<string name="pref_plugin_mousepad_send_keystrokes">Düğme basımları olarak gönder</string>
@@ -101,9 +101,9 @@
<string name="mouse_receiver_plugin_name">Fare alıcısı</string>
<string name="mouse_receiver_no_permissions">Dokunma girdilerini uzaktan almak için aygıtı tümüyle denetlemek üzere Erişilebilirlik izinleri sağlamanız gerekir</string>
<string name="view_status_title">Durum</string>
<string name="battery_status_format">Pil: %%%d</string>
<string name="battery_status_low_format">Pil: %%%d Düşük pil</string>
<string name="battery_status_charging_format">Pil: %%%d Şarj oluyor</string>
<string name="battery_status_format">Pil: %d%%</string>
<string name="battery_status_low_format">Pil: %d%% Düşük pil</string>
<string name="battery_status_charging_format">Pil: %d%% Şarj oluyor</string>
<string name="category_connected_devices">Bağlı aygıtlar</string>
<string name="category_not_paired_devices">Kullanılabilir aygıtlar</string>
<string name="category_remembered_devices">Anımsanan aygıtlar</string>
@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Kullanıcı tarafından iptal edildi</string>
<string name="error_canceled_by_other_peer">Diğer eş tarafından iptal edildi</string>
<string name="encryption_info_title">Şifreleme Bilgisi</string>
<string name="encryption_info_msg_no_ssl">Diğer aygıt, KDE Bağlan\'ın son sürümünü kullanmıyor, eski şifreleme yöntemini kullanıyor.</string>
<string name="my_device_fingerprint">Aygıt sertifikanızın SHA256 parmak izi:</string>
<string name="remote_device_fingerprint">Uzak aygıt sertifikanızın SHA256 parmak izi:</string>
<string name="pair_requested">Eşleşme talep edildi</string>
<string name="pair_succeeded">Eşleşme başarılı</string>
<string name="pairing_request_from">%1s için eşleşme talebi</string>
<string name="pairing_request_from">%1s için eşleşme talebi</string>
<plurals name="incoming_file_title">
<item quantity="one">%2$s içinden %1$d dosya alınıyor</item>
<item quantity="other">%2$s içinden %1$d dosyalar alınıyor</item>
@@ -156,7 +157,7 @@
<item quantity="other">Dosya gönderilemedi %2$d %3$d şuraya %1$s</item>
</plurals>
<string name="tap_to_open">Açmak için dokunun</string>
<string name="received_file_text">%1s açmak için dokunun</string>
<string name="received_file_text">\'%1s\' açmak için dokunun</string>
<string name="cannot_create_file">Dosya oluşturulamıyor %s</string>
<string name="tap_to_answer">Cevap için dokunun</string>
<string name="left_click">Sol Tık Gönder</string>
@@ -188,7 +189,7 @@
</string-array>
<string name="mpris_notifications_explanation">Bildirim izni, bildirim çekmecesinde uzak konum ortamını göstermek için gereklidir</string>
<string name="mpris_notification_settings_title">Ortam denetim bildirimini göster</string>
<string name="mpris_notification_settings_summary">KDE Bağlanı açmadan ortam oynatıcılarınızı denetlemenize izin verin</string>
<string name="mpris_notification_settings_summary">KDE Bağlan\'ı açmadan ortam oynatıcılarınızı denetlemenize izin verin</string>
<string name="share_to">Şuraya Paylaş…</string>
<string name="unreachable_device">%s (Erişilebilir değil)</string>
<string name="unreachable_device_url_share_text">Erişilemeyen bir aygıta gönderilen URLler, aygıt erişilebilir olduğunda teslim edilir.\n\n</string>
@@ -197,7 +198,7 @@
<string name="invalid_device_name">Geçersiz aygıt adı</string>
<string name="shareplugin_text_saved">Gelen ileti, panoya kaydet</string>
<string name="custom_devices_settings">Özel aygıt listesi</string>
<string name="custom_device_list">IPye göre aygıtları ekle</string>
<string name="custom_device_list">IP\'ye göre aygıtları ekle</string>
<string name="custom_device_deleted">Özel aygıt silindi</string>
<string name="custom_device_list_help">Aygıtınız kendiliğinden algılanmazsa İşlem Düğmesine tıklayarak IP adresini veya ana bilgisayar adını ekleyebilirsiniz</string>
<string name="custom_device_fab_hint">Aygıt ekle</string>
@@ -205,11 +206,11 @@
<string name="share_notification_preference">Sesli bildirimler</string>
<string name="share_notification_preference_summary">Bir dosya alırken, ses çıkar ve titret</string>
<string name="share_destination_customize">Hedef dizini özelleştir</string>
<string name="share_destination_customize_summary_disabled">Gelen dosyalar İndirilenlerde gözükecektir</string>
<string name="share_destination_customize_summary_disabled">Gelen dosyalar İndirilenler\'de gözükecektir</string>
<string name="share_destination_customize_summary_enabled">Dosyalar aşağıdaki dizinden depolanacaktır</string>
<string name="share_destination_folder_preference">Hedef dizin</string>
<string name="share">Paylaş</string>
<string name="share_received_file">Paylaş: “%s”</string>
<string name="share_received_file">Paylaş \"%s\"</string>
<string name="title_activity_notification_filter">Bildirim süzgeci</string>
<string name="filter_apps_info">Bildirimler, seçili uygulamalar için eşzamanlanacaktır.</string>
<string name="show_notification_if_screen_off">Yalnızca ekran kapalıysa bildirimler gönder</string>
@@ -227,18 +228,18 @@
<string name="sftp_action_mode_menu_delete">Sil</string>
<string name="sftp_no_storage_locations_configured">Yapılandırılmış depolama yeri yok</string>
<string name="sftp_saf_permission_explanation">Dosyalara uzaktan erişmek için depolama konumlarını yapılandırmanız gerekir</string>
<string name="sftp_manage_storage_permission_explanation">Bu aygıttaki dosyalara uzak erişime izin vermek için KDE Bağlana depolamayı yönetmesi için izin vermeniz gerekiyor.</string>
<string name="sftp_manage_storage_permission_explanation">Bu aygıttaki dosyalara uzak erişime izin vermek için KDE Bağlan\'a depolamayı yönetmesi için izin vermeniz gerekiyor.</string>
<string name="no_players_connected">Onatıcı bulunamadı</string>
<string name="send_files">Dosyaları gönder</string>
<string name="block_notification_contents">Bildirim içeriğini engelle</string>
<string name="block_notification_images">Bildirim görsellerini engelle</string>
<string name="pairing_title">KDE Bağlan Aygıtları</string>
<string name="pairing_description">KDE Bağlante çalışan, aynı ağdaki diğer aygıtlar burada gözükmelidir.</string>
<string name="pairing_description">KDE Bağlan\'te çalışan, aynı ağdaki diğer aygıtlar burada gözükmelidir.</string>
<string name="device_rename_title">Aygıtı yeniden adlandır</string>
<string name="device_rename_confirm">Yeniden adlandır</string>
<string name="refresh">Yenile</string>
<string name="unreachable_description">Eşleştirilmiş aygıt ulaşılabilir değil. Aynı ağa bağlı olduğundan emin olun.</string>
<string name="no_wifi">Bir Wi-Fi ağına bağlı değilsiniz dolayısıyla herhangi bir aygıt göremeyebilirsiniz. Wi-Fiyi etkinleştirmek için buraya tıklayın.</string>
<string name="no_wifi">Bir Wi-Fi ağına bağlı değilsiniz dolayısıyla herhangi bir aygıt göremeyebilirsiniz. Wi-Fi\'yi etkinleştirmek için buraya tıklayın.</string>
<string name="on_non_trusted_message">Güvenilir bir ağda değil: otomatik bulma devre dışı.</string>
<string name="no_file_browser">Kurulu bir dosya tarayıcı yok.</string>
<string name="pref_plugin_telepathy">SMS Gönder</string>
@@ -247,7 +248,7 @@
<string name="pref_plugin_telepathy_mms_desc">KDE Bağlan üzerinden MMS göndermek için onu öntanımlı SMS uygulaması olarak ayarlayın.</string>
<string name="findmyphone_title">Telefonumu bul</string>
<string name="findmyphone_title_tablet">Tabletimi bul</string>
<string name="findmyphone_title_tv">TVmi bul</string>
<string name="findmyphone_title_tv">TV\'mi bul</string>
<string name="findmyphone_description">Aygıtı bulmak için onu çaldır</string>
<string name="findmyphone_found">Bulundu</string>
<string name="open"></string>
@@ -266,7 +267,7 @@
<string name="contacts_per_device_confirmation">Telefondaki kişileriniz bu aygıta kopyalanacak; böylece KDE Bağlan ve başka uygulamalar tarafından kullanılabilecekler.</string>
<string name="select_ringtone">Bir zil sesi seç</string>
<string name="telephony_pref_blocked_title">Engellenen numaralar</string>
<string name="telephony_pref_blocked_dialog_desc">Bu numaralardan gelen aramaları ve SMSleri göstermeyin. Lütfen her satıra bir numara belirtin</string>
<string name="telephony_pref_blocked_dialog_desc">Bu numaralardan gelen aramaları ve SMS\'leri gösterme. Lütfen her satıra bir numara belirtin</string>
<string name="mpris_coverart_description">Geçerli ortamın kapak resmi</string>
<string name="settings_icon_description">Ayarlar simgesi</string>
<string name="presenter_fullscreen">Tam ekran</string>
@@ -286,14 +287,14 @@
<string name="notification_channel_filetransfer_error">Dosya aktarımı hatası</string>
<string name="notification_channel_high_priority">Yüksek öncelik</string>
<string name="mpris_stop">Geçerli oynatıcıyı durdur</string>
<string name="copy_url_to_clipboard">URLyi panoya kopyala</string>
<string name="copy_url_to_clipboard">URL\'yi panoya kopyala</string>
<string name="clipboard_toast">Panoya kopyalandı</string>
<string name="runcommand_notreachable">Aygıt erişilebilir değil</string>
<string name="runcommand_notpaired">Aygıt eşleştirilmedi</string>
<string name="runcommand_nosuchdevice">Böyle bir aygıt yok</string>
<string name="runcommand_noruncommandplugin">Bu aygıtta Komut Çalıştır Eklentisi etkin değil</string>
<string name="runcommand_category_device_controls_title">Aygıt Denetimleri</string>
<string name="runcommand_device_controls_summary">Aygıtınız Aygıt Denetimlerini destekliyorsa yapılandırdığınız komutlar orada görünür.</string>
<string name="runcommand_device_controls_summary">Aygıtınız Aygıt Denetimleri\'ni destekliyorsa yapılandırdığınız komutlar orada görünür.</string>
<string name="set_runcommand_name_as_title">çalıştırılacak_komut_adını_başlık_olarak_ayarla</string>
<string name="runcommand_name_as_title_title">Adı başlık olarak göster</string>
<string name="pref_plugin_findremotedevice">Uzak aygıtı bul</string>
@@ -307,7 +308,7 @@
<string name="settings_rename">Aygıt adı</string>
<string name="settings_dark_mode">Karanlık tema</string>
<string name="settings_more_settings_title">Daha fazla ayar</string>
<string name="settings_more_settings_text">Aygıt başına ayarlar, bir aygıt içinden Eklenti Ayarları altında bulunabilir.</string>
<string name="settings_more_settings_text">Aygıt başına ayarlar, bir aygıt içinden \'Eklenti ayarları\' altında bulunabilir.</string>
<string name="setting_persistent_notification">Kalıcı bildirim göster</string>
<string name="setting_persistent_notification_oreo">Kalıcı bildirim</string>
<string name="setting_persistent_notification_description">Bildirim ayarlarında etkinleştirmek/devre dışı bırakmak için dokun</string>
@@ -326,7 +327,7 @@
<string name="empty_trusted_networks_list_text">Henüz herhangi bir güvenilen ağ eklemediniz</string>
<string name="allow_all_networks_text">Hepsine izin ver</string>
<string name="location_permission_needed_title">İzin gerekli</string>
<string name="location_permission_needed_desc">KDE Bağlan, uygulama arka planda olsa bile bağlı olduğunuz Wi-Fi ağını bilmek için arka plan konumu iznine gereksinim duyar. Bunun nedeni, çevrenizdeki Wi-Fi ağlarının adının, KDE Bağlanın yaptığı bu olmasa bile konumunuzu bulmak için kullanılabilmesidir.</string>
<string name="location_permission_needed_desc">KDE Bağlan, uygulama arka planda olsa bile bağlı olduğunuz WiFi ağını bilmek için arka plan konumu iznine gereksinim duyar. Bunun nedeni, çevrenizdeki WiFi ağlarının adının, KDE Bağlan\'ın yaptığı bu olmasa bile konumunuzu bulmak için kullanılabilmesidir.</string>
<string name="clipboard_android_x_incompat">Android 10, tüm uygulamalara pano erişimini kaldırdı. Bu eklenti devre dışı bırakılacak.</string>
<string name="mpris_open_url">Oynamayı burada sürdürün</string>
<string name="cant_open_url">Oynamayı sürdürmek için URL açılamıyor</string>
@@ -347,7 +348,7 @@
<string name="set_default_sms_app_title">MMS Gönder</string>
<string name="set_group_message_as_mms_title">Grup MMS gönder</string>
<string name="set_long_text_as_mms_title">Uzun metni MMS olarak gönder</string>
<string name="convert_to_mms_after_title">MMSe dönüştür</string>
<string name="convert_to_mms_after_title">MMS\'e dönüştür</string>
<string-array name="convert_to_mms_after_entries">
<item>Bir iletiden sonra</item>
<item>İki iletiden sonra</item>
@@ -379,7 +380,7 @@
<string name="visit_contributors_homepage">Katkıcının web sayfasını ziyaret edin\n%s</string>
<string name="version">Sürüm %s</string>
<string name="about_kde">KDE Hakkında</string>
<string name="kde_be_free">KDE Özgür olun!</string>
<string name="kde_be_free">KDE - Özgür olun!</string>
<string name="kde">KDE</string>
<string name="konqi">Konqi</string>
<string name="rise_up">Kalk</string>
@@ -389,12 +390,10 @@
<string name="send_compose">Gönder</string>
<string name="compose_send_title">Gönderi oluştur</string>
<string name="open_compose_send">Metin oluştur</string>
<string name="double_tap_to_drag">Sürüklemek için çift dokunun</string>
<string name="hold_to_drag">Sürüklemek için tutun</string>
<string name="about_kde_about">&lt;h1&gt;Hakkında&lt;/h1&gt; &lt;p&gt;KDE, &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;Özgür Yazılım&lt;/a&gt; hareketine destek veren yazılım mühendislerinin, sanatçıların, yazarların, çevirmenlerin ve yaratıcıların bir araya geldiği dünya çapında bir topluluktur KDE, Plasma masaüstü ortamını, yüzlerce uygulamayı ve onları destekleyen sayısız yazılım kitaplığını üretir.&lt;/p&gt; &lt;p&gt;KDE, işbirliğine dayalı bir kuruluştur: yönünü veya ürünlerini tek başına denetleyen bir kuruluş yoktur. Bunun yerine, dünyanın en iyi Özgür Yazılımını oluşturma ortak hedefine ulaşmak için birlikte çalışıyoruz. Siz de dahil olmak üzere herkes &lt;a href=https://community.kde.org/Get_Involved&gt;katılabilir&lt;/a&gt; ve katkıda bulunabilir.&lt;/p&gt; KDE topluluğu ve ürettiğimiz yazılımlar hakkında daha fazla bilgi için &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; adresini ziyaret edin.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Hataları veya İsteklerinizi Bildirin&lt;/h1&gt; &lt;p&gt;Yazılımlar her zaman iyileştirilebilir ve KDE takımın bunu yapmaya hazırdır. Ancak siz de bir şey beklendiği gibi gitmezse veya hata verirse bize bildirin.&lt;/p&gt; &lt;p&gt;KDEnin bir hata takip sistemi vardır. &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; adresini ziyaret edin veya hakkında ekranının Hata Bildir düğmesini kullanarak hataları bildirin.&lt;/p&gt; Bir iyileştirme için öneriniz varsa bunu bildirmek için hata takip sistemini kullanabilirsiniz; yalnızca Wishlist” önceliğini kullandığınızdan emin olun.</string>
<string name="about_kde_join_kde">"&lt;h1&gt;KDEye Katılın&lt;/h1&gt; &lt;p&gt;KDE takımının bir üyesi olmak için yazılım geliştirici olmanıza gerek yoktur. Program arayüzlerini çeviren dil takımlarına katılabilirsiniz. Grafikler, temalar, sesler ve iyileştirilmiş belgelendirme sağlayabilirsiniz. Karar sizin!&lt;/p&gt; &lt;p&gt;Katılabileceğiniz bazı projeler hakkında bilgi almak için &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; sayfasını ziyaret edin.&lt;/p&gt; Daha fazla bilgiye veya belgeye gereksiniminiz varsa &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; sayfasında aradığınızı bulabilirsiniz."</string>
<string name="about_kde_support_kde">"&lt;h1&gt;KDEyi Destekleyin&lt;/h1&gt; &lt;p&gt;KDE yazılımları her zaman ücretsiz kalmayı sürdürecektir; ancak bunu oluşturmak bedava değildir. &lt;/p&gt; &lt;p&gt;Geliştirmeyi desteklemek için KDE topluluğu, kar amacı gütmeyen bir kuruluş olan KDE e.V.yi kurmuştur, bu topluluk KDE topluğunu yasal ve finansal konularda temsil eder. KDE e.V. hakkında daha fazla bilgi için &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; adresini ziyaret edin.&lt;/p&gt; &lt;p&gt;KDE, finansal da dahil olmak üzere her türlü katkıdan yarar sağlar. Maddi kaynaklarımızla, geliştiricilerimizin ve diğerlerinin katkıda bulunurken oluşan masraflarını karşılıyoruz. Ayrıca yasal destek ve konferanslar ve toplantılar için de kullanılmaktadır.&lt;/p&gt; &lt;p&gt;Emeklerimizi, finansal destekle desteklemeniz için &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt; adresinde bulunan yollardan birini kullanabilirsiniz.&lt;/p&gt; Desteğiniz için şimdiden teşekkürler."</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Hataları veya İsteklerinizi Bildirin&lt;/h1&gt; &lt;p&gt;Yazılım her zaman iyileştirilebilir ve KDE takımın bunu yapmaya hazır. Ancak siz de bir şey beklendiği gibi gitmezse veya hata verirse bize bildirin.&lt;/p&gt; &lt;p&gt;KDE\'nin bir hata takip sistemi vardır. &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; adresini ziyaret edin veya hakkında ekranının \"Hata Bildir\" düğmesini kullanarak hataları bildirin.&lt;/p&gt; Bir iyileştirme için öneriniz varsa bunu bildirmek için hata takip sistemini kullanabilirsiniz; yalnızca \"Wishlist\" ciddiyet düzeyini kullandığınızdan emin olun.</string>
<string name="about_kde_join_kde">"&lt;h1&gt;KDE\'ye Katılın&lt;/h1&gt; &lt;p&gt;KDE takımının bir üyesi olmak için yazılım geliştirici olmanıza gerek yok. Program arayüzlerini çeviren dil takımlarına katılabilirsiniz. Grafikler, temalar, sesler ve iyileştirilmiş belgelendirme sağlayabilirsiniz. Karar sizin!&lt;/p&gt; &lt;p&gt;Katılabileceğiniz bazı projeler hakkında bilgi almak için &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; sayfasını ziyaret edin.&lt;/p&gt; Daha fazla bilgiye veya belgeye gereksiniminiz varsa &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt; sayfasında aradığınızı bulabilirsiniz."</string>
<string name="about_kde_support_kde">"&lt;h1&gt;KDE\'yi Destekleyin&lt;/h1&gt; &lt;p&gt;KDE yazılımları her zaman ücretsiz kalmayı sürdürecektir; ancak bunu oluşturmak bedava değildir. &lt;/p&gt; &lt;p&gt;Geliştirmeyi desteklemek için KDE topluluğu, kar amacı gütmeyen bir kuruluş olan KDE e.V.\'yi kurmuştur, bu topluluk KDE topluğunu yasal ve finansal konularda temsil eder. KDE e.V. hakkında daha fazla bilgi için &lt;a href=https://ev.kde.org/&gt;https://ev.kde.org/&lt;/a&gt; adresini ziyadet edin.&lt;/p&gt; &lt;p&gt;KDE, finansal da dahil olmak üzere her türlü katkıdan yarar sağlar. Maddi kaynaklarımızla, geliştiricilerimizin ve diğerlerinin katkıda bulunurken oluşan masraflarını karşılıyoruz. Ayrıca yasal destek ve konferanslar ve toplantılar için de kullanılmaktadır.&lt;/p&gt; &lt;p&gt;Emeklerimizi, finansal destekle desteklemeniz için &lt;a href=https://www.kde.org/community/donations/&gt;https://www.kde.org/community/donations/&lt;/a&gt; adresinde bulunan yollardan birini kullanabilirsiniz.&lt;/p&gt; Desteğiniz için şimdiden teşekkürler."</string>
<string name="maintainer_and_developer">Projeyi sürdüren ve geliştirici</string>
<string name="developer">Geliştirici</string>
<string name="apple_support">macOS ve iOS desteği üzerinde çalışılmaktadır.</string>
@@ -405,8 +404,7 @@
<string name="maxim_leshchenko_task">Kullanıcı arabirimi iyileştirmeleri ve bu hakkında sayfası</string>
<string name="holger_kaelberer_task">Uzak klavye eklentisi ve hata düzeltmeleri</string>
<string name="saikrishna_arcot_task">Uzaktan girdi eklentisinde klavye kullanımı desteği, hata düzeltmeleri ve genel iyileştirmeler</string>
<string name="shellwen_chen_task">SFTP güvenliğini artır, projenin bakımını daha da kolaylaştır, hata düzeltmeleri ve genel iyileştirmeler</string>
<string name="everyone_else">KDE Bağlana yıllar boyunca katkıda bulunan herkes</string>
<string name="everyone_else">KDE Bağlan\'a yıllar boyunca katkıda bulunan herkes</string>
<string name="send_clipboard">Pano gönder</string>
<string name="tap_to_execute">Yürütmek için dokun</string>
<string name="plugin_stats">Eklenti istatistikleri</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">Скасовано користувачем</string>
<string name="error_canceled_by_other_peer">Скасовано з іншого вузла пов’язування</string>
<string name="encryption_info_title">Дані щодо шифрування</string>
<string name="encryption_info_msg_no_ssl">На сторонньому пристрої не використовується нова версія KDE Connect, у якій використовується застарілий спосіб шифрування.</string>
<string name="my_device_fingerprint">Відбиток SHA256 сертифіката пристрою:</string>
<string name="remote_device_fingerprint">Відбиток SHA256 сертифіката віддаленого пристрою:</string>
<string name="pair_requested">Запит щодо пов’язування</string>
<string name="pair_succeeded">Успішне пов’язування</string>
<string name="pairing_request_from">Запит щодо пов’язування від «%1s»</string>
<string name="pairing_request_from">Запит щодо пов’язування від %1s</string>
<plurals name="incoming_file_title">
<item quantity="one">Отримуємо %1$d файл з %2$s</item>
<item quantity="few">Отримуємо %1$d файли з %2$s</item>
@@ -405,8 +406,6 @@
<string name="send_compose">Надіслати</string>
<string name="compose_send_title">Надсилання редагованого</string>
<string name="open_compose_send">Редагувати текст</string>
<string name="double_tap_to_drag">Подвійне торкання для перетягування</string>
<string name="hold_to_drag">Утримування для перетягування</string>
<string name="about_kde_about">&lt;h1&gt;Інформація&lt;/h1&gt; &lt;p&gt;KDE — це всесвітня спільнота програмістів, художників, авторів текстів, перекладачів та фахівців з полегшення користування програмами, які роблять свій внесок до розвитку &lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;вільного програмного забезпечення&lt;/a&gt;. KDE створено стільничне середовище Плазма, сотні вільних програм і багато бібліотек, які є їхньою основою.&lt;/p&gt; &lt;p&gt;Розробка KDE є спільною працею, у якій жоден з учасників не має переважного контролю над зусиллями або результатами роботи інших розробників KDE. Ми працюємо разом заради спільної мети — створення найкращого вільного програмного забезпечення. Кожен може &lt;a href=https://community.kde.org/Get_Involved&gt;долучитися і зробити свій внесок&lt;/a&gt;, зокрема це можете зробити ви.&lt;/p&gt; Відвідайте сайт &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt;, щоб дізнатися більше про спільноту KDE та створене нею програмне забезпечення.</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;Повідомляйте про вади і ваші побажання&lt;/h1&gt; &lt;p&gt;Програмне забезпечення завжди потребує вдосконалення, і команда KDE готова це робити. Проте, вам (користувачеві) варто повідомити нам, якщо щось не працює, як слід, або щось можна покращити.&lt;/p&gt; &lt;p&gt;KDE має систему стеження за вадами. Завітайте на сторінку &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; , щоб повідомити розробників про ваду у програмі.&lt;/p&gt;Якщо у вас є пропозиція щодо вдосконалення, за допомогою цієї системи можна зареєструвати ваше побажання. Переконайтеся, що поле «Важливість» встановлено у значення «Список побажань» («Wishlist»).</string>
<string name="about_kde_join_kde">&lt;h1&gt;Долучайтеся до KDE&lt;/h1&gt; &lt;p&gt;Не обов\'язково бути програмістом, щоб належати до Команди KDE. Можете приєднатися до команд, що перекладають інтерфейс програм. Можете забезпечувати користувачів графікою, темами, звуками та вдосконаленою документацію. Вам вирішувати!&lt;/p&gt; &lt;p&gt;Завітайте на сторінку &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; щодо інформації про деякі проєкти, у яких можна взяти участь.&lt;/p&gt;Якщо ви потребуєте більше інформації або документації, відвідайте &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;, щоб ознайомитися з нею.</string>
@@ -421,7 +420,6 @@
<string name="maxim_leshchenko_task">Удосконалення інтерфейсу та ця інформаційна сторінка</string>
<string name="holger_kaelberer_task">Додаток бездротової клавіатури та виправлення вад</string>
<string name="saikrishna_arcot_task">Підтримка використання клавіатури у додатку віддаленого введення, виправлення вад і загальні удосконалення</string>
<string name="shellwen_chen_task">Удосконалення захисту SFTP, удосконалення можливості супроводу проєкту, виправлення вад і загальні удосконалення</string>
<string name="everyone_else">Усім іншим, хто робив внесок до KDE Connect протягом років розробки</string>
<string name="send_clipboard">Надіслати вміст буфера</string>
<string name="tap_to_execute">Торкніться, щоб виконати</string>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">已被用户取消</string>
<string name="error_canceled_by_other_peer">已被其他对等点取消</string>
<string name="encryption_info_title">加密信息</string>
<string name="encryption_info_msg_no_ssl">另一设备没有使用最新的 KDE Connect使用旧版加密方法。</string>
<string name="my_device_fingerprint">您的设备证书的 SHA256 指纹是:</string>
<string name="remote_device_fingerprint">远程设备证书的 SHA256 指纹是:</string>
<string name="pair_requested">已请求配对</string>
<string name="pair_succeeded">配对成功</string>
<string name="pairing_request_from">来自%1s的配对请求</string>
<string name="pairing_request_from">来自 %1s 的配对请求</string>
<plurals name="incoming_file_title">
<item quantity="other">正在从 %2$s 接收 %1$d 个文件</item>
</plurals>
@@ -381,8 +382,6 @@
<string name="send_compose">发送</string>
<string name="compose_send_title">编写发送</string>
<string name="open_compose_send">编写文本</string>
<string name="double_tap_to_drag">双击进行拖动</string>
<string name="hold_to_drag">按住进行拖动</string>
<string name="about_kde_about">&lt;h1&gt;关于&lt;/h1&gt; &lt;p&gt;KDE 是由一群致力于&lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;自由软件&lt;/a&gt;事业的人们所组成的全球性协作社区。它的成员包括了来自世界各地的软件工程师、艺术工作者、文字工作者、翻译人员和其他创意人员。KDE 社区开发了 Plasma 桌面环境、数百款功能各异的应用软件、以及用于支持它们的大量程序库。&lt;/p&gt; &lt;p&gt;KDE 是一项立足于协作精神的事业,它的运作和产出不受任何单一个人或者机构的控制。我们的共同目标是为全世界带来高品质的自由软件。不管您来自何方,我们都欢迎您&lt;a href=https://community.kde.org/Get_Involved&gt;加入 KDE 并做出贡献&lt;/a&gt;&lt;/p&gt;请访问 &lt;a href=https://www.kde.org/&gt;https://www.kde.org/&lt;/a&gt; 来了解 KDE 社区和软件的更多信息。</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;报告程序缺陷和需求&lt;/h1&gt; &lt;p&gt;KDE 团队一直致力于改进软件的品质。为了做到这一点,倾听来自用户的反馈非常重要。如果您遇到了软件不能正常工作的情况,请务必告诉我们。如果您有关于改进软件的想法,也请与我们分享。&lt;/p&gt; &lt;p&gt;KDE 建有程序缺陷跟踪系统,请访问 &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; 或者使用“帮助”菜单中的“报告缺陷”对话框填写报告。&lt;/p&gt;如果您想要提出改进建议而不是报告程序缺陷,请确保在表格的 Severity (严重程度) 选单中选择“Wishlist (需求)”。</string>
<string name="about_kde_join_kde">&lt;h1&gt;加入 KDE&lt;/h1&gt; &lt;p&gt;即使您不是软件开发人员,我们也欢迎您加入 KDE 的队伍!您可以加入各种语言的翻译团队来翻译软件的界面,您还可以制作图像、主题、音效,或者改进软件配套的文档……您的角色您来定!&lt;/p&gt; &lt;p&gt;请访问 &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; 来物色您感兴趣的项目。&lt;/p&gt;如需了解更多相关信息和文档,请访问 &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;</string>
@@ -397,7 +396,6 @@
<string name="maxim_leshchenko_task">界面改进和此关于页面</string>
<string name="holger_kaelberer_task">远程键盘插件和程序缺陷修正</string>
<string name="saikrishna_arcot_task">支持在远程输入插件中使用键盘、程序缺陷修正和常规改进</string>
<string name="shellwen_chen_task">改进 SFTP 的安全性,改进此项目的可维护性,修复程序缺陷和常规改进</string>
<string name="everyone_else">以及多年来为 KDE Connect 作出过贡献的其他所有人</string>
<string name="send_clipboard">发送剪贴板</string>
<string name="tap_to_execute">轻触执行</string>
@@ -406,8 +404,4 @@
<string name="receive_notifications_permission_explanation">需要允许通知才能从其他设备接收通知</string>
<string name="findmyphone_notifications_explanation">需要通知权限,这样当应用程序处于后台时手机可以发出铃声</string>
<string name="no_notifications">通知已禁用,您将不会收到传入的配对通知。</string>
<string name="mpris_keepwatching">继续播放</string>
<string name="mpris_keepwatching_settings_title">继续播放</string>
<string name="mpris_keepwatching_settings_summary">关闭媒体后显示一条用于继续在此设备上播放的静音通知</string>
<string name="notification_channel_keepwatching">继续播放</string>
</resources>

View File

@@ -118,11 +118,12 @@
<string name="error_canceled_by_user">使用者中斷</string>
<string name="error_canceled_by_other_peer">被其他同等功能應用中斷</string>
<string name="encryption_info_title">加密資訊</string>
<string name="encryption_info_msg_no_ssl">其他的裝置沒有使用新版本的KDE連線使用傳統的加密模式。</string>
<string name="my_device_fingerprint">您裝置憑證的 SHA256 指紋是:</string>
<string name="remote_device_fingerprint">遠端裝置憑證的 SHA256 指紋是:</string>
<string name="pair_requested">已請求配對</string>
<string name="pair_succeeded">配對成功</string>
<string name="pairing_request_from">來自%1s的配對請求</string>
<string name="pairing_request_from">來自 %1s 的配對請求</string>
<plurals name="incoming_file_title">
<item quantity="other">正在從 %2$s 接收 %1$d 個檔案</item>
</plurals>
@@ -181,9 +182,6 @@
<string name="mpris_notifications_explanation">需要通知權限來在通知欄內顯示遠端媒體</string>
<string name="mpris_notification_settings_title">顯示媒體控制項通知</string>
<string name="mpris_notification_settings_summary">允許控制您的媒體播放器而不需要開啟 KDE 連線</string>
<string name="share_to">分享給…</string>
<string name="unreachable_device">%s無法連線</string>
<string name="unreachable_device_url_share_text">分享給無法連線的裝置的網址會在該裝置重新連線後傳送給它。\n\n</string>
<string name="protocol_version_newer">此裝置使用較新的通訊協定</string>
<string name="plugin_settings_with_name">%s 設定</string>
<string name="invalid_device_name">無效的裝置名稱</string>
@@ -374,15 +372,11 @@
<string name="kde_be_free">KDE ─ 擁抱自由!</string>
<string name="kde">KDE</string>
<string name="konqi">Konqi</string>
<string name="rise_up">往上</string>
<string name="rise_down">往下</string>
<string name="click_here_to_type">按這裡來打字</string>
<string name="clear_compose">清除</string>
<string name="send_compose">傳送</string>
<string name="compose_send_title">撰寫傳送</string>
<string name="open_compose_send">撰寫簡訊</string>
<string name="double_tap_to_drag">雙擊來拖曳</string>
<string name="hold_to_drag">按住來拖曳</string>
<string name="about_kde_about">&lt;h1&gt;關於&lt;/h1&gt;&lt;p&gt;KDE 是一個由眾多軟體工程師、藝術作業者、文字作業者、翻譯人員和其他有志於&lt;a href=https://www.gnu.org/philosophy/free-sw.html&gt;自由軟體&lt;/a&gt;事業的人們組成的世界性社群。KDE 做出了 Plasma 桌面環境、數百個應用程式和支援它們的軟體函式庫。&lt;/p&gt;&lt;p&gt;KDE 團隊不受任何單獨的團體、公司或機構控制。我們的目標是一同為製作世界上最好的自由軟體而努力。我們歡迎任何人&lt;a href=https://community.kde.org/Get_Involved&gt;加入並作出貢獻&lt;/a&gt;——包含您。&lt;/p&gt;請造訪 &lt;a href=&amp;quot;https://www.kde.org/&amp;quot;&gt;https://www.kde.org/&lt;/a&gt; 來了解有關 KDE 社群與我們所做的軟體的更多資訊。</string>
<string name="about_kde_report_bugs_or_wishes">&lt;h1&gt;回報問題或希望功能&lt;/h1&gt;&lt;p&gt;軟體總是可以改善,而 KDE 團隊準備好繼續此項工作。不過您 — 作為使用者 — 需要在有東西沒有正常運作或是可以更好的時候告訴我們。&lt;/p&gt;&lt;p&gt;KDE 有一個問題追蹤系統。請造訪 &lt;a href=https://bugs.kde.org/&gt;https://bugs.kde.org/&lt;/a&gt; 或是從關於頁面使用「回報問題」按鈕來回報問題。&lt;/p&gt;如果您有改善的建議您也可以使用問題追蹤系統來寫下您的希望。此時請使用「Wishlist」願望清單作為問題的嚴重程度。</string>
<string name="about_kde_join_kde">&lt;h1&gt;加入 KDE&lt;/h1&gt;&lt;p&gt;您不需要是軟體工程師也能加入 KDE 團隊。您可以加入翻譯團隊來翻譯程式的介面。您可以提供圖形、佈景主題、音效,或幫忙撰寫文件,看您喜歡做哪一項。&lt;/p&gt;&lt;p&gt;請參考 &lt;a href=https://community.kde.org/Get_Involved&gt;https://community.kde.org/Get_Involved&lt;/a&gt; 上的資訊看看您能幫上什麼忙。&lt;/p&gt;如果您需要更多資訊或說明文件,請參照 &lt;a href=https://techbase.kde.org/&gt;https://techbase.kde.org/&lt;/a&gt;,上面會有一些能幫忙您的資訊。</string>
@@ -397,7 +391,6 @@
<string name="maxim_leshchenko_task">使用者介面的改善,以及這個關於頁面</string>
<string name="holger_kaelberer_task">遠端鍵盤外掛程式與問題修正</string>
<string name="saikrishna_arcot_task">在遠端輸入外掛程式中對於鍵盤的支援、錯誤修正與一般改進</string>
<string name="shellwen_chen_task">改善 SFTP 的安全性、改善本專案的易維護性、錯誤修正與一般改進</string>
<string name="everyone_else">其他所有這些年來向 KDE 連線貢獻的人們</string>
<string name="send_clipboard">傳送剪貼簿</string>
<string name="tap_to_execute">按一下執行</string>
@@ -406,8 +399,4 @@
<string name="receive_notifications_permission_explanation">需要允許通知才能接收來自其他裝置的通知</string>
<string name="findmyphone_notifications_explanation">需要通知權限讓應用程式在背景時也能讓手機響鈴</string>
<string name="no_notifications">通知已停用,您不會接收到送來的配對請求。</string>
<string name="mpris_keepwatching">繼續播放</string>
<string name="mpris_keepwatching_settings_title">繼續播放</string>
<string name="mpris_keepwatching_settings_summary">關閉媒體之後在此裝置顯示繼續播放用的靜音通知</string>
<string name="notification_channel_keepwatching">繼續播放</string>
</resources>

View File

@@ -85,7 +85,6 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="mousepad_scroll_sensitivity_title">Scroll sensitivity</string>
<string name="gyro_mouse_enabled" translatable="false">gyro_mouse_enabled</string>
<string name="mousepad_mouse_buttons_enabled_pref" translatable="false">mouse_buttons_enabled</string>
<string name="mousepad_doubletap_drag_enabled_pref" translatable="false">doubletap_drag_enabled</string>
<string name="gyro_mouse_enabled_title">Enable gyroscope mouse</string>
<string name="gyro_mouse_sensitivity_title">Gyroscope sensitivity</string>
<string name="gyro_mouse_sensitivity" translatable="false">gyro_mouse_sensitivity</string>
@@ -179,12 +178,13 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="error_canceled_by_user">Canceled by user</string>
<string name="error_canceled_by_other_peer">Canceled by other peer</string>
<string name="encryption_info_title">Encryption Info</string>
<string name="encryption_info_msg_no_ssl">The other device doesn\'t use a recent version of KDE Connect, using the legacy encryption method.</string>
<string name="my_device_fingerprint">SHA256 fingerprint of your device certificate is:</string>
<string name="remote_device_fingerprint">SHA256 fingerprint of remote device certificate is:</string>
<string name="pair_requested">Pair requested</string>
<string name="pair_succeeded">Pair succeeded</string>
<string name="pairing_verification_code" translatable="false">🔑 %1s</string>
<string name="pairing_request_from">Pairing request from \'%1s\'</string>
<string name="pairing_request_from">Pairing request from %1s</string>
<string name="pairing_verification_code" translatable="false">🔑%1s...</string>
<plurals name="incoming_file_title">Receiving file from %1s>
<item quantity="one">Receiving %1$d file from %2$s</item>
<item quantity="other">Receiving %1$d files from %2$s</item>
@@ -514,8 +514,6 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="send_compose">Send</string>
<string name="compose_send_title">Compose send</string>
<string name="open_compose_send">Compose text</string>
<string name="double_tap_to_drag">Double tap to drag</string>
<string name="hold_to_drag">Hold to drag</string>
<string name="about_kde_about"><![CDATA[
<h1>About</h1>
@@ -558,7 +556,6 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="maxim_leshchenko_task">UI improvements and this about page</string>
<string name="holger_kaelberer_task">Remote keyboard plugin and bug fixes</string>
<string name="saikrishna_arcot_task">Support for using the keyboard in the remote input plugin, bug fixes and general improvements</string>
<string name="shellwen_chen_task">Improve the security of SFTP, improve the maintainability of this project, bug fixes and general improvements</string>
<string name="everyone_else">Everyone else who has contributed to KDE Connect over the years</string>
<string name="send_clipboard">Send clipboard</string>

View File

@@ -90,15 +90,6 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
android:key="@string/mousepad_mouse_buttons_enabled_pref"
android:title="@string/mousepad_mouse_buttons_title" />
<SwitchPreference
android:id="@+id/mousepad_double_tap_drag_enabled_pref"
android:defaultValue="true"
android:key="@string/mousepad_doubletap_drag_enabled_pref"
android:title="Drag and drop behavior"
android:summaryOn="@string/double_tap_to_drag"
android:summaryOff="@string/hold_to_drag"
/>
<org.kde.kdeconnect.Helpers.LongSummaryPreferenceCategory
android:key="@string/sendkeystrokes_pref_category"

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<share-target android:targetClass="org.kde.kdeconnect.Plugins.SharePlugin.ShareActivity">
<data android:mimeType="*/*" />
<category android:name="org.kde.kdeconnect.category.SHARE_TARGET" />
</share-target>
</shortcuts>

View File

@@ -20,15 +20,4 @@ dependencyResolutionManagement {
}
}
}
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("org.ow2.asm:asm-util:9.6")
}
}
rootProject.name = "kdeconnect-android"

View File

@@ -11,15 +11,12 @@ import android.net.Network;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.kde.kdeconnect.DeviceInfo;
import java.util.concurrent.CopyOnWriteArrayList;
public abstract class BaseLinkProvider {
public interface ConnectionReceiver {
void onConnectionReceived(@NonNull final BaseLink link);
void onDeviceInfoUpdated(@NonNull final DeviceInfo deviceInfo);
void onConnectionLost(BaseLink link);
}
@@ -53,15 +50,6 @@ public abstract class BaseLinkProvider {
}
}
/**
* To be called from the child classes when we discover new DeviceInfo for an already linked device.
*/
protected void onDeviceInfoUpdated(@NonNull final DeviceInfo deviceInfo) {
for(ConnectionReceiver cr : connectionReceivers) {
cr.onDeviceInfoUpdated(deviceInfo);
}
}
public abstract void onStart();
public abstract void onStop();
public abstract void onNetworkChange(@Nullable Network network);

View File

@@ -22,7 +22,6 @@ import android.util.Log
import org.apache.commons.io.IOUtils
import org.kde.kdeconnect.Backends.BaseLinkProvider
import org.kde.kdeconnect.Device
import org.kde.kdeconnect.DeviceInfo
import org.kde.kdeconnect.DeviceInfo.Companion.fromIdentityPacketAndCert
import org.kde.kdeconnect.Helpers.DeviceHelper
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
@@ -196,8 +195,8 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
}
val response = sb.toString()
val identityPacket = NetworkPacket.unserialize(response)
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
Log.w("BTLinkProvider/Server", "Invalid identity packet received.")
if (identityPacket.type != NetworkPacket.PACKET_TYPE_IDENTITY) {
Log.e("BTLinkProvider/Server", "2 Expecting an identity packet")
return
}
Log.i("BTLinkProvider/Server", "Received identity packet")
@@ -255,8 +254,6 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
context.unregisterReceiver(this)
} catch (se: SecurityException) {
Log.w("BluetoothLinkProvider", se)
} catch (ia: IllegalArgumentException) {
Log.w("BluetoothLinkProvider", ia) // Happens sometimes in unregisterReceiver
}
}
@@ -367,13 +364,11 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
Log.i("BTLinkProvider/Client", "Device: " + device.address + " Before unserialize (message: '" + message + "')")
val identityPacket = NetworkPacket.unserialize(message)
Log.i("BTLinkProvider/Client", "Device: " + device.address + " After unserialize")
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
Log.w("BTLinkProvider/Client", "Invalid identity packet received.")
connection.close()
if (identityPacket.type != NetworkPacket.PACKET_TYPE_IDENTITY) {
Log.e("BTLinkProvider/Client", "1 Expecting an identity packet")
socket.close()
return
}
Log.i("BTLinkProvider/Client", "Received identity packet")
val myId = DeviceHelper.getDeviceId(context)
if (identityPacket.getString("deviceId") == myId) {
@@ -420,4 +415,4 @@ class BluetoothLinkProvider(private val context: Context) : BaseLinkProvider() {
private val SERVICE_UUID = UUID.fromString("185f3df4-3268-4e3f-9fca-d4d5059915bd")
private val BYTE_REVERSED_SERVICE_UUID = UUID(java.lang.Long.reverseBytes(SERVICE_UUID.leastSignificantBits), java.lang.Long.reverseBytes(SERVICE_UUID.mostSignificantBits))
}
}
}

View File

@@ -202,7 +202,7 @@ class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
socket!!.outputStream.write(data)
}
private fun handleException(@Suppress("UNUSED_PARAMETER") ignored: Exception) {
private fun handleException(@Suppress("UNUSED_PARAMETER") ignored: IOException) {
lock.withLock {
open = false
for (channel in channels.values) {
@@ -257,8 +257,6 @@ class ConnectionMultiplexer(socket: BluetoothSocket) : Closeable {
socket!!.outputStream.write(data)
} catch (e: IOException) {
handleException(e)
} catch (e: NullPointerException) {
handleException(e)
}
channel.lockCondition.signalAll()
}

View File

@@ -44,7 +44,7 @@ public class LanLink extends BaseLink {
Locally, Remotely
}
private DeviceInfo deviceInfo;
private final DeviceInfo deviceInfo;
private volatile SSLSocket socket = null;
@@ -59,9 +59,7 @@ public class LanLink extends BaseLink {
}
//Returns the old socket
public SSLSocket reset(final SSLSocket newSocket, final DeviceInfo deviceInfo) throws IOException {
this.deviceInfo = deviceInfo;
public SSLSocket reset(final SSLSocket newSocket) throws IOException {
SSLSocket oldSocket = socket;
socket = newSocket;
@@ -105,7 +103,8 @@ public class LanLink extends BaseLink {
public LanLink(@NonNull Context context, @NonNull DeviceInfo deviceInfo, @NonNull BaseLinkProvider linkProvider, @NonNull SSLSocket socket) throws IOException {
super(context, linkProvider);
reset(socket, deviceInfo);
this.deviceInfo = deviceInfo;
reset(socket);
}
@Override

View File

@@ -108,6 +108,11 @@ public class LanLinkProvider extends BaseLinkProvider {
return;
}
if (!networkPacket.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
Log.e("KDE/LanLinkProvider", "Expecting an identity packet instead of " + networkPacket.getType());
return;
}
Log.i("KDE/LanLinkProvider", "identity packet received from a TCP connection from " + networkPacket.getString("deviceName"));
identityPacketReceived(networkPacket, socket, LanLink.ConnectionStarted.Locally);
}
@@ -120,13 +125,12 @@ public class LanLinkProvider extends BaseLinkProvider {
String message = new String(packet.getData(), Charsets.UTF_8);
final NetworkPacket identityPacket = NetworkPacket.unserialize(message);
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
Log.w("KDE/LanLinkProvider", "Invalid identity packet received.");
final String deviceId = identityPacket.getString("deviceId");
if (!identityPacket.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
Log.e("KDE/LanLinkProvider", "Expecting an UDP identity packet");
return;
}
final String deviceId = identityPacket.getString("deviceId");
String myId = DeviceHelper.getDeviceId(context);
if (deviceId.equals(myId)) {
//Ignore my own broadcast
@@ -188,11 +192,6 @@ public class LanLinkProvider extends BaseLinkProvider {
@WorkerThread
private void identityPacketReceived(final NetworkPacket identityPacket, final Socket socket, final LanLink.ConnectionStarted connectionStarted) throws IOException {
if (!DeviceInfo.isValidIdentityPacket(identityPacket)) {
Log.w("KDE/LanLinkProvider", "Invalid identity packet received.");
return;
}
String myId = DeviceHelper.getDeviceId(context);
final String deviceId = identityPacket.getString("deviceId");
if (deviceId.equals(myId)) {
@@ -227,7 +226,7 @@ public class LanLinkProvider extends BaseLinkProvider {
Certificate certificate = event.getPeerCertificates()[0];
DeviceInfo deviceInfo = DeviceInfo.fromIdentityPacketAndCert(identityPacket, certificate);
Log.i("KDE/LanLinkProvider", "Handshake as " + mode + " successful with " + deviceName + " secured with " + event.getCipherSuite());
addOrUpdateLink(sslSocket, deviceInfo);
addLink(sslSocket, deviceInfo);
} catch (IOException e) {
Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + deviceName, e);
Device device = KdeConnect.getInstance().getDevice(deviceId);
@@ -249,9 +248,9 @@ public class LanLinkProvider extends BaseLinkProvider {
*
* @param socket a new Socket, which should be used to send and receive packets from the remote device
* @param deviceInfo remote device info
* @throws IOException if an exception is thrown by {@link LanLink#reset(SSLSocket, DeviceInfo)}
* @throws IOException if an exception is thrown by {@link LanLink#reset(SSLSocket)}
*/
private void addOrUpdateLink(SSLSocket socket, DeviceInfo deviceInfo) throws IOException {
private void addLink(SSLSocket socket, DeviceInfo deviceInfo) throws IOException {
LanLink link = visibleDevices.get(deviceInfo.id);
if (link != null) {
if (!link.getDeviceInfo().certificate.equals(deviceInfo.certificate)) {
@@ -260,8 +259,7 @@ public class LanLinkProvider extends BaseLinkProvider {
}
// Update existing link
Log.d("KDE/LanLinkProvider", "Reusing same link for device " + deviceInfo.id);
link.reset(socket, deviceInfo);
onDeviceInfoUpdated(deviceInfo);
final Socket oldSocket = link.reset(socket);
} else {
// Create a new link
Log.d("KDE/LanLinkProvider", "Creating a new link for device " + deviceInfo.id);
@@ -416,7 +414,7 @@ public class LanLinkProvider extends BaseLinkProvider {
DatagramSocket socket;
try {
socket = new DatagramSocket();
if (network != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
if (network != null) {
try {
network.bindSocket(socket);
} catch (IOException e) {

View File

@@ -131,7 +131,7 @@ public class MdnsDiscovery {
// Each field (key + value) needs to be < 255 bytes. All the fields combined need to be < 1300 bytes.
// Also, on Android Lollipop those fields aren't resolved.
String deviceName = DeviceHelper.getDeviceName(context);
String deviceType = DeviceHelper.getDeviceType().toString();
String deviceType = DeviceHelper.getDeviceType(context).toString();
String protocolVersion = Integer.toString(DeviceHelper.ProtocolVersion);
serviceInfo.setAttribute("id", deviceId);
serviceInfo.setAttribute("name", deviceName);

View File

@@ -0,0 +1,737 @@
/*
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.util.Log;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.kde.kdeconnect.Backends.BaseLink;
import org.kde.kdeconnect.Helpers.DeviceHelper;
import org.kde.kdeconnect.Helpers.NotificationHelper;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Plugins.Plugin;
import org.kde.kdeconnect.Plugins.PluginFactory;
import org.kde.kdeconnect.UserInterface.MainActivity;
import org.kde.kdeconnect_tp.R;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
public class Device implements BaseLink.PacketReceiver {
private final Context context;
final DeviceInfo deviceInfo;
private int notificationId;
PairingHandler pairingHandler;
private final CopyOnWriteArrayList<PairingHandler.PairingCallback> pairingCallbacks = new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList<BaseLink> links = new CopyOnWriteArrayList<>();
private DevicePacketQueue packetQueue;
private List<String> supportedPlugins;
private final ConcurrentHashMap<String, Plugin> plugins = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Plugin> pluginsWithoutPermissions = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Plugin> pluginsWithoutOptionalPermissions = new ConcurrentHashMap<>();
private MultiValuedMap<String, String> pluginsByIncomingInterface = new ArrayListValuedHashMap<>();
private final SharedPreferences settings;
private final CopyOnWriteArrayList<PluginsChangedListener> pluginsChangedListeners = new CopyOnWriteArrayList<>();
private String connectivityType;
public boolean supportsPacketType(String type) {
if (deviceInfo.incomingCapabilities == null) {
return true;
} else {
return deviceInfo.incomingCapabilities.contains(type);
}
}
public String getConnectivityType() {
return connectivityType;
}
public interface PluginsChangedListener {
void onPluginsChanged(@NonNull Device device);
}
/**
* Constructor for remembered, already-trusted devices.
* Given the deviceId, it will load the other properties from SharedPreferences.
*/
Device(@NonNull Context context, @NonNull String deviceId) throws CertificateException {
this.context = context;
this.settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
this.deviceInfo = DeviceInfo.loadFromSettings(context, deviceId, settings);
this.pairingHandler = new PairingHandler(this, pairingCallback, PairingHandler.PairState.Paired);
this.supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins()); // Assume all are supported until we receive capabilities
this.connectivityType = "";
Log.i("Device","Loading trusted device: " + deviceInfo.name);
}
/**
* Constructor for devices discovered but not trusted yet.
* Gets the DeviceInfo by calling link.getDeviceInfo() on the link passed.
* This constructor also calls addLink() with the link you pass to it, since it's not legal to have an unpaired Device with 0 links.
*/
Device(@NonNull Context context, @NonNull BaseLink link) {
this.context = context;
this.deviceInfo = link.getDeviceInfo();
this.settings = context.getSharedPreferences(deviceInfo.id, Context.MODE_PRIVATE);
this.pairingHandler = new PairingHandler(this, pairingCallback, PairingHandler.PairState.NotPaired);
this.supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins()); // Assume all are supported until we receive capabilities
this.connectivityType = link.getLinkProvider().getName();
Log.i("Device","Creating untrusted device: "+ deviceInfo.name);
addLink(link);
}
public String getName() {
return deviceInfo.name;
}
public Drawable getIcon() {
return deviceInfo.type.getIcon(context);
}
public DeviceType getDeviceType() {
return deviceInfo.type;
}
public String getDeviceId() {
return deviceInfo.id;
}
public Certificate getCertificate() {
return deviceInfo.certificate;
}
public Context getContext() {
return context;
}
//Returns 0 if the version matches, < 0 if it is older or > 0 if it is newer
public int compareProtocolVersion() {
return deviceInfo.protocolVersion - DeviceHelper.ProtocolVersion;
}
//
// Pairing-related functions
//
public boolean isPaired() {
return pairingHandler.getState() == PairingHandler.PairState.Paired;
}
public boolean isPairRequested() {
return pairingHandler.getState() == PairingHandler.PairState.Requested;
}
public boolean isPairRequestedByPeer() {
return pairingHandler.getState() == PairingHandler.PairState.RequestedByPeer;
}
public void addPairingCallback(PairingHandler.PairingCallback callback) {
pairingCallbacks.add(callback);
}
public void removePairingCallback(PairingHandler.PairingCallback callback) {
pairingCallbacks.remove(callback);
}
public void requestPairing() {
pairingHandler.requestPairing();
}
public void unpair() {
pairingHandler.unpair();
}
/* This method is called after accepting pair request form GUI */
public void acceptPairing() {
Log.i("KDE/Device", "Accepted pair request started by the other device");
pairingHandler.acceptPairing();
}
/* This method is called after rejecting pairing from GUI */
public void cancelPairing() {
Log.i("KDE/Device", "This side cancelled the pair request");
pairingHandler.cancelPairing();
}
PairingHandler.PairingCallback pairingCallback = new PairingHandler.PairingCallback() {
@Override
public void incomingPairRequest() {
displayPairingNotification();
for (PairingHandler.PairingCallback cb : pairingCallbacks) {
cb.incomingPairRequest();
}
}
@Override
public void pairingSuccessful() {
Log.i("Device", "pairing successful, adding to trusted devices list");
hidePairingNotification();
// Store current device certificate so we can check it in the future (TOFU)
deviceInfo.saveInSettings(Device.this.settings);
// Store as trusted device
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
preferences.edit().putBoolean(deviceInfo.id, true).apply();
try {
reloadPluginsFromSettings();
for (PairingHandler.PairingCallback cb : pairingCallbacks) {
cb.pairingSuccessful();
}
} catch (Exception e) {
Log.e("PairingHandler", "Exception in pairingSuccessful. Not unpairing because saving the trusted device succeeded");
e.printStackTrace();
}
}
@Override
public void pairingFailed(String error) {
hidePairingNotification();
for (PairingHandler.PairingCallback cb : pairingCallbacks) {
cb.pairingFailed(error);
}
}
@Override
public void unpaired() {
Log.i("Device", "unpaired, removing from trusted devices list");
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
preferences.edit().remove(deviceInfo.id).apply();
SharedPreferences devicePreferences = context.getSharedPreferences(deviceInfo.id, Context.MODE_PRIVATE);
devicePreferences.edit().clear().apply();
for (PairingHandler.PairingCallback cb : pairingCallbacks) {
cb.unpaired();
}
notifyPluginsOfDeviceUnpaired(context, deviceInfo.id);
reloadPluginsFromSettings();
}
};
//
// Notification related methods used during pairing
//
public void displayPairingNotification() {
hidePairingNotification();
notificationId = (int) System.currentTimeMillis();
Intent intent = new Intent(getContext(), MainActivity.class);
intent.putExtra(MainActivity.EXTRA_DEVICE_ID, getDeviceId());
intent.putExtra(MainActivity.PAIR_REQUEST_STATUS, MainActivity.PAIRING_PENDING);
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 1, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
Intent acceptIntent = new Intent(getContext(), MainActivity.class);
Intent rejectIntent = new Intent(getContext(), MainActivity.class);
acceptIntent.putExtra(MainActivity.EXTRA_DEVICE_ID, getDeviceId());
acceptIntent.putExtra(MainActivity.PAIR_REQUEST_STATUS, MainActivity.PAIRING_ACCEPTED);
rejectIntent.putExtra(MainActivity.EXTRA_DEVICE_ID, getDeviceId());
rejectIntent.putExtra(MainActivity.PAIR_REQUEST_STATUS, MainActivity.PAIRING_REJECTED);
PendingIntent acceptedPendingIntent = PendingIntent.getActivity(getContext(), 2, acceptIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
PendingIntent rejectedPendingIntent = PendingIntent.getActivity(getContext(), 4, rejectIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
Resources res = getContext().getResources();
final NotificationManager notificationManager = ContextCompat.getSystemService(getContext(), NotificationManager.class);
String verificationKeyShort = SslHelper.getVerificationKey(SslHelper.certificate, deviceInfo.certificate).substring(8);
Notification noti = new NotificationCompat.Builder(getContext(), NotificationHelper.Channels.DEFAULT)
.setContentTitle(res.getString(R.string.pairing_request_from, getName()))
.setContentText(res.getString(R.string.pairing_verification_code, verificationKeyShort))
.setTicker(res.getString(R.string.pair_requested))
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_accept_pairing_24dp, res.getString(R.string.pairing_accept), acceptedPendingIntent)
.addAction(R.drawable.ic_reject_pairing_24dp, res.getString(R.string.pairing_reject), rejectedPendingIntent)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.build();
NotificationHelper.notifyCompat(notificationManager, notificationId, noti);
}
public void hidePairingNotification() {
final NotificationManager notificationManager = ContextCompat.getSystemService(getContext(),
NotificationManager.class);
notificationManager.cancel(notificationId);
}
//
// Link-related functions
//
public boolean isReachable() {
return !links.isEmpty();
}
public void addLink(BaseLink link) {
if (links.isEmpty()) {
packetQueue = new DevicePacketQueue(this);
}
//FilesHelper.LogOpenFileCount();
links.add(link);
List linksToSort = Arrays.asList(links.toArray());
Collections.sort(linksToSort, (Comparator<BaseLink>) (o1, o2) -> Integer.compare(o2.getLinkProvider().getPriority(), o1.getLinkProvider().getPriority()));
links.clear();
links.addAll(linksToSort);
link.addPacketReceiver(this);
boolean hasChanges = updateDeviceInfo(link.getDeviceInfo());
if (hasChanges || links.size() == 1) {
reloadPluginsFromSettings();
}
}
public void removeLink(BaseLink link) {
//FilesHelper.LogOpenFileCount();
link.removePacketReceiver(this);
links.remove(link);
Log.i("KDE/Device", "removeLink: " + link.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size());
if (links.isEmpty()) {
reloadPluginsFromSettings();
if (packetQueue != null) {
packetQueue.disconnected();
packetQueue = null;
}
}
}
public boolean updateDeviceInfo(@NonNull DeviceInfo newDeviceInfo) {
boolean hasChanges = false;
if (!deviceInfo.name.equals(newDeviceInfo.name) || deviceInfo.type != newDeviceInfo.type) {
hasChanges = true;
deviceInfo.name = newDeviceInfo.name;
deviceInfo.type = newDeviceInfo.type;
if (isPaired()) {
deviceInfo.saveInSettings(settings);
}
}
if (deviceInfo.outgoingCapabilities != newDeviceInfo.outgoingCapabilities ||
deviceInfo.incomingCapabilities != newDeviceInfo.incomingCapabilities) {
if (newDeviceInfo.outgoingCapabilities != null
&& !newDeviceInfo.outgoingCapabilities.isEmpty()
&& newDeviceInfo.incomingCapabilities != null
&& !newDeviceInfo.incomingCapabilities.isEmpty()
) {
hasChanges = true;
Log.i("updateDeviceInfo", "Updating supported plugins according to new capabilities");
supportedPlugins = new Vector<>(PluginFactory.pluginsForCapabilities(newDeviceInfo.incomingCapabilities, newDeviceInfo.outgoingCapabilities));
}
}
return hasChanges;
}
@Override
public void onPacketReceived(@NonNull NetworkPacket np) {
DeviceStats.INSTANCE.countReceived(getDeviceId(), np.getType());
if (NetworkPacket.PACKET_TYPE_PAIR.equals(np.getType())) {
Log.i("KDE/Device", "Pair packet");
pairingHandler.packetReceived(np);
} else if (isPaired()) {
// pluginsByIncomingInterface may not be built yet
if(pluginsByIncomingInterface.isEmpty()) {
reloadPluginsFromSettings();
}
Collection<String> targetPlugins = pluginsByIncomingInterface.get(np.getType());
if (!targetPlugins.isEmpty()) { // When a key doesn't exist the multivaluemap returns an empty collection, so we don't need to check for null
for (String pluginKey : targetPlugins) {
Plugin plugin = plugins.get(pluginKey);
try {
plugin.onPacketReceived(np);
} catch (Exception e) {
Log.e("KDE/Device", "Exception in " + plugin.getPluginKey() + "'s onPacketReceived()", e);
//try { Log.e("KDE/Device", "NetworkPacket:" + np.serialize()); } catch (Exception _) { }
}
}
} else {
Log.w("Device", "Ignoring packet with type " + np.getType() + " because no plugin can handle it");
}
} else {
//Log.e("KDE/onPacketReceived","Device not paired, will pass packet to unpairedPacketListeners");
// If it is pair packet, it should be captured by "if" at start
// If not and device is paired, it should be captured by isPaired
// Else unpair, this handles the situation when one device unpairs, but other dont know like unpairing when wi-fi is off
unpair();
// The following code is NOT USED. It adds support for receiving packets from not trusted devices, but as of March 2023 no plugin implements "onUnpairedDevicePacketReceived".
Collection<String> targetPlugins = pluginsByIncomingInterface.get(np.getType());
if (!targetPlugins.isEmpty()) {
for (String pluginKey : targetPlugins) {
Plugin plugin = plugins.get(pluginKey);
try {
plugin.onUnpairedDevicePacketReceived(np);
} catch (Exception e) {
Log.e("KDE/Device", "Exception in " + plugin.getDisplayName() + "'s onPacketReceived() in unPairedPacketListeners", e);
}
}
} else {
Log.e("Device", "Ignoring packet with type " + np.getType() + " because no plugin can handle it");
}
}
}
public static abstract class SendPacketStatusCallback {
public abstract void onSuccess();
public abstract void onFailure(Throwable e);
public void onPayloadProgressChanged(int percent) {
}
}
private final SendPacketStatusCallback defaultCallback = new SendPacketStatusCallback() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(Throwable e) {
Log.e("KDE/sendPacket", "Exception", e);
}
};
@AnyThread
public void sendPacket(@NonNull NetworkPacket np) {
sendPacket(np, -1, defaultCallback);
}
@AnyThread
public void sendPacket(@NonNull NetworkPacket np, int replaceID) {
sendPacket(np, replaceID, defaultCallback);
}
@WorkerThread
public boolean sendPacketBlocking(@NonNull NetworkPacket np) {
return sendPacketBlocking(np, defaultCallback);
}
@AnyThread
public void sendPacket(@NonNull final NetworkPacket np, @NonNull final SendPacketStatusCallback callback) {
sendPacket(np, -1, callback);
}
/**
* Send a packet to the device asynchronously
* @param np The packet
* @param replaceID If positive, replaces all unsent packets with the same replaceID
* @param callback A callback for success/failure
*/
@AnyThread
public void sendPacket(@NonNull final NetworkPacket np, int replaceID, @NonNull final SendPacketStatusCallback callback) {
if (packetQueue == null) {
callback.onFailure(new Exception("Device disconnected!"));
} else {
// TODO: Migrate to coroutine version (addPacket)
packetQueue.addPacketSync(np, replaceID, callback);
}
}
/**
* Check if we still have an unsent packet in the queue with the given ID.
* If so, remove it from the queue and return it
* @param replaceID The replace ID (must be positive)
* @return The found packet, or null
*/
public NetworkPacket getAndRemoveUnsentPacket(int replaceID) {
if (packetQueue == null) {
return null;
} else {
// TODO: Migrate to coroutine version (getAndRemoveUnsentPacket)
return packetQueue.getAndRemoveUnsentPacketSync(replaceID);
}
}
@WorkerThread
public boolean sendPacketBlocking(@NonNull final NetworkPacket np, @NonNull final SendPacketStatusCallback callback) {
return sendPacketBlocking(np, callback, false);
}
/**
* Send {@code np} over one of this device's connected {@link #links}.
*
* @param np the packet to send
* @param callback a callback that can receive realtime updates
* @param sendPayloadFromSameThread when set to true and np contains a Payload, this function
* won't return until the Payload has been received by the
* other end, or times out after 10 seconds
* @return true if the packet was sent ok, false otherwise
* @see BaseLink#sendPacket(NetworkPacket, SendPacketStatusCallback, boolean)
*/
@WorkerThread
public boolean sendPacketBlocking(@NonNull final NetworkPacket np, @NonNull final SendPacketStatusCallback callback, boolean sendPayloadFromSameThread) {
boolean success = false;
for (final BaseLink link : links) {
if (link == null) continue;
try {
success = link.sendPacket(np, callback, sendPayloadFromSameThread);
} catch (IOException e) {
e.printStackTrace();
}
DeviceStats.INSTANCE.countSent(getDeviceId(), np.getType(), success);
if (success) break;
}
if (!success) {
Log.e("KDE/sendPacket", "No device link (of " + links.size() + " available) could send the packet. Packet " + np.getType() + " to " + deviceInfo.name + " lost!");
}
return success;
}
//
// Plugin-related functions
//
@Nullable
public <T extends Plugin> T getPlugin(Class<T> pluginClass) {
Plugin plugin = getPlugin(Plugin.getPluginKey(pluginClass));
return (T) plugin;
}
@Nullable
public Plugin getPlugin(String pluginKey) {
return plugins.get(pluginKey);
}
@Nullable
public Plugin getPluginIncludingWithoutPermissions(String pluginKey) {
Plugin p = plugins.get(pluginKey);
if (p == null) {
p = pluginsWithoutPermissions.get(pluginKey);
}
return p;
}
private synchronized boolean addPlugin(final String pluginKey) {
Plugin existing = plugins.get(pluginKey);
if (existing != null) {
if (!existing.isCompatible()) {
Log.d("KDE/addPlugin", "Minimum requirements (e.g. API level) not fulfilled " + pluginKey);
return false;
}
//Log.w("KDE/addPlugin","plugin already present:" + pluginKey);
if (existing.checkOptionalPermissions()) {
Log.d("KDE/addPlugin", "Optional Permissions OK " + pluginKey);
pluginsWithoutOptionalPermissions.remove(pluginKey);
} else {
Log.d("KDE/addPlugin", "No optional permission " + pluginKey);
pluginsWithoutOptionalPermissions.put(pluginKey, existing);
}
return true;
}
final Plugin plugin = PluginFactory.instantiatePluginForDevice(context, pluginKey, this);
if (plugin == null) {
Log.e("KDE/addPlugin", "could not instantiate plugin: " + pluginKey);
return false;
}
if (!plugin.isCompatible()) {
Log.d("KDE/addPlugin", "Minimum requirements (e.g. API level) not fulfilled " + pluginKey);
return false;
}
if (!plugin.checkRequiredPermissions()) {
Log.d("KDE/addPlugin", "No permission " + pluginKey);
plugins.remove(pluginKey);
pluginsWithoutPermissions.put(pluginKey, plugin);
return false;
} else {
Log.d("KDE/addPlugin", "Permissions OK " + pluginKey);
plugins.put(pluginKey, plugin);
pluginsWithoutPermissions.remove(pluginKey);
if (plugin.checkOptionalPermissions()) {
Log.d("KDE/addPlugin", "Optional Permissions OK " + pluginKey);
pluginsWithoutOptionalPermissions.remove(pluginKey);
} else {
Log.d("KDE/addPlugin", "No optional permission " + pluginKey);
pluginsWithoutOptionalPermissions.put(pluginKey, plugin);
}
}
try {
return plugin.onCreate();
} catch (Exception e) {
Log.e("KDE/addPlugin", "plugin failed to load " + pluginKey, e);
return false;
}
}
private synchronized boolean removePlugin(String pluginKey) {
Plugin plugin = plugins.remove(pluginKey);
if (plugin == null) {
return false;
}
try {
plugin.onDestroy();
//Log.e("removePlugin","removed " + pluginKey);
} catch (Exception e) {
Log.e("KDE/removePlugin", "Exception calling onDestroy for plugin " + pluginKey, e);
}
return true;
}
public void setPluginEnabled(String pluginKey, boolean value) {
settings.edit().putBoolean(pluginKey, value).apply();
reloadPluginsFromSettings();
}
public boolean isPluginEnabled(String pluginKey) {
boolean enabledByDefault = PluginFactory.getPluginInfo(pluginKey).isEnabledByDefault();
return settings.getBoolean(pluginKey, enabledByDefault);
}
public void notifyPluginsOfDeviceUnpaired(Context context, String deviceId) {
for (String pluginKey : supportedPlugins) {
Plugin plugin = getPlugin(pluginKey);
if (plugin != null) {
plugin.onDeviceUnpaired(context, deviceId);
} else {
// This is a hacky way to temporarily create plugins just so that they can be notified of the
// device being unpaired. This else part will only come into picture when 1) the user tries to
// unpair a device while that device is not reachable or 2) the plugin was never initialized
// for this device, e.g., the plugins that need additional permissions from the user, and those
// permissions were never granted.
plugin = PluginFactory.instantiatePluginForDevice(context, pluginKey, this);
if (plugin != null) {
plugin.onDeviceUnpaired(context, deviceId);
}
}
}
}
public void reloadPluginsFromSettings() {
Log.i("Device", deviceInfo.name +": reloading plugins");
MultiValuedMap<String, String> newPluginsByIncomingInterface = new ArrayListValuedHashMap<>();
for (String pluginKey : supportedPlugins) {
PluginFactory.PluginInfo pluginInfo = PluginFactory.getPluginInfo(pluginKey);
boolean pluginEnabled = false;
boolean listenToUnpaired = pluginInfo.listenToUnpaired();
if ((isPaired() || listenToUnpaired) && isReachable()) {
pluginEnabled = isPluginEnabled(pluginKey);
}
if (pluginEnabled) {
boolean success = addPlugin(pluginKey);
if (success) {
for (String packetType : pluginInfo.getSupportedPacketTypes()) {
newPluginsByIncomingInterface.put(packetType, pluginKey);
}
} else {
removePlugin(pluginKey);
}
} else {
removePlugin(pluginKey);
}
}
pluginsByIncomingInterface = newPluginsByIncomingInterface;
onPluginsChanged();
}
public void onPluginsChanged() {
for (PluginsChangedListener listener : pluginsChangedListeners) {
listener.onPluginsChanged(Device.this);
}
}
public ConcurrentHashMap<String, Plugin> getLoadedPlugins() {
return plugins;
}
public ConcurrentHashMap<String, Plugin> getPluginsWithoutPermissions() {
return pluginsWithoutPermissions;
}
public ConcurrentHashMap<String, Plugin> getPluginsWithoutOptionalPermissions() {
return pluginsWithoutOptionalPermissions;
}
public void addPluginsChangedListener(PluginsChangedListener listener) {
pluginsChangedListeners.add(listener);
}
public void removePluginsChangedListener(PluginsChangedListener listener) {
pluginsChangedListeners.remove(listener);
}
public void disconnect() {
for (BaseLink link : links) {
link.disconnect();
}
}
public List<String> getSupportedPlugins() {
return supportedPlugins;
}
}

View File

@@ -1,652 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.drawable.Drawable
import android.util.Log
import androidx.annotation.AnyThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import org.apache.commons.collections4.MultiValuedMap
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap
import org.kde.kdeconnect.Backends.BaseLink
import org.kde.kdeconnect.Backends.BaseLink.PacketReceiver
import org.kde.kdeconnect.DeviceInfo.Companion.loadFromSettings
import org.kde.kdeconnect.DeviceStats.countReceived
import org.kde.kdeconnect.DeviceStats.countSent
import org.kde.kdeconnect.Helpers.DeviceHelper
import org.kde.kdeconnect.Helpers.NotificationHelper
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
import org.kde.kdeconnect.PairingHandler.PairingCallback
import org.kde.kdeconnect.Plugins.Plugin
import org.kde.kdeconnect.Plugins.Plugin.Companion.getPluginKey
import org.kde.kdeconnect.Plugins.PluginFactory
import org.kde.kdeconnect.UserInterface.MainActivity
import org.kde.kdeconnect_tp.R
import java.io.IOException
import java.security.cert.Certificate
import java.util.Vector
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.CopyOnWriteArrayList
class Device : PacketReceiver {
data class NetworkPacketWithCallback(val np : NetworkPacket, val callback: SendPacketStatusCallback)
val context: Context
@VisibleForTesting
val deviceInfo: DeviceInfo
/**
* The notification ID for the pairing notification.
* This ID should be only set once, and it should be unique for each device.
* We use the current time in milliseconds as the ID as default.
*/
private var notificationId = 0
@VisibleForTesting
var pairingHandler: PairingHandler
private val links = CopyOnWriteArrayList<BaseLink>()
/**
* Plugins that have matching capabilities.
*/
var supportedPlugins: List<String>
private set
/**
* Plugins that have been instantiated successfully. A subset of supportedPlugins.
*/
val loadedPlugins: ConcurrentMap<String, Plugin> = ConcurrentHashMap()
/**
* Plugins that have not been instantiated because of missing permissions.
* The supportedPlugins that aren't in loadedPlugins will be here.
*/
val pluginsWithoutPermissions: ConcurrentMap<String, Plugin> = ConcurrentHashMap()
/**
* Subset of loadedPlugins that, despite being able to run, will have some limitation because of missing permissions.
*/
val pluginsWithoutOptionalPermissions: ConcurrentMap<String, Plugin> = ConcurrentHashMap()
/**
* Same as loadedPlugins but indexed by incoming packet type
*/
private var pluginsByIncomingInterface: MultiValuedMap<String, String> = ArrayListValuedHashMap()
private val settings: SharedPreferences
private val pairingCallbacks = CopyOnWriteArrayList<PairingCallback>()
private val pluginsChangedListeners = CopyOnWriteArrayList<PluginsChangedListener>()
private val sendChannel = Channel<NetworkPacketWithCallback>(Channel.UNLIMITED)
private var sendCoroutine : Job? = null
/**
* Constructor for remembered, already-trusted devices.
* Given the deviceId, it will load the other properties from SharedPreferences.
*/
internal constructor(context: Context, deviceId: String) {
this.context = context
this.settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE)
this.deviceInfo = loadFromSettings(context, deviceId, settings)
this.pairingHandler = PairingHandler(this, createDefaultPairingCallback(), PairingHandler.PairState.Paired)
this.supportedPlugins = Vector(PluginFactory.getAvailablePlugins()) // Assume all are supported until we receive capabilities
Log.i("Device", "Loading trusted device: ${deviceInfo.name}")
}
/**
* Constructor for devices discovered but not trusted yet.
* Gets the DeviceInfo by calling link.getDeviceInfo() on the link passed.
* This constructor also calls addLink() with the link you pass to it, since it's not legal to have an unpaired Device with 0 links.
*/
internal constructor(context: Context, link: BaseLink) {
this.context = context
this.deviceInfo = link.deviceInfo
this.settings = context.getSharedPreferences(deviceInfo.id, Context.MODE_PRIVATE)
this.pairingHandler = PairingHandler(this, createDefaultPairingCallback(), PairingHandler.PairState.NotPaired)
this.supportedPlugins = Vector(PluginFactory.getAvailablePlugins()) // Assume all are supported until we receive capabilities
Log.i("Device", "Creating untrusted device: " + deviceInfo.name)
addLink(link)
}
fun supportsPacketType(type: String): Boolean =
deviceInfo.incomingCapabilities?.contains(type) ?: true
fun interface PluginsChangedListener {
fun onPluginsChanged(device: Device)
}
val connectivityType: String?
get() = links.firstOrNull()?.name
val name: String
get() = deviceInfo.name
val icon: Drawable
get() = deviceInfo.type.getIcon(context)
val deviceType: DeviceType
get() = deviceInfo.type
val deviceId: String
get() = deviceInfo.id
val certificate: Certificate
get() = deviceInfo.certificate
// Returns 0 if the version matches, < 0 if it is older or > 0 if it is newer
fun compareProtocolVersion(): Int =
deviceInfo.protocolVersion - DeviceHelper.ProtocolVersion
val isPaired: Boolean
get() = pairingHandler.state == PairingHandler.PairState.Paired
val isPairRequested: Boolean
get() = pairingHandler.state == PairingHandler.PairState.Requested
val isPairRequestedByPeer: Boolean
get() = pairingHandler.state == PairingHandler.PairState.RequestedByPeer
fun addPairingCallback(callback: PairingCallback) = pairingCallbacks.add(callback)
fun removePairingCallback(callback: PairingCallback) = pairingCallbacks.remove(callback)
fun requestPairing() = pairingHandler.requestPairing()
fun unpair() = pairingHandler.unpair()
/* This method is called after accepting pair request form GUI */
fun acceptPairing() {
Log.i("Device", "Accepted pair request started by the other device")
pairingHandler.acceptPairing()
}
/* This method is called after rejecting pairing from GUI */
fun cancelPairing() {
Log.i("Device", "This side cancelled the pair request")
pairingHandler.cancelPairing()
}
private fun createDefaultPairingCallback(): PairingCallback {
return object : PairingCallback {
override fun incomingPairRequest() {
displayPairingNotification()
pairingCallbacks.forEach(PairingCallback::incomingPairRequest)
}
override fun pairingSuccessful() {
Log.i("Device", "pairing successful, adding to trusted devices list")
hidePairingNotification()
// Store current device certificate so we can check it in the future (TOFU)
deviceInfo.saveInSettings(this@Device.settings)
// Store as trusted device
val preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE)
preferences.edit().putBoolean(deviceInfo.id, true).apply()
try {
reloadPluginsFromSettings()
pairingCallbacks.forEach(PairingCallback::pairingSuccessful)
} catch (e: Exception) {
Log.e("Device", "Exception in pairingSuccessful. Not unpairing because saving the trusted device succeeded", e)
}
}
override fun pairingFailed(error: String) {
hidePairingNotification()
pairingCallbacks.forEach { it.pairingFailed(error) }
}
override fun unpaired() {
Log.i("Device", "unpaired, removing from trusted devices list")
val preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE)
preferences.edit().remove(deviceInfo.id).apply()
val devicePreferences = context.getSharedPreferences(deviceInfo.id, Context.MODE_PRIVATE)
devicePreferences.edit().clear().apply()
pairingCallbacks.forEach(PairingCallback::unpaired)
notifyPluginsOfDeviceUnpaired(context, deviceInfo.id)
reloadPluginsFromSettings()
}
}
}
//
// Notification related methods used during pairing
//
fun displayPairingNotification() {
hidePairingNotification()
notificationId = System.currentTimeMillis().toInt()
val intent = Intent(context, MainActivity::class.java).apply {
putExtra(MainActivity.EXTRA_DEVICE_ID, deviceId)
putExtra(MainActivity.PAIR_REQUEST_STATUS, MainActivity.PAIRING_PENDING)
}
val pendingIntent = PendingIntent.getActivity(
context,
1,
intent,
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
)
val acceptIntent = Intent(context, MainActivity::class.java).apply {
putExtra(MainActivity.EXTRA_DEVICE_ID, deviceId)
putExtra(MainActivity.PAIR_REQUEST_STATUS, MainActivity.PAIRING_ACCEPTED)
}
val rejectIntent = Intent(context, MainActivity::class.java).apply {
putExtra(MainActivity.EXTRA_DEVICE_ID, deviceId)
putExtra(MainActivity.PAIR_REQUEST_STATUS, MainActivity.PAIRING_REJECTED)
}
val acceptedPendingIntent = PendingIntent.getActivity(
context,
2,
acceptIntent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_MUTABLE
)
val rejectedPendingIntent = PendingIntent.getActivity(
context,
4,
rejectIntent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_MUTABLE
)
val res = context.resources
val notificationManager = ContextCompat.getSystemService(context, NotificationManager::class.java)!!
val verificationKey = SslHelper.getVerificationKey(SslHelper.certificate, deviceInfo.certificate)
val noti = NotificationCompat.Builder(context, NotificationHelper.Channels.DEFAULT)
.setContentTitle(res.getString(R.string.pairing_request_from, name))
.setContentText(res.getString(R.string.pairing_verification_code, verificationKey))
.setTicker(res.getString(R.string.pair_requested))
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_accept_pairing_24dp, res.getString(R.string.pairing_accept), acceptedPendingIntent)
.addAction(R.drawable.ic_reject_pairing_24dp, res.getString(R.string.pairing_reject), rejectedPendingIntent)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.build()
NotificationHelper.notifyCompat(notificationManager, notificationId, noti)
}
fun hidePairingNotification() {
val notificationManager = ContextCompat.getSystemService(context, NotificationManager::class.java)!!
notificationManager.cancel(notificationId)
}
val isReachable: Boolean
get() = links.isNotEmpty()
fun addLink(link: BaseLink) {
synchronized(sendChannel) {
if (sendCoroutine == null) {
sendCoroutine = CoroutineScope(Dispatchers.IO).launch {
for ((np, callback) in sendChannel) {
sendPacketBlocking(np, callback)
}
}
}
}
// FilesHelper.LogOpenFileCount();
links.add(link)
links.sortWith { o1, o2 ->
o2.linkProvider.priority compareTo o1.linkProvider.priority
}
link.addPacketReceiver(this)
val hasChanges = updateDeviceInfo(link.deviceInfo)
if (hasChanges || links.size == 1) {
reloadPluginsFromSettings()
}
}
fun removeLink(link: BaseLink) {
// FilesHelper.LogOpenFileCount();
link.removePacketReceiver(this)
links.remove(link)
Log.i(
"KDE/Device",
"removeLink: ${link.linkProvider.name} -> $name active links: ${links.size}"
)
if (links.isEmpty()) {
reloadPluginsFromSettings()
synchronized(sendChannel) {
sendCoroutine?.cancel(CancellationException("Device disconnected"))
sendCoroutine = null
}
}
}
fun updateDeviceInfo(newDeviceInfo: DeviceInfo): Boolean {
var hasChanges = false
if (deviceInfo.name != newDeviceInfo.name || deviceInfo.type != newDeviceInfo.type) {
hasChanges = true
deviceInfo.name = newDeviceInfo.name
deviceInfo.type = newDeviceInfo.type
if (isPaired) {
deviceInfo.saveInSettings(settings)
}
}
val incomingCapabilities = deviceInfo.incomingCapabilities
val outgoingCapabilities = deviceInfo.outgoingCapabilities
val newIncomingCapabilities = newDeviceInfo.incomingCapabilities
val newOutgoingCapabilities = newDeviceInfo.outgoingCapabilities
if (
!newIncomingCapabilities.isNullOrEmpty() &&
!newOutgoingCapabilities.isNullOrEmpty() &&
(
incomingCapabilities != newIncomingCapabilities ||
outgoingCapabilities != newOutgoingCapabilities
)
) {
hasChanges = true
Log.i("updateDeviceInfo", "Updating supported plugins according to new capabilities")
supportedPlugins = Vector(
PluginFactory.pluginsForCapabilities(
newIncomingCapabilities,
newOutgoingCapabilities
)
)
}
return hasChanges
}
override fun onPacketReceived(np: NetworkPacket) {
countReceived(deviceId, np.type)
if (NetworkPacket.PACKET_TYPE_PAIR == np.type) {
Log.i("KDE/Device", "Pair packet")
pairingHandler.packetReceived(np)
return
}
// pluginsByIncomingInterface may not be built yet
if (pluginsByIncomingInterface.isEmpty) {
reloadPluginsFromSettings()
}
if (!isPaired) {
// If it is pair packet, it should be captured by "if" at start
// If not and device is paired, it should be captured by isPaired
// Else unpair, this handles the situation when one device unpairs,
// but other don't know like unpairing when wi-fi is off.
unpair()
}
// The following code when `isPaired == false` is NOT USED.
// It adds support for receiving packets from not trusted devices,
// but as of March 2023 no plugin implements "onUnpairedDevicePacketReceived".
notifyPluginPacketReceived(np)
}
private fun notifyPluginPacketReceived(np: NetworkPacket) {
val targetPlugins = pluginsByIncomingInterface[np.type] // Returns an empty collection if the key doesn't exist
if (targetPlugins.isEmpty()) {
Log.w("Device", "Ignoring packet with type ${np.type} because no plugin can handle it")
return
}
targetPlugins.map { it to loadedPlugins[it]!! }.forEach { (pluginKey, plugin) ->
plugin.runCatching {
if (isPaired) onPacketReceived(np) else onUnpairedDevicePacketReceived(np)
}.onFailure { e ->
Log.e("Device", "Exception in ${pluginKey}'s onPacketReceived()", e)
}
}
}
abstract class SendPacketStatusCallback {
abstract fun onSuccess()
abstract fun onFailure(e: Throwable)
open fun onPayloadProgressChanged(percent: Int) {}
}
private val defaultCallback: SendPacketStatusCallback = object : SendPacketStatusCallback() {
override fun onSuccess() {
}
override fun onFailure(e: Throwable) {
Log.e("Device", "Send packet exception", e)
}
}
/**
* Send a packet to the device asynchronously
* @param np The packet
* @param callback A callback for success/failure
*/
@AnyThread
fun sendPacket(np: NetworkPacket, callback: SendPacketStatusCallback) {
sendChannel.trySend(NetworkPacketWithCallback(np, callback))
}
@AnyThread
fun sendPacket(np: NetworkPacket) = sendPacket(np, defaultCallback)
@WorkerThread
fun sendPacketBlocking(np: NetworkPacket, callback: SendPacketStatusCallback): Boolean =
sendPacketBlocking(np, callback, false)
@WorkerThread
fun sendPacketBlocking(np: NetworkPacket): Boolean = sendPacketBlocking(np, defaultCallback, false)
/**
* Send `np` over one of this device's connected [.links].
*
* @param np the packet to send
* @param callback a callback that can receive realtime updates
* @param sendPayloadFromSameThread when set to true and np contains a Payload, this function
* won't return until the Payload has been received by the
* other end, or times out after 10 seconds
* @return true if the packet was sent ok, false otherwise
* @see BaseLink.sendPacket
*/
@WorkerThread
fun sendPacketBlocking(
np: NetworkPacket,
callback: SendPacketStatusCallback,
sendPayloadFromSameThread: Boolean
): Boolean {
val success = links.any { link ->
try {
link.sendPacket(np, callback, sendPayloadFromSameThread)
} catch (e: IOException) {
Log.w("KDE/sendPacket", "Failed to send packet", e)
false
}.also { sent ->
countSent(deviceId, np.type, sent)
}
}
if (!success) {
Log.e(
"KDE/sendPacket",
"No device link (of ${links.size} available) could send the packet. Packet ${np.type} to ${deviceInfo.name} lost!"
)
}
return success
}
//
// Plugin-related functions
//
fun <T : Plugin> getPlugin(pluginClass: Class<T>): T? {
val plugin = getPlugin(getPluginKey(pluginClass))
return plugin?.let(pluginClass::cast)
}
fun getPlugin(pluginKey: String): Plugin? = loadedPlugins[pluginKey]
fun getPluginIncludingWithoutPermissions(pluginKey: String): Plugin? {
return loadedPlugins[pluginKey] ?: pluginsWithoutPermissions[pluginKey]
}
@Synchronized
private fun addPlugin(pluginKey: String): Boolean {
val existing = loadedPlugins[pluginKey]
if (existing != null) {
if (!existing.isCompatible) {
Log.d("KDE/addPlugin", "Minimum requirements (e.g. API level) not fulfilled $pluginKey")
return false
}
// Log.w("KDE/addPlugin","plugin already present:" + pluginKey);
if (existing.checkOptionalPermissions()) {
Log.d("KDE/addPlugin", "Optional Permissions OK $pluginKey")
pluginsWithoutOptionalPermissions.remove(pluginKey)
} else {
Log.d("KDE/addPlugin", "No optional permission $pluginKey")
pluginsWithoutOptionalPermissions[pluginKey] = existing
}
return true
}
val plugin = PluginFactory.instantiatePluginForDevice(context, pluginKey, this) ?: run {
Log.e("KDE/addPlugin", "could not instantiate plugin: $pluginKey")
return false
}
if (!plugin.isCompatible) {
Log.d("KDE/addPlugin", "Minimum requirements (e.g. API level) not fulfilled $pluginKey")
return false
}
if (!plugin.checkRequiredPermissions()) {
Log.d("KDE/addPlugin", "No permission $pluginKey")
loadedPlugins.remove(pluginKey)
pluginsWithoutPermissions[pluginKey] = plugin
return false
} else {
Log.d("KDE/addPlugin", "Permissions OK $pluginKey")
loadedPlugins[pluginKey] = plugin
pluginsWithoutPermissions.remove(pluginKey)
if (plugin.checkOptionalPermissions()) {
Log.d("KDE/addPlugin", "Optional Permissions OK $pluginKey")
pluginsWithoutOptionalPermissions.remove(pluginKey)
} else {
Log.d("KDE/addPlugin", "No optional permission $pluginKey")
pluginsWithoutOptionalPermissions[pluginKey] = plugin
}
}
return runCatching {
plugin.onCreate()
}.onFailure {
Log.e("KDE/addPlugin", "plugin failed to load $pluginKey", it)
}.getOrDefault(false)
}
@Synchronized
private fun removePlugin(pluginKey: String): Boolean {
val plugin = loadedPlugins.remove(pluginKey) ?: return false
try {
plugin.onDestroy()
// Log.e("removePlugin","removed " + pluginKey);
} catch (e: Exception) {
Log.e("KDE/removePlugin", "Exception calling onDestroy for plugin $pluginKey", e)
}
return true
}
fun setPluginEnabled(pluginKey: String, value: Boolean) {
settings.edit().putBoolean(pluginKey, value).apply()
reloadPluginsFromSettings()
}
fun isPluginEnabled(pluginKey: String): Boolean {
val enabledByDefault = PluginFactory.getPluginInfo(pluginKey).isEnabledByDefault
return settings.getBoolean(pluginKey, enabledByDefault)
}
fun notifyPluginsOfDeviceUnpaired(context: Context, deviceId: String) {
for (pluginKey in supportedPlugins) {
// This is a hacky way to temporarily create plugins just so that they can be notified of the
// device being unpaired. This else part will only come into picture when 1) the user tries to
// unpair a device while that device is not reachable or 2) the plugin was never initialized
// for this device, e.g., the plugins that need additional permissions from the user, and those
// permissions were never granted.
val plugin = getPlugin(pluginKey) ?: PluginFactory.instantiatePluginForDevice(context, pluginKey, this)
plugin?.onDeviceUnpaired(context, deviceId)
}
}
fun reloadPluginsFromSettings() {
Log.i("Device", "${deviceInfo.name}: reloading plugins")
val newPluginsByIncomingInterface: MultiValuedMap<String, String> = ArrayListValuedHashMap()
supportedPlugins.forEach { pluginKey ->
val pluginInfo = PluginFactory.getPluginInfo(pluginKey)
val listenToUnpaired = pluginInfo.listenToUnpaired()
val pluginEnabled = (isPaired || listenToUnpaired) && this.isReachable && isPluginEnabled(pluginKey)
if (pluginEnabled && addPlugin(pluginKey)) {
pluginInfo.supportedPacketTypes.forEach { packetType ->
newPluginsByIncomingInterface.put(packetType, pluginKey)
}
} else {
removePlugin(pluginKey)
}
}
pluginsByIncomingInterface = newPluginsByIncomingInterface
onPluginsChanged()
}
fun onPluginsChanged() = pluginsChangedListeners.forEach { it.onPluginsChanged(this) }
fun addPluginsChangedListener(listener: PluginsChangedListener) = pluginsChangedListeners.add(listener)
fun removePluginsChangedListener(listener: PluginsChangedListener) = pluginsChangedListeners.remove(listener)
fun disconnect() {
links.forEach(BaseLink::disconnect)
}
}

View File

@@ -9,9 +9,7 @@ package org.kde.kdeconnect
import android.content.Context
import android.content.SharedPreferences
import android.util.Base64
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import org.kde.kdeconnect.Helpers.DeviceHelper
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
import org.kde.kdeconnect_tp.R
import java.security.cert.Certificate
@@ -22,13 +20,13 @@ import java.security.cert.CertificateException
* DeviceInfo contains all the properties needed to instantiate a Device.
*/
class DeviceInfo(
@JvmField val id: String,
@JvmField val certificate: Certificate,
@JvmField var name: String,
@JvmField var type: DeviceType,
@JvmField var protocolVersion: Int = 0,
@JvmField var incomingCapabilities: Set<String>? = null,
@JvmField var outgoingCapabilities: Set<String>? = null,
@JvmField val id : String,
@JvmField val certificate : Certificate,
@JvmField var name : String,
@JvmField var type : DeviceType,
@JvmField var protocolVersion : Int = 0,
@JvmField var incomingCapabilities : Set<String>? = null,
@JvmField var outgoingCapabilities : Set<String>? = null,
) {
/**
@@ -40,7 +38,7 @@ class DeviceInfo(
try {
val encodedCertificate = Base64.encodeToString(certificate.encoded, 0)
with(settings.edit()) {
with (settings.edit()) {
putString("certificate", encodedCertificate)
putString("deviceName", name)
putString("deviceType", type.toString())
@@ -73,7 +71,7 @@ class DeviceInfo(
*/
@JvmStatic
@Throws(CertificateException::class)
fun loadFromSettings(context: Context, deviceId: String, settings: SharedPreferences) =
fun loadFromSettings(context : Context, deviceId: String, settings: SharedPreferences) =
with(settings) {
DeviceInfo(
id = deviceId,
@@ -92,7 +90,7 @@ class DeviceInfo(
with(identityPacket) {
DeviceInfo(
id = getString("deviceId"), // Redundant: We could read this from the certificate instead
name = DeviceHelper.filterName(getString("deviceName", "unknown")),
name = getString("deviceName", "unknown"),
type = DeviceType.fromString(getString("deviceType", "desktop")),
certificate = certificate,
protocolVersion = getInt("protocolVersion"),
@@ -100,13 +98,6 @@ class DeviceInfo(
outgoingCapabilities = getStringSet("outgoingCapabilities")
)
}
@JvmStatic
fun isValidIdentityPacket(identityPacket: NetworkPacket): Boolean = with(identityPacket) {
type == NetworkPacket.PACKET_TYPE_IDENTITY &&
DeviceHelper.filterName(getString("deviceName", "")).isNotBlank() &&
getString("deviceId", "").isNotBlank()
}
}
}
@@ -123,10 +114,9 @@ enum class DeviceType {
}
fun getIcon(context: Context) =
ContextCompat.getDrawable(context, toDrawableId())!!
ContextCompat.getDrawable(context, toDrawableId())
@DrawableRes
fun toDrawableId() =
private fun toDrawableId() =
when (this) {
PHONE -> R.drawable.ic_device_phone_32dp
TABLET -> R.drawable.ic_device_tablet_32dp
@@ -135,15 +125,6 @@ enum class DeviceType {
else -> R.drawable.ic_device_desktop_32dp
}
fun toShortcutDrawableId() =
when (this) {
PHONE -> R.drawable.ic_device_phone_shortcut
TABLET -> R.drawable.ic_device_tablet_shortcut
TV -> R.drawable.ic_device_tv_shortcut
LAPTOP -> R.drawable.ic_device_laptop_shortcut
else -> R.drawable.ic_device_desktop_shortcut
}
companion object {
@JvmStatic
fun fromString(s: String) =

View File

@@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: 2019 Matthijs Tijink <matthijstijink@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.collections.ArrayDeque
/**
* Keeps a queue of packets to send to a device, to prevent either blocking or using lots of threads
*/
class DevicePacketQueue @JvmOverloads constructor(private val device: Device, startRunning: Boolean = true) {
/**
* Holds the packet and related stuff to keep in the queue
*/
private class Item(
var packet: NetworkPacket,
/**
* Replacement ID: if positive, it can be replaced by later packets with the same ID
*/
val replaceID: Int,
var callback: Device.SendPacketStatusCallback
)
private val scope = CoroutineScope(Dispatchers.IO)
private val sendingJob = SupervisorJob()
private val loopJob = Job()
private val items = ArrayDeque<Item>()
private val mutex = Mutex()
init {
if (startRunning) {
scope.launch(loopJob) {
sending()
}
}
}
fun addPacketSync(packet: NetworkPacket, replaceID: Int, callback: Device.SendPacketStatusCallback) {
runBlocking {
addPacket(packet, replaceID, callback)
}
}
/**
* Send a packet (at some point in the future)
* @param packet The packet
* @param replaceID If positive, it will replace all older packets still in the queue
* @param callback The callback after sending the packet
*/
suspend fun addPacket(packet: NetworkPacket, replaceID: Int, callback: Device.SendPacketStatusCallback) {
if (sendingJob.isCancelled) {
callback.onFailure(Exception("Device disconnected!"))
} else {
mutex.withLock {
var replaced = false
if (replaceID >= 0) {
items.forEach {
if (it.replaceID == replaceID) {
it.packet = packet
it.callback = callback
replaced = true
}
}
}
if (!replaced) {
items.addLast(Item(packet, replaceID, callback))
}
}
}
}
fun getAndRemoveUnsentPacketSync(replaceID: Int): NetworkPacket? {
return runBlocking {
getAndRemoveUnsentPacket(replaceID)
}
}
/**
* Check if we still have an unsent packet in the queue with the given ID.
* If so, remove it from the queue and return it
* @param replaceID The replace ID (must be positive)
* @return The found packet, or null
*/
suspend fun getAndRemoveUnsentPacket(replaceID: Int): NetworkPacket? {
mutex.withLock {
val itemOptional = items.stream()
.filter { item: Item -> item.replaceID == replaceID }.findFirst()
if (itemOptional.isPresent) {
val item = itemOptional.get()
items.remove(item)
return item.packet
}
}
return null
}
fun disconnected() {
sendingJob.cancel()
}
private suspend fun sending() {
while (true) {
val item = mutex.withLock {
if (items.isEmpty()) {
null
} else {
items.removeFirst()
}
}
if (item == null) {
yield()
continue
}
if (sendingJob.isCancelled) {
item.callback.onFailure(Exception("Device disconnected!"))
} else {
scope.launch(sendingJob) {
device.sendPacketBlocking(item.packet, item.callback)
}
}
}
}
}

View File

@@ -1,871 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 The Android Open Source Project
* SPDX-FileCopyrightText: 1997, 2021, Oracle and/or its affiliates. All rights reserved
*
* SPDX-FileCopyrightText: 2024 ShellWen Chen <me@shellwen.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers;
import android.os.Build;
import android.os.Build.VERSION;
import androidx.annotation.RequiresApi;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Spliterator;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/** @noinspection unused*/
public final class CollectionsBackport {
public static <T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s) {
if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return Collections.unmodifiableNavigableSet(s);
} else {
return new UnmodifiableNavigableSetBackport<>(s);
}
}
public static <T> Set<T> unmodifiableSet(Set<T> s) {
if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return Collections.unmodifiableSet(s);
} else {
return new UnmodifiableSetBackport<>(s);
}
}
public static <T> Collection<T> unmodifiableCollection(Collection<T> c) {
if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return Collections.unmodifiableCollection(c);
} else {
return new UnmodifiableCollectionBackport<>(c);
}
}
public static <K, V> NavigableMap<K, V> unmodifiableNavigableMap(NavigableMap<K, V> m) {
if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return Collections.unmodifiableNavigableMap(m);
} else {
return new UnmodifiableNavigableMapBackport<>(m);
}
}
public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> m) {
if (VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return Collections.unmodifiableMap(m);
} else {
return new UnmodifiableMapBackport<>(m);
}
}
public static <T> NavigableSet<T> emptyNavigableSet() {
//noinspection unchecked
return (NavigableSet<T>) UnmodifiableNavigableSetBackport.EMPTY_NAVIGABLE_SET;
}
public static <K, V> NavigableMap<K, V> emptyNavigableMap() {
//noinspection unchecked
return (NavigableMap<K, V>) UnmodifiableNavigableMapBackport.EMPTY_NAVIGABLE_MAP;
}
static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
static class UnmodifiableNavigableSetBackport<E>
extends UnmodifiableSortedSetBackport<E>
implements NavigableSet<E>, Serializable {
/**
* A singleton empty unmodifiable navigable set used for
* {@link #emptyNavigableSet()}.
*
* @param <E> type of elements, if there were any, and bounds
*/
private static class EmptyNavigableSet<E> extends UnmodifiableNavigableSetBackport<E>
implements Serializable {
public EmptyNavigableSet() {
super(new TreeSet<>());
}
@java.io.Serial
private Object readResolve() {
return EMPTY_NAVIGABLE_SET;
}
}
@SuppressWarnings("rawtypes")
private static final NavigableSet<?> EMPTY_NAVIGABLE_SET =
new EmptyNavigableSet<>();
/**
* The instance we are protecting.
*/
@SuppressWarnings("serial") // Conditionally serializable
private final NavigableSet<E> ns;
UnmodifiableNavigableSetBackport(NavigableSet<E> s) {
super(s);
ns = s;
}
public E lower(E e) {
return ns.lower(e);
}
public E floor(E e) {
return ns.floor(e);
}
public E ceiling(E e) {
return ns.ceiling(e);
}
public E higher(E e) {
return ns.higher(e);
}
public E pollFirst() {
throw new UnsupportedOperationException();
}
public E pollLast() {
throw new UnsupportedOperationException();
}
public NavigableSet<E> descendingSet() {
return new UnmodifiableNavigableSetBackport<>(ns.descendingSet());
}
public Iterator<E> descendingIterator() {
return descendingSet().iterator();
}
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
return new UnmodifiableNavigableSetBackport<>(
ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
}
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
return new UnmodifiableNavigableSetBackport<>(
ns.headSet(toElement, inclusive));
}
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return new UnmodifiableNavigableSetBackport<>(
ns.tailSet(fromElement, inclusive));
}
}
static class UnmodifiableSortedSetBackport<E>
extends UnmodifiableSetBackport<E>
implements SortedSet<E>, Serializable {
@SuppressWarnings("serial") // Conditionally serializable
private final SortedSet<E> ss;
UnmodifiableSortedSetBackport(SortedSet<E> s) {
super(s);
ss = s;
}
public Comparator<? super E> comparator() {
return ss.comparator();
}
public SortedSet<E> subSet(E fromElement, E toElement) {
return new UnmodifiableSortedSetBackport<>(ss.subSet(fromElement, toElement));
}
public SortedSet<E> headSet(E toElement) {
return new UnmodifiableSortedSetBackport<>(ss.headSet(toElement));
}
public SortedSet<E> tailSet(E fromElement) {
return new UnmodifiableSortedSetBackport<>(ss.tailSet(fromElement));
}
public E first() {
return ss.first();
}
public E last() {
return ss.last();
}
}
static class UnmodifiableSetBackport<E> extends UnmodifiableCollectionBackport<E>
implements Set<E>, Serializable {
UnmodifiableSetBackport(Set<? extends E> s) {
super(s);
}
public boolean equals(Object o) {
return o == this || c.equals(o);
}
public int hashCode() {
return c.hashCode();
}
}
static class UnmodifiableCollectionBackport<E> implements Collection<E>, Serializable {
@SuppressWarnings("serial") // Conditionally serializable
final Collection<? extends E> c;
UnmodifiableCollectionBackport(Collection<? extends E> c) {
if (c == null)
throw new NullPointerException();
this.c = c;
}
public int size() {
return c.size();
}
public boolean isEmpty() {
return c.isEmpty();
}
public boolean contains(Object o) {
return c.contains(o);
}
public Object[] toArray() {
return c.toArray();
}
public <T> T[] toArray(T[] a) {
return c.toArray(a);
}
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
public <T> T[] toArray(IntFunction<T[]> f) {
return c.toArray(f);
}
public String toString() {
return c.toString();
}
public Iterator<E> iterator() {
return new Iterator<E>() {
private final Iterator<? extends E> i = c.iterator();
public boolean hasNext() {
return i.hasNext();
}
public E next() {
return i.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void forEachRemaining(Consumer<? super E> action) {
// Use backing collection version
i.forEachRemaining(action);
}
};
}
public boolean add(E e) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(Collection<?> coll) {
return c.containsAll(coll);
}
public boolean addAll(Collection<? extends E> coll) {
throw new UnsupportedOperationException();
}
public boolean removeAll(Collection<?> coll) {
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> coll) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> action) {
c.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
@Override
public Spliterator<E> spliterator() {
return (Spliterator<E>) c.spliterator();
}
@RequiresApi(api = Build.VERSION_CODES.N)
@SuppressWarnings("unchecked")
@Override
public Stream<E> stream() {
return (Stream<E>) c.stream();
}
@RequiresApi(api = Build.VERSION_CODES.N)
@SuppressWarnings("unchecked")
@Override
public Stream<E> parallelStream() {
return (Stream<E>) c.parallelStream();
}
}
static class UnmodifiableNavigableMapBackport<K, V> extends UnmodifiableSortedMapBackport<K, V> implements NavigableMap<K, V>, Serializable {
private static final long serialVersionUID = -4858195264774772197L;
private static final EmptyNavigableMapBackport<?, ?> EMPTY_NAVIGABLE_MAP = new EmptyNavigableMapBackport();
private final NavigableMap<K, ? extends V> nm;
UnmodifiableNavigableMapBackport(NavigableMap<K, ? extends V> m) {
super(m);
this.nm = m;
}
public K lowerKey(K key) {
return this.nm.lowerKey(key);
}
public K floorKey(K key) {
return this.nm.floorKey(key);
}
public K ceilingKey(K key) {
return this.nm.ceilingKey(key);
}
public K higherKey(K key) {
return this.nm.higherKey(key);
}
public Map.Entry<K, V> lowerEntry(K key) {
Map.Entry<K, V> lower = (Entry<K, V>) this.nm.lowerEntry(key);
return null != lower ? new UnmodifiableMapBackport.UnmodifiableEntrySetBackport.UnmodifiableEntry(lower) : null;
}
public Map.Entry<K, V> floorEntry(K key) {
Map.Entry<K, V> floor = (Entry<K, V>) this.nm.floorEntry(key);
return null != floor ? new UnmodifiableMapBackport.UnmodifiableEntrySetBackport.UnmodifiableEntry(floor) : null;
}
public Map.Entry<K, V> ceilingEntry(K key) {
Map.Entry<K, V> ceiling = (Entry<K, V>) this.nm.ceilingEntry(key);
return null != ceiling ? new UnmodifiableMapBackport.UnmodifiableEntrySetBackport.UnmodifiableEntry(ceiling) : null;
}
public Map.Entry<K, V> higherEntry(K key) {
Map.Entry<K, V> higher = (Entry<K, V>) this.nm.higherEntry(key);
return null != higher ? new UnmodifiableMapBackport.UnmodifiableEntrySetBackport.UnmodifiableEntry(higher) : null;
}
public Map.Entry<K, V> firstEntry() {
Map.Entry<K, V> first = (Entry<K, V>) this.nm.firstEntry();
return null != first ? new UnmodifiableMapBackport.UnmodifiableEntrySetBackport.UnmodifiableEntry(first) : null;
}
public Map.Entry<K, V> lastEntry() {
Map.Entry<K, V> last = (Entry<K, V>) this.nm.lastEntry();
return null != last ? new UnmodifiableMapBackport.UnmodifiableEntrySetBackport.UnmodifiableEntry(last) : null;
}
public Map.Entry<K, V> pollFirstEntry() {
throw new UnsupportedOperationException();
}
public Map.Entry<K, V> pollLastEntry() {
throw new UnsupportedOperationException();
}
public NavigableMap<K, V> descendingMap() {
return (NavigableMap<K, V>) CollectionsBackport.unmodifiableNavigableMap(this.nm.descendingMap());
}
public NavigableSet<K> navigableKeySet() {
return CollectionsBackport.unmodifiableNavigableSet(this.nm.navigableKeySet());
}
public NavigableSet<K> descendingKeySet() {
return CollectionsBackport.unmodifiableNavigableSet(this.nm.descendingKeySet());
}
public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
return (NavigableMap<K, V>) CollectionsBackport.unmodifiableNavigableMap(this.nm.subMap(fromKey, fromInclusive, toKey, toInclusive));
}
public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
return (NavigableMap<K, V>) CollectionsBackport.unmodifiableNavigableMap(this.nm.headMap(toKey, inclusive));
}
public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
return (NavigableMap<K, V>) CollectionsBackport.unmodifiableNavigableMap(this.nm.tailMap(fromKey, inclusive));
}
private static class EmptyNavigableMapBackport<K, V> extends UnmodifiableNavigableMapBackport<K, V> implements Serializable {
private static final long serialVersionUID = -2239321462712562324L;
EmptyNavigableMapBackport() {
super(new TreeMap());
}
public NavigableSet<K> navigableKeySet() {
return CollectionsBackport.emptyNavigableSet();
}
private Object readResolve() {
return UnmodifiableNavigableMapBackport.EMPTY_NAVIGABLE_MAP;
}
}
}
static class UnmodifiableSortedMapBackport<K,V>
extends UnmodifiableMapBackport<K,V>
implements SortedMap<K,V>, Serializable {
@SuppressWarnings("serial") // Conditionally serializable
private final SortedMap<K, ? extends V> sm;
UnmodifiableSortedMapBackport(SortedMap<K, ? extends V> m) {super(m); sm = m; }
public Comparator<? super K> comparator() { return sm.comparator(); }
public SortedMap<K,V> subMap(K fromKey, K toKey)
{ return new UnmodifiableSortedMapBackport<>(sm.subMap(fromKey, toKey)); }
public SortedMap<K,V> headMap(K toKey)
{ return new UnmodifiableSortedMapBackport<>(sm.headMap(toKey)); }
public SortedMap<K,V> tailMap(K fromKey)
{ return new UnmodifiableSortedMapBackport<>(sm.tailMap(fromKey)); }
public K firstKey() { return sm.firstKey(); }
public K lastKey() { return sm.lastKey(); }
}
private static class UnmodifiableMapBackport<K, V> implements Map<K, V>, Serializable {
@java.io.Serial
private static final long serialVersionUID = -1034234728574286014L;
@SuppressWarnings("serial") // Conditionally serializable
private final Map<? extends K, ? extends V> m;
UnmodifiableMapBackport(Map<? extends K, ? extends V> m) {
if (m == null)
throw new NullPointerException();
this.m = m;
}
public int size() {
return m.size();
}
public boolean isEmpty() {
return m.isEmpty();
}
public boolean containsKey(Object key) {
return m.containsKey(key);
}
public boolean containsValue(Object val) {
return m.containsValue(val);
}
public V get(Object key) {
return m.get(key);
}
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public V remove(Object key) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
private transient Set<K> keySet;
private transient Set<Map.Entry<K, V>> entrySet;
private transient Collection<V> values;
public Set<K> keySet() {
if (keySet == null)
keySet = (Set<K>) unmodifiableSet(m.keySet());
return keySet;
}
public Set<Map.Entry<K, V>> entrySet() {
if (entrySet == null)
entrySet = new UnmodifiableEntrySetBackport<>(m.entrySet());
return entrySet;
}
public Collection<V> values() {
if (values == null)
values = (Collection<V>) unmodifiableCollection(m.values());
return values;
}
public boolean equals(Object o) {
return o == this || m.equals(o);
}
public int hashCode() {
return m.hashCode();
}
public String toString() {
return m.toString();
}
// Override default methods in Map
@Override
@SuppressWarnings("unchecked")
public V getOrDefault(Object k, V defaultValue) {
// Safe cast as we don't change the value
return ((Map<K, V>) m).getOrDefault(k, defaultValue);
}
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
m.forEach(action);
}
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
throw new UnsupportedOperationException();
}
@Override
public V putIfAbsent(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException();
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
throw new UnsupportedOperationException();
}
@Override
public V replace(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
/**
* We need this class in addition to UnmodifiableSet as
* Map.Entries themselves permit modification of the backing Map
* via their setValue operation. This class is subtle: there are
* many possible attacks that must be thwarted.
*
* @serial include
*/
static class UnmodifiableEntrySetBackport<K, V>
extends UnmodifiableSetBackport<Map.Entry<K, V>> {
@java.io.Serial
private static final long serialVersionUID = 7854390611657943733L;
@SuppressWarnings({"unchecked", "rawtypes"})
UnmodifiableEntrySetBackport(Set<? extends Map.Entry<? extends K, ? extends V>> s) {
// Need to cast to raw in order to work around a limitation in the type system
super((Set) s);
}
static <K, V> Consumer<Map.Entry<? extends K, ? extends V>> entryConsumer(
Consumer<? super Entry<K, V>> action) {
return e -> action.accept(new UnmodifiableEntry<>(e));
}
public void forEach(Consumer<? super Entry<K, V>> action) {
Objects.requireNonNull(action);
c.forEach(entryConsumer(action));
}
static final class UnmodifiableEntrySetSpliterator<K, V>
implements Spliterator<Entry<K, V>> {
final Spliterator<Map.Entry<K, V>> s;
UnmodifiableEntrySetSpliterator(Spliterator<Entry<K, V>> s) {
this.s = s;
}
@Override
public boolean tryAdvance(Consumer<? super Entry<K, V>> action) {
Objects.requireNonNull(action);
return s.tryAdvance(entryConsumer(action));
}
@Override
public void forEachRemaining(Consumer<? super Entry<K, V>> action) {
Objects.requireNonNull(action);
s.forEachRemaining(entryConsumer(action));
}
@Override
public Spliterator<Entry<K, V>> trySplit() {
Spliterator<Entry<K, V>> split = s.trySplit();
return split == null
? null
: new UnmodifiableEntrySetSpliterator<>(split);
}
@Override
public long estimateSize() {
return s.estimateSize();
}
@Override
public long getExactSizeIfKnown() {
return s.getExactSizeIfKnown();
}
@Override
public int characteristics() {
return s.characteristics();
}
@Override
public boolean hasCharacteristics(int characteristics) {
return s.hasCharacteristics(characteristics);
}
@Override
public Comparator<? super Entry<K, V>> getComparator() {
return s.getComparator();
}
}
@SuppressWarnings("unchecked")
public Spliterator<Entry<K, V>> spliterator() {
return new UnmodifiableEntrySetSpliterator<>(
(Spliterator<Map.Entry<K, V>>) c.spliterator());
}
@Override
public Stream<Entry<K, V>> stream() {
return StreamSupport.stream(spliterator(), false);
}
@Override
public Stream<Entry<K, V>> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
public Iterator<Map.Entry<K, V>> iterator() {
return new Iterator<Map.Entry<K, V>>() {
private final Iterator<? extends Map.Entry<? extends K, ? extends V>> i = c.iterator();
public boolean hasNext() {
return i.hasNext();
}
public Map.Entry<K, V> next() {
return new UnmodifiableEntry<>(i.next());
}
public void remove() {
throw new UnsupportedOperationException();
}
// Seems like an oversight. http://b/110351017
public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
i.forEachRemaining(entryConsumer(action));
}
};
}
@SuppressWarnings("unchecked")
public Object[] toArray() {
Object[] a = c.toArray();
for (int i = 0; i < a.length; i++)
a[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>) a[i]);
return a;
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// We don't pass a to c.toArray, to avoid window of
// vulnerability wherein an unscrupulous multithreaded client
// could get his hands on raw (unwrapped) Entries from c.
Object[] arr = c.toArray(a.length == 0 ? a : Arrays.copyOf(a, 0));
for (int i = 0; i < arr.length; i++)
arr[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>) arr[i]);
if (arr.length > a.length)
return (T[]) arr;
System.arraycopy(arr, 0, a, 0, arr.length);
if (a.length > arr.length)
a[arr.length] = null;
return a;
}
/**
* This method is overridden to protect the backing set against
* an object with a nefarious equals function that senses
* that the equality-candidate is Map.Entry and calls its
* setValue method.
*/
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
return c.contains(
new UnmodifiableEntry<>((Map.Entry<?, ?>) o));
}
/**
* The next two methods are overridden to protect against
* an unscrupulous List whose contains(Object o) method senses
* when o is a Map.Entry, and calls o.setValue.
*/
public boolean containsAll(Collection<?> coll) {
for (Object e : coll) {
if (!contains(e)) // Invokes safe contains() above
return false;
}
return true;
}
public boolean equals(Object o) {
if (o == this)
return true;
// Android-changed: (b/247094511) instanceof pattern variable is not yet supported.
/*
return o instanceof Set<?> s
&& s.size() == c.size()
&& containsAll(s); // Invokes safe containsAll() above
*/
if (!(o instanceof Set))
return false;
Set<?> s = (Set<?>) o;
if (s.size() != c.size())
return false;
return containsAll(s); // Invokes safe containsAll() above
}
/**
* This "wrapper class" serves two purposes: it prevents
* the client from modifying the backing Map, by short-circuiting
* the setValue method, and it protects the backing Map against
* an ill-behaved Map.Entry that attempts to modify another
* Map Entry when asked to perform an equality check.
*/
private static class UnmodifiableEntry<K, V> implements Map.Entry<K, V> {
private Map.Entry<? extends K, ? extends V> e;
UnmodifiableEntry(Map.Entry<? extends K, ? extends V> e) {
this.e = Objects.requireNonNull(e);
}
public K getKey() {
return e.getKey();
}
public V getValue() {
return e.getValue();
}
public V setValue(V value) {
throw new UnsupportedOperationException();
}
public int hashCode() {
return e.hashCode();
}
public boolean equals(Object o) {
if (this == o)
return true;
// Android-changed: (b/247094511) instanceof pattern variable is not yet
// supported.
/*
return o instanceof Map.Entry<?, ?> t
&& eq(e.getKey(), t.getKey())
&& eq(e.getValue(), t.getValue());
*/
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?, ?> t = (Map.Entry<?, ?>) o;
return eq(e.getKey(), t.getKey()) &&
eq(e.getValue(), t.getValue());
}
public String toString() {
return e.toString();
}
}
}
}
}

View File

@@ -0,0 +1,163 @@
/*
* SPDX-FileCopyrightText: 2014 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import com.univocity.parsers.common.TextParsingException;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;
import org.kde.kdeconnect.DeviceInfo;
import org.kde.kdeconnect.DeviceType;
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
import org.kde.kdeconnect.Plugins.PluginFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.UUID;
public class DeviceHelper {
public static final int ProtocolVersion = 7;
public static final String KEY_DEVICE_NAME_PREFERENCE = "device_name_preference";
public static final String KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET = "device_name_downloaded_preference";
public static final String KEY_DEVICE_ID_PREFERENCE = "device_id_preference";
private static boolean fetchingName = false;
public static final String DEVICE_DATABASE = "https://storage.googleapis.com/play_public/supported_devices.csv";
private static boolean isTablet() {
Configuration config = Resources.getSystem().getConfiguration();
//This assumes that the values for the screen sizes are consecutive, so XXLARGE > XLARGE > LARGE
return ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE);
}
private static boolean isTv(Context context) {
int uiMode = context.getResources().getConfiguration().uiMode;
return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
}
public static DeviceType getDeviceType(Context context) {
if (isTv(context)) {
return DeviceType.TV;
} else if (isTablet()) {
return DeviceType.TABLET;
} else {
return DeviceType.PHONE;
}
}
public static String getDeviceName(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (!preferences.contains(KEY_DEVICE_NAME_PREFERENCE)
&& !preferences.getBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, false)
&& !fetchingName) {
fetchingName = true;
DeviceHelper.backgroundFetchDeviceName(context);
return Build.MODEL;
}
return preferences.getString(KEY_DEVICE_NAME_PREFERENCE, Build.MODEL);
}
private static void backgroundFetchDeviceName(final Context context) {
ThreadHelper.execute(() -> {
try {
URL url = new URL(DEVICE_DATABASE);
URLConnection connection = url.openConnection();
// If we get here we managed to download the file. Mark that as done so we don't try again even if we don't end up finding a name.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences.edit().putBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, true).apply();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_16))) {
CsvParserSettings settings = new CsvParserSettings();
settings.setHeaderExtractionEnabled(true);
CsvParser parser = new CsvParser(settings);
boolean found = false;
for (String[] records : parser.iterate(reader)) {
if (records.length < 4) {
continue;
}
String buildModel = records[3];
if (Build.MODEL.equalsIgnoreCase(buildModel)) {
String deviceName = records[1];
Log.i("DeviceHelper", "Got device name: " + deviceName);
// Update the shared preference. Places that display the name should be listening to this change and update it
setDeviceName(context, deviceName);
found = true;
break;
}
}
if (!found) {
Log.e("DeviceHelper", "Didn't find a device name for " + Build.MODEL);
}
}
} catch(IOException | TextParsingException e) {
e.printStackTrace();
}
fetchingName = false;
});
}
public static void setDeviceName(Context context, String name) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
preferences.edit().putString(KEY_DEVICE_NAME_PREFERENCE, name).apply();
}
@SuppressLint("HardwareIds")
public static void initializeDeviceId(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> preferenceKeys = preferences.getAll().keySet();
if (preferenceKeys.contains(KEY_DEVICE_ID_PREFERENCE)) {
return; // We already have an ID
}
String deviceName;
if (preferenceKeys.isEmpty()) {
// For new installations, use random IDs
Log.i("DeviceHelper", "No device ID found and this looks like a new installation, creating a random ID");
deviceName = UUID.randomUUID().toString().replace('-','_');
} else {
// Use the ANDROID_ID as device ID for existing installations, for backwards compatibility
Log.i("DeviceHelper", "No device ID found but this seems an existing installation, using the Android ID");
deviceName = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
preferences.edit().putString(KEY_DEVICE_ID_PREFERENCE, deviceName).apply();
}
public static String getDeviceId(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getString(KEY_DEVICE_ID_PREFERENCE, null);
}
public static DeviceInfo getDeviceInfo(Context context) {
return new DeviceInfo(getDeviceId(context),
SslHelper.certificate,
getDeviceName(context),
DeviceHelper.getDeviceType(context),
ProtocolVersion,
PluginFactory.getIncomingCapabilities(),
PluginFactory.getOutgoingCapabilities());
}
}

View File

@@ -1,170 +0,0 @@
/*
* SPDX-FileCopyrightText: 2024 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Build
import android.preference.PreferenceManager
import android.provider.Settings
import android.util.Log
import com.univocity.parsers.common.TextParsingException
import com.univocity.parsers.csv.CsvParser
import com.univocity.parsers.csv.CsvParserSettings
import org.kde.kdeconnect.DeviceInfo
import org.kde.kdeconnect.DeviceType
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
import org.kde.kdeconnect.Plugins.PluginFactory
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.net.URL
import java.nio.charset.StandardCharsets
import java.util.UUID
object DeviceHelper {
const val ProtocolVersion = 7
const val KEY_DEVICE_NAME_PREFERENCE = "device_name_preference"
private const val KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET = "device_name_downloaded_preference"
private const val KEY_DEVICE_ID_PREFERENCE = "device_id_preference"
private var fetchingName = false
private const val DEVICE_DATABASE = "https://storage.googleapis.com/play_public/supported_devices.csv"
private val NAME_INVALID_CHARACTERS_REGEX = "[\"',;:.!?()\\[\\]<>]".toRegex()
const val MAX_DEVICE_NAME_LENGTH = 32
private val isTablet: Boolean by lazy {
val config = Resources.getSystem().configuration
//This assumes that the values for the screen sizes are consecutive, so XXLARGE > XLARGE > LARGE
((config.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE)
}
private val isTv: Boolean by lazy {
val uiMode = Resources.getSystem().configuration.uiMode
(uiMode and Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION
}
@JvmStatic
val deviceType: DeviceType by lazy {
if (isTv) {
DeviceType.TV
} else if (isTablet) {
DeviceType.TABLET
} else {
DeviceType.PHONE
}
}
@JvmStatic
fun getDeviceName(context: Context): String {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
if (!preferences.contains(KEY_DEVICE_NAME_PREFERENCE)
&& !preferences.getBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, false)
&& !fetchingName
) {
fetchingName = true
backgroundFetchDeviceName(context)
return Build.MODEL
}
return preferences.getString(KEY_DEVICE_NAME_PREFERENCE, Build.MODEL)!!
}
private fun backgroundFetchDeviceName(context: Context) {
ThreadHelper.execute {
try {
val url = URL(DEVICE_DATABASE)
val connection = url.openConnection()
// If we get here we managed to download the file. Mark that as done so we don't try again even if we don't end up finding a name.
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
preferences.edit().putBoolean(KEY_DEVICE_NAME_FETCHED_FROM_THE_INTERNET, true).apply()
BufferedReader(
InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_16)
).use { reader ->
val settings = CsvParserSettings()
settings.isHeaderExtractionEnabled = true
val parser = CsvParser(settings)
var found = false
for (records in parser.iterate(reader)) {
if (records.size < 4) {
continue
}
val buildModel = records[3]
if (Build.MODEL.equals(buildModel, ignoreCase = true)) {
val deviceName = records[1]
Log.i("DeviceHelper", "Got device name: $deviceName")
// Update the shared preference. Places that display the name should be listening to this change and update it
setDeviceName(context, deviceName)
found = true
break
}
}
if (!found) {
Log.e("DeviceHelper", "Didn't find a device name for " + Build.MODEL)
}
}
} catch (e: IOException) {
e.printStackTrace()
} catch (e: TextParsingException) {
e.printStackTrace()
}
fetchingName = false
}
}
fun setDeviceName(context: Context, name: String) {
val filteredName = filterName(name)
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
preferences.edit().putString(KEY_DEVICE_NAME_PREFERENCE, filteredName).apply()
}
fun initializeDeviceId(context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val preferenceKeys: Set<String> = preferences.all.keys
if (preferenceKeys.contains(KEY_DEVICE_ID_PREFERENCE)) {
return // We already have an ID
}
@SuppressLint("HardwareIds")
val deviceName = if (preferenceKeys.isEmpty()) {
// For new installations, use random IDs
Log.i("DeviceHelper","No device ID found and this looks like a new installation, creating a random ID")
UUID.randomUUID().toString().replace('-', '_')
} else {
// Use the ANDROID_ID as device ID for existing installations, for backwards compatibility
Log.i("DeviceHelper", "No device ID found but this seems an existing installation, using the Android ID")
Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
}
preferences.edit().putString(KEY_DEVICE_ID_PREFERENCE, deviceName).apply()
}
@JvmStatic
fun getDeviceId(context: Context): String {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getString(KEY_DEVICE_ID_PREFERENCE, null)!!
}
@JvmStatic
fun getDeviceInfo(context: Context): DeviceInfo {
return DeviceInfo(
getDeviceId(context),
SslHelper.certificate,
getDeviceName(context),
deviceType,
ProtocolVersion,
PluginFactory.getIncomingCapabilities(),
PluginFactory.getOutgoingCapabilities()
)
}
@JvmStatic
fun filterName(input: String): String = input.replace(NAME_INVALID_CHARACTERS_REGEX, "").take(MAX_DEVICE_NAME_LENGTH)
}

View File

@@ -0,0 +1,251 @@
/*
* SPDX-FileCopyrightText: 2014 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import android.webkit.MimeTypeMap;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.kde.kdeconnect.NetworkPacket;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
public class FilesHelper {
public static final String LOG_TAG = "SendFileActivity";
public static String getMimeTypeFromFile(String file) {
String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(FilenameUtils.getExtension(file));
return StringUtils.defaultString(mime, "*/*");
}
public static String findNonExistingNameForNewFile(String path, String filename) {
String name = FilenameUtils.getBaseName(filename);
String ext = FilenameUtils.getExtension(filename);
int num = 1;
while (new File(path + "/" + filename).exists()) {
filename = name + " (" + num + ")." + ext;
num++;
}
return filename;
}
//Following code from http://activemq.apache.org/maven/5.7.0/kahadb/apidocs/src-html/org/apache/kahadb/util/IOHelper.html
/**
* Converts any string into a string that is safe to use as a file name.
* The result will only include ascii characters and numbers, and the "-","_", and "." characters.
*/
private static String toFileSystemSafeName(String name, boolean dirSeparators, int maxFileLength) {
int size = name.length();
StringBuilder rc = new StringBuilder(size * 2);
for (int i = 0; i < size; i++) {
char c = name.charAt(i);
boolean valid = c >= 'a' && c <= 'z';
valid = valid || (c >= 'A' && c <= 'Z');
valid = valid || (c >= '0' && c <= '9');
valid = valid || (c == '_') || (c == '-') || (c == '.');
valid = valid || (dirSeparators && ((c == '/') || (c == '\\')));
if (valid) {
rc.append(c);
}
}
String result = rc.toString();
if (result.length() > maxFileLength) {
result = result.substring(result.length() - maxFileLength);
}
return result;
}
public static String toFileSystemSafeName(String name, boolean dirSeparators) {
return toFileSystemSafeName(name, dirSeparators, 255);
}
public static String toFileSystemSafeName(String name) {
return toFileSystemSafeName(name, true, 255);
}
private static int GetOpenFileCount() {
return new File("/proc/self/fd").listFiles().length;
}
public static void LogOpenFileCount() {
Log.e("KDE/FileCount", "" + GetOpenFileCount());
}
//Create the network packet from the URI
public static NetworkPacket uriToNetworkPacket(final Context context, final Uri uri, String type) {
try {
ContentResolver cr = context.getContentResolver();
InputStream inputStream = cr.openInputStream(uri);
NetworkPacket np = new NetworkPacket(type);
String filename = null;
long size = -1;
Long lastModified = null;
if (uri.getScheme().equals("file")) {
// file:// is a non media uri, so we cannot query the ContentProvider
try {
File mFile = new File(uri.getPath());
filename = mFile.getName();
size = mFile.length();
lastModified = mFile.lastModified();
} catch (NullPointerException e) {
Log.e(LOG_TAG, "Received bad file URI", e);
}
} else {
// Since we used Intent.CATEGORY_OPENABLE, these two columns are the only ones we are
// guaranteed to have: https://developer.android.com/reference/android/provider/OpenableColumns
String[] proj = {
OpenableColumns.SIZE,
OpenableColumns.DISPLAY_NAME,
};
try (Cursor cursor = cr.query(uri, proj, null, null, null)) {
int nameColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
int sizeColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE);
cursor.moveToFirst();
filename = cursor.getString(nameColumnIndex);
// It is recommended to check for the value to be null because there are
// situations were we don't know the size (for instance, if the file is
// not local to the device)
if (!cursor.isNull(sizeColumnIndex)) {
size = cursor.getLong(sizeColumnIndex);
}
lastModified = getLastModifiedTime(context, uri);
} catch (Exception e) {
Log.e(LOG_TAG, "Problem getting file information", e);
}
}
if (filename != null) {
np.set("filename", filename);
} else {
// It would be very surprising if this happens
Log.e(LOG_TAG, "Unable to read filename");
}
if (lastModified != null) {
np.set("lastModified", lastModified);
} else {
// This would not be too surprising, and probably means we need to improve
// FilesHelper.getLastModifiedTime
Log.w(LOG_TAG, "Unable to read file last modified time");
}
np.setPayload(new NetworkPacket.Payload(inputStream, size));
return np;
} catch (Exception e) {
Log.e(LOG_TAG, "Exception creating network packet", e);
return null;
}
}
/**
* By hook or by crook, get the last modified time of the passed content:// URI
*
* This is a challenge because different content sources have different columns defined, and
* I don't know how to tell what the source of the content is.
*
* Therefore, my brilliant solution is to just try everything until something works.
*
* Will return null if nothing worked.
*/
public static Long getLastModifiedTime(final Context context, final Uri uri) {
ContentResolver cr = context.getContentResolver();
Long lastModifiedTime = null;
// Open a cursor without a column because we do not yet know what columns are defined
try (Cursor cursor = cr.query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
String[] allColumns = cursor.getColumnNames();
// MediaStore.MediaColumns.DATE_MODIFIED resolves to "date_modified"
// I see this column defined in case we used the Gallery app to select the file to transfer
// This can occur both for devices running Storage Access Framework (SAF) if we select
// the Gallery to provide the file to transfer, as well as for older devices by doing the same
int mediaDataModifiedColumnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED);
// DocumentsContract.Document.COLUMN_LAST_MODIFIED resolves to "last_modified"
// I see this column defined when, on a device using SAF we select a file using the
// file browser
// According to https://developer.android.com/reference/kotlin/android/provider/DocumentsContract
// all "document providers" must provide certain columns. Do we actually have a DocumentProvider here?
// I do not think this code path will ever happen for a non-media file is selected on
// an API < KitKat device, since those will be delivered as a file:// URI and handled
// accordingly. Therefore, it is safe to ignore the warning that this field requires
// API 19
@SuppressLint("InlinedApi")
int documentLastModifiedColumnIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED);
// If we have an image, it may be the case that MediaStore.MediaColumns.DATE_MODIFIED
// catches the modification date, but if not, here is another column we can look for.
// This should be checked *after* DATE_MODIFIED since I think that column might give
// better information
int imageDateTakenColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN);
// Report whether the captured timestamp is in milliseconds or seconds
// The truthy-ness of this value for each different type of column is known from either
// experimentation or the docs (when docs exist...)
boolean milliseconds;
int properColumnIndex;
if (mediaDataModifiedColumnIndex >= 0) {
properColumnIndex = mediaDataModifiedColumnIndex;
milliseconds = false;
} else if (documentLastModifiedColumnIndex >= 0) {
properColumnIndex = documentLastModifiedColumnIndex;
milliseconds = true;
} else if (imageDateTakenColumnIndex >= 0) {
properColumnIndex = imageDateTakenColumnIndex;
milliseconds = true;
} else {
// Nothing worked :(
String formattedColumns = Arrays.toString(allColumns);
Log.w("SendFileActivity", "Unable to get file modification time. Available columns were: " + formattedColumns);
return null;
}
if (!cursor.isNull(properColumnIndex)) {
lastModifiedTime = cursor.getLong(properColumnIndex);
}
if (!milliseconds) {
lastModifiedTime *= 1000;
milliseconds = true;
}
}
}
return lastModifiedTime;
}
}

View File

@@ -1,206 +0,0 @@
/*
* SPDX-FileCopyrightText: 2014 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers
import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Log
import android.webkit.MimeTypeMap
import org.apache.commons.io.FilenameUtils
import org.kde.kdeconnect.NetworkPacket
import java.io.File
import kotlin.math.min
object FilesHelper {
private const val LOG_TAG: String = "SendFileActivity"
@JvmStatic
fun getMimeTypeFromFile(file: String?): String {
val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(FilenameUtils.getExtension(file))
return mime ?: "*/*"
}
@JvmStatic
fun findNonExistingNameForNewFile(path: String, filename: String): String {
var newFilename = filename
val name = FilenameUtils.getBaseName(newFilename)
val ext = FilenameUtils.getExtension(newFilename)
var num = 1
while (File("$path/$newFilename").exists()) {
newFilename = "$name ($num).$ext"
num++
}
return newFilename
}
/**
* Converts any string into a string that is safe to use as a file name.
* The result will only include ascii characters and numbers, and the "-","_", and "." characters.
*/
private fun toFileSystemSafeName(name: String, dirSeparators: Boolean, maxFileLength: Int): String {
fun isSafeChar(c: Char): Boolean =
c in 'a'..'z' || c in 'A'..'Z' || c in '0'..'9' ||
c == '_' || c == '-' || c == '.' ||
(dirSeparators && ((c == '/') || (c == '\\')))
val nameSafeChars = name.filter(::isSafeChar)
val nameSafeLength = nameSafeChars.substring(nameSafeChars.length - min(nameSafeChars.length, maxFileLength))
return nameSafeLength
}
fun toFileSystemSafeName(name: String, dirSeparators: Boolean): String = toFileSystemSafeName(name, dirSeparators, 255)
fun toFileSystemSafeName(name: String): String = toFileSystemSafeName(name, true, 255)
private fun getOpenFileCount(): Int? = File("/proc/self/fd").listFiles()?.size
fun LogOpenFileCount() {
Log.e("KDE/FileCount", "" + getOpenFileCount())
}
/**
* Creates a network packet from the given URI
*/
@JvmStatic
fun uriToNetworkPacket(context: Context, uri: Uri, type: String?): NetworkPacket? {
try {
val contentResolver = context.contentResolver
val inputStream = contentResolver.openInputStream(uri)
val packet = NetworkPacket(type!!)
val sizeDefault = -1L
// file:// is a non media uri, so we cannot query the ContentProvider
fun fileSchemeExtract(): Triple<String?, Long, Long?> {
val path = uri.path
if (path != null) {
val mFile = File(path)
val filename = mFile.name
val size = mFile.length()
val lastModified = mFile.lastModified()
return Triple(filename, size, lastModified)
}
else {
Log.e(LOG_TAG, "Received bad file URI, path was null")
return Triple(null, sizeDefault, null)
}
}
fun contentResolverExtract(): Triple<String?, Long, Long?> {
// Since we used Intent.CATEGORY_OPENABLE, these two columns are the only ones we are guaranteed to have: https://developer.android.com/reference/android/provider/OpenableColumns
val proj = arrayOf(OpenableColumns.SIZE, OpenableColumns.DISPLAY_NAME,)
try {
contentResolver.query(uri, proj, null, null, null).use { cursor ->
val nameColumnIndex = cursor!!.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
val sizeColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE)
cursor.moveToFirst()
val filename = cursor.getString(nameColumnIndex)
// It is recommended to check for the value to be null because there are situations were we don't know the size (for instance, if the file is not local to the device)
val size = if (!cursor.isNull(sizeColumnIndex)) cursor.getLong(sizeColumnIndex) else sizeDefault
val lastModified = getLastModifiedTime(context, uri)
return Triple(filename, size, lastModified)
}
}
catch (e: Exception) {
Log.e(LOG_TAG, "Problem getting file information", e)
}
return Triple(null, sizeDefault, null)
}
val (filename, size, lastModified) = when (uri.scheme) {
"file" -> fileSchemeExtract()
else -> contentResolverExtract()
}
if (filename != null) {
packet["filename"] = filename
}
else {
// It would be very surprising if this happens
Log.e(LOG_TAG, "Unable to read filename")
}
if (lastModified != null) {
packet["lastModified"] = lastModified
}
else {
// This would not be too surprising, and probably means we need to improve FilesHelper.getLastModifiedTime
Log.w(LOG_TAG, "Unable to read file last modified time")
}
packet.payload = NetworkPacket.Payload(inputStream, size)
return packet
}
catch (e: Exception) {
Log.e(LOG_TAG, "Exception creating network packet", e)
return null
}
}
/**
* By hook or by crook, get the last modified time of the passed content:// URI
*
* This is a challenge because different content sources have different columns defined, and
* I don't know how to tell what the source of the content is.
*
* Therefore, my brilliant solution is to just try everything until something works.
*
* Will return null if nothing worked.
*
* @return Time last modified in milliseconds or null
*/
fun getLastModifiedTime(context: Context, uri: Uri): Long? {
context.contentResolver.query(uri, null, null, null, null).use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
val allColumns = cursor.columnNames
// MediaStore.MediaColumns.DATE_MODIFIED resolves to "date_modified"
// I see this column defined in case we used the Gallery app to select the file to transfer
// This can occur both for devices running Storage Access Framework (SAF) if we select the Gallery to provide the file to transfer, as well as for older devices by doing the same
val mediaDataModifiedColumnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED)
// DocumentsContract.Document.COLUMN_LAST_MODIFIED resolves to "last_modified"
// I see this column defined when, on a device using SAF we select a file using the file browser
// According to https://developer.android.com/reference/kotlin/android/provider/DocumentsContract all "document providers" must provide certain columns.
// Do we actually have a DocumentProvider here?
// I do not think this code path will ever happen for a non-media file is selected on an API < KitKat device, since those will be delivered as a file:// URI and handled accordingly.
// Therefore, it is safe to ignore the warning that this field requires API 19
@SuppressLint("InlinedApi") val documentLastModifiedColumnIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED)
// If we have an image, it may be the case that MediaStore.MediaColumns.DATE_MODIFIED catches the modification date, but if not, here is another column we can look for.
// This should be checked *after* DATE_MODIFIED since I think that column might give better information
val imageDateTakenColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN)
// Report whether the captured timestamp is in milliseconds or seconds
// The truthy-ness of this value for each different type of column is known from either experimentation or the docs (when docs exist...)
val (properColumnIndex: Int, milliseconds: Boolean) = when {
mediaDataModifiedColumnIndex >= 0 -> Pair(mediaDataModifiedColumnIndex, false)
documentLastModifiedColumnIndex >= 0 -> Pair(documentLastModifiedColumnIndex, true)
imageDateTakenColumnIndex >= 0 -> Pair(imageDateTakenColumnIndex, true)
else -> {
// Nothing worked :(
Log.w("SendFileActivity", "Unable to get file modification time. Available columns were: ${allColumns.contentToString()}")
return null
}
}
val lastModifiedTime: Long? = if (!cursor.isNull(properColumnIndex)) cursor.getLong(properColumnIndex) else null
return if (!milliseconds) lastModifiedTime!! * 1000 else lastModifiedTime
}
}
return null
}
}

View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2023 Albert Vaca Cintora <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
package org.kde.kdeconnect.Helpers;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
public class MediaStoreHelper {
//Maybe this class could batch successive calls together
public static void indexFile(Context context, Uri path) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(path);
context.sendBroadcast(mediaScanIntent);
}
}

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