mirror of
https://github.com/amnezia-vpn/amneziawg-android.git
synced 2026-07-03 14:05:13 +02:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0750c29c7f | |||
| 639ee6b5b2 | |||
| f764f2aaa9 | |||
| d2a9c56d9c | |||
| 4c3289aa52 | |||
| 79376bca64 | |||
| b709d36c01 | |||
| 0301c85e2c | |||
| 7e979817e2 | |||
| 13cc4436ca | |||
| bcfbf37ed1 | |||
| 74ff870cf5 | |||
| b4f54e8958 | |||
| d179a3af15 | |||
| 2bac2feeb5 | |||
| 261236c8ce | |||
| 4a7969ef24 | |||
| f670ff22c6 | |||
| cb3194f10a | |||
| f6b2bbf433 | |||
| 56a4862442 | |||
| 20390d65c8 | |||
| 177457e67b | |||
| 8caec4d739 | |||
| fb819b99a4 | |||
| fe82037f06 | |||
| c2aa1b21f8 | |||
| d69415b55a | |||
| 4fae2d1255 | |||
| a300f269f1 | |||
| 961cba3f7c | |||
| 6bc7386bff | |||
| 5fa08f286e | |||
| 35f868733c | |||
| e71b3d2583 | |||
| 755148242c | |||
| 15fea6f02f | |||
| cb2842e8ef | |||
| 106b67d892 | |||
| 996587f792 | |||
| 3a4bf35c77 | |||
| 46b37c0c26 | |||
| 5b5ba88a97 | |||
| ceb3095a0a | |||
| a31f0cf788 | |||
| 1dc74b171c | |||
| 9266487fe5 | |||
| 5d7ce139bc | |||
| ddb6c87ebf | |||
| 8a6f8f73cd | |||
| f4fc15538d | |||
| 938399d881 | |||
| 53ca421a85 | |||
| 32778d1c03 | |||
| a870bf6e04 | |||
| 7a8f708157 | |||
| e729c5dc51 | |||
| 4bf34c49b7 | |||
| 05511d4900 | |||
| 15da17b595 | |||
| b3c43e428f | |||
| 7bec539722 | |||
| a8dfebb086 | |||
| e72b4fc144 | |||
| 03189e7b20 | |||
| 10bb413187 | |||
| 1c814310b9 | |||
| 3fe9e3162f | |||
| 6da6f7886a | |||
| 8c2029870f | |||
| a5031a44a0 | |||
| 44b27fe472 | |||
| 93fb3b345b | |||
| 8b596697b7 | |||
| c536bbb7e9 | |||
| a978aac129 | |||
| eb8cab4110 | |||
| 0a36d9a5e9 | |||
| 309571039d | |||
| d56f2fb1bb | |||
| 9df8e5e239 | |||
| 444a86cc9f | |||
| 382e10e103 | |||
| dc002d77fa | |||
| aaa55c0dcc | |||
| 0ad3781ae5 | |||
| d738161a2e | |||
| 52c2e9cd24 | |||
| 5fd1a32ae4 | |||
| 655a853857 | |||
| 847da23300 | |||
| d5c07374ff |
@@ -22,12 +22,16 @@ The tunnel library is [on JCenter](https://bintray.com/wireguard/wireguard-andro
|
||||
implementation 'com.wireguard.android:tunnel:$wireguardTunnelVersion'
|
||||
```
|
||||
|
||||
The library makes use of Java 8 features, so be sure to support those in your gradle configuration:
|
||||
The library makes use of Java 8 features, so be sure to support those in your gradle configuration with desugaring:
|
||||
|
||||
```
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
coreLibraryDesugaringEnabled = true
|
||||
}
|
||||
dependencies {
|
||||
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.0.10"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+57
-21
@@ -1,25 +1,23 @@
|
||||
buildscript {
|
||||
ext {
|
||||
activityVersion = '1.2.0-alpha07'
|
||||
agpVersion = '4.0.1'
|
||||
activityVersion = '1.2.0-rc01'
|
||||
agpVersion = '4.1.2'
|
||||
annotationsVersion = '1.1.0'
|
||||
appcompatVersion = '1.2.0'
|
||||
bintrayPluginVersion = '1.8.5'
|
||||
biometricVersion = '1.1.0-alpha02'
|
||||
biometricVersion = '1.1.0-rc01'
|
||||
collectionVersion = '1.1.0'
|
||||
constraintLayoutVersion = '2.0.1'
|
||||
constraintLayoutVersion = '2.0.4'
|
||||
coordinatorLayoutVersion = '1.1.0'
|
||||
coreKtxVersion = '1.3.1'
|
||||
coroutinesVersion = '1.3.9'
|
||||
datastoreVersion = '1.0.0-alpha01'
|
||||
coreKtxVersion = '1.3.2'
|
||||
coroutinesVersion = '1.4.2'
|
||||
datastoreVersion = '1.0.0-alpha02'
|
||||
desugarVersion = '1.0.10'
|
||||
fragmentVersion = '1.3.0-alpha07'
|
||||
fragmentVersion = '1.3.0-rc02'
|
||||
jsr305Version = '3.0.2'
|
||||
junitVersion = '4.13'
|
||||
kotlinVersion = '1.4.10'
|
||||
lifecycleRuntimeKtxVersion = '2.3.0-alpha07'
|
||||
materialComponentsVersion = '22973ff10305397bfc72fed41684175fee8aeefb'
|
||||
mavenPluginVersion = '2.1'
|
||||
junitVersion = '4.13.1'
|
||||
kotlinVersion = '1.4.21-2'
|
||||
lifecycleRuntimeKtxVersion = '2.3.0-rc01'
|
||||
materialComponentsVersion = '1.3.0-rc01'
|
||||
preferenceVersion = '1.1.1'
|
||||
zxingEmbeddedVersion = '3.6.0'
|
||||
|
||||
@@ -28,20 +26,58 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:$agpVersion"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
classpath "com.github.dcendents:android-maven-gradle-plugin:$mavenPluginVersion"
|
||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$bintrayPluginVersion"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "de.undercouch.download" version "4.1.1"
|
||||
}
|
||||
|
||||
task downloadCrowdin(type: Download) {
|
||||
src 'https://crowdin.com/backend/download/project/wireguard.zip'
|
||||
dest file('build/translations.zip')
|
||||
overwrite true
|
||||
}
|
||||
|
||||
task cleanCrowdin(type: Delete) {
|
||||
delete 'ui/src/main/res/values-*/strings.xml'
|
||||
}
|
||||
|
||||
task extractCrowdin(type: Copy, dependsOn: ['downloadCrowdin', 'cleanCrowdin']) {
|
||||
mustRunAfter 'downloadCrowdin'
|
||||
from zipTree(file('build/translations.zip'))
|
||||
into file('build/translations')
|
||||
doFirst {
|
||||
delete 'build/translations'
|
||||
}
|
||||
}
|
||||
|
||||
task crowdin(type: Copy, dependsOn: ['extractCrowdin']) {
|
||||
mustRunAfter 'extractCrowdin'
|
||||
from 'build/translations/wireguard-android/ui/src/main/res'
|
||||
into 'ui/src/main/res/'
|
||||
doLast {
|
||||
delete 'build/translations'
|
||||
delete 'build/translations.zip'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'https://jitpack.io' }
|
||||
mavenCentral()
|
||||
jcenter() {
|
||||
content {
|
||||
// https://github.com/journeyapps/zxing-android-embedded/issues/606
|
||||
includeModule("com.journeyapps", "zxing-android-embedded")
|
||||
// https://youtrack.jetbrains.com/issue/IDEA-261387
|
||||
includeModule("org.jetbrains.trove4j", "trove4j")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +87,9 @@ task clean(type: Delete) {
|
||||
|
||||
tasks {
|
||||
wrapper {
|
||||
gradleVersion = "6.6.1"
|
||||
gradleVersion = "6.8.2"
|
||||
distributionType = Wrapper.DistributionType.ALL
|
||||
distributionSha256Sum = "11657af6356b7587bfb37287b5992e94a9686d5c8a0a1b60b87b9928a2decde5"
|
||||
distributionSha256Sum = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# R8 Full mode
|
||||
android.enableR8.fullMode=true
|
||||
|
||||
# https://jakewharton.com/increased-accuracy-of-aapt2-keep-rules/
|
||||
android.useMinimalKeepRules=true
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Thu Feb 11 16:09:16 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=11657af6356b7587bfb37287b5992e94a9686d5c8a0a1b60b87b9928a2decde5
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-all.zip
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
curl -Lo - https://crowdin.com/backend/download/project/wireguard.zip | bsdtar -C ui/src/main/res -x -f - --strip-components 5 wireguard-android
|
||||
find ui/src/main/res -name strings.xml -exec bash -c '[[ $(xmllint --xpath "count(//resources/*)" {}) -ne 0 ]] || rm -rf "$(dirname {})"' \;
|
||||
@@ -46,6 +46,7 @@ android {
|
||||
}
|
||||
lintOptions {
|
||||
disable('LongLogTag')
|
||||
disable('NewApi') // Desugaring!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+54
-48
@@ -1,53 +1,58 @@
|
||||
apply plugin: 'com.github.dcendents.android-maven'
|
||||
apply plugin: 'com.jfrog.bintray'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'signing'
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
pom.project {
|
||||
name 'WireGuard Tunnel Library'
|
||||
description 'Embeddable tunnel library for WireGuard for Android'
|
||||
url 'https://www.wireguard.com/'
|
||||
afterEvaluate {
|
||||
publishing {
|
||||
publications {
|
||||
release(MavenPublication) {
|
||||
groupId = groupName
|
||||
artifactId = 'tunnel'
|
||||
version wireguardVersionName
|
||||
|
||||
packaging 'aar'
|
||||
groupId groupName
|
||||
artifactId 'tunnel'
|
||||
version wireguardVersionName
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'The Apache Software License, Version 2.0'
|
||||
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
distribution 'repo'
|
||||
from components.getByName("release")
|
||||
|
||||
pom {
|
||||
name = 'WireGuard Tunnel Library'
|
||||
description = 'Embeddable tunnel library for WireGuard for Android'
|
||||
url = 'https://www.wireguard.com/'
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = 'The Apache Software License, Version 2.0'
|
||||
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
distribution = 'repo'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:https://git.zx2c4.com/wireguard-android'
|
||||
developerConnection = 'scm:git:https://git.zx2c4.com/wireguard-android'
|
||||
url = 'https://git.zx2c4.com/wireguard-android'
|
||||
}
|
||||
developers {
|
||||
organization {
|
||||
name = 'WireGuard'
|
||||
url = 'https://www.wireguard.com/'
|
||||
}
|
||||
developer {
|
||||
name = 'WireGuard'
|
||||
email = 'team@wireguard.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection 'scm:git:https://git.zx2c4.com/wireguard-android'
|
||||
url 'https://git.zx2c4.com/wireguard-android'
|
||||
}
|
||||
organization {
|
||||
name 'WireGuard'
|
||||
url 'https://www.wireguard.com/'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bintray {
|
||||
user = hasProperty('BINTRAY_USER') ? getProperty('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
||||
key = hasProperty('BINTRAY_KEY') ? getProperty('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
||||
|
||||
configurations = [ 'archives' ]
|
||||
|
||||
pkg {
|
||||
repo = 'wireguard-android'
|
||||
name = 'wireguard-android'
|
||||
userOrg = 'wireguard'
|
||||
licenses = [ 'Apache-2.0' ]
|
||||
vcsUrl = 'https://git.zx2c4.com/wireguard-android'
|
||||
publish = true
|
||||
|
||||
version {
|
||||
name = wireguardVersionName
|
||||
repositories {
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||
credentials {
|
||||
username = hasProperty('SONATYPE_USER') ? getProperty('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = hasProperty('SONATYPE_PASSWORD') ? getProperty('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,9 +73,10 @@ android.libraryVariants.all { variant ->
|
||||
archiveClassifier = 'sources'
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
}
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign publishing.publications
|
||||
}
|
||||
|
||||
@@ -214,8 +214,10 @@ public final class GoBackend implements Backend {
|
||||
throw new BackendException(Reason.VPN_NOT_AUTHORIZED);
|
||||
|
||||
final VpnService service;
|
||||
if (!vpnService.isDone())
|
||||
startVpnService();
|
||||
if (!vpnService.isDone()) {
|
||||
Log.d(TAG, "Requesting to start VpnService");
|
||||
context.startService(new Intent(context, VpnService.class));
|
||||
}
|
||||
|
||||
try {
|
||||
service = vpnService.get(2, TimeUnit.SECONDS);
|
||||
@@ -302,11 +304,6 @@ public final class GoBackend implements Backend {
|
||||
tunnel.onStateChange(state);
|
||||
}
|
||||
|
||||
private void startVpnService() {
|
||||
Log.d(TAG, "Requesting to start VpnService");
|
||||
context.startService(new Intent(context, VpnService.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for {@link GoBackend} that is invoked when {@link VpnService} is started by the
|
||||
* system's Always-On VPN mode.
|
||||
|
||||
@@ -56,9 +56,10 @@ public class Statistics {
|
||||
* @return a long representing the number of bytes received by this peer.
|
||||
*/
|
||||
public long peerRx(final Key peer) {
|
||||
if (!peerBytes.containsKey(peer))
|
||||
final Pair<Long, Long> rxTx = peerBytes.get(peer);
|
||||
if (rxTx == null)
|
||||
return 0;
|
||||
return peerBytes.get(peer).first;
|
||||
return rxTx.first;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,9 +70,10 @@ public class Statistics {
|
||||
* @return a long representing the number of bytes transmitted by this peer.
|
||||
*/
|
||||
public long peerTx(final Key peer) {
|
||||
if (!peerBytes.containsKey(peer))
|
||||
final Pair<Long, Long> rxTx = peerBytes.get(peer);
|
||||
if (rxTx == null)
|
||||
return 0;
|
||||
return peerBytes.get(peer).second;
|
||||
return rxTx.second;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,8 @@ import java.util.Set;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* WireGuard backend that uses {@code wg-quick} to implement tunnel configuration.
|
||||
* Implementation of {@link Backend} that uses the kernel module and {@code wg-quick} to provide
|
||||
* WireGuard tunnels.
|
||||
*/
|
||||
|
||||
@NonNullForAll
|
||||
|
||||
@@ -43,8 +43,11 @@ public class RootShell {
|
||||
public RootShell(final Context context) {
|
||||
localBinaryDir = new File(context.getCodeCacheDir(), "bin");
|
||||
localTemporaryDir = new File(context.getCacheDir(), "tmp");
|
||||
preamble = String.format("export CALLING_PACKAGE=%s PATH=\"%s:$PATH\" TMPDIR='%s'; id -u\n",
|
||||
context.getPackageName(), localBinaryDir, localTemporaryDir);
|
||||
final String packageName = context.getPackageName();
|
||||
if (packageName.contains("'"))
|
||||
throw new RuntimeException("Impossibly invalid package name contains a single quote");
|
||||
preamble = String.format("export CALLING_PACKAGE=%s PATH=\"%s:$PATH\" TMPDIR='%s'; magisk --sqlite \"UPDATE policies SET notification=0, logging=0 WHERE package_name='%s'\" >/dev/null 2>&1; id -u\n",
|
||||
packageName, localBinaryDir, localTemporaryDir, packageName);
|
||||
}
|
||||
|
||||
private static boolean isExecutableInPath(final String name) {
|
||||
|
||||
@@ -143,7 +143,7 @@ public final class ToolsInstaller {
|
||||
extract();
|
||||
final StringBuilder script = new StringBuilder("set -ex; ");
|
||||
|
||||
script.append("trap 'rm -rf /data/adb/moduleswireguard' INT TERM EXIT; ");
|
||||
script.append("trap 'rm -rf /data/adb/modules/wireguard' INT TERM EXIT; ");
|
||||
script.append(String.format("rm -rf /data/adb/modules/wireguard/; mkdir -p /data/adb/modules/wireguard%s; ", INSTALL_DIR));
|
||||
script.append("printf 'name=WireGuard Command Line Tools\nversion=1.0\nversionCode=1\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /data/adb/modules/wireguard/module.prop; ");
|
||||
script.append("touch /data/adb/modules/wireguard/auto_mount; ");
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.Arrays;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Implementation of the Curve25519 elliptic curve algorithm.
|
||||
* Implementation of Curve25519 ECDH.
|
||||
* <p>
|
||||
* This implementation was imported to WireGuard from noise-java:
|
||||
* https://github.com/rweather/noise-java
|
||||
|
||||
@@ -13,7 +13,9 @@ import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This implementation is based on the ed25519/ref10 implementation in NaCl.
|
||||
* Implementation of Ed25519 signature verification.
|
||||
*
|
||||
* <p>This implementation is based on the ed25519/ref10 implementation in NaCl.</p>
|
||||
*
|
||||
* <p>It implements this twisted Edwards curve:
|
||||
*
|
||||
|
||||
@@ -20,11 +20,11 @@ export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
|
||||
export GOOS := android
|
||||
export CGO_ENABLED := 1
|
||||
|
||||
GO_VERSION := 1.15.2
|
||||
GO_VERSION := 1.15.6
|
||||
GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m))
|
||||
GO_TARBALL := go$(GO_VERSION).$(GO_PLATFORM).tar.gz
|
||||
GO_HASH_darwin-amd64 := 9bd39600d9fa1fa4a5ccce8761d249f7421cffe671376f791293c4138f3d7c62
|
||||
GO_HASH_linux-amd64 := b49fda1ca29a1946d6bb2a5a6982cf07ccd2aba849289508ee0f9918f6bb4552
|
||||
GO_HASH_darwin-amd64 := 940a73b45993a3bae5792cf324140dded34af97c548af4864d22fd6d49f3bd9f
|
||||
GO_HASH_linux-amd64 := 3918e6cc85e7eaaa6f859f1bdbaac772e7a825b0eb423c63d3ae68b21f84b844
|
||||
|
||||
default: $(DESTDIR)/libwg-go.so
|
||||
|
||||
|
||||
@@ -10,15 +10,12 @@ package main
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"log"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
@@ -29,13 +26,21 @@ import (
|
||||
)
|
||||
|
||||
type AndroidLogger struct {
|
||||
level C.int
|
||||
interfaceName string
|
||||
level C.int
|
||||
tag *C.char
|
||||
}
|
||||
|
||||
func (l AndroidLogger) Write(p []byte) (int, error) {
|
||||
C.__android_log_write(l.level, C.CString("WireGuard/GoBackend/"+l.interfaceName), C.CString(string(p)))
|
||||
return len(p), nil
|
||||
func cstring(s string) *C.char {
|
||||
b, err := unix.BytePtrFromString(s)
|
||||
if err != nil {
|
||||
b := [1]C.char{}
|
||||
return &b[0]
|
||||
}
|
||||
return (*C.char)(unsafe.Pointer(b))
|
||||
}
|
||||
|
||||
func (l AndroidLogger) Printf(format string, args ...interface{}) {
|
||||
C.__android_log_write(l.level, l.tag, cstring(fmt.Sprintf(format, args...)))
|
||||
}
|
||||
|
||||
type TunnelHandle struct {
|
||||
@@ -46,7 +51,6 @@ type TunnelHandle struct {
|
||||
var tunnelHandles map[int32]TunnelHandle
|
||||
|
||||
func init() {
|
||||
device.RoamingDisabled = true
|
||||
tunnelHandles = make(map[int32]TunnelHandle)
|
||||
signals := make(chan os.Signal)
|
||||
signal.Notify(signals, unix.SIGUSR2)
|
||||
@@ -56,52 +60,52 @@ func init() {
|
||||
select {
|
||||
case <-signals:
|
||||
n := runtime.Stack(buf, true)
|
||||
if n == len(buf) {
|
||||
n--
|
||||
}
|
||||
buf[n] = 0
|
||||
C.__android_log_write(C.ANDROID_LOG_ERROR, C.CString("WireGuard/GoBackend/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0])))
|
||||
C.__android_log_write(C.ANDROID_LOG_ERROR, cstring("WireGuard/GoBackend/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0])))
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//export wgTurnOn
|
||||
func wgTurnOn(ifnameRef string, tunFd int32, settings string) int32 {
|
||||
interfaceName := string([]byte(ifnameRef))
|
||||
|
||||
func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 {
|
||||
tag := cstring("WireGuard/GoBackend/" + interfaceName)
|
||||
logger := &device.Logger{
|
||||
Debug: log.New(&AndroidLogger{level: C.ANDROID_LOG_DEBUG, interfaceName: interfaceName}, "", 0),
|
||||
Info: log.New(&AndroidLogger{level: C.ANDROID_LOG_INFO, interfaceName: interfaceName}, "", 0),
|
||||
Error: log.New(&AndroidLogger{level: C.ANDROID_LOG_ERROR, interfaceName: interfaceName}, "", 0),
|
||||
Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf,
|
||||
Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf,
|
||||
}
|
||||
|
||||
logger.Debug.Println("Debug log enabled")
|
||||
|
||||
tun, name, err := tun.CreateUnmonitoredTUNFromFD(int(tunFd))
|
||||
if err != nil {
|
||||
unix.Close(int(tunFd))
|
||||
logger.Error.Println(err)
|
||||
logger.Errorf("CreateUnmonitoredTUNFromFD: %v", err)
|
||||
return -1
|
||||
}
|
||||
|
||||
logger.Info.Println("Attaching to interface", name)
|
||||
logger.Verbosef("Attaching to interface %v", name)
|
||||
device := device.NewDevice(tun, logger)
|
||||
|
||||
setError := device.IpcSetOperation(bufio.NewReader(strings.NewReader(settings)))
|
||||
if setError != nil {
|
||||
err = device.IpcSet(settings)
|
||||
if err != nil {
|
||||
unix.Close(int(tunFd))
|
||||
logger.Error.Println(setError)
|
||||
logger.Errorf("IpcSet: %v", err)
|
||||
return -1
|
||||
}
|
||||
device.DisableSomeRoamingForBrokenMobileSemantics()
|
||||
|
||||
var uapi net.Listener
|
||||
|
||||
uapiFile, err := ipc.UAPIOpen(name)
|
||||
if err != nil {
|
||||
logger.Error.Println(err)
|
||||
logger.Errorf("UAPIOpen: %v", err)
|
||||
} else {
|
||||
uapi, err = ipc.UAPIListen(name, uapiFile)
|
||||
if err != nil {
|
||||
uapiFile.Close()
|
||||
logger.Error.Println(err)
|
||||
logger.Errorf("UAPIListen: %v", err)
|
||||
} else {
|
||||
go func() {
|
||||
for {
|
||||
@@ -115,8 +119,14 @@ func wgTurnOn(ifnameRef string, tunFd int32, settings string) int32 {
|
||||
}
|
||||
}
|
||||
|
||||
device.Up()
|
||||
logger.Info.Println("Device started")
|
||||
err = device.Up()
|
||||
if err != nil {
|
||||
logger.Errorf("Unable to bring up device: %v", err)
|
||||
uapiFile.Close()
|
||||
device.Close()
|
||||
return -1
|
||||
}
|
||||
logger.Verbosef("Device started")
|
||||
|
||||
var i int32
|
||||
for i = 0; i < math.MaxInt32; i++ {
|
||||
@@ -125,7 +135,9 @@ func wgTurnOn(ifnameRef string, tunFd int32, settings string) int32 {
|
||||
}
|
||||
}
|
||||
if i == math.MaxInt32 {
|
||||
unix.Close(int(tunFd))
|
||||
logger.Errorf("Unable to find empty handle")
|
||||
uapiFile.Close()
|
||||
device.Close()
|
||||
return -1
|
||||
}
|
||||
tunnelHandles[i] = TunnelHandle{device: device, uapi: uapi}
|
||||
@@ -185,14 +197,11 @@ func wgGetConfig(tunnelHandle int32) *C.char {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
settings := new(bytes.Buffer)
|
||||
writer := bufio.NewWriter(settings)
|
||||
err := handle.device.IpcGetOperation(writer)
|
||||
settings, err := handle.device.IpcGet()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
writer.Flush()
|
||||
return C.CString(settings.String())
|
||||
return C.CString(settings)
|
||||
}
|
||||
|
||||
//export wgVersion
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
module golang.zx2c4.com/wireguard/android
|
||||
|
||||
go 1.14
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 // indirect
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980
|
||||
golang.zx2c4.com/wireguard v0.0.20200321-0.20200622004228-b84f1d4db25e
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210211144856-ef8115f63b22
|
||||
)
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 h1:/dSxr6gT0FNI1MO5WLJo8mTmItROeOKTkDn+7OwWBos=
|
||||
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.zx2c4.com/wireguard v0.0.20200321-0.20200622004228-b84f1d4db25e h1:f8BS3yEMeIGx/zzJfihxDRedx6lT7EiJlfih4j6LY98=
|
||||
golang.zx2c4.com/wireguard v0.0.20200321-0.20200622004228-b84f1d4db25e/go.mod h1:GJvYs5O24/ASlwPiRklVnjMx2xQzrOic0DuU6GvYJL4=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210211144856-ef8115f63b22 h1:7Ct1Jps4o4u2hBFWrg8Rt65VmXfMPTeR0OSXxdq8gMk=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210211144856-ef8115f63b22/go.mod h1:r0ExowOoGFfDoLDxx+M9SYbNVsoZ0xviLL+K4f2mt+A=
|
||||
|
||||
Submodule tunnel/tools/wireguard-tools updated: 265e81a344...e8fa0f662f
+1
-1
@@ -69,7 +69,7 @@ dependencies {
|
||||
implementation "androidx.preference:preference-ktx:$preferenceVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleRuntimeKtxVersion"
|
||||
implementation "androidx.datastore:datastore-preferences:$datastoreVersion"
|
||||
implementation "com.github.material-components:material-components-android:$materialComponentsVersion"
|
||||
implementation "com.google.android.material:material:$materialComponentsVersion"
|
||||
implementation "com.journeyapps:zxing-android-embedded:$zxingEmbeddedVersion"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
@@ -56,6 +55,15 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activity.TvMainActivity"
|
||||
android:theme="@style/TvTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activity.SettingsActivity"
|
||||
android:label="@string/settings"
|
||||
|
||||
@@ -19,6 +19,7 @@ import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@@ -146,12 +147,14 @@ class LogViewerActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private val downloadsFileSaver = DownloadsFileSaver(this)
|
||||
|
||||
private suspend fun saveLog() {
|
||||
var exception: Throwable? = null
|
||||
var outputFile: DownloadsFileSaver.DownloadsFile? = null
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
outputFile = DownloadsFileSaver.save(this@LogViewerActivity, "wireguard-log.txt", "text/plain", true)
|
||||
outputFile = downloadsFileSaver.save("wireguard-log.txt", "text/plain", true)
|
||||
outputFile?.outputStream?.write(rawLogLines.toString().toByteArray(Charsets.UTF_8))
|
||||
} catch (e: Throwable) {
|
||||
outputFile?.delete()
|
||||
@@ -177,7 +180,7 @@ class LogViewerActivity : AppCompatActivity() {
|
||||
process = try {
|
||||
builder.start()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
return@withContext
|
||||
}
|
||||
val stdout = BufferedReader(InputStreamReader(process!!.inputStream, StandardCharsets.UTF_8))
|
||||
@@ -251,6 +254,7 @@ class LogViewerActivity : AppCompatActivity() {
|
||||
*/
|
||||
private val THREADTIME_LINE: Pattern = Pattern.compile("^(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3})(?:\\s+[0-9A-Za-z]+)?\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s+(.+?)\\s*: (.*)$")
|
||||
private val LOGS: MutableMap<String, ByteArray> = ConcurrentHashMap()
|
||||
private const val TAG = "WireGuard/LogViewerActivity"
|
||||
}
|
||||
|
||||
private inner class LogEntryAdapter : RecyclerView.Adapter<LogEntryAdapter.ViewHolder>() {
|
||||
|
||||
@@ -12,6 +12,7 @@ import android.view.View
|
||||
import androidx.appcompat.app.ActionBar
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.fragment.app.commit
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.fragment.TunnelDetailFragment
|
||||
import com.wireguard.android.fragment.TunnelEditorFragment
|
||||
@@ -72,11 +73,11 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
||||
true
|
||||
}
|
||||
R.id.menu_action_edit -> {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.detail_container, TunnelEditorFragment())
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
supportFragmentManager.commit {
|
||||
replace(R.id.detail_container, TunnelEditorFragment())
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
addToBackStack(null)
|
||||
}
|
||||
true
|
||||
}
|
||||
// This menu item is handled by the editor fragment.
|
||||
@@ -104,11 +105,11 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
||||
fragmentManager.popBackStackImmediate()
|
||||
} else if (backStackEntries == 0) {
|
||||
// Create and show a new detail fragment.
|
||||
fragmentManager.beginTransaction()
|
||||
.add(R.id.detail_container, TunnelDetailFragment())
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
.addToBackStack(null)
|
||||
.commit()
|
||||
fragmentManager.commit {
|
||||
add(R.id.detail_container, TunnelDetailFragment())
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
addToBackStack(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.fragment.app.commit
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
@@ -28,9 +29,9 @@ class SettingsActivity : ThemeChangeAwareActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (supportFragmentManager.findFragmentById(android.R.id.content) == null) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(android.R.id.content, SettingsFragment())
|
||||
.commit()
|
||||
supportFragmentManager.commit {
|
||||
add(android.R.id.content, SettingsFragment())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package com.wireguard.android.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.commit
|
||||
import com.wireguard.android.fragment.TunnelEditorFragment
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
|
||||
@@ -15,9 +16,9 @@ class TunnelCreatorActivity : BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (supportFragmentManager.findFragmentById(android.R.id.content) == null) {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(android.R.id.content, TunnelEditorFragment())
|
||||
.commit()
|
||||
supportFragmentManager.commit {
|
||||
add(android.R.id.content, TunnelEditorFragment())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,20 +10,23 @@ import android.os.Bundle
|
||||
import android.service.quicksettings.TileService
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.QuickTileService
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.backend.GoBackend
|
||||
import com.wireguard.android.backend.Tunnel
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
class TunnelToggleActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
private val permissionActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() }
|
||||
|
||||
private fun toggleTunnelWithPermissionsResult() {
|
||||
val tunnel = Application.getTunnelManager().lastUsedTunnel ?: return
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
@@ -42,6 +45,20 @@ class TunnelToggleActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
lifecycleScope.launch {
|
||||
if (Application.getBackend() is GoBackend) {
|
||||
val intent = GoBackend.VpnService.prepare(this@TunnelToggleActivity)
|
||||
if (intent != null) {
|
||||
permissionActivityResultLauncher.launch(intent)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
toggleTunnelWithPermissionsResult()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "WireGuard/TunnelToggleActivity"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.android.activity
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.storage.StorageManager
|
||||
import android.os.storage.StorageVolume
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.forEach
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import androidx.databinding.ObservableField
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.backend.GoBackend
|
||||
import com.wireguard.android.backend.Tunnel
|
||||
import com.wireguard.android.databinding.Keyed
|
||||
import com.wireguard.android.databinding.ObservableKeyedArrayList
|
||||
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter
|
||||
import com.wireguard.android.databinding.TvActivityBinding
|
||||
import com.wireguard.android.databinding.TvFileListItemBinding
|
||||
import com.wireguard.android.databinding.TvTunnelListItemBinding
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import com.wireguard.android.util.QuantityFormatter
|
||||
import com.wireguard.android.util.TunnelImporter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
class TvMainActivity : AppCompatActivity() {
|
||||
private val tunnelFileImportResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { data ->
|
||||
if (data == null) return@registerForActivityResult
|
||||
lifecycleScope.launch {
|
||||
TunnelImporter.importTunnel(contentResolver, data) {
|
||||
Toast.makeText(this@TvMainActivity, it, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
private var pendingTunnel: ObservableTunnel? = null
|
||||
private val permissionActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val tunnel = pendingTunnel
|
||||
if (tunnel != null)
|
||||
setTunnelStateWithPermissionsResult(tunnel)
|
||||
pendingTunnel = null
|
||||
}
|
||||
|
||||
private fun setTunnelStateWithPermissionsResult(tunnel: ObservableTunnel) {
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
tunnel.setStateAsync(Tunnel.State.TOGGLE)
|
||||
} catch (e: Throwable) {
|
||||
val error = ErrorMessages[e]
|
||||
val message = getString(R.string.error_up, error)
|
||||
Toast.makeText(this@TvMainActivity, message, Toast.LENGTH_LONG).show()
|
||||
Log.e(TAG, message, e)
|
||||
}
|
||||
updateStats()
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var binding: TvActivityBinding
|
||||
private val isDeleting = ObservableBoolean()
|
||||
private val files = ObservableKeyedArrayList<String, KeyedFile>()
|
||||
private val filesRoot = ObservableField("")
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = TvActivityBinding.inflate(layoutInflater)
|
||||
lifecycleScope.launch {
|
||||
binding.tunnels = Application.getTunnelManager().getTunnels()
|
||||
if (binding.tunnels?.isEmpty() == true)
|
||||
binding.importButton.requestFocus()
|
||||
else
|
||||
binding.tunnelList.requestFocus()
|
||||
}
|
||||
binding.isDeleting = isDeleting
|
||||
binding.files = files
|
||||
binding.filesRoot = filesRoot
|
||||
val gridManager = binding.tunnelList.layoutManager as GridLayoutManager
|
||||
gridManager.spanSizeLookup = SlatedSpanSizeLookup(gridManager)
|
||||
binding.tunnelRowConfigurationHandler = object : ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TvTunnelListItemBinding, ObservableTunnel> {
|
||||
override fun onConfigureRow(binding: TvTunnelListItemBinding, item: ObservableTunnel, position: Int) {
|
||||
binding.isDeleting = isDeleting
|
||||
binding.isFocused = ObservableBoolean()
|
||||
binding.root.setOnFocusChangeListener { _, focused ->
|
||||
binding.isFocused?.set(focused)
|
||||
}
|
||||
binding.root.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
if (isDeleting.get()) {
|
||||
try {
|
||||
item.deleteAsync()
|
||||
if (this@TvMainActivity.binding.tunnels?.isEmpty() != false)
|
||||
isDeleting.set(false)
|
||||
} catch (e: Throwable) {
|
||||
val error = ErrorMessages[e]
|
||||
val message = getString(R.string.config_delete_error, error)
|
||||
Toast.makeText(this@TvMainActivity, message, Toast.LENGTH_LONG).show()
|
||||
Log.e(TAG, message, e)
|
||||
}
|
||||
} else {
|
||||
if (Application.getBackend() is GoBackend) {
|
||||
val intent = GoBackend.VpnService.prepare(binding.root.context)
|
||||
if (intent != null) {
|
||||
pendingTunnel = item
|
||||
permissionActivityResultLauncher.launch(intent)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
setTunnelStateWithPermissionsResult(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.filesRowConfigurationHandler = object : ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TvFileListItemBinding, KeyedFile> {
|
||||
override fun onConfigureRow(binding: TvFileListItemBinding, item: KeyedFile, position: Int) {
|
||||
binding.root.setOnClickListener {
|
||||
if (item.file.isDirectory)
|
||||
navigateTo(item.file)
|
||||
else {
|
||||
val uri = Uri.fromFile(item.file)
|
||||
files.clear()
|
||||
filesRoot.set("")
|
||||
lifecycleScope.launch {
|
||||
TunnelImporter.importTunnel(contentResolver, uri) {
|
||||
Toast.makeText(this@TvMainActivity, it, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
runOnUiThread {
|
||||
this@TvMainActivity.binding.tunnelList.requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.importButton.setOnClickListener {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
if (filesRoot.get()?.isEmpty() != false) {
|
||||
navigateTo(File("/"))
|
||||
runOnUiThread {
|
||||
binding.filesList.requestFocus()
|
||||
}
|
||||
} else {
|
||||
files.clear()
|
||||
filesRoot.set("")
|
||||
runOnUiThread {
|
||||
binding.tunnelList.requestFocus()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
tunnelFileImportResultLauncher.launch("*/*")
|
||||
} catch (_: Throwable) {
|
||||
Toast.makeText(this@TvMainActivity, getString(R.string.tv_no_file_picker), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.deleteButton.setOnClickListener {
|
||||
isDeleting.set(!isDeleting.get())
|
||||
runOnUiThread {
|
||||
binding.tunnelList.requestFocus()
|
||||
}
|
||||
}
|
||||
binding.executePendingBindings()
|
||||
setContentView(binding.root)
|
||||
|
||||
lifecycleScope.launch {
|
||||
while (true) {
|
||||
updateStats()
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var pendingNavigation: File? = null
|
||||
private val permissionRequestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||
val to = pendingNavigation
|
||||
if (it && to != null)
|
||||
navigateTo(to)
|
||||
pendingNavigation = null
|
||||
}
|
||||
|
||||
private var cachedRoots: Collection<KeyedFile>? = null
|
||||
|
||||
private suspend fun makeStorageRoots(): Collection<KeyedFile> = withContext(Dispatchers.IO) {
|
||||
cachedRoots?.let { return@withContext it }
|
||||
val list = HashSet<KeyedFile>()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val storageManager: StorageManager = getSystemService() ?: return@withContext list
|
||||
list.addAll(storageManager.storageVolumes.mapNotNull { volume ->
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
volume.directory?.let { KeyedFile(it, volume.getDescription(this@TvMainActivity)) }
|
||||
} else {
|
||||
KeyedFile((StorageVolume::class.java.getMethod("getPathFile").invoke(volume) as File), volume.getDescription(this@TvMainActivity))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
list.add(KeyedFile(Environment.getExternalStorageDirectory()))
|
||||
try {
|
||||
File("/storage").listFiles()?.forEach {
|
||||
if (!it.isDirectory) return@forEach
|
||||
try {
|
||||
if (Environment.isExternalStorageRemovable(it)) {
|
||||
list.add(KeyedFile(it))
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
}
|
||||
cachedRoots = list
|
||||
list
|
||||
}
|
||||
|
||||
private fun isBelowCachedRoots(maybeChild: File): Boolean {
|
||||
val cachedRoots = cachedRoots ?: return true
|
||||
for (root in cachedRoots) {
|
||||
if (maybeChild.canonicalPath.startsWith(root.file.canonicalPath))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun navigateTo(directory: File) {
|
||||
require(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
pendingNavigation = directory
|
||||
permissionRequestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
return
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
if (isBelowCachedRoots(directory)) {
|
||||
val roots = makeStorageRoots()
|
||||
if (roots.count() == 1) {
|
||||
navigateTo(roots.first().file)
|
||||
return@launch
|
||||
}
|
||||
files.clear()
|
||||
files.addAll(roots)
|
||||
filesRoot.set(getString(R.string.tv_select_a_storage_drive))
|
||||
return@launch
|
||||
}
|
||||
|
||||
val newFiles = withContext(Dispatchers.IO) {
|
||||
val newFiles = ArrayList<KeyedFile>()
|
||||
try {
|
||||
directory.parentFile?.let {
|
||||
newFiles.add(KeyedFile(it, "../"))
|
||||
}
|
||||
val listing = directory.listFiles() ?: return@withContext null
|
||||
listing.forEach {
|
||||
if (it.extension == "conf" || it.extension == "zip" || it.isDirectory)
|
||||
newFiles.add(KeyedFile(it))
|
||||
}
|
||||
newFiles.sortWith { a, b ->
|
||||
if (a.file.isDirectory && !b.file.isDirectory) -1
|
||||
else if (!a.file.isDirectory && b.file.isDirectory) 1
|
||||
else a.file.compareTo(b.file)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
newFiles
|
||||
}
|
||||
if (newFiles?.isEmpty() != false)
|
||||
return@launch
|
||||
files.clear()
|
||||
files.addAll(newFiles)
|
||||
filesRoot.set(directory.canonicalPath)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
when {
|
||||
isDeleting.get() -> {
|
||||
isDeleting.set(false)
|
||||
runOnUiThread {
|
||||
binding.tunnelList.requestFocus()
|
||||
}
|
||||
}
|
||||
filesRoot.get()?.isNotEmpty() == true -> {
|
||||
files.clear()
|
||||
filesRoot.set("")
|
||||
runOnUiThread {
|
||||
binding.tunnelList.requestFocus()
|
||||
}
|
||||
}
|
||||
else -> super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateStats() {
|
||||
binding.tunnelList.forEach { viewItem ->
|
||||
val listItem = DataBindingUtil.findBinding<TvTunnelListItemBinding>(viewItem)
|
||||
?: return@forEach
|
||||
try {
|
||||
val tunnel = listItem.item!!
|
||||
if (tunnel.state != Tunnel.State.UP || isDeleting.get()) {
|
||||
throw Exception()
|
||||
}
|
||||
val statistics = tunnel.getStatisticsAsync()
|
||||
val rx = statistics.totalRx()
|
||||
val tx = statistics.totalTx()
|
||||
listItem.tunnelTransfer.text = getString(R.string.transfer_rx_tx, QuantityFormatter.formatBytes(rx), QuantityFormatter.formatBytes(tx))
|
||||
listItem.tunnelTransfer.visibility = View.VISIBLE
|
||||
} catch (_: Throwable) {
|
||||
listItem.tunnelTransfer.visibility = View.GONE
|
||||
listItem.tunnelTransfer.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KeyedFile(val file: File, private val forcedKey: String? = null) : Keyed<String> {
|
||||
override val key: String
|
||||
get() = forcedKey ?: if (file.isDirectory) "${file.name}/" else file.name
|
||||
}
|
||||
|
||||
private class SlatedSpanSizeLookup(private val gridManager: GridLayoutManager) : SpanSizeLookup() {
|
||||
private val originalHeight = gridManager.spanCount
|
||||
private var newWidth = 0
|
||||
private lateinit var sizeMap: Array<IntArray?>
|
||||
|
||||
private fun emptyUnderIndex(index: Int, size: Int): Int {
|
||||
sizeMap[size - 1]?.let { return it[index] }
|
||||
val sizes = IntArray(size)
|
||||
val oh = originalHeight
|
||||
val nw = newWidth
|
||||
var empties = 0
|
||||
for (i in 0 until size) {
|
||||
val ox = (i + empties) / oh
|
||||
val oy = (i + empties) % oh
|
||||
var empty = 0
|
||||
for (j in oy + 1 until oh) {
|
||||
val ni = nw * j + ox
|
||||
if (ni < size)
|
||||
break
|
||||
empty++
|
||||
}
|
||||
empties += empty
|
||||
sizes[i] = empty
|
||||
}
|
||||
sizeMap[size - 1] = sizes
|
||||
return sizes[index]
|
||||
}
|
||||
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
if (newWidth == 0) {
|
||||
val child = gridManager.getChildAt(0) ?: return 1
|
||||
if (child.width == 0) return 1
|
||||
newWidth = gridManager.width / child.width
|
||||
sizeMap = Array(originalHeight * newWidth - 1) { null }
|
||||
}
|
||||
val total = gridManager.itemCount
|
||||
if (total >= originalHeight * newWidth || total == 0)
|
||||
return 1
|
||||
return emptyUnderIndex(position, total) + 1
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "WireGuard/TvMainActivity"
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class AddTunnelsSheet : BottomSheetDialogFragment() {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
if (savedInstanceState != null) dismiss()
|
||||
val view = inflater.inflate(R.layout.add_tunnels_bottom_sheet, container, false)
|
||||
if (activity?.packageManager?.hasSystemFeature(PackageManager.FEATURE_CAMERA) != true) {
|
||||
if (activity?.packageManager?.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) != true) {
|
||||
val qrcode = view.findViewById<View>(R.id.create_from_qrcode)
|
||||
qrcode.isEnabled = false
|
||||
qrcode.visibility = View.GONE
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*/
|
||||
package com.wireguard.android.fragment
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
@@ -40,12 +40,11 @@ class AppListDialogFragment : DialogFragment() {
|
||||
try {
|
||||
val applicationData: MutableList<ApplicationData> = ArrayList()
|
||||
withContext(Dispatchers.IO) {
|
||||
val launcherIntent = Intent(Intent.ACTION_MAIN, null)
|
||||
launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
val resolveInfos = pm.queryIntentActivities(launcherIntent, 0)
|
||||
resolveInfos.forEach {
|
||||
val packageName = it.activityInfo.packageName
|
||||
val appData = ApplicationData(it.loadIcon(pm), it.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
|
||||
val packageInfos = pm.getPackagesHoldingPermissions(arrayOf(Manifest.permission.INTERNET), 0)
|
||||
packageInfos.forEach {
|
||||
val packageName = it.packageName
|
||||
val appInfo = it.applicationInfo
|
||||
val appData = ApplicationData(appInfo.loadIcon(pm), appInfo.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
|
||||
applicationData.add(appData)
|
||||
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
|
||||
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import kotlinx.coroutines.launch
|
||||
* attached to a `BaseActivity`.
|
||||
*/
|
||||
abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener {
|
||||
private var baseActivity: BaseActivity? = null
|
||||
private var pendingTunnel: ObservableTunnel? = null
|
||||
private var pendingTunnelUp: Boolean? = null
|
||||
private val permissionActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
@@ -44,24 +43,18 @@ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener {
|
||||
}
|
||||
|
||||
protected var selectedTunnel: ObservableTunnel?
|
||||
get() = baseActivity?.selectedTunnel
|
||||
get() = (activity as? BaseActivity)?.selectedTunnel
|
||||
protected set(tunnel) {
|
||||
baseActivity?.selectedTunnel = tunnel
|
||||
(activity as? BaseActivity)?.selectedTunnel = tunnel
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
if (context is BaseActivity) {
|
||||
baseActivity = context
|
||||
baseActivity?.addOnSelectedTunnelChangedListener(this)
|
||||
} else {
|
||||
baseActivity = null
|
||||
}
|
||||
(activity as? BaseActivity)?.addOnSelectedTunnelChangedListener(this)
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
baseActivity?.removeOnSelectedTunnelChangedListener(this)
|
||||
baseActivity = null
|
||||
(activity as? BaseActivity)?.removeOnSelectedTunnelChangedListener(this)
|
||||
super.onDetach()
|
||||
}
|
||||
|
||||
@@ -71,9 +64,10 @@ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener {
|
||||
is TunnelListItemBinding -> binding.item
|
||||
else -> return
|
||||
} ?: return
|
||||
lifecycleScope.launch {
|
||||
val activity = activity ?: return
|
||||
activity.lifecycleScope.launch {
|
||||
if (Application.getBackend() is GoBackend) {
|
||||
val intent = GoBackend.VpnService.prepare(view.context)
|
||||
val intent = GoBackend.VpnService.prepare(activity)
|
||||
if (intent != null) {
|
||||
pendingTunnel = tunnel
|
||||
pendingTunnelUp = checked
|
||||
@@ -86,20 +80,21 @@ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener {
|
||||
}
|
||||
|
||||
private fun setTunnelStateWithPermissionsResult(tunnel: ObservableTunnel, checked: Boolean) {
|
||||
lifecycleScope.launch {
|
||||
val activity = activity ?: return
|
||||
activity.lifecycleScope.launch {
|
||||
try {
|
||||
tunnel.setStateAsync(Tunnel.State.of(checked))
|
||||
} catch (e: Throwable) {
|
||||
val error = ErrorMessages[e]
|
||||
val messageResId = if (checked) R.string.error_up else R.string.error_down
|
||||
val message = requireContext().getString(messageResId, error)
|
||||
val message = activity.getString(messageResId, error)
|
||||
val view = view
|
||||
if (view != null)
|
||||
Snackbar.make(view, message, Snackbar.LENGTH_LONG)
|
||||
.setAnchorView(view.findViewById(R.id.create_fab))
|
||||
.show()
|
||||
else
|
||||
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(activity, message, Toast.LENGTH_LONG).show()
|
||||
Log.e(TAG, message, e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ class ConfigNamingDialogFragment : DialogFragment() {
|
||||
private var imm: InputMethodManager? = null
|
||||
|
||||
private fun createTunnelAndDismiss() {
|
||||
binding?.let {
|
||||
val name = it.tunnelNameText.text.toString()
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
Application.getTunnelManager().create(name, config)
|
||||
dismiss()
|
||||
} catch (e: Throwable) {
|
||||
it.tunnelNameTextLayout.error = e.message
|
||||
}
|
||||
val binding = binding ?: return
|
||||
val activity = activity ?: return
|
||||
val name = binding.tunnelNameText.text.toString()
|
||||
activity.lifecycleScope.launch {
|
||||
try {
|
||||
Application.getTunnelManager().create(name, config)
|
||||
dismiss()
|
||||
} catch (e: Throwable) {
|
||||
binding.tunnelNameTextLayout.error = e.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ import com.wireguard.android.backend.Tunnel
|
||||
import com.wireguard.android.databinding.TunnelDetailFragmentBinding
|
||||
import com.wireguard.android.databinding.TunnelDetailPeerBinding
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
import com.wireguard.android.util.QuantityFormatter
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Timer
|
||||
import java.util.TimerTask
|
||||
|
||||
/**
|
||||
* Fragment that shows details about a specific tunnel.
|
||||
@@ -27,18 +27,7 @@ import java.util.TimerTask
|
||||
class TunnelDetailFragment : BaseFragment() {
|
||||
private var binding: TunnelDetailFragmentBinding? = null
|
||||
private var lastState = Tunnel.State.TOGGLE
|
||||
private var timer: Timer? = null
|
||||
|
||||
private fun formatBytes(bytes: Long): String {
|
||||
val context = requireContext()
|
||||
return when {
|
||||
bytes < 1024 -> context.getString(R.string.transfer_bytes, bytes)
|
||||
bytes < 1024 * 1024 -> context.getString(R.string.transfer_kibibytes, bytes / 1024.0)
|
||||
bytes < 1024 * 1024 * 1024 -> context.getString(R.string.transfer_mibibytes, bytes / (1024.0 * 1024.0))
|
||||
bytes < 1024 * 1024 * 1024 * 1024L -> context.getString(R.string.transfer_gibibytes, bytes / (1024.0 * 1024.0 * 1024.0))
|
||||
else -> context.getString(R.string.transfer_tibibytes, bytes / (1024.0 * 1024.0 * 1024.0) / 1024.0)
|
||||
}
|
||||
}
|
||||
private var timerActive = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -64,34 +53,36 @@ class TunnelDetailFragment : BaseFragment() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
timer = Timer()
|
||||
timer!!.scheduleAtFixedRate(object : TimerTask() {
|
||||
override fun run() {
|
||||
timerActive = true
|
||||
lifecycleScope.launch {
|
||||
while (timerActive) {
|
||||
updateStats()
|
||||
delay(1000)
|
||||
}
|
||||
}, 0, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?) {
|
||||
binding ?: return
|
||||
binding!!.tunnel = newTunnel
|
||||
if (newTunnel == null) binding!!.config = null else lifecycleScope.launch {
|
||||
try {
|
||||
binding!!.config = newTunnel.getConfigAsync()
|
||||
} catch (_: Throwable) {
|
||||
binding!!.config = null
|
||||
val binding = binding ?: return
|
||||
binding.tunnel = newTunnel
|
||||
if (newTunnel == null) {
|
||||
binding.config = null
|
||||
} else {
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
binding.config = newTunnel.getConfigAsync()
|
||||
} catch (_: Throwable) {
|
||||
binding.config = null
|
||||
}
|
||||
}
|
||||
}
|
||||
lastState = Tunnel.State.TOGGLE
|
||||
updateStats()
|
||||
lifecycleScope.launch { updateStats() }
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
timerActive = false
|
||||
super.onStop()
|
||||
if (timer != null) {
|
||||
timer!!.cancel()
|
||||
timer = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
@@ -101,37 +92,36 @@ class TunnelDetailFragment : BaseFragment() {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun updateStats() {
|
||||
if (binding == null || !isResumed) return
|
||||
val tunnel = binding!!.tunnel ?: return
|
||||
private suspend fun updateStats() {
|
||||
val binding = binding ?: return
|
||||
val tunnel = binding.tunnel ?: return
|
||||
if (!isResumed) return
|
||||
val state = tunnel.state
|
||||
if (state != Tunnel.State.UP && lastState == state) return
|
||||
lastState = state
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val statistics = tunnel.getStatisticsAsync()
|
||||
for (i in 0 until binding!!.peersLayout.childCount) {
|
||||
val peer: TunnelDetailPeerBinding = DataBindingUtil.getBinding(binding!!.peersLayout.getChildAt(i))
|
||||
?: continue
|
||||
val publicKey = peer.item!!.publicKey
|
||||
val rx = statistics.peerRx(publicKey)
|
||||
val tx = statistics.peerTx(publicKey)
|
||||
if (rx == 0L && tx == 0L) {
|
||||
peer.transferLabel.visibility = View.GONE
|
||||
peer.transferText.visibility = View.GONE
|
||||
continue
|
||||
}
|
||||
peer.transferText.text = requireContext().getString(R.string.transfer_rx_tx, formatBytes(rx), formatBytes(tx))
|
||||
peer.transferLabel.visibility = View.VISIBLE
|
||||
peer.transferText.visibility = View.VISIBLE
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
for (i in 0 until binding!!.peersLayout.childCount) {
|
||||
val peer: TunnelDetailPeerBinding = DataBindingUtil.getBinding(binding!!.peersLayout.getChildAt(i))
|
||||
?: continue
|
||||
try {
|
||||
val statistics = tunnel.getStatisticsAsync()
|
||||
for (i in 0 until binding.peersLayout.childCount) {
|
||||
val peer: TunnelDetailPeerBinding = DataBindingUtil.getBinding(binding.peersLayout.getChildAt(i))
|
||||
?: continue
|
||||
val publicKey = peer.item!!.publicKey
|
||||
val rx = statistics.peerRx(publicKey)
|
||||
val tx = statistics.peerTx(publicKey)
|
||||
if (rx == 0L && tx == 0L) {
|
||||
peer.transferLabel.visibility = View.GONE
|
||||
peer.transferText.visibility = View.GONE
|
||||
continue
|
||||
}
|
||||
peer.transferText.text = getString(R.string.transfer_rx_tx, QuantityFormatter.formatBytes(rx), QuantityFormatter.formatBytes(tx))
|
||||
peer.transferLabel.visibility = View.VISIBLE
|
||||
peer.transferText.visibility = View.VISIBLE
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
for (i in 0 until binding.peersLayout.childCount) {
|
||||
val peer: TunnelDetailPeerBinding = DataBindingUtil.getBinding(binding.peersLayout.getChildAt(i))
|
||||
?: continue
|
||||
peer.transferLabel.visibility = View.GONE
|
||||
peer.transferText.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,24 +39,27 @@ class TunnelEditorFragment : BaseFragment() {
|
||||
private var haveShownKeys = false
|
||||
private var binding: TunnelEditorFragmentBinding? = null
|
||||
private var tunnel: ObservableTunnel? = null
|
||||
|
||||
private fun onConfigLoaded(config: Config) {
|
||||
binding?.config = ConfigProxy(config)
|
||||
}
|
||||
|
||||
private fun onConfigSaved(savedTunnel: Tunnel, throwable: Throwable?) {
|
||||
val message: String
|
||||
val ctx = activity ?: Application.get()
|
||||
if (throwable == null) {
|
||||
message = getString(R.string.config_save_success, savedTunnel.name)
|
||||
val message = ctx.getString(R.string.config_save_success, savedTunnel.name)
|
||||
Log.d(TAG, message)
|
||||
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
|
||||
onFinished()
|
||||
} else {
|
||||
val error = ErrorMessages[throwable]
|
||||
message = getString(R.string.config_save_error, savedTunnel.name, error)
|
||||
val message = ctx.getString(R.string.config_save_error, savedTunnel.name, error)
|
||||
Log.e(TAG, message, throwable)
|
||||
binding?.let {
|
||||
Snackbar.make(it.mainContainer, message, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
val binding = binding
|
||||
if (binding != null)
|
||||
Snackbar.make(binding.mainContainer, message, Snackbar.LENGTH_LONG).show()
|
||||
else
|
||||
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +118,8 @@ class TunnelEditorFragment : BaseFragment() {
|
||||
Snackbar.make(binding!!.mainContainer, error, Snackbar.LENGTH_LONG).show()
|
||||
return false
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
val activity = requireActivity()
|
||||
activity.lifecycleScope.launch {
|
||||
when {
|
||||
tunnel == null -> {
|
||||
Log.d(TAG, "Attempting to create new tunnel " + binding!!.name)
|
||||
@@ -209,46 +213,48 @@ class TunnelEditorFragment : BaseFragment() {
|
||||
}
|
||||
|
||||
private fun onTunnelCreated(newTunnel: ObservableTunnel?, throwable: Throwable?) {
|
||||
val message: String
|
||||
val ctx = activity ?: Application.get()
|
||||
if (throwable == null) {
|
||||
tunnel = newTunnel
|
||||
message = getString(R.string.tunnel_create_success, tunnel!!.name)
|
||||
val message = ctx.getString(R.string.tunnel_create_success, tunnel!!.name)
|
||||
Log.d(TAG, message)
|
||||
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
|
||||
onFinished()
|
||||
} else {
|
||||
val error = ErrorMessages[throwable]
|
||||
message = getString(R.string.tunnel_create_error, error)
|
||||
val message = ctx.getString(R.string.tunnel_create_error, error)
|
||||
Log.e(TAG, message, throwable)
|
||||
binding?.let {
|
||||
Snackbar.make(it.mainContainer, message, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
val binding = binding
|
||||
if (binding != null)
|
||||
Snackbar.make(binding.mainContainer, message, Snackbar.LENGTH_LONG).show()
|
||||
else
|
||||
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onTunnelRenamed(renamedTunnel: ObservableTunnel, newConfig: Config,
|
||||
throwable: Throwable?) {
|
||||
val message: String
|
||||
private suspend fun onTunnelRenamed(renamedTunnel: ObservableTunnel, newConfig: Config,
|
||||
throwable: Throwable?) {
|
||||
val ctx = activity ?: Application.get()
|
||||
if (throwable == null) {
|
||||
message = getString(R.string.tunnel_rename_success, renamedTunnel.name)
|
||||
val message = ctx.getString(R.string.tunnel_rename_success, renamedTunnel.name)
|
||||
Log.d(TAG, message)
|
||||
// Now save the rest of configuration changes.
|
||||
Log.d(TAG, "Attempting to save config of renamed tunnel " + tunnel!!.name)
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
renamedTunnel.setConfigAsync(newConfig)
|
||||
onConfigSaved(renamedTunnel, null)
|
||||
} catch (e: Throwable) {
|
||||
onConfigSaved(renamedTunnel, e)
|
||||
}
|
||||
try {
|
||||
renamedTunnel.setConfigAsync(newConfig)
|
||||
onConfigSaved(renamedTunnel, null)
|
||||
} catch (e: Throwable) {
|
||||
onConfigSaved(renamedTunnel, e)
|
||||
}
|
||||
} else {
|
||||
val error = ErrorMessages[throwable]
|
||||
message = getString(R.string.tunnel_rename_error, error)
|
||||
val message = ctx.getString(R.string.tunnel_rename_error, error)
|
||||
Log.e(TAG, message, throwable)
|
||||
binding?.let {
|
||||
Snackbar.make(it.mainContainer, message, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
val binding = binding
|
||||
if (binding != null)
|
||||
Snackbar.make(binding.mainContainer, message, Snackbar.LENGTH_LONG).show()
|
||||
else
|
||||
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ package com.wireguard.android.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
@@ -17,6 +15,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
@@ -29,27 +28,16 @@ import com.wireguard.android.activity.TunnelCreatorActivity
|
||||
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
|
||||
import com.wireguard.android.databinding.TunnelListFragmentBinding
|
||||
import com.wireguard.android.databinding.TunnelListItemBinding
|
||||
import com.wireguard.android.fragment.ConfigNamingDialogFragment.Companion.newInstance
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import com.wireguard.android.util.TunnelImporter
|
||||
import com.wireguard.android.widget.MultiselectableRelativeLayout
|
||||
import com.wireguard.config.Config
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.BufferedReader
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
import java.util.Locale
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
/**
|
||||
* Fragment containing a list of known WireGuard tunnels. It allows creating and deleting tunnels.
|
||||
@@ -59,114 +47,20 @@ class TunnelListFragment : BaseFragment() {
|
||||
private var actionMode: ActionMode? = null
|
||||
private var binding: TunnelListFragmentBinding? = null
|
||||
private val tunnelFileImportResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { data ->
|
||||
importTunnel(data)
|
||||
if (data == null) return@registerForActivityResult
|
||||
val activity = activity ?: return@registerForActivityResult
|
||||
val contentResolver = activity.contentResolver ?: return@registerForActivityResult
|
||||
activity.lifecycleScope.launch {
|
||||
TunnelImporter.importTunnel(contentResolver, data) { showSnackbar(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private val qrImportResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
val qrCode = IntentIntegrator.parseActivityResult(result.resultCode, result.data)
|
||||
qrCode?.contents?.let { importTunnel(it) }
|
||||
}
|
||||
|
||||
private fun importTunnel(configText: String) {
|
||||
try {
|
||||
// Ensure the config text is parseable before proceeding…
|
||||
Config.parse(ByteArrayInputStream(configText.toByteArray(StandardCharsets.UTF_8)))
|
||||
|
||||
// Config text is valid, now create the tunnel…
|
||||
newInstance(configText).show(parentFragmentManager, null)
|
||||
} catch (e: Throwable) {
|
||||
onTunnelImportFinished(emptyList(), listOf<Throwable>(e))
|
||||
}
|
||||
}
|
||||
|
||||
private fun importTunnel(uri: Uri?) {
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val activity = activity
|
||||
if (activity == null || uri == null) {
|
||||
return@withContext
|
||||
}
|
||||
val contentResolver = activity.contentResolver
|
||||
val futureTunnels = ArrayList<Deferred<ObservableTunnel>>()
|
||||
val throwables = ArrayList<Throwable>()
|
||||
try {
|
||||
val columns = arrayOf(OpenableColumns.DISPLAY_NAME)
|
||||
var name = ""
|
||||
contentResolver.query(uri, columns, null, null, null)?.use { cursor ->
|
||||
if (cursor.moveToFirst() && !cursor.isNull(0)) {
|
||||
name = cursor.getString(0)
|
||||
}
|
||||
}
|
||||
if (name.isEmpty()) {
|
||||
name = Uri.decode(uri.lastPathSegment)
|
||||
}
|
||||
var idx = name.lastIndexOf('/')
|
||||
if (idx >= 0) {
|
||||
require(idx < name.length - 1) { resources.getString(R.string.illegal_filename_error, name) }
|
||||
name = name.substring(idx + 1)
|
||||
}
|
||||
val isZip = name.toLowerCase(Locale.ROOT).endsWith(".zip")
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".conf")) {
|
||||
name = name.substring(0, name.length - ".conf".length)
|
||||
} else {
|
||||
require(isZip) { resources.getString(R.string.bad_extension_error) }
|
||||
}
|
||||
|
||||
if (isZip) {
|
||||
ZipInputStream(contentResolver.openInputStream(uri)).use { zip ->
|
||||
val reader = BufferedReader(InputStreamReader(zip, StandardCharsets.UTF_8))
|
||||
var entry: ZipEntry?
|
||||
while (true) {
|
||||
entry = zip.nextEntry ?: break
|
||||
name = entry.name
|
||||
idx = name.lastIndexOf('/')
|
||||
if (idx >= 0) {
|
||||
if (idx >= name.length - 1) {
|
||||
continue
|
||||
}
|
||||
name = name.substring(name.lastIndexOf('/') + 1)
|
||||
}
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".conf")) {
|
||||
name = name.substring(0, name.length - ".conf".length)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
Config.parse(reader)
|
||||
} catch (e: Throwable) {
|
||||
throwables.add(e)
|
||||
null
|
||||
}?.let {
|
||||
val nameCopy = name
|
||||
futureTunnels.add(async(SupervisorJob()) { Application.getTunnelManager().create(nameCopy, it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
futureTunnels.add(async(SupervisorJob()) { Application.getTunnelManager().create(name, Config.parse(contentResolver.openInputStream(uri)!!)) })
|
||||
}
|
||||
|
||||
if (futureTunnels.isEmpty()) {
|
||||
if (throwables.size == 1) {
|
||||
throw throwables[0]
|
||||
} else {
|
||||
require(throwables.isNotEmpty()) { resources.getString(R.string.no_configs_error) }
|
||||
}
|
||||
}
|
||||
val tunnels = futureTunnels.mapNotNull {
|
||||
try {
|
||||
it.await()
|
||||
} catch (e: Throwable) {
|
||||
throwables.add(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main.immediate) { onTunnelImportFinished(tunnels, throwables) }
|
||||
} catch (e: Throwable) {
|
||||
withContext(Dispatchers.Main.immediate) { onTunnelImportFinished(emptyList(), listOf(e)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
val qrCode = IntentIntegrator.parseActivityResult(result.resultCode, result.data)?.contents
|
||||
?: return@registerForActivityResult
|
||||
val activity = activity ?: return@registerForActivityResult
|
||||
val fragManager = parentFragmentManager
|
||||
activity.lifecycleScope.launch { TunnelImporter.importTunnel(fragManager, qrCode) { showSnackbar(it) } }
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -224,43 +118,24 @@ class TunnelListFragment : BaseFragment() {
|
||||
binding ?: return
|
||||
lifecycleScope.launch {
|
||||
val tunnels = Application.getTunnelManager().getTunnels()
|
||||
if (newTunnel != null) viewForTunnel(newTunnel, tunnels).setSingleSelected(true)
|
||||
if (oldTunnel != null) viewForTunnel(oldTunnel, tunnels).setSingleSelected(false)
|
||||
if (newTunnel != null) viewForTunnel(newTunnel, tunnels)?.setSingleSelected(true)
|
||||
if (oldTunnel != null) viewForTunnel(oldTunnel, tunnels)?.setSingleSelected(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onTunnelDeletionFinished(count: Int, throwable: Throwable?) {
|
||||
val message: String
|
||||
val ctx = activity ?: Application.get()
|
||||
if (throwable == null) {
|
||||
message = resources.getQuantityString(R.plurals.delete_success, count, count)
|
||||
message = ctx.resources.getQuantityString(R.plurals.delete_success, count, count)
|
||||
} else {
|
||||
val error = ErrorMessages[throwable]
|
||||
message = resources.getQuantityString(R.plurals.delete_error, count, count, error)
|
||||
message = ctx.resources.getQuantityString(R.plurals.delete_error, count, count, error)
|
||||
Log.e(TAG, message, throwable)
|
||||
}
|
||||
showSnackbar(message)
|
||||
}
|
||||
|
||||
private fun onTunnelImportFinished(tunnels: List<ObservableTunnel>, throwables: Collection<Throwable>) {
|
||||
var message = ""
|
||||
for (throwable in throwables) {
|
||||
val error = ErrorMessages[throwable]
|
||||
message = getString(R.string.import_error, error)
|
||||
Log.e(TAG, message, throwable)
|
||||
}
|
||||
if (tunnels.size == 1 && throwables.isEmpty())
|
||||
message = getString(R.string.import_success, tunnels[0].name)
|
||||
else if (tunnels.isEmpty() && throwables.size == 1)
|
||||
else if (throwables.isEmpty())
|
||||
message = resources.getQuantityString(R.plurals.import_total_success,
|
||||
tunnels.size, tunnels.size)
|
||||
else if (!throwables.isEmpty())
|
||||
message = resources.getQuantityString(R.plurals.import_partial_success,
|
||||
tunnels.size + throwables.size,
|
||||
tunnels.size, tunnels.size + throwables.size)
|
||||
showSnackbar(message)
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
binding ?: return
|
||||
@@ -289,15 +164,17 @@ class TunnelListFragment : BaseFragment() {
|
||||
}
|
||||
|
||||
private fun showSnackbar(message: CharSequence) {
|
||||
binding?.let {
|
||||
Snackbar.make(it.mainContainer, message, Snackbar.LENGTH_LONG)
|
||||
.setAnchorView(it.createFab)
|
||||
val binding = binding
|
||||
if (binding != null)
|
||||
Snackbar.make(binding.mainContainer, message, Snackbar.LENGTH_LONG)
|
||||
.setAnchorView(binding.createFab)
|
||||
.show()
|
||||
}
|
||||
else
|
||||
Toast.makeText(activity ?: Application.get(), message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun viewForTunnel(tunnel: ObservableTunnel, tunnels: List<*>): MultiselectableRelativeLayout {
|
||||
return binding!!.tunnelList.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel))!!.itemView as MultiselectableRelativeLayout
|
||||
private fun viewForTunnel(tunnel: ObservableTunnel, tunnels: List<*>): MultiselectableRelativeLayout? {
|
||||
return binding?.tunnelList?.findViewHolderForAdapterPosition(tunnels.indexOf(tunnel))?.itemView as? MultiselectableRelativeLayout
|
||||
}
|
||||
|
||||
private inner class ActionModeListener : ActionMode.Callback {
|
||||
@@ -311,13 +188,14 @@ class TunnelListFragment : BaseFragment() {
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_action_delete -> {
|
||||
val activity = activity ?: return true
|
||||
val copyCheckedItems = HashSet(checkedItems)
|
||||
binding?.createFab?.apply {
|
||||
visibility = View.VISIBLE
|
||||
scaleX = 1f
|
||||
scaleY = 1f
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
activity.lifecycleScope.launch {
|
||||
try {
|
||||
val tunnels = Application.getTunnelManager().getTunnels()
|
||||
val tunnelsToDelete = ArrayList<ObservableTunnel>()
|
||||
@@ -423,8 +301,6 @@ class TunnelListFragment : BaseFragment() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST_IMPORT = 1
|
||||
private const val REQUEST_TARGET_FRAGMENT = 2
|
||||
private const val CHECKED_ITEMS = "CHECKED_ITEMS"
|
||||
private const val TAG = "WireGuard/TunnelListFragment"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.databinding.BaseObservable
|
||||
import androidx.databinding.Bindable
|
||||
import com.wireguard.android.Application.Companion.get
|
||||
@@ -20,6 +21,7 @@ import com.wireguard.android.backend.Statistics
|
||||
import com.wireguard.android.backend.Tunnel
|
||||
import com.wireguard.android.configStore.ConfigStore
|
||||
import com.wireguard.android.databinding.ObservableSortedKeyedArrayList
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import com.wireguard.android.util.UserKnobs
|
||||
import com.wireguard.android.util.applicationScope
|
||||
import com.wireguard.config.Config
|
||||
@@ -229,7 +231,11 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
|
||||
val tunnelName = intent.getStringExtra("tunnel") ?: return@launch
|
||||
val tunnels = manager.getTunnels()
|
||||
val tunnel = tunnels[tunnelName] ?: return@launch
|
||||
manager.setTunnelState(tunnel, state)
|
||||
try {
|
||||
manager.setTunnelState(tunnel, state)
|
||||
} catch (e: Throwable) {
|
||||
Toast.makeText(context, ErrorMessages[e], Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
@@ -15,6 +16,7 @@ import com.wireguard.android.activity.SettingsActivity
|
||||
import com.wireguard.android.backend.Tunnel
|
||||
import com.wireguard.android.backend.WgQuickBackend
|
||||
import com.wireguard.android.util.UserKnobs
|
||||
import com.wireguard.android.util.activity
|
||||
import com.wireguard.android.util.lifecycleScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@@ -39,7 +41,7 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
|
||||
override fun getTitle() = if (state == State.UNKNOWN) "" else context.getString(state.titleResourceId)
|
||||
|
||||
override fun onClick() {
|
||||
lifecycleScope.launch {
|
||||
activity.lifecycleScope.launch {
|
||||
if (state == State.DISABLED) {
|
||||
setState(State.ENABLING)
|
||||
UserKnobs.setDisableKernelModule(false)
|
||||
|
||||
@@ -32,6 +32,8 @@ import java.util.zip.ZipOutputStream
|
||||
*/
|
||||
class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
|
||||
private var exportedFilePath: String? = null
|
||||
private val downloadsFileSaver = DownloadsFileSaver(activity)
|
||||
|
||||
private fun exportZip() {
|
||||
lifecycleScope.launch {
|
||||
val tunnels = Application.getTunnelManager().getTunnels()
|
||||
@@ -41,7 +43,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
||||
if (configs.isEmpty()) {
|
||||
throw IllegalArgumentException(context.getString(R.string.no_tunnels_error))
|
||||
}
|
||||
val outputFile = DownloadsFileSaver.save(activity, "wireguard-export.zip", "application/zip", true)
|
||||
val outputFile = downloadsFileSaver.save("wireguard-export.zip", "application/zip", true)
|
||||
if (outputFile == null) {
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
isEnabled = true
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.biometric.BiometricConstants
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricManager.Authenticators
|
||||
import androidx.biometric.BiometricPrompt
|
||||
@@ -41,12 +40,12 @@ object BiometricAuthenticator {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
Log.d(TAG, "BiometricAuthentication error: errorCode=$errorCode, msg=$errString")
|
||||
callback(when (errorCode) {
|
||||
BiometricConstants.ERROR_CANCELED, BiometricConstants.ERROR_USER_CANCELED,
|
||||
BiometricConstants.ERROR_NEGATIVE_BUTTON -> {
|
||||
BiometricPrompt.ERROR_CANCELED, BiometricPrompt.ERROR_USER_CANCELED,
|
||||
BiometricPrompt.ERROR_NEGATIVE_BUTTON -> {
|
||||
Result.Cancelled
|
||||
}
|
||||
BiometricConstants.ERROR_HW_NOT_PRESENT, BiometricConstants.ERROR_HW_UNAVAILABLE,
|
||||
BiometricConstants.ERROR_NO_BIOMETRICS, BiometricConstants.ERROR_NO_DEVICE_CREDENTIAL -> {
|
||||
BiometricPrompt.ERROR_HW_NOT_PRESENT, BiometricPrompt.ERROR_HW_UNAVAILABLE,
|
||||
BiometricPrompt.ERROR_NO_BIOMETRICS, BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
|
||||
Result.HardwareUnavailableOrDisabled
|
||||
}
|
||||
else -> Result.Failure(errorCode, fragment.getString(R.string.biometric_auth_error_reason, errString))
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.widget.TextView
|
||||
import androidx.core.content.getSystemService
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.wireguard.android.R
|
||||
|
||||
/**
|
||||
* Standalone utilities for interacting with the system clipboard.
|
||||
@@ -28,6 +29,6 @@ object ClipboardUtils {
|
||||
}
|
||||
val service = view.context.getSystemService<ClipboardManager>() ?: return
|
||||
service.setPrimaryClip(ClipData.newPlainText(data.second, data.first))
|
||||
Snackbar.make(view, "${data.second} copied to clipboard", Snackbar.LENGTH_LONG).show()
|
||||
Snackbar.make(view, view.context.getString(R.string.copied_to_clipboard, data.second), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.MediaColumns
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.wireguard.android.R
|
||||
@@ -25,9 +26,18 @@ import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
object DownloadsFileSaver {
|
||||
@Throws(Exception::class)
|
||||
suspend fun save(context: ComponentActivity, name: String, mimeType: String?, overwriteExisting: Boolean) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
class DownloadsFileSaver(private val context: ComponentActivity) {
|
||||
private lateinit var activityResult: ActivityResultLauncher<String>
|
||||
private lateinit var futureGrant: CompletableDeferred<Boolean>
|
||||
|
||||
init {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
futureGrant = CompletableDeferred()
|
||||
activityResult = context.registerForActivityResult(ActivityResultContracts.RequestPermission()) { ret -> futureGrant.complete(ret) }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun save(name: String, mimeType: String?, overwriteExisting: Boolean) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val contentResolver = context.contentResolver
|
||||
if (overwriteExisting)
|
||||
@@ -66,13 +76,12 @@ object DownloadsFileSaver {
|
||||
} else {
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
val futureGrant = CompletableDeferred<Boolean>()
|
||||
val activityResult = context.registerForActivityResult(ActivityResultContracts.RequestPermission(), futureGrant::complete)
|
||||
activityResult.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
val granted = futureGrant.await()
|
||||
activityResult.unregister()
|
||||
if (!granted)
|
||||
if (!granted) {
|
||||
futureGrant = CompletableDeferred()
|
||||
return@withContext null
|
||||
}
|
||||
}
|
||||
@Suppress("DEPRECATION") val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
withContext(Dispatchers.IO) {
|
||||
|
||||
@@ -6,7 +6,7 @@ package com.wireguard.android.util
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.os.RemoteException
|
||||
import com.wireguard.android.Application.Companion.get
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.backend.BackendException
|
||||
import com.wireguard.android.util.RootShell.RootShellException
|
||||
@@ -63,7 +63,7 @@ object ErrorMessages {
|
||||
)
|
||||
|
||||
operator fun get(throwable: Throwable?): String {
|
||||
val resources = get().resources
|
||||
val resources = Application.get().resources
|
||||
if (throwable == null) return resources.getString(R.string.unknown_error)
|
||||
val rootCause = rootCause(throwable)
|
||||
return when {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.android.util
|
||||
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
|
||||
object QuantityFormatter {
|
||||
fun formatBytes(bytes: Long): String {
|
||||
val context = Application.get().applicationContext
|
||||
return when {
|
||||
bytes < 1024 -> context.getString(R.string.transfer_bytes, bytes)
|
||||
bytes < 1024 * 1024 -> context.getString(R.string.transfer_kibibytes, bytes / 1024.0)
|
||||
bytes < 1024 * 1024 * 1024 -> context.getString(R.string.transfer_mibibytes, bytes / (1024.0 * 1024.0))
|
||||
bytes < 1024 * 1024 * 1024 * 1024L -> context.getString(R.string.transfer_gibibytes, bytes / (1024.0 * 1024.0 * 1024.0))
|
||||
else -> context.getString(R.string.transfer_tibibytes, bytes / (1024.0 * 1024.0 * 1024.0) / 1024.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.android.util
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.fragment.ConfigNamingDialogFragment
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
import com.wireguard.config.Config
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.BufferedReader
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.ArrayList
|
||||
import java.util.Locale
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
object TunnelImporter {
|
||||
suspend fun importTunnel(contentResolver: ContentResolver, uri: Uri, messageCallback: (CharSequence) -> Unit) = withContext(Dispatchers.IO) {
|
||||
val context = Application.get().applicationContext
|
||||
val futureTunnels = ArrayList<Deferred<ObservableTunnel>>()
|
||||
val throwables = ArrayList<Throwable>()
|
||||
try {
|
||||
val columns = arrayOf(OpenableColumns.DISPLAY_NAME)
|
||||
var name = ""
|
||||
contentResolver.query(uri, columns, null, null, null)?.use { cursor ->
|
||||
if (cursor.moveToFirst() && !cursor.isNull(0)) {
|
||||
name = cursor.getString(0)
|
||||
}
|
||||
}
|
||||
if (name.isEmpty()) {
|
||||
name = Uri.decode(uri.lastPathSegment)
|
||||
}
|
||||
var idx = name.lastIndexOf('/')
|
||||
if (idx >= 0) {
|
||||
require(idx < name.length - 1) { context.getString(R.string.illegal_filename_error, name) }
|
||||
name = name.substring(idx + 1)
|
||||
}
|
||||
val isZip = name.toLowerCase(Locale.ROOT).endsWith(".zip")
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".conf")) {
|
||||
name = name.substring(0, name.length - ".conf".length)
|
||||
} else {
|
||||
require(isZip) { context.getString(R.string.bad_extension_error) }
|
||||
}
|
||||
|
||||
if (isZip) {
|
||||
ZipInputStream(contentResolver.openInputStream(uri)).use { zip ->
|
||||
val reader = BufferedReader(InputStreamReader(zip, StandardCharsets.UTF_8))
|
||||
var entry: ZipEntry?
|
||||
while (true) {
|
||||
entry = zip.nextEntry ?: break
|
||||
name = entry.name
|
||||
idx = name.lastIndexOf('/')
|
||||
if (idx >= 0) {
|
||||
if (idx >= name.length - 1) {
|
||||
continue
|
||||
}
|
||||
name = name.substring(name.lastIndexOf('/') + 1)
|
||||
}
|
||||
if (name.toLowerCase(Locale.ROOT).endsWith(".conf")) {
|
||||
name = name.substring(0, name.length - ".conf".length)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
Config.parse(reader)
|
||||
} catch (e: Throwable) {
|
||||
throwables.add(e)
|
||||
null
|
||||
}?.let {
|
||||
val nameCopy = name
|
||||
futureTunnels.add(async(SupervisorJob()) { Application.getTunnelManager().create(nameCopy, it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
futureTunnels.add(async(SupervisorJob()) { Application.getTunnelManager().create(name, Config.parse(contentResolver.openInputStream(uri)!!)) })
|
||||
}
|
||||
|
||||
if (futureTunnels.isEmpty()) {
|
||||
if (throwables.size == 1) {
|
||||
throw throwables[0]
|
||||
} else {
|
||||
require(throwables.isNotEmpty()) { context.getString(R.string.no_configs_error) }
|
||||
}
|
||||
}
|
||||
val tunnels = futureTunnels.mapNotNull {
|
||||
try {
|
||||
it.await()
|
||||
} catch (e: Throwable) {
|
||||
throwables.add(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main.immediate) { onTunnelImportFinished(tunnels, throwables, messageCallback) }
|
||||
} catch (e: Throwable) {
|
||||
withContext(Dispatchers.Main.immediate) { onTunnelImportFinished(emptyList(), listOf(e), messageCallback) }
|
||||
}
|
||||
}
|
||||
|
||||
fun importTunnel(parentFragmentManager: FragmentManager, configText: String, messageCallback: (CharSequence) -> Unit) {
|
||||
try {
|
||||
// Ensure the config text is parseable before proceeding…
|
||||
Config.parse(ByteArrayInputStream(configText.toByteArray(StandardCharsets.UTF_8)))
|
||||
|
||||
// Config text is valid, now create the tunnel…
|
||||
ConfigNamingDialogFragment.newInstance(configText).show(parentFragmentManager, null)
|
||||
} catch (e: Throwable) {
|
||||
onTunnelImportFinished(emptyList(), listOf<Throwable>(e), messageCallback)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onTunnelImportFinished(tunnels: List<ObservableTunnel>, throwables: Collection<Throwable>, messageCallback: (CharSequence) -> Unit) {
|
||||
val context = Application.get().applicationContext
|
||||
var message = ""
|
||||
for (throwable in throwables) {
|
||||
val error = ErrorMessages[throwable]
|
||||
message = context.getString(R.string.import_error, error)
|
||||
Log.e(TAG, message, throwable)
|
||||
}
|
||||
if (tunnels.size == 1 && throwables.isEmpty())
|
||||
message = context.getString(R.string.import_success, tunnels[0].name)
|
||||
else if (tunnels.isEmpty() && throwables.size == 1)
|
||||
else if (throwables.isEmpty())
|
||||
message = context.resources.getQuantityString(R.plurals.import_total_success,
|
||||
tunnels.size, tunnels.size)
|
||||
else if (!throwables.isEmpty())
|
||||
message = context.resources.getQuantityString(R.plurals.import_partial_success,
|
||||
tunnels.size + throwables.size,
|
||||
tunnels.size, tunnels.size + throwables.size)
|
||||
|
||||
messageCallback(message)
|
||||
}
|
||||
|
||||
private const val TAG = "WireGuard/TunnelImporter"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<!--
|
||||
~ Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,211 @@
|
||||
<!--
|
||||
~ Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="1934.5dp"
|
||||
android:height="393.14dp"
|
||||
android:viewportWidth="1934.5"
|
||||
android:viewportHeight="393.14">
|
||||
<path
|
||||
android:fillColor="#88171a"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M0,0L1934.5,0L1934.5,393.14L0,393.14Z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M432.69,266.47 L367.47,66.48l24.46,0l49.64,154.34 50.91,-154.34l22.28,0l50.72,153.98 49.81,-153.98L639.03,66.48L573.99,266.47L555.87,266.47L503.16,105.43 450.99,266.47Z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m634.56,111.4l24.64,0l0,155.07l-24.64,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m716.31,198.9l0,67.57L692.04,266.47L692.04,112.13l106.52,0c15.82,0 28.2,3.8 37.14,11.41 8.94,7.61 13.41,18.18 13.41,31.7 0.18,10.5 -3.6,20.69 -10.6,28.53 -7.06,8.03 -16.27,12.95 -27.63,14.77l42.93,67.93l-26.27,0l-43.84,-67.57zM716.31,176.25l82.24,0c8.33,0 14.7,-1.81 19.11,-5.43 4.41,-3.63 6.61,-8.82 6.61,-15.58 0,-6.77 -2.2,-11.93 -6.61,-15.49 -4.41,-3.56 -10.78,-5.34 -19.11,-5.34l-82.24,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M871.98,266.47L871.98,111.77l145.1,0l0,22.64l-120.83,0l0,38.59l79.34,0l0,22.28l-79.34,0l0,48.91l127.53,0l0,22.28L871.97,266.47Z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1194.46,212.31l0,-29.35l-54.53,0l0,-23.01l79.34,0l0,60.14c-9.66,16.67 -22.25,29.44 -37.77,38.31 -15.52,8.88 -33.13,13.32 -52.81,13.32 -29.95,0 -54.68,-9.87 -74.18,-29.62 -19.51,-19.75 -29.26,-44.78 -29.26,-75.09 0,-30.43 9.78,-55.52 29.34,-75.27 19.57,-19.75 44.27,-29.62 74.09,-29.62 18.48,0 35.32,4.05 50.54,12.13 15.2,8.08 28.01,20.01 37.13,34.6L1195.55,123.72c-6.13,-11.8 -15.58,-21.56 -27.17,-28.08 -12.09,-6.83 -25.79,-10.33 -39.67,-10.15 -22.46,0 -41.06,7.7 -55.8,23.1 -14.73,15.4 -22.1,34.87 -22.1,58.42 0,23.55 7.37,42.99 22.1,58.33 14.73,15.34 33.33,23.01 55.8,23.01 14.01,0 26.48,-3.02 37.41,-9.06 10.93,-6.04 20.38,-15.03 28.35,-26.99z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1246.36,112.14l24.28,0l0,99.09c0,14.85 3.5,24.87 10.5,30.07 7.01,5.2 20.89,7.79 41.67,7.79 20.89,0 34.84,-2.59 41.84,-7.79 7.01,-5.19 10.51,-15.21 10.51,-30.07L1375.16,112.14l24.09,0l0,105.43c0,18.96 -6.01,32.67 -18.02,41.13 -12.02,8.45 -31.61,12.68 -58.79,12.68 -27.05,0 -46.49,-4.17 -58.33,-12.5 -11.84,-8.33 -17.75,-22.1 -17.75,-41.3z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1395.46,266.47 l78.62,-154.7l15.22,0l79.34,154.7l-25.9,0l-20.11,-39.31l-81.7,0l-19.93,39.31zM1451.44,206.69l60.51,0l-30.07,-59.23z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1595.56,198.9l0,67.57l-24.28,0L1571.29,112.13l106.52,0c15.82,0 28.2,3.8 37.14,11.41 8.94,7.61 13.41,18.18 13.41,31.7 0.18,10.5 -3.6,20.69 -10.6,28.53 -7.06,8.03 -16.27,12.95 -27.62,14.77l42.93,67.93l-26.27,0l-43.84,-67.57zM1595.56,176.25l82.24,0c8.33,0 14.7,-1.81 19.11,-5.43 4.41,-3.63 6.61,-8.82 6.61,-15.58 0,-6.77 -2.2,-11.93 -6.61,-15.49 -4.41,-3.56 -10.78,-5.34 -19.11,-5.34l-82.24,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1820.26,111.77c25.24,0 45.59,7.21 61.05,21.65 15.46,14.43 23.19,33.18 23.19,56.25 0,23.31 -7.58,41.94 -22.73,55.89 -15.16,13.95 -35.66,20.92 -61.5,20.92l-68.66,0L1751.6,111.78l68.66,0zM1820.63,134.05l-44.75,0l0,110.14l44.75,0c18.35,0 32.79,-4.92 43.29,-14.77 10.51,-9.84 15.76,-23.21 15.76,-40.12 0,-16.3 -5.43,-29.59 -16.3,-39.85 -10.87,-10.26 -25.12,-15.4 -42.75,-15.4l0,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m429.67,318.63l0,18.61l-6.35,0l0,-40.45l37.37,0l0,5.92l-31.02,0l0,10.08l20.04,0l0,5.83z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m455.24,337.24 l20.56,-40.45l3.98,0l20.75,40.45l-6.78,0l-5.26,-10.28l-21.36,0l-5.21,10.28zM469.87,321.61l15.82,0l-7.86,-15.49z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m505.02,332.08 l3.08,-5.3c2.81,1.87 5.87,3.34 9.09,4.35 3.04,1.01 6.22,1.53 9.43,1.57 3.06,0.14 6.09,-0.62 8.71,-2.2 2.03,-1.16 3.3,-3.32 3.32,-5.66 0.08,-2.16 -1.1,-4.17 -3.03,-5.14 -2.03,-1.12 -5.21,-1.75 -9.57,-1.87 -7.36,-0.09 -12.41,-0.95 -15.16,-2.56 -2.75,-1.61 -4.13,-4.28 -4.13,-8.01 -0.04,-3.39 1.67,-6.56 4.53,-8.38 3.01,-2.12 7.06,-3.18 12.15,-3.18 3.43,-0.01 6.83,0.49 10.11,1.47 3.33,1.01 6.52,2.48 9.45,4.36l-3.17,5.26c-2.52,-1.7 -5.25,-3.03 -8.15,-3.95 -2.69,-0.9 -5.5,-1.37 -8.34,-1.4 -2.56,-0.11 -5.1,0.44 -7.39,1.61 -1.66,0.76 -2.75,2.39 -2.8,4.21 -0.03,1.77 1.13,3.33 2.82,3.84 1.88,0.76 5.14,1.14 9.78,1.14 6.44,0 11.31,1.09 14.59,3.27 3.29,2.18 4.93,5.42 4.93,9.71 0.01,3.8 -1.86,7.37 -5,9.52 -3.33,2.53 -7.65,3.79 -12.95,3.79 -3.95,-0.01 -7.88,-0.57 -11.67,-1.68 -3.75,-1.07 -7.34,-2.67 -10.63,-4.76z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m568.06,337.24l0,-34.81l-17.05,0l0,-5.63l40.45,0l0,5.63L574.36,302.43l0,34.81z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m604.52,345.48c0.91,-1.32 1.73,-2.7 2.46,-4.12 0.68,-1.32 1.25,-2.7 1.7,-4.12l-0.38,0c-0.96,0.01 -1.86,-0.44 -2.44,-1.21 -0.67,-0.87 -1.01,-1.95 -0.97,-3.06 -0.05,-1.22 0.36,-2.41 1.16,-3.34 0.73,-0.84 1.8,-1.32 2.92,-1.3 1.3,-0.02 2.52,0.64 3.22,1.73 0.89,1.39 1.32,3.02 1.23,4.67 -0.09,2.03 -0.71,3.99 -1.8,5.71 -1.5,2.45 -3.3,4.7 -5.35,6.7z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m668.13,337.24l0,-40.45l5.25,0l16.58,23.68 16.58,-23.68l5.26,0l0,40.45l-6.3,0l0,-29.08l-15.54,22.49 -15.49,-22.49l0,29.08z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m748.83,338.52c-7.2,0 -13.12,-2.04 -17.76,-6.11 -4.42,-3.87 -6.96,-9.46 -6.96,-15.33 -0.01,-5.87 2.52,-11.47 6.94,-15.34 4.63,-4.02 10.55,-6.04 17.78,-6.04 7.3,0 13.25,2.01 17.88,6.02 4.42,3.89 6.95,9.48 6.94,15.36 -0.01,5.88 -2.54,11.47 -6.96,15.35 -4.64,4.06 -10.59,6.09 -17.85,6.09zM748.83,332.6c5.4,0 9.81,-1.46 13.22,-4.38 3.25,-2.79 5.12,-6.86 5.11,-11.15 -0.01,-4.29 -1.89,-8.35 -5.14,-11.14 -3.43,-2.94 -7.82,-4.4 -13.19,-4.4 -5.36,0 -9.75,1.46 -13.14,4.38 -3.23,2.8 -5.09,6.87 -5.09,11.15 0,4.28 1.86,8.35 5.09,11.16 3.39,2.92 7.78,4.38 13.14,4.38z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m803.92,296.79c6.6,0 11.92,1.89 15.96,5.66 4.04,3.78 6.06,8.68 6.06,14.71 0,6.09 -1.98,10.96 -5.94,14.61 -3.96,3.65 -9.32,5.47 -16.08,5.47l-17.95,0l0,-40.45zM804.02,302.61l-11.7,0l0,28.8l11.7,0c4.8,0 8.57,-1.29 11.32,-3.86 2.75,-2.57 4.13,-6.07 4.13,-10.49 0.13,-3.93 -1.42,-7.72 -4.27,-10.42 -2.84,-2.68 -6.57,-4.03 -11.18,-4.03z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m837.87,337.24l0,-40.45l37.94,0l0,5.92l-31.59,0l0,10.09l20.75,0l0,5.82l-20.75,0l0,12.79l33.34,0l0,5.82z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m894.94,319.57l0,17.67l-6.35,0L888.59,296.88l27.85,0c4.14,0 7.37,0.99 9.71,2.98 2.38,2.08 3.67,5.14 3.51,8.29 0.05,2.75 -0.94,5.41 -2.77,7.46 -1.86,2.11 -4.43,3.48 -7.22,3.86l11.22,17.76l-6.87,0l-11.46,-17.67zM894.94,313.65l21.5,0c1.78,0.12 3.55,-0.39 5,-1.42 1.18,-1.01 1.82,-2.52 1.72,-4.07 0.1,-1.55 -0.54,-3.05 -1.72,-4.05 -1.46,-1.02 -3.22,-1.52 -5,-1.4l-21.5,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m943.11,337.24l0,-40.45l3.32,0l25.72,28.42l0,-28.42l6.2,0l0,40.45l-3.32,0l-25.67,-28.32l0,28.32z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m999,345.48c0.91,-1.32 1.73,-2.7 2.46,-4.12 0.68,-1.32 1.25,-2.7 1.7,-4.12l-0.37,0c-0.96,0.01 -1.87,-0.44 -2.44,-1.21 -0.67,-0.87 -1.01,-1.95 -0.97,-3.06 -0.05,-1.22 0.37,-2.41 1.16,-3.34 0.72,-0.84 1.8,-1.32 2.91,-1.3 1.3,-0.02 2.52,0.64 3.22,1.73 0.89,1.39 1.32,3.02 1.23,4.67 -0.09,2.03 -0.71,3.99 -1.8,5.71 -1.5,2.45 -3.3,4.7 -5.35,6.7z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1059.16,332.08 l3.08,-5.3c2.81,1.87 5.87,3.34 9.09,4.35 3.04,1.01 6.22,1.53 9.43,1.57 3.06,0.14 6.09,-0.62 8.71,-2.2 2.03,-1.16 3.3,-3.32 3.31,-5.66 0.09,-2.16 -1.1,-4.17 -3.03,-5.14 -2.02,-1.12 -5.21,-1.75 -9.57,-1.87 -7.35,-0.09 -12.41,-0.95 -15.15,-2.56 -2.75,-1.61 -4.12,-4.28 -4.12,-8.01 -0.04,-3.39 1.67,-6.56 4.53,-8.38 3.02,-2.12 7.06,-3.18 12.15,-3.18 3.43,-0.01 6.83,0.49 10.11,1.47 3.33,1.01 6.52,2.48 9.45,4.36l-3.17,5.26c-2.51,-1.7 -5.25,-3.03 -8.15,-3.95 -2.69,-0.9 -5.51,-1.37 -8.34,-1.4 -2.56,-0.11 -5.1,0.44 -7.39,1.61 -1.66,0.76 -2.74,2.39 -2.8,4.21 -0.03,1.77 1.13,3.33 2.82,3.84 1.88,0.76 5.14,1.14 9.78,1.14 6.44,0 11.3,1.09 14.59,3.27 3.28,2.18 4.93,5.41 4.93,9.71 0.01,3.8 -1.86,7.37 -5,9.52 -3.33,2.53 -7.65,3.79 -12.95,3.79 -3.95,-0.01 -7.88,-0.57 -11.68,-1.68 -3.75,-1.07 -7.33,-2.67 -10.63,-4.76z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1112.56,337.24l0,-40.45l37.94,0l0,5.92L1118.91,302.71l0,10.09l20.74,0l0,5.82L1118.91,318.63l0,12.79l33.34,0l0,5.82z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1206.06,327.34c-2.21,3.55 -5.35,6.42 -9.07,8.31 -3.96,1.96 -8.34,2.94 -12.77,2.87 -7.1,0 -12.95,-2.01 -17.55,-6.04 -4.38,-3.89 -6.89,-9.48 -6.89,-15.34 0,-5.87 2.51,-11.45 6.89,-15.35 4.59,-4.06 10.44,-6.08 17.55,-6.08 4.15,-0.06 8.25,0.79 12.03,2.49 3.47,1.55 6.47,3.97 8.71,7.04l-5.02,3.51c-1.7,-2.33 -3.97,-4.16 -6.6,-5.33 -2.87,-1.28 -5.98,-1.92 -9.12,-1.87 -4.69,-0.17 -9.27,1.41 -12.86,4.43 -3.23,2.78 -5.09,6.84 -5.09,11.11 0.01,4.27 1.87,8.32 5.11,11.1 3.58,3.02 8.16,4.59 12.83,4.43 3.3,0.07 6.57,-0.66 9.52,-2.13 2.93,-1.58 5.41,-3.86 7.24,-6.64z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1218.66,296.89l6.34,0l0,25.91c0,3.89 0.92,6.51 2.75,7.86 1.83,1.36 5.46,2.04 10.89,2.04 5.46,0 9.11,-0.68 10.94,-2.04 1.83,-1.36 2.75,-3.98 2.75,-7.86l0,-25.91l6.3,0l0,27.56c0,4.96 -1.57,8.54 -4.71,10.75 -3.14,2.21 -8.27,3.31 -15.37,3.31 -7.07,0 -12.16,-1.09 -15.25,-3.27 -3.09,-2.18 -4.64,-5.78 -4.64,-10.8z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1280.86,319.57l0,17.67l-6.34,0L1274.52,296.88l27.85,0c4.14,0 7.37,0.99 9.71,2.98 2.38,2.08 3.67,5.14 3.51,8.29 0.05,2.75 -0.94,5.41 -2.77,7.46 -1.86,2.11 -4.43,3.48 -7.22,3.86l11.22,17.76l-6.86,0l-11.46,-17.67zM1280.86,313.65l21.5,0c1.78,0.12 3.55,-0.39 5,-1.42 1.18,-1.01 1.82,-2.52 1.73,-4.07 0.1,-1.55 -0.55,-3.05 -1.73,-4.05 -1.46,-1.02 -3.22,-1.52 -5,-1.4l-21.5,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1328.96,337.24l0,-40.45l37.94,0l0,5.92l-31.59,0l0,10.09l20.75,0l0,5.82l-20.75,0l0,12.79l33.34,0l0,5.82z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1431.46,337.24l-3.27,0l-20.32,-40.45l6.72,0l15.2,30.27 14.97,-30.27l6.96,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1468.06,319.57l0,17.67l-6.35,0L1461.71,296.79l29.41,0c4.17,0 7.42,0.99 9.73,2.96 2.37,2.09 3.66,5.15 3.48,8.31 0.1,3.13 -1.16,6.16 -3.46,8.29 -2.49,2.22 -5.76,3.37 -9.09,3.22zM1468.06,313.65l23.06,0c1.77,0.11 3.51,-0.39 4.95,-1.42 2.28,-2.21 2.31,-5.85 0.07,-8.1 -1.35,-1.03 -3.04,-1.53 -4.73,-1.42l-23.35,0z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1515.26,337.24l0,-40.45l3.32,0l25.71,28.42l0,-28.42l6.21,0l0,40.45l-3.32,0l-25.67,-28.32l0,28.32z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1610.06,337.24l0,-34.81l-17.05,0l0,-5.63l40.45,0l0,5.63l-17.1,0l0,34.81z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1641.76,296.89l6.35,0l0,25.91c0,3.89 0.91,6.51 2.75,7.86 1.83,1.36 5.46,2.04 10.89,2.04 5.46,0 9.11,-0.68 10.94,-2.04 1.83,-1.36 2.75,-3.98 2.75,-7.86l0,-25.91l6.3,0l0,27.56c0,4.96 -1.57,8.54 -4.71,10.75 -3.14,2.21 -8.27,3.31 -15.37,3.31 -7.07,0 -12.16,-1.09 -15.25,-3.27 -3.09,-2.18 -4.64,-5.78 -4.64,-10.8z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1697.66,337.24l0,-40.45l3.31,0l25.72,28.42l0,-28.42l6.21,0l0,40.45l-3.32,0l-25.67,-28.32l0,28.32z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1748.76,337.24l0,-40.45l3.32,0l25.71,28.42L1777.79,296.79L1784,296.79l0,40.45l-3.32,0l-25.67,-28.32l0,28.32z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1799.76,337.24l0,-40.45l37.94,0l0,5.92l-31.59,0l0,10.09l20.75,0l0,5.82l-20.75,0l0,12.79l33.34,0l0,5.82z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1850.46,337.24l0,-40.45l6.35,0l0,34.62l30.03,0l0,5.82z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M329.74,185.56C329.74,185.56 336.68,40 176.7,40 35.22,40 30.8,179.63 30.8,179.63 30.8,179.63 9.99,340 179.96,340 342.98,340 329.74,185.56 329.74,185.56ZM131.94,134.7c30.02,-18.36 68.36,-7.14 82.73,20.47 2.72,5.23 3.07,13.29 1.34,18.78 -5.95,18.96 -20.02,29.59 -39.31,34.1 5.69,-4.87 10.22,-10.4 11.66,-18.03 1.52,-7.31 -0.13,-14.93 -4.55,-20.95 -7.03,-9.65 -19.59,-13.49 -30.81,-9.39 -11.89,4.51 -18.39,15.35 -17.22,28.68 1.09,12.38 10.48,20.41 28.06,23.45 -2.63,1.39 -4.65,2.42 -6.63,3.52 -8.05,4.41 -15.06,10.51 -20.54,17.87 -1.79,2.41 -3.01,2.6 -5.73,0.94 -35.34,-21.61 -37.61,-75.84 0.98,-99.45zM105.49,268.23c-5.68,1.44 -11.18,3.57 -16.98,5.47 2.84,-19.15 25.27,-36.79 44.23,-34.78 -5.49,7.57 -8.7,16.56 -9.24,25.9 -6.3,1.16 -12.25,1.94 -18.01,3.4zM226.28,81.25c5.61,0.21 11.23,0.12 16.84,0.25 1.4,0.09 2.8,0.29 4.17,0.58 -1.26,1.93 -2.67,3.75 -4.23,5.43 -2.01,1.87 -4.28,3.7 -7.17,0.85 -0.69,-0.68 -2.34,-0.53 -3.55,-0.54 -5.58,-0.07 -11.17,-0.25 -16.75,-0.04 -4.84,0.16 -9.66,0.65 -14.43,1.47 -0.9,0.16 -2.23,3.13 -1.82,4.22 0.97,2.59 2.38,5.44 4.47,7.09 7.75,6.11 15.97,11.59 23.75,17.66 7.56,5.9 14.59,12.36 18.87,21.25 5.58,11.59 5.74,23.74 3.34,35.95 -4.02,20.38 -14.33,37.26 -31.03,49.53 -6.73,4.94 -15.06,7.74 -22.77,11.29 -6.78,3.13 -13.75,5.81 -20.55,8.9 -12.25,5.57 -19.13,18.87 -17.1,32.69 1.85,12.69 12.98,23.27 25.73,25.46 15.29,2.62 31.07,-7.32 34.81,-22.86 4.2,-17.48 -5.29,-33.08 -23.07,-37.81 -0.78,-0.21 -1.57,-0.41 -3.2,-0.83 4.75,-2.12 8.86,-3.64 12.66,-5.72 6.61,-3.64 13.11,-7.49 19.48,-11.56 1.88,-1.2 2.89,-1.2 4.49,0.18 12.23,10.57 19.52,23.72 21.56,39.84 3.39,26.68 -9.25,51.2 -33.07,63.76 -36.87,19.44 -81.97,-2.68 -90.11,-43.55 -6.97,-35 17.73,-66.75 47.46,-72.88 12.79,-2.63 24.48,-7.96 33.57,-17.81 5.87,-6.35 8.71,-11.81 9.68,-14.27 1.81,-4.61 2.73,-9.52 2.72,-14.47 -0.2,-4.29 -1.2,-8.49 -2.96,-12.4 -3.1,-7.07 -15,-18.33 -17.94,-20.7l-28,-21.92c-0.98,-0.81 -2.1,-0.75 -4.51,-0.59 -2.86,0.19 -10.18,0.6 -13.33,-0.23 2.55,-1.93 9.52,-4.74 12.51,-7.01 -9.08,-6.13 -19.43,-3.92 -28.94,-5.75 2.2,-4.09 13.08,-10.39 19.27,-11.09 -0.37,-3.46 -0.93,-6.89 -1.69,-10.28 -0.38,-1.39 -1.93,-2.74 -3.29,-3.54 -3.29,-1.93 -6.77,-3.52 -10.55,-5.43 3.39,-2.19 7.31,-3.4 11.33,-3.51 3.82,-0.15 7.63,0.23 11.35,1.1 6.74,1.54 12.12,0.54 17.49,-4.05 -4.22,-1.7 -8.45,-3.25 -12.54,-5.09 -4.03,-1.84 -7.96,-3.9 -11.78,-6.16 10.62,1.48 20.89,5.46 31.75,4 0.09,-0.49 0.19,-0.99 0.28,-1.48 -8.12,-1.89 -16.24,-3.78 -25.23,-5.87 15.04,-1.37 29.04,-1.6 42.3,4.85 3.73,1.82 7.63,3.32 11.21,5.4 1.74,1.02 2.92,3.01 4.35,4.56 1.13,1.23 2.05,2.88 3.44,3.63 5.3,2.82 11.13,2.93 17.08,2.79 0.05,-0.68 0.09,-1.31 0.13,-1.99 5.98,1.87 12.72,8.77 12.71,13.8 -9.69,0 -19.37,-0.04 -29.06,0.06 -1.04,0.01 -2.06,0.77 -3.09,1.17 0.98,0.57 1.94,1.6 2.94,1.64z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m213.78,66.91c-0.84,0.53 -0.94,1.71 -0.19,2.37 0.61,1.08 1.99,1.45 3.07,0.82 0.94,-0.47 1.85,-0.97 2.98,-1.57 -0.91,-0.78 -1.64,-1.42 -2.39,-2.03 -1.32,-1.09 -2.41,-0.41 -3.47,0.41z"
|
||||
android:strokeColor="#00000000" />
|
||||
<path
|
||||
android:fillColor="#d1d1d1"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m1890,97.71l-1.24,0c-7.56,0.08 -11.84,6.64 -11.84,13 0,6.16 3.92,12.32 12.2,12.32l0.56,0c8.6,-0.24 12.36,-6.16 12.36,-12.24l0,-0.72c-0.28,-6.36 -4.84,-12.36 -12.04,-12.36zM1884.48,102.87l0,14.44l1.8,0l0,-12.96l3.4,0c1.88,0 2.8,1.16 2.8,2.32 0,1.4 -1.36,3 -3.8,3 -0.37,0 -0.84,-0.08 -1.28,-0.16l5.44,7.8l2.36,0l-4.92,-6.64c2.4,-0.44 4,-2.36 4,-4.24 0,-1.76 -1.52,-3.56 -4.88,-3.56zM1881.04,103.16c2.52,-2.72 5.16,-3.72 8.24,-3.72l1.28,0c5.48,0.24 9.44,5.8 9.44,11.16 0,0.76 -0.08,1.64 -0.24,2.36 -0.84,4.92 -5.12,8.36 -10.08,8.36 -0.12,0 -0.37,0.04 -0.49,0.04 -6.28,0 -10.28,-5.68 -10.28,-11.36 0,-0.48 0.08,-1.12 0.12,-1.64 0,0 0.28,-3.12 2,-5.2z"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -31,7 +31,6 @@
|
||||
android:id="@+id/tunnel_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:choiceMode="multipleChoiceModal"
|
||||
android:clipToPadding="false"
|
||||
android:nextFocusDown="@id/create_fab"
|
||||
android:nextFocusForward="@id/create_fab"
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<import type="android.view.View" />
|
||||
|
||||
<import type="com.wireguard.android.model.ObservableTunnel" />
|
||||
|
||||
<import type="com.wireguard.android.activity.TvMainActivity.KeyedFile" />
|
||||
|
||||
<variable
|
||||
name="isDeleting"
|
||||
type="androidx.databinding.ObservableBoolean" />
|
||||
|
||||
<variable
|
||||
name="files"
|
||||
type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, KeyedFile>" />
|
||||
|
||||
<variable
|
||||
name="filesRoot"
|
||||
type="androidx.databinding.ObservableField<String>" />
|
||||
|
||||
<variable
|
||||
name="tunnels"
|
||||
type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, ObservableTunnel>" />
|
||||
|
||||
<variable
|
||||
name="tunnelRowConfigurationHandler"
|
||||
type="com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler" />
|
||||
|
||||
<variable
|
||||
name="filesRowConfigurationHandler"
|
||||
type="com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/banner_logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
app:cardElevation="2dp"
|
||||
app:contentPadding="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="67dp"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:scaleType="fitXY"
|
||||
app:srcCompat="@drawable/tv_logo_banner" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tunnel_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="@{(tunnels.isEmpty || !filesRoot.isEmpty) ? View.GONE : View.VISIBLE}"
|
||||
app:configurationHandler="@{tunnelRowConfigurationHandler}"
|
||||
app:items="@{tunnels}"
|
||||
app:layout="@{@layout/tv_tunnel_list_item}"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:layout_constraintBottom_toTopOf="@id/delete_button"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/banner_logo"
|
||||
app:spanCount="3"
|
||||
tools:itemCount="10"
|
||||
tools:listitem="@layout/tv_tunnel_list_item" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/files_root_label"
|
||||
style="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@{filesRoot}"
|
||||
android:visibility="@{filesRoot.isEmpty ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/banner_logo"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/files_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="@{filesRoot.isEmpty ? View.GONE : View.VISIBLE}"
|
||||
app:configurationHandler="@{filesRowConfigurationHandler}"
|
||||
app:items="@{files}"
|
||||
app:layout="@{@layout/tv_file_list_item}"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:layout_constraintBottom_toTopOf="@id/import_button"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/files_root_label"
|
||||
app:spanCount="5"
|
||||
tools:itemCount="10"
|
||||
tools:listitem="@layout/tv_file_list_item"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.MaterialComponents.Headline4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/tv_add_tunnel_get_started"
|
||||
android:visibility="@{(filesRoot.isEmpty && tunnels.isEmpty) ? View.VISIBLE : View.GONE}"
|
||||
app:layout_constraintBottom_toTopOf="@id/delete_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/banner_logo"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/import_button"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:minWidth="0dp"
|
||||
android:visibility="@{isDeleting ? View.GONE : View.VISIBLE}"
|
||||
app:icon="@{filesRoot.isEmpty ? @drawable/ic_action_add_white : @drawable/ic_arrow_back}"
|
||||
app:iconPadding="0dp"
|
||||
app:iconTint="?attr/colorOnPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/delete_button"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:minWidth="0dp"
|
||||
android:visibility="@{((tunnels.isEmpty && !isDeleting) || !filesRoot.isEmpty) ? View.GONE : View.VISIBLE}"
|
||||
app:icon="@{isDeleting ? @drawable/ic_arrow_back : @drawable/ic_action_delete}"
|
||||
app:iconPadding="0dp"
|
||||
app:iconTint="?attr/colorOnPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
|
||||
<import type="com.wireguard.android.activity.TvMainActivity.KeyedFile" />
|
||||
|
||||
<variable
|
||||
name="key"
|
||||
type="String" />
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="KeyedFile" />
|
||||
</data>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:backgroundTint="@color/tv_card_background"
|
||||
android:checkable="true"
|
||||
android:focusable="true"
|
||||
app:contentPadding="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
style="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{key}"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</layout>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
|
||||
<import type="android.view.View" />
|
||||
|
||||
<import type="com.wireguard.android.model.ObservableTunnel" />
|
||||
|
||||
<import type="com.wireguard.android.backend.Tunnel.State" />
|
||||
|
||||
<variable
|
||||
name="isDeleting"
|
||||
type="androidx.databinding.ObservableBoolean" />
|
||||
|
||||
<variable
|
||||
name="isFocused"
|
||||
type="androidx.databinding.ObservableBoolean" />
|
||||
|
||||
<variable
|
||||
name="key"
|
||||
type="String" />
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.wireguard.android.model.ObservableTunnel" />
|
||||
</data>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="225dp"
|
||||
android:layout_height="110dp"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:backgroundTint="@{(item.state == State.UP && !isDeleting) ? @color/secondary_dark_color : (isDeleting && isFocused) ? @color/tv_card_delete_background : @color/tv_card_background}"
|
||||
android:checkable="true"
|
||||
android:focusable="true"
|
||||
app:contentPadding="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/tunnel_name"
|
||||
style="@style/TextAppearance.MaterialComponents.Headline5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{item.name}"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@sample/interface_names.json/names/names/name" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/tunnel_transfer"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="@{isDeleting ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:text="rx: 200 MB, tx: 100 MB" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/tunnel_delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/tv_delete"
|
||||
android:visibility="@{(isDeleting && isFocused) ? View.VISIBLE : View.GONE}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="gone" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</layout>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="zero">تم حذف نفق %d بنجاح</item>
|
||||
<item quantity="one">تم حذف %d نفق بنجاح</item>
|
||||
<item quantity="two">تم حذف %d نفق بنجاح</item>
|
||||
<item quantity="few">تم حذف %d نفق بنجاح</item>
|
||||
<item quantity="many">تم حذف %d نفق بنجاح</item>
|
||||
<item quantity="other">تم حذف %d انفاق بنجاح</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="zero">%d نفق محدد</item>
|
||||
<item quantity="one">%d نفق محدد</item>
|
||||
<item quantity="two">%d نفق محدد</item>
|
||||
<item quantity="few">%d عنصر محدد</item>
|
||||
<item quantity="many">%d عنصر محدد</item>
|
||||
<item quantity="other">%d عنصر محدد</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">No s\'ha pogut esborrar %d túnel: %s</item>
|
||||
<item quantity="other">No s\'han pogut esborrar %d túnels: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d túnel seleccionat</item>
|
||||
<item quantity="other">%d túnels seleccionats</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d exclòs</item>
|
||||
<item quantity="other">%d exclosos</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d inclòs</item>
|
||||
<item quantity="other">%d inclosos</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Totes les aplicacions</string>
|
||||
<string name="exclude_from_tunnel">Exclou</string>
|
||||
<string name="include_in_tunnel">Inclou només</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Inclou %d aplicació</item>
|
||||
<item quantity="other">Inclou %d aplicacions</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Exclou %d aplicació</item>
|
||||
<item quantity="other">Exclou %d aplicacions</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">cada segon</item>
|
||||
<item quantity="other">cada %d segons</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">segon</item>
|
||||
<item quantity="other">segons</item>
|
||||
</plurals>
|
||||
<string name="add_peer">Afegir parell</string>
|
||||
<string name="addresses">Adreces</string>
|
||||
<string name="applications">Aplicacions</string>
|
||||
<string name="allowed_ips">IPs permeses</string>
|
||||
<string name="bad_config_explanation_positive_number">: Ha de ser positiu</string>
|
||||
<string name="bad_config_reason_invalid_key">Clau no vàlida</string>
|
||||
<string name="bad_config_reason_invalid_number">Número no vàlid</string>
|
||||
<string name="bad_config_reason_invalid_value">Valor no vàlid</string>
|
||||
<string name="bad_config_reason_syntax_error">Error de sintaxi</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Atribut desconegut</string>
|
||||
<string name="bad_config_reason_unknown_section">Secció desconeguda</string>
|
||||
<string name="cancel">Cancel·la</string>
|
||||
<string name="create_activity_title">Crear túnel WireGuard</string>
|
||||
<string name="create_empty">Crea des de zero</string>
|
||||
<string name="create_from_file">Importa des de fitxer o arxiu</string>
|
||||
<string name="create_from_qr_code">Escaneja codi QR</string>
|
||||
<string name="create_tunnel">Crear túnel</string>
|
||||
<string name="dark_theme_title">Utilitza tema fosc</string>
|
||||
<string name="delete">Elimina</string>
|
||||
<string name="dns_servers">Servidors DNS</string>
|
||||
<string name="edit">Edita</string>
|
||||
<string name="exclude_private_ips">Exclou IPs privades</string>
|
||||
<string name="generate_new_private_key">Genera nova clau privada</string>
|
||||
<string name="generic_error">Error “%s” desconegut</string>
|
||||
<string name="hint_generated">(generat)</string>
|
||||
<string name="hint_optional">(opcional)</string>
|
||||
<string name="hint_optional_discouraged">(opcional, no recomanat)</string>
|
||||
<string name="hint_random">(aleatori)</string>
|
||||
<string name="import_from_qr_code">Importa túnel desde codi QR</string>
|
||||
<string name="import_success">Importat “%s”</string>
|
||||
<string name="interface_title">Interfície</string>
|
||||
<string name="key_length_error">Longitud de clau incorrecta</string>
|
||||
<string name="log_export_success">Guardat a \"%s\"</string>
|
||||
<string name="log_export_title">Exporta el registre</string>
|
||||
<string name="log_saver_activity_label">Guarda registre</string>
|
||||
<string name="log_viewer_pref_title">Mostra el registre d\'aplicació</string>
|
||||
<string name="log_viewer_title">Registre</string>
|
||||
<string name="multiple_tunnels_title">Permet múltiples túnels simultanis</string>
|
||||
<string name="name">Nom</string>
|
||||
<string name="no_tunnels_error">No existeixen túnels</string>
|
||||
<string name="parse_error_inet_address">Adreça IP</string>
|
||||
<string name="parse_error_inet_network">Xarxa IP</string>
|
||||
<string name="parse_error_integer">número</string>
|
||||
<string name="peer">Parell</string>
|
||||
<string name="pre_shared_key_enabled">activat</string>
|
||||
<string name="private_key">Clau privada</string>
|
||||
<string name="public_key">Clau pública</string>
|
||||
<string name="restore_on_boot_title">Restableix a l\'inici</string>
|
||||
<string name="save">Guarda</string>
|
||||
<string name="select_all">Selecciona-ho tot</string>
|
||||
<string name="settings">Configuració</string>
|
||||
<string name="tunnel_error_already_exists">El túnel \"%s\" ja existeix</string>
|
||||
<string name="tunnel_error_invalid_name">Nom no vàlid</string>
|
||||
<string name="tunnel_list_placeholder">Afegiu un túnel usant el botó blau</string>
|
||||
<string name="tunnel_name">Nom del túnel</string>
|
||||
<string name="unknown_error">Error desconegut</string>
|
||||
<string name="version_summary_unknown">Versió de %s desconeguda</string>
|
||||
<string name="zip_export_success">Guardat a \"%s\"</string>
|
||||
<string name="biometric_auth_error">Error d\'autenticació</string>
|
||||
<string name="biometric_auth_error_reason">Error d\'autenticació: %s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Kan ikke slette %d tunnel: %s</item>
|
||||
<item quantity="other">Ikke i stand til at slette %d tunneler: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">Slettede %d tunnel</item>
|
||||
<item quantity="other">%d tunneller blev slettet</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">%d Tunnel konnte nicht gelöscht werden: %s</item>
|
||||
<item quantity="one">%d Tunnel konnten nicht gelöscht werden: %s</item>
|
||||
<item quantity="other">%d Tunnel konnten nicht gelöscht werden: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Δεν είναι δυνατή η διαγραφή του %d tunnel: %s</item>
|
||||
<item quantity="other">Δεν είναι δυνατή η διαγραφή %d tunnels: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">Το %d tunnel διαγράφηκε με επιτυχία</item>
|
||||
<item quantity="other">Διαγράφηκαν επιτυχώς τα %d tunnels</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d επιλεγμένο tunnel</item>
|
||||
<item quantity="other">%d επιλεγμένα tunnels</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">Έγινε εισαγωγή %1$d από %2$d tunnels</item>
|
||||
<item quantity="other">Έγινε εισαγωγή %1$d από %2$d tunnels</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">Εισαγωγή tunnel %d</item>
|
||||
<item quantity="other">Εισαγωγή tunnels %d</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d Εξαιρούμενη εφαρμογή</item>
|
||||
<item quantity="other">%d Εξαιρούμενες εφαρμογές</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d Συμπεριλαμβανόμενη εφαρμογή</item>
|
||||
<item quantity="other">%d Συμπεριλαμβανόμενες εφαρμογές</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">εξαιρέθηκε %d</item>
|
||||
<item quantity="other">εξαιρέθηκε %d</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">περιλαμβάνεται %d</item>
|
||||
<item quantity="other">περιλαμβάνεται %d</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Όλες οι εφαρμογές</string>
|
||||
<string name="exclude_from_tunnel">Εξαίρεση</string>
|
||||
<string name="include_in_tunnel">Συμπεριλάβετε μόνο</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Συμπερίληψη %d app</item>
|
||||
<item quantity="other">Συμπερίληψη %d apps</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Εξαίρεση %d app</item>
|
||||
<item quantity="other">Εξαίρεση %d apps</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">κάθε δευτερόλεπτο</item>
|
||||
<item quantity="other">κάθε %d δευτερόλεπτα</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">δευτερόλεπτο</item>
|
||||
<item quantity="other">δευτερόλεπτα</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Χρησιμοποίησε όλες τις εφαρμογές</string>
|
||||
<string name="add_peer">Προσθήκη peer</string>
|
||||
<string name="addresses">Διευθύνσεις</string>
|
||||
<string name="applications">Εφαρμογές</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d excluido</item>
|
||||
<item quantity="other">%d excluidos</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Todas las Aplicaciones</string>
|
||||
<string name="exclude_from_tunnel">Excluir</string>
|
||||
<string name="include_in_tunnel">Sólo inclusión</string>
|
||||
<string name="use_all_applications">Usar todas las aplicaciones</string>
|
||||
<string name="add_peer">Añadir par</string>
|
||||
<string name="addresses">Direcciones</string>
|
||||
<string name="applications">Aplicaciones</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Las aplicaciones externas no pueden cambiar túneles (recomendado)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Las aplicaciones externas pueden cambiar túneles (avanzado)</string>
|
||||
<string name="allow_remote_control_intents_title">Permitir aplicaciones de mando remoto</string>
|
||||
<string name="allowed_ips">IPs permitidas</string>
|
||||
<string name="bad_config_context">%1$s de %2$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%1$s en %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Debe ser positivo y no más de 65535</string>
|
||||
<string name="bad_config_explanation_positive_number">: Debe ser positivo</string>
|
||||
<string name="bad_config_explanation_udp_port">: Debe ser un número válido de puerto UDP</string>
|
||||
<string name="bad_config_reason_invalid_key">Clave inválida</string>
|
||||
<string name="bad_config_reason_invalid_number">Número inválido</string>
|
||||
<string name="bad_config_reason_invalid_value">Valor inválido</string>
|
||||
<string name="bad_config_reason_missing_attribute">Falta atributo</string>
|
||||
<string name="bad_config_reason_missing_section">Sección faltante</string>
|
||||
<string name="bad_config_reason_syntax_error">Error de sintaxis</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Atributo desconocido</string>
|
||||
<string name="bad_config_reason_unknown_section">Sección desconocida</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Valor fuera de rango</string>
|
||||
<string name="bad_extension_error">El archivo debe ser .conf o .zip</string>
|
||||
<string name="cancel">Cancelar</string>
|
||||
<string name="config_delete_error">No se puede eliminar el archivo de configuración %s</string>
|
||||
<string name="config_exists_error">La configuración para “%s” ya existe</string>
|
||||
<string name="config_file_exists_error">El archivo de configuración “%s” ya existe</string>
|
||||
<string name="config_not_found_error">Archivo de configuración “%s” no encontrado</string>
|
||||
<string name="config_rename_error">No se puede renombrar el archivo de configuración “%s”</string>
|
||||
<string name="config_save_error">No se puede guardar la configuración para “%1$s”: %2$s</string>
|
||||
<string name="config_save_success">Configuración guardada correctamente para “%s”</string>
|
||||
<string name="create_activity_title">Crear túnel WireGuard</string>
|
||||
<string name="create_bin_dir_error">No se puede crear el directorio binario local</string>
|
||||
<string name="create_downloads_file_error">No se puede crear archivo en el directorio de descargas</string>
|
||||
<string name="create_empty">Crear de cero</string>
|
||||
<string name="create_from_file">Importar desde archivo</string>
|
||||
<string name="create_from_qr_code">Escanear desde código QR</string>
|
||||
<string name="create_output_dir_error">No se puede crear el directorio de salida</string>
|
||||
<string name="create_temp_dir_error">No se puede crear la carpeta temporal</string>
|
||||
<string name="create_tunnel">Crear túnel</string>
|
||||
<string name="dark_theme_summary_off">Actualmente usando tema claro (día)</string>
|
||||
<string name="dark_theme_summary_on">Actualmente usando tema oscuro (noche)</string>
|
||||
<string name="dark_theme_title">Usar tema oscuro</string>
|
||||
<string name="delete">Eliminar</string>
|
||||
<string name="dns_servers">Servidores DNS</string>
|
||||
<string name="edit">Editar</string>
|
||||
<string name="endpoint">Punto final</string>
|
||||
<string name="error_down">Error al bajar el túnel: %s</string>
|
||||
<string name="error_fetching_apps">Error al obtener la lista de aplicaciones: %s</string>
|
||||
<string name="error_root">Por favor, obtén acceso root y vuelve a intentarlo</string>
|
||||
<string name="error_up">Error al abrir el túnel: %s</string>
|
||||
<string name="exclude_private_ips">Excluir direcciones privadas</string>
|
||||
<string name="generate_new_private_key">Generar nueva clave privada</string>
|
||||
<string name="generic_error">Error desconocido “%s”</string>
|
||||
<string name="hint_automatic">(auto)</string>
|
||||
<string name="hint_generated">(generado)</string>
|
||||
<string name="hint_optional">(opcional)</string>
|
||||
<string name="hint_optional_discouraged">(opcional, no recomendado)</string>
|
||||
<string name="hint_random">(aleatorio)</string>
|
||||
<string name="illegal_filename_error">Nombre de archivo no válido “%s”</string>
|
||||
<string name="import_error">No se puede importar túnel: %s</string>
|
||||
<string name="import_from_qr_code">Importar túnel desde código QR</string>
|
||||
<string name="import_success">Importado “%s”</string>
|
||||
<string name="interface_title">Interfaz</string>
|
||||
<string name="key_contents_error">Caracteres incorrectos en la clave</string>
|
||||
<string name="key_length_error">Longitud de clave incorrecta</string>
|
||||
<string name="key_length_explanation_base64">Las claves base64 de WireGuard deben tener 44 caracteres (32 bytes)</string>
|
||||
<string name="key_length_explanation_binary">: Las claves WireGuard deben tener 32 bytes</string>
|
||||
<string name="key_length_explanation_hex">: Las claves hexadecimales de Wirex deben tener 64 caracteres (32 bytes)</string>
|
||||
<string name="listen_port">Puerto de escucha</string>
|
||||
<string name="log_export_error">No se pudo exportar el registro: %s</string>
|
||||
<string name="log_export_subject">Archivo de registro WireGuard Android</string>
|
||||
<string name="log_export_success">Guardado en “%s”</string>
|
||||
<string name="log_export_title">Exportar archivo de registro</string>
|
||||
<string name="log_saver_activity_label">Guardar registro</string>
|
||||
<string name="log_viewer_pref_summary">Los registros pueden ayudar con la depuración</string>
|
||||
<string name="log_viewer_pref_title">Ver registro de aplicación</string>
|
||||
<string name="log_viewer_title">Registro</string>
|
||||
<string name="logcat_error">No se puede ejecutar logcat: </string>
|
||||
<string name="module_disabler_disabled_summary">El módulo experimental del kernel puede mejorar el rendimiento</string>
|
||||
<string name="module_disabler_disabled_title">Habilitar backend del módulo del kernel</string>
|
||||
<string name="module_disabler_enabled_summary">El backend más lento del espacio de usuario puede mejorar la estabilidad</string>
|
||||
<string name="module_disabler_enabled_title">Desactivar backend del módulo del kernel</string>
|
||||
<string name="module_installer_error">Ocurrió un error. Intente de nuevo</string>
|
||||
<string name="module_installer_initial">El módulo experimental del kernel puede mejorar el rendimiento</string>
|
||||
<string name="module_installer_not_found">No hay módulos disponibles para tu dispositivo</string>
|
||||
<string name="module_installer_title">Descargar e instalar el módulo del kernel</string>
|
||||
<string name="module_installer_working">Descargando e instalando…</string>
|
||||
<string name="module_version_error">No se puede determinar la versión del módulo del kernel</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Activar un túnel apagará los demás</string>
|
||||
<string name="multiple_tunnels_summary_on">Múltiples túneles pueden ser activados simultáneamente</string>
|
||||
<string name="multiple_tunnels_title">Permitir múltiples túneles simultáneos</string>
|
||||
<string name="name">Nombre</string>
|
||||
<string name="no_config_error">Intentando abrir un túnel sin configuración</string>
|
||||
<string name="no_configs_error">No se encontraron configuraciones</string>
|
||||
<string name="no_tunnels_error">No existen túneles</string>
|
||||
<string name="parse_error_generic">cadena</string>
|
||||
<string name="parse_error_inet_address">Dirección IP</string>
|
||||
<string name="parse_error_inet_endpoint">punto final</string>
|
||||
<string name="parse_error_inet_network">Red IP</string>
|
||||
<string name="parse_error_integer">número</string>
|
||||
<string name="parse_error_reason">No se puede analizar %1$s “%2$s”</string>
|
||||
<string name="peer">Pares</string>
|
||||
<string name="permission_description">controlar túneles de WireGuard, habilitando y desactivando túneles a su antojo, lo que podría conducir mal al tráfico de Internet</string>
|
||||
<string name="permission_label">controlar túneles de WireGuard</string>
|
||||
<string name="persistent_keepalive">Mantenimiento persistente</string>
|
||||
<string name="pre_shared_key">Clave precompartida</string>
|
||||
<string name="pre_shared_key_enabled">activado</string>
|
||||
<string name="private_key">Clave privada</string>
|
||||
<string name="public_key">Clave pública</string>
|
||||
<string name="qr_code_hint">Consejo: generar con `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_off">No mostrará túneles habilitados al arrancar</string>
|
||||
<string name="restore_on_boot_summary_on">Mostrará túneles habilitados al arrancar</string>
|
||||
<string name="restore_on_boot_title">Restaurar al arrancar</string>
|
||||
<string name="save">Guardar</string>
|
||||
<string name="select_all">Seleccionar todo</string>
|
||||
<string name="settings">Preferencias</string>
|
||||
<string name="shell_exit_status_read_error">Shell no puede leer estado de salida</string>
|
||||
<string name="shell_marker_count_error">Shell esperaba 4 marcadores, recibió %d</string>
|
||||
<string name="shell_start_error">No se pudo iniciar Shell: %d</string>
|
||||
<string name="success_application_will_restart">Éxito. La aplicación se reiniciará ahora…</string>
|
||||
<string name="toggle_all">Cambiar Todos</string>
|
||||
<string name="toggle_error">Error al cambiar el túnel WireGuard: %s</string>
|
||||
<string name="tools_installer_already">wg y wg-quick ya están instalados</string>
|
||||
<string name="tools_installer_failure">No se puede instalar herramientas de línea de comandos (sin root?)</string>
|
||||
<string name="tools_installer_initial">Instalar herramientas opcionales para el scripting</string>
|
||||
<string name="tools_installer_initial_magisk">Instalar herramientas opcionales para el scripting como módulo Magisk</string>
|
||||
<string name="tools_installer_initial_system">Instalar herramientas opcionales para el scripting en la partición del sistema</string>
|
||||
<string name="tools_installer_success_magisk">wg y wg-quick instalados como un módulo Magisk (requiere reinicio)</string>
|
||||
<string name="tools_installer_success_system">wg y wg-quick instalados en la partición del sistema</string>
|
||||
<string name="tools_installer_title">Instalar herramientas de línea de comandos</string>
|
||||
<string name="tools_installer_working">Instalando wg y wg-quick</string>
|
||||
<string name="tools_unavailable_error">Herramientas requeridas no disponibles</string>
|
||||
<string name="transfer">Transferir</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">No se puede crear el dispositivo túnel</string>
|
||||
<string name="tunnel_config_error">No se puede configurar el túnel (wg-quick devuelto %d)</string>
|
||||
<string name="tunnel_create_error">No se puede crear el dispositivo túnel: %s</string>
|
||||
<string name="tunnel_create_success">Túnel creado con éxito “%s”</string>
|
||||
<string name="tunnel_error_already_exists">Túnel “%s” ya existe</string>
|
||||
<string name="tunnel_error_invalid_name">Nombre inválido</string>
|
||||
<string name="tunnel_list_placeholder">Añadir un túnel usando el botón azul</string>
|
||||
<string name="tunnel_name">Nombre del túnel</string>
|
||||
<string name="tunnel_on_error">No se puede activar el túnel (wgTurnOn devolvió %d)</string>
|
||||
<string name="tunnel_rename_error">No se puede renombrar túnel: %s</string>
|
||||
<string name="tunnel_rename_success">Túnel renombrado con éxito a “%s”</string>
|
||||
<string name="type_name_go_userspace">Ir al espacio de usuario</string>
|
||||
<string name="type_name_kernel_module">Módulo Kernel</string>
|
||||
<string name="unknown_error">Error desconocido</string>
|
||||
<string name="version_summary">%1$s backend v%2$s</string>
|
||||
<string name="version_summary_checking">Comprobando versión de backend %s</string>
|
||||
<string name="version_summary_unknown">Versión %s desconocida</string>
|
||||
<string name="version_title">WireGuard para Android -%s</string>
|
||||
<string name="vpn_not_authorized_error">Servicio VPN no autorizado por el usuario</string>
|
||||
<string name="vpn_start_error">No se puede iniciar el servicio VPN Android</string>
|
||||
<string name="zip_export_error">No se pueden exportar túneles: %s</string>
|
||||
<string name="zip_export_success">Guardado en “%s”</string>
|
||||
<string name="zip_export_summary">El archivo Zip se guardará en la carpeta de descargas</string>
|
||||
<string name="zip_export_title">Exportar túneles a archivo zip</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Autenticar para exportar túneles</string>
|
||||
<string name="biometric_prompt_private_key_title">Autenticar para ver la clave privada</string>
|
||||
<string name="biometric_auth_error">Error de autenticación</string>
|
||||
<string name="biometric_auth_error_reason">Error de autenticación: %s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">حذف %d تونل امکانپذیر نیست: %s</item>
|
||||
<item quantity="other">حذف %d تونلها امکانپذیر نیست: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">%d تونل با موقیت حذف شد</item>
|
||||
<item quantity="other">%d تونلها با موقیت حذف شدند</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d تونل انتخاب شد</item>
|
||||
<item quantity="other">%d تونلها انتخاب شدند</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">%1$d از %2$d تونل اضافه شد</item>
|
||||
<item quantity="other">%1$d از %2$d تونل اضافه شد</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">%d تونل اضافه شد</item>
|
||||
<item quantity="other">%d از تونل اضافه شد</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d برنامه استثنا</item>
|
||||
<item quantity="other">%d برنامههای استثنا</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d برنامه مشمول</item>
|
||||
<item quantity="other">%d برنامههای مشمول</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d استثنا</item>
|
||||
<item quantity="other">%d استثناها</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">شامل %d</item>
|
||||
<item quantity="other">شامل %d</item>
|
||||
</plurals>
|
||||
<string name="all_applications">همه برنامهها</string>
|
||||
<string name="exclude_from_tunnel">جدا کردن</string>
|
||||
<string name="include_in_tunnel">تنها شامل</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">شامل %d برنامه</item>
|
||||
<item quantity="other">شامل %d برنامه</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">جداکردن %d برنامه</item>
|
||||
<item quantity="other">جداکردن %d برنامه</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">هر ثانیه</item>
|
||||
<item quantity="other">هر %d ثانیه</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">ثانیه</item>
|
||||
<item quantity="other">ثانیه</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">از همه برنامهها استفاده کن</string>
|
||||
<string name="add_peer">افزودن همتا</string>
|
||||
<string name="addresses">نشانیها</string>
|
||||
<string name="applications">برنامهها</string>
|
||||
<string name="allow_remote_control_intents_summary_off">برنامههای بیرونی تونل ها را عوض نکنند
|
||||
(توصیه میشود)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">برنامههای بیرونی تونلها را عوض کنند (پیشرفته)</string>
|
||||
<string name="allow_remote_control_intents_title">اجازه به برنامههای کنترل از راهدور</string>
|
||||
<string name="allowed_ips">IPهای مجاز</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$s\'s %2$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%1$s در %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: باید مثبت و بیشتر از ۶۵۵۳۵ نباشد</string>
|
||||
<string name="bad_config_explanation_positive_number">: باید مثبت باشد</string>
|
||||
<string name="bad_config_explanation_udp_port">: باید یک شماره پورت UDP معتبر باشد</string>
|
||||
<string name="bad_config_reason_invalid_key">کلید نامعتبر است</string>
|
||||
<string name="bad_config_reason_invalid_number">شماره نامعتبر است</string>
|
||||
<string name="bad_config_reason_invalid_value">مقدار نامعتبر است</string>
|
||||
<string name="bad_config_reason_missing_attribute">مشخصه موجود نیست</string>
|
||||
<string name="bad_config_reason_missing_section">بخش موجود نیست</string>
|
||||
<string name="bad_config_reason_syntax_error">خطای نحوی</string>
|
||||
<string name="bad_config_reason_unknown_attribute">مشخصهٔ نامعلوم</string>
|
||||
<string name="bad_config_reason_unknown_section">بخش نامعلوم</string>
|
||||
<string name="bad_config_reason_value_out_of_range">مقدار خارج از محدوده</string>
|
||||
<string name="bad_extension_error">پرونده باید .conf یا .zip باشد</string>
|
||||
<string name="cancel">لغو</string>
|
||||
<string name="config_delete_error">نمیتوان پرونده پیکربندی %s را حذف کرد</string>
|
||||
<string name="config_exists_error">پیکربندی برای ”%s” در حال حاضر وجود دارد</string>
|
||||
<string name="config_file_exists_error">فایل پیکربندی ”%s” در حال حاضر وجود دارد</string>
|
||||
<string name="config_not_found_error">پرونده پیکربندی “%s” یافت نشد</string>
|
||||
<string name="config_rename_error">نمیتوان نام پرونده پیکربندی “%s” را تغییر داد</string>
|
||||
<string name="config_save_error">نمیتوان پیکربندی برای “%1$s”: %2$s را ذخیره کرد</string>
|
||||
<string name="config_save_success">پیکربندی برای “%s” با موفقیت ذخیره شد</string>
|
||||
<string name="create_activity_title">ساخت تونل WireGuard</string>
|
||||
<string name="create_bin_dir_error">نمیتوان دایرکتوری باینری محلی را ایجاد کرد</string>
|
||||
<string name="create_downloads_file_error">نمیتوان در مسیر بارگیری پروندهای ساخت</string>
|
||||
<string name="create_empty">ساختن از ابتدا</string>
|
||||
<string name="create_from_file">واردکردن از طریق پرونده یا آرشیو</string>
|
||||
<string name="create_from_qr_code">اسکن از کد QR</string>
|
||||
<string name="create_output_dir_error">نمیتوان دایرکتوری خروجی را ایجاد کرد</string>
|
||||
<string name="create_temp_dir_error">نمیتوان دایرکتوری موقت محلی را ساخت</string>
|
||||
<string name="create_tunnel">ساختن تونل</string>
|
||||
<string name="dark_theme_summary_off">اکنون از پوسته روشن(روز) استفاده میشود</string>
|
||||
<string name="dark_theme_summary_on">اکنون از پوسته تاریک(شب) استفاده میشود</string>
|
||||
<string name="dark_theme_title">استفاده از پوسته تاریک</string>
|
||||
<string name="delete">حذف</string>
|
||||
<string name="dns_servers">سرورهای DNS</string>
|
||||
<string name="edit">ویرایش</string>
|
||||
<string name="endpoint">نقطه پایان</string>
|
||||
<string name="error_down">خطا هنگام بستن تونل: %s</string>
|
||||
<string name="error_fetching_apps">خطا هنگام واکشی فهرست برنامهها: %s</string>
|
||||
<string name="error_root">لطفا دسترسی روت را فراهمکرده و دوباره تلاش کنید</string>
|
||||
<string name="error_up">خطا هنگام راهاندازی تونل: %s</string>
|
||||
<string name="exclude_private_ips">مستثنی کردن IPهای خصوصی</string>
|
||||
<string name="generate_new_private_key">تولید کلید خصوصی جدید</string>
|
||||
<string name="generic_error">خطای “%s” ناشناخته</string>
|
||||
<string name="hint_automatic">(خودکار)</string>
|
||||
<string name="hint_generated">(تولید شده)</string>
|
||||
<string name="hint_optional">(دلخواه)</string>
|
||||
<string name="hint_optional_discouraged">(اختیاری، پیشنهاد نمیشود)</string>
|
||||
<string name="hint_random">(تصادفی)</string>
|
||||
<string name="illegal_filename_error">نام پرونده “%s” غیرمجاز است</string>
|
||||
<string name="import_error">نمیتوان تونل را وارد کرد: %s</string>
|
||||
<string name="import_from_qr_code">وارد کردن تونل از کد QR</string>
|
||||
<string name="import_success">“%s” وارد شد</string>
|
||||
<string name="interface_title">رابط</string>
|
||||
<string name="key_contents_error">در کلید نویسههای بد وجود دارد</string>
|
||||
<string name="key_length_error">طول کلید نادرست است</string>
|
||||
<string name="key_length_explanation_base64">: کلیدهای WireGuard base64 باید دارای ۴۴ نویسه باشند ( ۳۲ بایت)</string>
|
||||
<string name="key_length_explanation_binary">: کلیدهای WireGuard باید ۳۲ بایت باشند</string>
|
||||
<string name="key_length_explanation_hex">: کلیدهای هگز WireGuard باید دارای ۶۴ نویسه باشند ( ۳۲ بایت)</string>
|
||||
<string name="listen_port">شنود پورت</string>
|
||||
<string name="log_export_error">نمیتوان گزارش رویداد را برونبرد: %s</string>
|
||||
<string name="log_export_subject">پرونده گزارش رویداد WireGuard اندروید</string>
|
||||
<string name="log_export_success">ذخیره شد در “%s”</string>
|
||||
<string name="log_export_title">برونبرد پرونده گزارش رویداد</string>
|
||||
<string name="log_saver_activity_label">ذخیره گزارش رویداد</string>
|
||||
<string name="log_viewer_pref_summary">گزارش رویداد شاید به اشکال زدایی کمک کند</string>
|
||||
<string name="log_viewer_pref_title">نمایش گزارش رویداد برنامه</string>
|
||||
<string name="log_viewer_title">گزارش رویداد</string>
|
||||
<string name="logcat_error">نمیتوان logcat را اجرا کرد: </string>
|
||||
<string name="module_disabler_disabled_summary">ماژول آزمایشیِ کرنل می تواند کارایی را افزایش دهد</string>
|
||||
<string name="module_disabler_disabled_title">فعالسازی ماژول کرنل ِبک اند</string>
|
||||
<string name="module_disabler_enabled_title">غیرفعالسازی پسزمینه واحد هسته</string>
|
||||
<string name="module_installer_error">مشکلی پیش آمد. لطفا دوباره تلاش کنید</string>
|
||||
<string name="module_installer_not_found">هیچ واحدی برای دستگاه شما در دسترس نیست</string>
|
||||
<string name="module_installer_title">واحد هسته را بارگیری و نصب کن</string>
|
||||
<string name="module_installer_working">در حال بارگیری و نصب…</string>
|
||||
<string name="module_version_error">نمیتوان نگارش واحد هسته را مشخص کرد</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">روشن کردن یک تونل ، تونل های دیگر را خاموش خواهد کرد</string>
|
||||
<string name="name">نام</string>
|
||||
<string name="no_config_error">تلاش برای فعالسازی تونل بدون تنظیمات</string>
|
||||
<string name="no_configs_error">هیچ پیکربندی یافت نشد</string>
|
||||
<string name="no_tunnels_error">هیچ تونلی وجود ندارد</string>
|
||||
<string name="parse_error_generic">رشته</string>
|
||||
<string name="parse_error_inet_address">نشانی IP</string>
|
||||
<string name="parse_error_inet_endpoint">نقطه پایان</string>
|
||||
<string name="parse_error_inet_network">شبکه IP</string>
|
||||
<string name="parse_error_integer">شماره</string>
|
||||
<string name="parse_error_reason">نمیتوان %1$s “%2$s” تجزیه کرد</string>
|
||||
<string name="peer">همتا</string>
|
||||
<string name="permission_description">کنترل تونل های وایرگارد، فعال و غیرفعال کردن تونل ها، و حتی تغییر مسیر ترافیک اینترنت</string>
|
||||
<string name="permission_label">کنترل تونلهای WireGuard</string>
|
||||
<string name="persistent_keepalive">زنده نگهداشتن پیوسته</string>
|
||||
<string name="pre_shared_key">کلید از پیش تقسیم شده</string>
|
||||
<string name="pre_shared_key_enabled">فعال شده</string>
|
||||
<string name="private_key">کلید خصوصی</string>
|
||||
<string name="public_key">کلید عمومی</string>
|
||||
<string name="restore_on_boot_summary_off">تونل های فعال در لحظه بالا آمدن سیستم، روشن نخواهند شد</string>
|
||||
<string name="restore_on_boot_summary_on">تونل های فعال در لحظه بالا آمدن سیستم، روشن خواهند شد</string>
|
||||
<string name="restore_on_boot_title">بازگردانی در بوت</string>
|
||||
<string name="save">ذخیره</string>
|
||||
<string name="select_all">انتخاب همه</string>
|
||||
<string name="settings">تنظیمات</string>
|
||||
<string name="shell_start_error">آغاز پوسته شکست خورد: %d</string>
|
||||
<string name="success_application_will_restart">موفقیت. برنامه اکنون دوباره راهاندازی خواهد شد…</string>
|
||||
<string name="toggle_all">معکوس کردن همه</string>
|
||||
<string name="tools_installer_title">ابزارهای خط فرمان را نصب کنید</string>
|
||||
<string name="tools_installer_working">در حال نصب wg و wg-quick</string>
|
||||
<string name="tools_unavailable_error">ابزارهای لازم در دسترس نیست</string>
|
||||
<string name="transfer">انتقال</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tunnel_create_error">نمیتوان تونل را ساخت: %s</string>
|
||||
<string name="tunnel_create_success">تونل “%s” با موفقیت ساخته شد</string>
|
||||
<string name="tunnel_error_already_exists">تونل “%s” از قبل وجود دارد</string>
|
||||
<string name="tunnel_error_invalid_name">نام نامعتبر</string>
|
||||
<string name="tunnel_list_placeholder">بهوسیله دکمه آبی یک تونل بیفزایید</string>
|
||||
<string name="tunnel_name">نام تونل</string>
|
||||
<string name="tunnel_rename_error">ناتوان در تغییر نام تونل: %s</string>
|
||||
<string name="tunnel_rename_success">نام تونل با موفقیت تغییر یافت به “%s”</string>
|
||||
<string name="type_name_go_userspace">رفتن به فضای کاربر</string>
|
||||
<string name="type_name_kernel_module">واحد هسته</string>
|
||||
<string name="unknown_error">خطای نامشخص</string>
|
||||
<string name="version_summary">%1$s پسزمینه نگارش%2$s</string>
|
||||
<string name="version_summary_checking">در حال بررسی نگارش پسزمینه %s</string>
|
||||
<string name="version_summary_unknown">نگارش %s ناشناخته</string>
|
||||
<string name="version_title">WireGuard برای اندروید نگارش %s</string>
|
||||
<string name="vpn_not_authorized_error">کاربر به سرویس VPN اجازه نداد</string>
|
||||
<string name="vpn_start_error">نمیتوان سرویس VPN اندروید را آغاز کرد</string>
|
||||
<string name="zip_export_error">نمیتوان تونلها را برونبرد: %s</string>
|
||||
<string name="zip_export_success">ذخیره شد در “%s”</string>
|
||||
<string name="zip_export_summary">پرونده زیپ در پوشه بارگیریها ذخیره خواهد شد</string>
|
||||
<string name="zip_export_title">برونبری تونلها در پرونده زیپ</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">برای برونبری تونلها، هویت خود را تایید کنید</string>
|
||||
<string name="biometric_prompt_private_key_title">برای دیدن کلید خصوصی، هویت خود را تایید کنید</string>
|
||||
<string name="biometric_auth_error">شکست در تایید هویت</string>
|
||||
<string name="biometric_auth_error_reason">شکست در تایید هویت: %s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">joka sekunti</item>
|
||||
<item quantity="other">%d sekunnin välein</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">sekunti</item>
|
||||
<item quantity="other">sekuntia</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Käytä kaikkia sovelluksia</string>
|
||||
<string name="add_peer">Lisää toinen osapuoli</string>
|
||||
<string name="addresses">Osoitteet</string>
|
||||
<string name="applications">Sovellukset</string>
|
||||
<string name="allowed_ips">Sallitut IP-osoitteet</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_reason_invalid_key">Virheellinen avain</string>
|
||||
<string name="bad_config_reason_invalid_number">Virheellinen luku</string>
|
||||
<string name="bad_config_reason_invalid_value">Virheellinen arvo</string>
|
||||
<string name="bad_config_reason_missing_attribute">Attribuutti puuttuu</string>
|
||||
<string name="bad_config_reason_missing_section">Osio puuttuu</string>
|
||||
<string name="bad_config_reason_syntax_error">Syntaksivirhe</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Tuntematon määrite</string>
|
||||
<string name="bad_config_reason_unknown_section">Tuntematon osio</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Arvo alueen ulkopuolella</string>
|
||||
<string name="bad_extension_error">Tiedoston on oltava .conf tai .zip</string>
|
||||
<string name="cancel">Peruuta</string>
|
||||
<string name="config_not_found_error">Asetustiedostoa “%s” ei löydy</string>
|
||||
<string name="config_rename_error">Asetustiedostoa \"%s\" ei voi nimetä uudelleen</string>
|
||||
<string name="config_save_success">Asetustiedosto \"%s\" tallennettu onnistuneesti</string>
|
||||
<string name="create_activity_title">Luo WireGuard Tunnel</string>
|
||||
<string name="exclude_private_ips">Jätä pois yksityiset IP-osoitteet</string>
|
||||
<string name="generate_new_private_key">Luo uusi yksityinen avain</string>
|
||||
<string name="generic_error">Tuntematon ”%s” virhe</string>
|
||||
<string name="hint_automatic">(oletus)</string>
|
||||
<string name="hint_generated">(generoitu)</string>
|
||||
<string name="hint_optional">(valinnainen)</string>
|
||||
<string name="hint_optional_discouraged">(valinnainen, ei suositeltava)</string>
|
||||
<string name="hint_random">(satunnainen)</string>
|
||||
<string name="illegal_filename_error">Virheellinen tiedostonimi “%s”</string>
|
||||
<string name="import_error">Tunnelia \"%s\" ei voitu tuoda</string>
|
||||
<string name="import_from_qr_code">Tuo tunneli QR-koodista</string>
|
||||
<string name="import_success">Tuotu ”%s”</string>
|
||||
<string name="key_contents_error">Virheellinen merkki avaimessa</string>
|
||||
<string name="key_length_error">Virheellinen avaimen pituus</string>
|
||||
<string name="key_length_explanation_base64">: WireGuardin base64-avainten pituus on oltava 44 merkkiä (32 tavua)</string>
|
||||
<string name="key_length_explanation_binary">: WireGuard-avainten on oltava 32 tavua</string>
|
||||
<string name="key_length_explanation_hex">: WireGuardin base64-avainten pituus on oltava 64 merkkiä (32 tavua)</string>
|
||||
<string name="listen_port">Kuuntele porttia</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="no_configs_error">Asetuksia ei löydy</string>
|
||||
<string name="no_tunnels_error">Tunneleita ei ole</string>
|
||||
<string name="parse_error_generic">merkkijono</string>
|
||||
<string name="parse_error_inet_address">IP-osoite</string>
|
||||
<string name="parse_error_inet_network">IP-verkko</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tunnel_name">Tunnelin nimi</string>
|
||||
</resources>
|
||||
@@ -5,7 +5,7 @@
|
||||
<item quantity="other">Impossible de supprimer %d tunnels : %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">Supprimé avec succès %d tunnel</item>
|
||||
<item quantity="one">Suppression réussie du tunnel %d</item>
|
||||
<item quantity="other">Supprimé avec succès %d tunnels</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
@@ -191,7 +191,7 @@
|
||||
<string name="tools_installer_title">Installer les outils de ligne de commande</string>
|
||||
<string name="tools_installer_working">Installation de wg et wg-quick</string>
|
||||
<string name="tools_unavailable_error">Outils requis indisponibles</string>
|
||||
<string name="transfer">Transférer</string>
|
||||
<string name="transfer">Données transférées</string>
|
||||
<string name="transfer_bytes">%d Octets</string>
|
||||
<string name="transfer_gibibytes">%.2f Go</string>
|
||||
<string name="transfer_kibibytes">%.2f Ko</string>
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">%d टनल हटाने में असमर्थ: %s</item>
|
||||
<item quantity="other">%d टनलस को हटाने में असमर्थ: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">%d टनल को सफलतापूर्वक हटा दिया गया</item>
|
||||
<item quantity="other">%d टनलस को सफलतापूर्वक हटा दिया गया</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d टनल चयनित</item>
|
||||
<item quantity="other">%d टनलस का चयन किया गया</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">आयातित %d %d टनल</item>
|
||||
<item quantity="other">आयातित %d %d टनलस</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">आयातित %d टनल</item>
|
||||
<item quantity="other">आयातित %d टनलस</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d बहिष्कृत अनुप्रयोग</item>
|
||||
<item quantity="other">%d बहिष्कृत अनुप्रयोग</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d ऐप्स शामिल</item>
|
||||
<item quantity="other">%d ऐप्स शामिल किये गए</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d अपवर्जित</item>
|
||||
<item quantity="other">%d अपवर्जित</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d शामिल</item>
|
||||
<item quantity="other">%d शामिल</item>
|
||||
</plurals>
|
||||
<string name="all_applications">सभी एप्लीकेशन</string>
|
||||
<string name="exclude_from_tunnel">वर्जित</string>
|
||||
<string name="include_in_tunnel">केवल शामिल करें</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">%d ऐप शामिल करें</item>
|
||||
<item quantity="other">%d ऐप्स शामिल करें</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">%d ऐप को बाहर करें</item>
|
||||
<item quantity="other">%d ऐप्स को बाहर करें</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">हर सेकंड</item>
|
||||
<item quantity="other">हर %d सेकंड्स</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">सेकंड</item>
|
||||
<item quantity="other">सेकंड्स</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">सभी ऐप्स का उपयोग करें</string>
|
||||
<string name="add_peer">पीयर जोड़ें</string>
|
||||
<string name="addresses">एड्रेससैस</string>
|
||||
<string name="applications">ऍप्लिकेशन्स</string>
|
||||
<string name="allow_remote_control_intents_summary_off">बाहरी ऐप्स टनल्स को चालू नहीं कर सकते (अनुशंसित)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">बाहरी ऐप्स टनल्स को चालू कर सकते है (एडवांस्ड)</string>
|
||||
<string name="allow_remote_control_intents_title">रिमोट कंट्रोल ऐप्स की अनुमति दें</string>
|
||||
<string name="allowed_ips">अनुमत आईपी</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_explanation_pka">: सकारात्मक होना चाहिए और 65535 से अधिक नहीं होना चाहिए</string>
|
||||
<string name="bad_config_explanation_positive_number">: सकारात्मक होना चाहिए</string>
|
||||
<string name="bad_config_explanation_udp_port">: एक वैध यूडीपी पोर्ट नंबर होना चाहिए</string>
|
||||
<string name="bad_config_reason_invalid_key">अमान्य चाबी</string>
|
||||
<string name="bad_config_reason_invalid_number">अमान्य संख्या</string>
|
||||
<string name="bad_config_reason_invalid_value">अमान्य मूल्य</string>
|
||||
<string name="bad_config_reason_missing_attribute">गुम विशेषता</string>
|
||||
<string name="bad_config_reason_missing_section">छूटा हुआ भाग</string>
|
||||
<string name="bad_config_reason_syntax_error">वक्य रचना त्रुटि</string>
|
||||
<string name="bad_config_reason_unknown_attribute">अज्ञात एट्रिब्यूट</string>
|
||||
<string name="bad_config_reason_unknown_section">अज्ञात एट्रिब्यूट </string>
|
||||
<string name="bad_config_reason_value_out_of_range">मूल्य सीमा से बाहर</string>
|
||||
<string name="bad_extension_error">फ़ाइल .conf या .zip होनी चाहिए</string>
|
||||
<string name="cancel">रद्द</string>
|
||||
<string name="config_delete_error">कॉन्फ़िगरेशन फ़ाइल %s को नहीं हटा सकता</string>
|
||||
<string name="config_exists_error">“%s” के लिए कॉन्फ़िगरेशन पहले से मौजूद है</string>
|
||||
<string name="config_file_exists_error">कॉन्फ़िगरेशन फ़ाइल “%s” पहले से मौजूद है</string>
|
||||
<string name="config_not_found_error">कॉन्फ़िगरेशन फ़ाइल “%s” नहीं मिली</string>
|
||||
<string name="config_rename_error">कॉन्फ़िगरेशन फ़ाइल “%s” का नाम नहीं बदल सकता</string>
|
||||
<string name="config_save_error">“%1$s” के लिए कॉन्फ़िगरेशन को नहीं बचा सकता: %2$s</string>
|
||||
<string name="config_save_success">“%s” के लिए सफलतापूर्वक सहेजा गया कॉन्फ़िगरेशन</string>
|
||||
<string name="create_activity_title">वायरगार्ड टनल बनाएं</string>
|
||||
<string name="create_bin_dir_error">स्थानीय बाइनरी निर्देशिका नहीं बना सकते</string>
|
||||
<string name="create_downloads_file_error">डाउनलोड निर्देशिका में फ़ाइल नहीं बना सकते</string>
|
||||
<string name="create_empty">शुरू से बनाएँ</string>
|
||||
<string name="create_from_file">फ़ाइल या संग्रह से आयात करें</string>
|
||||
<string name="create_from_qr_code">QR कोड स्कैन करें</string>
|
||||
<string name="create_output_dir_error">आउटपुट निर्देशिका नहीं बना सकता</string>
|
||||
<string name="create_temp_dir_error">स्थानीय अस्थायी निर्देशिका नहीं बना सकते</string>
|
||||
<string name="create_tunnel">टनल बनाए</string>
|
||||
<string name="dark_theme_summary_off">अभी प्रकाश (दिन) थीम का उपयोग कर रहे हैं</string>
|
||||
<string name="dark_theme_summary_on">अभी डार्क (रात) थीम का उपयोग कर रहे हैं</string>
|
||||
<string name="dark_theme_title">डार्क थीम का इस्तेमाल करें</string>
|
||||
<string name="delete">हटाएं</string>
|
||||
<string name="dns_servers">डीएनएस सर्वर</string>
|
||||
<string name="edit">संपादित करें</string>
|
||||
<string name="endpoint">अंतिम</string>
|
||||
<string name="error_down">टनल को लाने में त्रुटि: %s</string>
|
||||
<string name="error_fetching_apps">ऐप्स सूची लाने में त्रुटि: %s</string>
|
||||
<string name="error_root">कृपया रूट एक्सेस प्राप्त करें और पुनः प्रयास करें</string>
|
||||
<string name="error_up">टनल को लाने में त्रुटि: %s</string>
|
||||
<string name="exclude_private_ips">निजी आईपी को छोड़ दें</string>
|
||||
<string name="generate_new_private_key">नई प्राइवेट की उत्पन्न करें</string>
|
||||
<string name="generic_error">अज्ञात “%s” त्रुटि</string>
|
||||
<string name="hint_automatic">(ऑटो)</string>
|
||||
<string name="hint_generated">(उत्पन्न)</string>
|
||||
<string name="hint_optional">(ऐच्छिक)</string>
|
||||
<string name="hint_optional_discouraged">(वैकल्पिक, अनुशंसित नहीं)</string>
|
||||
<string name="hint_random">(क्रमरहित)</string>
|
||||
<string name="illegal_filename_error">अवैध फ़ाइल नाम “%s”</string>
|
||||
<string name="import_error">टनल को आयात करने में असमर्थ: %s</string>
|
||||
<string name="import_from_qr_code">क्यूआर कोड से टनल को आयात करें</string>
|
||||
<string name="import_success">आयातित “%s”</string>
|
||||
<string name="interface_title">इंटरफेस</string>
|
||||
<string name="key_contents_error">चाबी में खराब वर्ण</string>
|
||||
<string name="key_length_error">चाबी की लम्बाई गलत </string>
|
||||
<string name="key_length_explanation_base64">: वायरगार्ड बेस 64 कीज़ में 44 अक्षर (32 बाइट्स) होने चाहिए</string>
|
||||
<string name="key_length_explanation_binary">: वायरगार्ड कीज 32 बाइट होनी चाहिए</string>
|
||||
<string name="key_length_explanation_hex">: वायरगार्ड हेक्स कीज़ 64 अक्षरों की होनी चाहिए (32 बाइट्स)</string>
|
||||
<string name="listen_port">पोर्ट सूने</string>
|
||||
<string name="log_export_error">लॉग निर्यात करने में असमर्थ: %s</string>
|
||||
<string name="log_export_subject">WireGuard एंड्राइड लॉग फ़ाइल</string>
|
||||
<string name="log_export_success">“%s” में सहेजा गया</string>
|
||||
<string name="log_export_title">लॉग फ़ाइल निर्यात करें</string>
|
||||
<string name="log_saver_activity_label">लॉग सहेजे</string>
|
||||
<string name="log_viewer_pref_summary">लॉग डीबगिंग में सहायता कर सकते हैं</string>
|
||||
<string name="log_viewer_pref_title">एप्लिकेशन लॉग देखें</string>
|
||||
<string name="log_viewer_title">लॉग</string>
|
||||
<string name="logcat_error">लॉगकैट चलाने में असमर्थ: </string>
|
||||
<string name="module_disabler_disabled_summary">प्रयोगात्मक कर्नेल मॉड्यूल प्रदर्शन में सुधार कर सकता है</string>
|
||||
<string name="module_disabler_disabled_title">कर्नेल मॉड्यूल बैकएंड सक्षम करें</string>
|
||||
<string name="module_disabler_enabled_summary">धीमे यूजरस्पेस बैकएंड में स्थिरता में सुधार हो सकता है</string>
|
||||
<string name="module_disabler_enabled_title">कर्नेल मॉड्यूल बैकएंड को अक्षम करें</string>
|
||||
<string name="module_installer_error">कुछ गलत हो गया। कृपया पुन: प्रयास करें</string>
|
||||
<string name="module_installer_initial">प्रयोगात्मक कर्नेल मॉड्यूल प्रदर्शन में सुधार कर सकता है</string>
|
||||
<string name="module_installer_not_found">आपके डिवाइस के लिए कोई मॉड्यूल उपलब्ध नहीं हैं</string>
|
||||
<string name="module_installer_title">कर्नेल मॉड्यूल डाउनलोड और इंस्टॉल करें</string>
|
||||
<string name="module_installer_working">डाउनलोड कर रहा है और स्थापित कर रहा है…</string>
|
||||
<string name="module_version_error">कर्नेल मॉड्यूल संस्करण निर्धारित करने में असमर्थ</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">एक टनल को चालू करने से अन्य बंद हो जाएंगे</string>
|
||||
<string name="multiple_tunnels_summary_on">एक साथ कई टनलस को चालू किया जा सकता है</string>
|
||||
<string name="multiple_tunnels_title">एक साथ कई टनलस को अनुमति दें</string>
|
||||
<string name="name">नाम</string>
|
||||
<string name="no_config_error">बिना किसी कॉन्फ़िगरेशन के एक टनल को लाने की कोशिश करना</string>
|
||||
<string name="no_configs_error">कोई कॉन्फ़िगरेशन नहीं मिला</string>
|
||||
<string name="no_tunnels_error">कोई टनल मौजूद नहीं है</string>
|
||||
<string name="parse_error_generic">पाठ</string>
|
||||
<string name="parse_error_inet_address">आईपी पता</string>
|
||||
<string name="parse_error_inet_endpoint">समाप्त</string>
|
||||
<string name="parse_error_inet_network">आईपी नेटवर्क</string>
|
||||
<string name="parse_error_integer">संख्या</string>
|
||||
<string name="parse_error_reason">%1$s “%2$s” को पार्स नहीं कर सकता</string>
|
||||
<string name="peer">पीयर</string>
|
||||
<string name="permission_description">वायरगार्ड टनल्स को नियंत्रित करना, टनल्स को सक्षम और अक्षम करना, संभवतः इंटरनेट ट्रैफ़िक को गलत तरीके से अक्षम करना है</string>
|
||||
<string name="permission_label">वायरगार्ड टनलस को नियंत्रित करें</string>
|
||||
<string name="persistent_keepalive">लगातार जिंदा रहो</string>
|
||||
<string name="pre_shared_key">प्री-शेयर्ड कीस</string>
|
||||
<string name="pre_shared_key_enabled">सक्षम</string>
|
||||
<string name="private_key">निजी कीस</string>
|
||||
<string name="public_key">सार्वजनिक कीस</string>
|
||||
<string name="qr_code_hint">सुझाव: `qrencode -t ansiutf8 < tunnel.conf` के साथ उत्पन्न करो</string>
|
||||
<string name="restore_on_boot_summary_off">बूट पर सक्षम टनलस को नहीं लाएगा</string>
|
||||
<string name="restore_on_boot_summary_on">बूट पर सक्षम टनलस को लाएगा</string>
|
||||
<string name="restore_on_boot_title">बूट पर पुनर्स्थापित करें</string>
|
||||
<string name="save">सहेजें</string>
|
||||
<string name="select_all">सभी का चयन करे</string>
|
||||
<string name="settings">सेटिंग्स</string>
|
||||
<string name="shell_exit_status_read_error">शेल बाहर निकलने की स्थिति नहीं पढ़ सकता</string>
|
||||
<string name="shell_marker_count_error">शेल ने 4 मार्करों की अपेक्षा की, %d प्राप्त किया</string>
|
||||
<string name="shell_start_error">शेल शुरू करने में विफल: %d</string>
|
||||
<string name="success_application_will_restart">सफलता। एप्लीकेशन अब पुनः आरंभ होगा...</string>
|
||||
<string name="toggle_all">सबको स्विच करे</string>
|
||||
<string name="toggle_error">वायरगार्ड टनल टॉगल करने में त्रुटि: %s</string>
|
||||
<string name="tools_installer_already">wg और wg-quick पहले से इंस्टॉल हैं</string>
|
||||
<string name="tools_installer_failure">कमांड-लाइन टूल स्थापित करने में असमर्थ (कोई रूट नहीं)</string>
|
||||
<string name="tools_installer_initial">स्क्रिप्टिंग के लिए वैकल्पिक उपकरण स्थापित करें</string>
|
||||
<string name="tools_installer_initial_magisk">Magisk मॉड्यूल के रूप में स्क्रिप्टिंग के लिए वैकल्पिक उपकरण स्थापित करें</string>
|
||||
<string name="tools_installer_initial_system">सिस्टम विभाजन में स्क्रिप्टिंग के लिए वैकल्पिक उपकरण स्थापित करें</string>
|
||||
<string name="tools_installer_success_magisk">wg और wg-quick को मैजिक मॉड्यूल के रूप में स्थापित किया गया है (रिबूट आवश्यक)</string>
|
||||
<string name="tools_installer_success_system">wg और wg-quick सिस्टम विभाजन में स्थापित है</string>
|
||||
<string name="tools_installer_title">कमांड लाइन उपकरण स्थापित करें</string>
|
||||
<string name="tools_installer_working">Wg और wg-quick इंस्टॉल करना</string>
|
||||
<string name="tools_unavailable_error">आवश्यक उपकरण अनुपलब्ध हैं</string>
|
||||
<string name="transfer">स्थानांतरण</string>
|
||||
<string name="tun_create_error">ट्यून डिवाइस बनाने में असमर्थ</string>
|
||||
<string name="tunnel_config_error">टनल को कॉन्फ़िगर करने में असमर्थ (wg-quick लौटा %d)</string>
|
||||
<string name="tunnel_create_error">टनल बनाने में असमर्थ: %s</string>
|
||||
<string name="tunnel_create_success">सफलतापूर्वक बनाया गया टनल “%s”</string>
|
||||
<string name="tunnel_error_already_exists">टनल “%s” पहले से मौजूद है</string>
|
||||
<string name="tunnel_error_invalid_name">गलत नाम</string>
|
||||
<string name="tunnel_list_placeholder">नीले बटन का उपयोग करके एक टनल को जोड़ें</string>
|
||||
<string name="tunnel_name">टनल का नाम</string>
|
||||
<string name="tunnel_on_error">टनल चालू करने में असमर्थ (wgTurnOn लौटा %d)</string>
|
||||
<string name="tunnel_rename_error">टनल का नाम बदलने में असमर्थ: %s</string>
|
||||
<string name="tunnel_rename_success">सफलतापूर्वक टनल का नाम बदलकर “%s” कर दिया गया</string>
|
||||
<string name="type_name_go_userspace">userspace पे जाए </string>
|
||||
<string name="type_name_kernel_module">कर्नेल मॉड्यूल</string>
|
||||
<string name="unknown_error">अज्ञात त्रुटि</string>
|
||||
<string name="version_summary">%1$s बैकएंड v%2$s</string>
|
||||
<string name="version_summary_checking">%s बैकएंड संस्करण की जाँच कर रहा है</string>
|
||||
<string name="version_summary_unknown">अज्ञात %s संस्करण</string>
|
||||
<string name="version_title">WireGuard for Android v%s</string>
|
||||
<string name="vpn_not_authorized_error">वीपीएन सेवा उपयोगकर्ता द्वारा अधिकृत नहीं है</string>
|
||||
<string name="vpn_start_error">एंड्रॉयड वीपीएन सेवा प्रारंभ करने में असमर्थ</string>
|
||||
<string name="zip_export_error">टनल का निर्यात करने में असमर्थ: %s</string>
|
||||
<string name="zip_export_success">“%s” पर सहेजा गया</string>
|
||||
<string name="zip_export_summary">ज़िप फ़ाइल को डाउनलोड फ़ोल्डर में सहेजा जाएगा</string>
|
||||
<string name="zip_export_title">जिप फाइल के लिए टनल को एक्सपोर्ट करें</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">टनल्स के निर्यात के लिए प्रमाणित करें</string>
|
||||
<string name="biometric_prompt_private_key_title">प्राइवेट की देखने के लिए प्रमाणित करें</string>
|
||||
<string name="biometric_auth_error">प्रमाणीकरण विफलता</string>
|
||||
<string name="biometric_auth_error_reason">प्रमाणीकरण विफल: %s</string>
|
||||
</resources>
|
||||
@@ -105,7 +105,7 @@
|
||||
<string name="hint_random">(ランダム)</string>
|
||||
<string name="illegal_filename_error">不正なファイル名 “%s”</string>
|
||||
<string name="import_error">トンネル設定をインポートできません: %s</string>
|
||||
<string name="import_from_qr_code">QR コードからトンネル設定をインポートできません</string>
|
||||
<string name="import_from_qr_code">QR コードからトンネル設定をインポートします</string>
|
||||
<string name="import_success">“%s” をインポートしました</string>
|
||||
<string name="interface_title">インターフェース</string>
|
||||
<string name="key_contents_error">鍵に不正な文字があります</string>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Kan ikke slette %d tunnel %s</item>
|
||||
<item quantity="other">Kan ikke slette %d tunneler %s</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Alle applikasjoner</string>
|
||||
<string name="exclude_from_tunnel">Ekskluder</string>
|
||||
<string name="include_in_tunnel">Inkluder kun</string>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">hvert %d sekund</item>
|
||||
<item quantity="other">hvert %d sekund</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">sekund</item>
|
||||
<item quantity="other">sekunder</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Bruk alle apper</string>
|
||||
<string name="add_peer">Legg til peer</string>
|
||||
<string name="addresses">Adresser</string>
|
||||
<string name="applications">Applikasjoner</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">%d ਟਨਲ ਹਟਾਉਣ ਲਈ ਅਸਮਰੱਥ: %s</item>
|
||||
<item quantity="other">%d ਟਨਲਾਂ ਹਟਾਉਣ ਲਈ ਅਸਮਰੱਥ: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">%d ਟਨਲ ਕਾਮਯਾਬੀ ਨਾਲ ਹਟਾਈ</item>
|
||||
<item quantity="other">%d ਟਨਲਾਂ ਕਾਮਯਾਬੀ ਨਾਲ ਹਟਾਈਆਂ</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d ਟਨਲ ਚੁਣੀ</item>
|
||||
<item quantity="other">%d ਟਨਲਾਂ ਚੁਣੀਆਂ</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">%2$d ਟਨਲਾਂ ਵਿੱਚੋਂ %1$d ਇੰਪੋਰਟ ਕੀਤੀ</item>
|
||||
<item quantity="other">%2$d ਟਨਲਾਂ ਵਿੱਚੋਂ %1$d ਇੰਪੋਰਟ ਕੀਤੀਆਂ</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">%d ਟਨਲ ਇੰਪੋਰਟ ਕੀਤੀ</item>
|
||||
<item quantity="other">%d ਟਨਲਾਂ ਇੰਪੋਰਟ ਕੀਤੀਆਂ</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d ਅਲਹਿਦਾ ਕੀਤੀ ਐਪਲੀਕੇਸ਼ਨ</item>
|
||||
<item quantity="other">%d ਅਲਹਿਦਾ ਕੀਤੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d ਐਪਲੀਕੇਸ਼ਨ ਸਮੇਤ</item>
|
||||
<item quantity="other">%d ਐਪਲੀਕੇਸ਼ਨਾਂ ਸਮੇਤ</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d ਅਲਹਿਦਾ ਰੱਖਿਆ</item>
|
||||
<item quantity="other">%d ਅਲਹਿਦਾ ਰੱਖੇ</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d ਸਮੇਤ</item>
|
||||
<item quantity="other">%d ਸਮੇਤ</item>
|
||||
</plurals>
|
||||
<string name="all_applications">ਸਾਰੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ</string>
|
||||
<string name="exclude_from_tunnel">ਅਲਹਿਦਾ</string>
|
||||
<string name="include_in_tunnel">ਸਿਰਫ਼ ਸ਼ਾਮਲ</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">%d ਐਪ ਸ਼ਾਮਲ ਕਰੋ</item>
|
||||
<item quantity="other">%d ਐਪਾਂ ਸ਼ਾਮਲ ਕਰੋ</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">%d ਐਪ ਅਲਹਿਦਾ ਰੱਖੋ</item>
|
||||
<item quantity="other">%d ਐਪਾਂ ਅਲਹਿਦਾ ਰੱਖੋ</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">ਹਰ ਸਕਿੰਟ</item>
|
||||
<item quantity="other">ਹਰ %d ਸਕਿੰਟ</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">ਸਕਿੰਟ</item>
|
||||
<item quantity="other">ਸਕਿੰਟ</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">ਸਾਰੀਆਂ ਐਪਾਂ ਵਰਤੋਂ</string>
|
||||
<string name="add_peer">ਪੀਅਰ ਜੋੜੋ</string>
|
||||
<string name="addresses">ਸਿਰਨਾਵੇ</string>
|
||||
<string name="applications">ਐਪਲੀਕੇਸ਼ਨਾਂ</string>
|
||||
<string name="allow_remote_control_intents_summary_off">ਬਾਹਰੀ ਐਪਾਂ ਟਨਲਾਂ ਨੂੰ ਬਦਲ ਨਹੀਂ ਸਕਦੀਆਂ (ਸਿਫਾਰਸ਼ੀ)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">ਬਾਹਰੀ ਐਪਾਂ ਟਨਲਾਂ ਨੂੰ ਬਦਲ ਸਕਦੀਆਂ ਹਨ (ਤਕਨੀਕੀ)</string>
|
||||
<string name="allow_remote_control_intents_title">ਰਿਮੋਟ ਕੰਟਰੋਲ ਐਪਾਂ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ</string>
|
||||
<string name="allowed_ips">ਮਨਜ਼ੂਰ ਕੀਤੇ IP</string>
|
||||
<string name="app_name">ਵਾਇਰਗਾਰਡ</string>
|
||||
<string name="bad_config_context">%1$s ਦੇ %2$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%2$s ਵਿੱਚ %1$s</string>
|
||||
<string name="bad_config_explanation_pka">: ਧਨਾਤਮਕ ਅਤੇ 65535 ਤੋਂ ਘੱਟ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ</string>
|
||||
<string name="bad_config_explanation_positive_number">: ਧਨਾਤਮਕ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ</string>
|
||||
<string name="bad_config_explanation_udp_port">: ਢੁੱਕਵਾਂ UDP ਪੋਰਟ ਨੰਬਰ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ</string>
|
||||
<string name="bad_config_reason_invalid_key">ਗ਼ੈਰਵਾਜਬ ਕੁੰਜੀ</string>
|
||||
<string name="bad_config_reason_invalid_number">ਗ਼ੈਰਵਾਜਬ ਨੰਬਰ</string>
|
||||
<string name="bad_config_reason_invalid_value">ਗ਼ੈਰਵਾਜਬ ਮੁੱਲ</string>
|
||||
<string name="bad_config_reason_missing_attribute">ਨਾ-ਮੌਜੂਦ ਗੁਣ</string>
|
||||
<string name="bad_config_reason_missing_section">ਨਾ-ਮੌਜੂਦ ਚੋਣ</string>
|
||||
<string name="bad_config_reason_syntax_error">ਸੰਟੈਕਸ ਗ਼ਲਤੀ</string>
|
||||
<string name="bad_config_reason_unknown_attribute">ਅਣਪਛਾਤਾ ਗੁਣ</string>
|
||||
<string name="bad_config_reason_unknown_section">ਅਣਪਛਾਤਾ ਭਾਗ</string>
|
||||
<string name="bad_config_reason_value_out_of_range">ਮੁੱਲ ਹੱਦ ਤੋਂ ਬਾਹਰ ਹੈ</string>
|
||||
<string name="bad_extension_error">ਫ਼ਾਇਲ .conf ਜਾਂ .zip ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ</string>
|
||||
<string name="cancel">ਰੱਦ ਕਰੋ</string>
|
||||
<string name="config_delete_error">ਸੰਰਚਨਾ ਫ਼ਾਇਲ %s ਹਟਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ ਹੈ</string>
|
||||
<string name="config_exists_error">“%s” ਲਈ ਸੰਰਚਨਾ ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ</string>
|
||||
<string name="config_file_exists_error">ਸੰਰਚਨਾ ਫ਼ਾਇਲ “%s” ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ</string>
|
||||
<string name="config_not_found_error">ਸੰਰਚਨਾ ਫ਼ਾਇਲ “%s” ਨਹੀਂ ਲੱਭੀ</string>
|
||||
<string name="config_rename_error">ਸੰਰਚਨਾ ਫ਼ਾਇਲ “%s” ਦਾ ਨਾਂ ਨਹੀਂ ਬਦਲਿਆ ਜਾ ਸਕਦਾ ਹੈ</string>
|
||||
<string name="config_save_error"> “%1$s” ਲਈ ਸੰਰਚਨਾ ਫ਼ਾਇਲ ਸੰਭਾਲੀ ਨਹੀਂ ਜਾ ਸਕਦੀ ਹੈ: %2$s</string>
|
||||
<string name="config_save_success">“%s” ਲਈ ਸੰਰਚਨਾ ਕਾਮਯਾਬੀ ਨਾਲ ਸੰਭਾਲੀ ਗਈ ਹੈ</string>
|
||||
<string name="create_activity_title">ਵਾਇਰਗਾਰਡ ਟਨਲ ਬਣਾਓ</string>
|
||||
<string name="create_bin_dir_error">ਲੋਕਲ ਬਾਈਨਰੀ ਡਾਇਰੈਕਟਰੀ ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ ਹੈ</string>
|
||||
<string name="create_downloads_file_error">ਡਾਊਨਲੋਡ ਡਾਇਰੈਕਟਰੀ ਵਿੱਚ ਫ਼ਾਇਲ ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ ਹੈ</string>
|
||||
<string name="create_empty">ਮੁੱਢ ਤੋਂ ਬਣਾਓ</string>
|
||||
<string name="create_from_file">ਫ਼ਾਇਲ ਜਾਂ ਅਕਾਇਵ ਤੋਂ ਦਰਾਮਦ ਕਰੋ</string>
|
||||
<string name="create_from_qr_code">QR ਕੋਡ ਤੋਂ ਸਕੈਨ ਕਰੋ</string>
|
||||
<string name="create_output_dir_error">ਆਉਟਪੁੱਟ ਡਾਇਰੈਕਟਰੀ ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ ਹੈ</string>
|
||||
<string name="create_temp_dir_error">ਲੋਕਲ ਆਰਜ਼ੀ ਡਾਇਰੈਕਟਰੀ ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕਦੀ ਹੈ</string>
|
||||
<string name="create_tunnel">ਟਨਲ ਬਣਾਓ</string>
|
||||
<string name="dark_theme_summary_off">ਇਸ ਵੇਲੇ ਹਲਕਾ (ਦਿਨ) ਥੀਮ ਵਰਤਿਆ ਜਾ ਰਿਹਾ ਹੈ</string>
|
||||
<string name="dark_theme_summary_on">ਇਸ ਵੇਲੇ ਗੂੜ੍ਹਾ (ਰਾਤ) ਥੀਮ ਵਰਤਿਆ ਜਾ ਰਿਹਾ ਹੈ</string>
|
||||
<string name="dark_theme_title">ਗੂੜ੍ਹਾ ਥੀਮ ਵਰਤੋਂ</string>
|
||||
<string name="delete">ਹਟਾਓ</string>
|
||||
<string name="dns_servers">DNS ਸਰਵਰ</string>
|
||||
<string name="edit">ਸੋਧੋ</string>
|
||||
<string name="endpoint">ਐਂਡ-ਪੁਆਇੰਟ</string>
|
||||
<string name="error_down">ਟਨਲ ਬੰਦ ਕਰਨ ਦੌਰਾਨ ਗ਼ਲਤੀ: %s</string>
|
||||
<string name="error_fetching_apps">ਐਪ ਸੂਚੀ ਲੈਣ ਦੌਰਾਨ ਗ਼ਲਤੀ: %s</string>
|
||||
<string name="error_root">ਰੂਟ ਪਹੁੰਚ ਲਵੋ ਅਤੇ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ</string>
|
||||
<string name="error_up">ਟਨਲ ਚਾਲੂ ਕਰਨ ਦੌਰਾਨ ਗ਼ਲਤੀ: %s</string>
|
||||
<string name="exclude_private_ips">ਪ੍ਰਾਈਵੇਟ IP ਅਲਹਿਦਾ ਰੱਖੋ</string>
|
||||
<string name="generate_new_private_key">ਨਵੀਂ ਪ੍ਰਾਈਵੇਟ ਕੁੰਜੀ ਬਣਾਓ</string>
|
||||
<string name="generic_error">ਅਣਪਛਾਤੀ “%s” ਗਲਤੀ</string>
|
||||
<string name="hint_automatic">(ਆਟੋ)</string>
|
||||
<string name="hint_generated">(ਤਿਆਰ ਕੀਤਾ)</string>
|
||||
<string name="hint_optional">(ਚੋਣਵਾਂ)</string>
|
||||
<string name="hint_optional_discouraged">(ਚੋਣਵਾਂ, ਪਰ ਸਿਫਾਰਸ਼ੀ ਨਹੀਂ)</string>
|
||||
<string name="hint_random">(ਰਲਵਾਂ)</string>
|
||||
<string name="illegal_filename_error">ਗ਼ੈਰ-ਵਾਜਬ ਫ਼ਾਇਲ ਨਾਂ \"%s\"</string>
|
||||
<string name="import_error">ਟਨਲ ਇੰਪੋਰਟ ਕਰਨ ਲਈ ਅਸਮਰੱਥ: %s</string>
|
||||
<string name="import_from_qr_code">QR ਕੋਡ ਤੋਂ ਟਨਲ ਇੰਪੋਰਟ ਕਰੋ</string>
|
||||
<string name="import_success">\"%s\" ਇੰਪੋਰਟ ਕੀਤੀ</string>
|
||||
<string name="interface_title">ਇੰਟਰਫੇਸ</string>
|
||||
<string name="key_contents_error">ਕੁੰਜੀ ਵਿੱਚ ਗ਼ਲਤ ਅੱਖਰ</string>
|
||||
<string name="key_length_error">ਗ਼ਲਤ ਕੁੰਜੀ ਦੀ ਲੰਬਾਈ</string>
|
||||
<string name="key_length_explanation_base64">: WireGuard base64 ਕੁੰਜੀਆਂ ਵਿੱਚ 44 ਅੱਖਰ ਹੋਣੇ ਚਾਹੀਦੇ ਹਨ (32 ਬਾਈਟ)</string>
|
||||
<string name="key_length_explanation_binary">: WireGuard ਕੁੰਜੀਆਂ 32 ਬਾਈਟ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ</string>
|
||||
<string name="key_length_explanation_hex">: WireGuard ਹੈਕਸਾ ਕੁੰਜੀਆਂ ਵਿੱਚ 64 ਅੱਖਰ ਹੋਣੇ ਚਾਹੀਦੇ ਹਨ (32 ਬਾਈਟ)</string>
|
||||
<string name="listen_port">ਸੁਣਨ ਵਾਲੀ ਪੋਰਟ</string>
|
||||
<string name="log_export_error">ਲਾਗ ਐਕਸਪੋਰਟ ਕਰਨ ਲਈ ਅਸਮਰੱਥ: %s</string>
|
||||
<string name="log_export_subject">ਵਾਇਰਗਾਰਡ ਐਂਡਰਾਈਡ ਲਾਗ ਫ਼ਾਇਲ</string>
|
||||
<string name="log_export_success">“%s” ਵਜੋਂ ਸੰਭਾਲਿਆ ਗਿਆ</string>
|
||||
<string name="log_export_title">ਲਾਗ ਫ਼ਾਇਲ ਬਰਾਮਦ ਕਰੋ</string>
|
||||
<string name="log_saver_activity_label">ਲਾਗ ਸੰਭਾਲੋ</string>
|
||||
<string name="log_viewer_pref_summary">ਲਾਗ ਡੀਬੱਗ ਕਰਨ ਲਈ ਸਹਾਇਤਾ ਕਰ ਸਕਦੇ ਹਨ</string>
|
||||
<string name="log_viewer_pref_title">ਐਪਲੀਕੇਸ਼ਨ ਲਾਗ ਵੇਖੋ</string>
|
||||
<string name="log_viewer_title">ਲਾਗ</string>
|
||||
<string name="logcat_error">logcat ਚਲਾਉਣ ਲਈ ਅਸਮਰੱਥ: </string>
|
||||
<string name="module_disabler_disabled_summary">ਤਜਰਬੇ ਅਧੀਨ ਕਰਨਲ ਮੋਡੀਊਲ ਕਾਰਗੁਜ਼ਾਰੀ ਸੁਧਾਰ ਸਕਦਾ ਹੈ</string>
|
||||
<string name="module_disabler_disabled_title">ਕਰਨਲ ਮੋਡੀਊਲ ਬੈਕਐਂਡ ਸਮਰੱਥ ਕਰੋ</string>
|
||||
<string name="module_disabler_enabled_summary">ਹੌਲੀ ਵਰਤੋਂਕਾਰ-ਸਪੇਸ ਬੈਂਕਡ ਸਥਿਰਤਾ ਸੁਧਾਰ ਕਰ ਸਕਦਾ ਹੈ</string>
|
||||
<string name="module_disabler_enabled_title">ਕਰਨਲ ਮੋਡੀਊਲ ਬੈਕਐਂਡ ਅਸਮਰੱਥ ਕਰੋ</string>
|
||||
<string name="module_installer_error">ਕੁਝ ਗਲਤ ਵਾਪਰ ਗਿਆ। ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ</string>
|
||||
<string name="module_installer_initial">ਤਜਰਬੇ ਅਧੀਨ ਕਰਨਲ ਮੋਡੀਊਲ ਕਾਰਗੁਜ਼ਾਰੀ ਸੁਧਾਰ ਸਕਦਾ ਹੈ</string>
|
||||
<string name="module_installer_not_found">ਤੁਹਾਡੇ ਡਿਵਾਈਸ ਲਈ ਕੋਈ ਮੋਡੀਊਲ ਮੌਜੂਦ ਨਹੀਂ ਹਨ</string>
|
||||
<string name="module_installer_title">ਕਰਨਲ ਮੋਡੀਊਲ ਡਾਊਨਲੋਡ ਕਰਕੇ ਇੰਸਟਾਲ ਕਰੋ</string>
|
||||
<string name="module_installer_working">ਡਾਊਨਲੋਡ ਤੇ ਇੰਸਟਾਲ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ…</string>
|
||||
<string name="module_version_error">ਕਰਨਲ ਮੋਡੀਊਲ ਵਰਜ਼ਨ ਪਤਾ ਲਗਾਉਣ ਲਈ ਅਸਮਰੱਥ ਹੈ</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">ਇੱਕ ਟਨਲ ਨੂੰ ਚਾਲੂ ਕਰਨ ਨਾਲ ਹੋਰ ਬੰਦ ਹੋ ਜਾਣਗੀਆਂ</string>
|
||||
<string name="multiple_tunnels_summary_on">ਕਈ ਟਨਲਾਂ ਇੱਕੋ ਸਮੇਂ ਵੀ ਚਾਲੂ ਕੀਤੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ</string>
|
||||
<string name="multiple_tunnels_title">ਇੱਕੋ ਸਮੇਂ ਕਈ ਟਨਲਾਂ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ</string>
|
||||
<string name="name">ਨਾਂ</string>
|
||||
<string name="no_config_error">ਬਿਨਾਂ ਸੰਰਚਨਾ ਦੇ ਟਲਨ ਨੂੰ ਚਾਲੂ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ</string>
|
||||
<string name="no_configs_error">ਕੋਈ ਸੰਰਚਨਾ ਨਹੀਂ ਲੱਭੀ</string>
|
||||
<string name="no_tunnels_error">ਕੋਈ ਟਨਲ ਮੌਜੂਦ ਨਹੀਂ ਹੈ</string>
|
||||
<string name="parse_error_generic">ਸਤਰ</string>
|
||||
<string name="parse_error_inet_address">IP ਸਿਰਨਾਵਾਂ</string>
|
||||
<string name="parse_error_inet_endpoint">ਐਂਡ-ਪੁਆਇੰਟ</string>
|
||||
<string name="parse_error_inet_network">IP ਨੈੱਟਵਰਕ</string>
|
||||
<string name="parse_error_integer">ਨੰਬਰ</string>
|
||||
<string name="parse_error_reason">%1$s “%2$s” ਨੂੰ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ</string>
|
||||
<string name="peer">ਪੀਅਰ</string>
|
||||
<string name="permission_description">ਵਾਇਰਗਾਰਡ ਟਨਲਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ, ਮਨਮਰਜ਼ੀ ਮੁਤਾਬਕ ਟਨਲਾਂ ਨੂੰ ਸਮਰੱਥ ਤੇ ਅਸਮਰੱਥ ਕਰੋ, ਸੰਭਾਵਿਤ ਇੰਟਰਨੈੱਟ ਟਰੈਫਿਕ ਦੀ ਦਿਸ਼ਾ ਬਦਲੋ</string>
|
||||
<string name="permission_label">ਵਾਇਰਗਰਾਡ ਟਨਲਾਂ ਕੰਟਰੋਲ ਕਰੋ</string>
|
||||
<string name="persistent_keepalive">ਸਥਿਰ ਲਗਾਤਾਰ ਜਾਰੀ ਰੱਖੋ</string>
|
||||
<string name="pre_shared_key">ਪਹਿਲਾਂ-ਸਾਂਝੀ ਕੀਤੀ ਕੁੰਜੀ</string>
|
||||
<string name="pre_shared_key_enabled">ਸਮਰੱਥ ਹੈ</string>
|
||||
<string name="private_key">ਪ੍ਰਾਈਵੇਟ ਕੁੰਜੀ</string>
|
||||
<string name="public_key">ਪਬਲਿਕ ਕੁੰਜੀ</string>
|
||||
<string name="qr_code_hint">ਟੋਟਕਾ: `qrencode -t ansiutf8 < tunnel.conf` ਨਾਲ ਤਿਆਰ ਕਰੋ।</string>
|
||||
<string name="restore_on_boot_summary_off">ਬੂਟ ਕਰਨ ਸਮੇਂ ਸਮਰੱਥ ਕੀਤੀਆਂ ਟਨਲਾਂ ਨੂੰ ਚਾਲੂ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ</string>
|
||||
<string name="restore_on_boot_summary_on">ਬੂਟ ਕਰਨ ਸਮੇਂ ਸਮਰੱਥ ਕੀਤੀਆਂ ਟਨਲਾਂ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਜਾਵੇਗਾ</string>
|
||||
<string name="restore_on_boot_title">ਬੂਟ ਕਰਨ ਉੱਤੇ ਬਹਾਲ ਕਰੋ</string>
|
||||
<string name="save">ਸੰਭਾਲੋ</string>
|
||||
<string name="select_all">ਸਾਰੇ ਚੁਣੋ</string>
|
||||
<string name="settings">ਸੈਟਿੰਗਾਂ</string>
|
||||
<string name="shell_exit_status_read_error">ਸ਼ੈਲ ਬਾਹਰ ਜਾਣ (exit) ਸਥਿਤੀ ਪੜ੍ਹ ਨਹੀਂ ਸਕਦੀ</string>
|
||||
<string name="shell_marker_count_error">ਸ਼ੈਲ 4 ਮਾਰਕਰਾਂ ਦੀ ਉਮੀਦ ਕਰਦੀ ਸੀ, %d ਮਿਲੇ</string>
|
||||
<string name="shell_start_error">ਸ਼ੈਲ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਅਸਫ਼ਲ ਹੈ: %d</string>
|
||||
<string name="success_application_will_restart">ਕਾਮਯਾਬ। ਐਪਲੀਕੇਸ਼ਨ ਹੁਣ ਮੁੜ-ਚਾਲੂ ਹੋਵੇਗੀ…</string>
|
||||
<string name="toggle_all">ਸਭ ਪਲਟੋ</string>
|
||||
<string name="toggle_error">ਵਾਇਰਗਾਰਡ ਟਨਲ ਬਦਲਣ ਦੌਰਾਨ ਗ਼ਲਤੀ: %s</string>
|
||||
<string name="tools_installer_already">wg ਅਤੇ wg-quick ਪਹਿਲਾਂ ਹੀ ਇੰਸਟਾਲ ਹਨ</string>
|
||||
<string name="tools_installer_failure">ਕਮਾਂਡ-ਲਾਈਨ ਟੂਲ ਇੰਸਟਾਲ ਕਰਨ ਲਈ ਅਸਮਰੱਥ (ਰੂਟ ਨਹੀਂ ਹੋ?)</string>
|
||||
<string name="tools_installer_initial">ਸਕ੍ਰਿਪਟ ਲਿਖਣ ਲਈ ਚੋਣਵੇਂ ਟੂਲ ਇੰਸਟਾਲ ਕਰੋ</string>
|
||||
<string name="tools_installer_initial_magisk">Magisk ਮੋਡੀਊਲ ਵਜੋਂ ਸਕ੍ਰਿਪਟਾਂ ਲਿਖਣ ਲਈ ਚੋਣਵੇਂ ਟੂਲ ਇੰਸਟਾਲ ਕਰੋ</string>
|
||||
<string name="tools_installer_initial_system">ਸਿਸਟਮ ਪਾਰਟੀਸ਼ਨ ਵਿੱਚ ਸਕ੍ਰਿਪਟ ਲਿਖਣ ਲਈ ਚੋਣਵੇਂ ਟੂਲ ਇੰਸਟਾਲ ਕਰੋ</string>
|
||||
<string name="tools_installer_success_magisk">wg ਅਤੇ wg-quick ਨੂੰ Magisk ਮੋਡੀਊਲ ਵਜੋਂ ਇੰਸਟਾਲ ਕੀਤਾ (ਮੁੜ-ਚਾਲੂ ਕਰਨ ਦੀ ਲੋੜ ਹੋਵੇਗੀ)</string>
|
||||
<string name="tools_installer_success_system">wg ਅਤੇ wg-quick ਨੂੰ ਸਿਸਟਮ ਪਾਰਟੀਸ਼ਨ ਵਿੱਚ ਇੰਸਟਾਲ ਕੀਤਾ</string>
|
||||
<string name="tools_installer_title">ਕਮਾਂਡ ਲਾਈਨ ਟੂਲ ਇੰਸਟਾਲ ਕਰੋ</string>
|
||||
<string name="tools_installer_working">wg ਤੇ wg-quick ਇੰਸਟਾਲ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ</string>
|
||||
<string name="tools_unavailable_error">ਚਾਹੀਦੇ ਟੂਲ ਮੌਜੂਦ ਨਹੀਂ ਹਨ</string>
|
||||
<string name="transfer">ਟਰਾਂਸਫਰ</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">tun ਡਿਵਾਈਸ ਬਣਾਉਣ ਲਈ ਅਸਮਰੱਥ</string>
|
||||
<string name="tunnel_config_error">ਟਨਲ ਦੀ ਸੰਰਚਨਾ ਕਰਨ ਲਈ ਅਸਮਰੱਥ (wg-quick ਨੇ %d ਵਾਪਸ ਕੀਤਾ)</string>
|
||||
<string name="tunnel_create_error">ਟਨਲ ਬਣਾਉਣ ਲਈ ਅਸਮਰੱਥ: %s</string>
|
||||
<string name="tunnel_create_success">“%s” ਟਨਲ ਕਾਮਯਾਬੀ ਨਾਲ ਬਣਾਈ</string>
|
||||
<string name="tunnel_error_already_exists">ਟਨਲ “%s” ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ</string>
|
||||
<string name="tunnel_error_invalid_name">ਅਯੋਗ ਨਾਂ</string>
|
||||
<string name="tunnel_list_placeholder">ਨੀਲੇ ਬਟਨ ਨੂੰ ਵਰਤ ਕੇ ਟਨਲ ਬਣਾਓ</string>
|
||||
<string name="tunnel_name">ਟਨਲ ਦਾ ਨਾਂ</string>
|
||||
<string name="tunnel_on_error">ਟਨਲ ਚਾਲੂ ਕਰਨ ਲਈ ਅਸਮਰੱਥ (wgTurnOn ਨੇ %d ਵਾਪਸ ਕੀਤਾ)</string>
|
||||
<string name="tunnel_rename_error">ਟਨਲ ਨਾਂ-ਬਦਲਣ ਲਈ ਅਸਮਰੱਥ: %s</string>
|
||||
<string name="tunnel_rename_success">ਟਨਲ ਦਾ ਨਾਂ \"%s\" ਵਜੋਂ ਕਾਮਯਾਬੀ ਨਾਲ ਬਦਲਿਆ ਗਿਆ</string>
|
||||
<string name="type_name_go_userspace">ਵਰਤੋਂ-ਸਪੇਸ ਤੇ ਜਾਓ</string>
|
||||
<string name="type_name_kernel_module">ਕਰਨਲ ਮੋਡੀਊਲ</string>
|
||||
<string name="unknown_error">ਅਣਪਛਾਤੀ ਗਲਤੀ</string>
|
||||
<string name="version_summary">%1$s ਬੈਕਐਂਡ v%2$s</string>
|
||||
<string name="version_summary_checking">%s ਬੈਕਐਂਡ ਵਰਜ਼ਨ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ</string>
|
||||
<string name="version_summary_unknown">ਅਣਪਛਾਤਾ %s ਵਰਜਨ</string>
|
||||
<string name="version_title">Android ਲਈ WireGuard v%s</string>
|
||||
<string name="vpn_not_authorized_error">VPN ਸੇਵਾ ਨੂੰ ਵਰਤੋਂਕਾਰ ਨੇ ਪਰਮਾਣਿਤ ਨਹੀਂ ਕੀਤਾ</string>
|
||||
<string name="vpn_start_error">ਐਂਡਰਾਈਡ VPN ਸੇਵਾ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਅਸਮਰੱਥ</string>
|
||||
<string name="zip_export_error">ਟਨਲਾਂ ਐਕਸਪੋਰਟ ਕਰਨ ਲਈ ਅਸਮਰੱਥ: %s</string>
|
||||
<string name="zip_export_success">“%s” ਉੱਤੇ ਸੰਭਾਲਿਆ ਗਿਆ</string>
|
||||
<string name="zip_export_summary">ਜ਼ਿਪ ਫਾਈਲ ਨੂੰ ਡਾਊਨਲੋਡ ਫੋਲਡਰ ਵਿੱਚ ਸੰਭਾਲਿਆ ਜਾਵੇਗਾ</string>
|
||||
<string name="zip_export_title">ਟਨਲ ਨੂੰ ਜ਼ਿੱਪ ਫ਼ਾਇਲ ਵਜੋਂ ਬਰਾਮਦ ਕਰੋ</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">ਟਨਲ ਬਰਾਮਦ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ</string>
|
||||
<string name="biometric_prompt_private_key_title">ਪ੍ਰਾਈਵੇਟ ਕੁੰਜੀ ਵੇਖਣ ਲਈ ਪਰਮਾਣਕਿਤਾ</string>
|
||||
<string name="biometric_auth_error">ਪਰਮਾਣਿਤ ਕਰਨ ਲਈ ਅਸਫ਼ਲ</string>
|
||||
<string name="biometric_auth_error_reason">ਪਰਮਾਣਿਤ ਕਰਨ ਲਈ ਅਸਫ਼ਲ: %s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,255 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Nie można usunąć %d tunelu: %s</item>
|
||||
<item quantity="few">Nie można usunąć %d tuneli: %s</item>
|
||||
<item quantity="many">Nie można usunąć %d tuneli: %s</item>
|
||||
<item quantity="other">Nie można usunąć %d tuneli: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">Pomyślnie usunięto tunel %d</item>
|
||||
<item quantity="few">Pomyślnie usunięto %d tunele</item>
|
||||
<item quantity="many">Pomyślnie usunięto %d tuneli</item>
|
||||
<item quantity="other">Pomyślnie usunięto %d tuneli</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d wybrany tunel</item>
|
||||
<item quantity="few">%d wybranych tuneli</item>
|
||||
<item quantity="many">%d wybranych tuneli</item>
|
||||
<item quantity="other">%d wybranych tuneli</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">Zaimportowano %1$d z %2$d tuneli</item>
|
||||
<item quantity="few">Zaimportowano %1$d z %2$d tuneli</item>
|
||||
<item quantity="many">Zaimportowano %1$d z %2$d tuneli</item>
|
||||
<item quantity="other">Zaimportowano %1$d z %2$d tuneli</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">Zaimportowano %d tunel</item>
|
||||
<item quantity="few">Zaimportowano %d tunele</item>
|
||||
<item quantity="many">Zaimportowano %d tuneli</item>
|
||||
<item quantity="other">Zaimportowano %d tuneli</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d wykluczona aplikacja</item>
|
||||
<item quantity="few">%d wykluczone aplikacje</item>
|
||||
<item quantity="many">%d wykluczonych aplikacji</item>
|
||||
<item quantity="other">%d wykluczonych aplikacji</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d dołączona aplikacja</item>
|
||||
<item quantity="few">%d dołączone aplikacje</item>
|
||||
<item quantity="many">%d dołączonych aplikacji</item>
|
||||
<item quantity="other">%d dołączonych aplikacji</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d wykluczona</item>
|
||||
<item quantity="few">%d wykluczone</item>
|
||||
<item quantity="many">%d wykluczonych</item>
|
||||
<item quantity="other">%d wykluczonych</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d dołączona</item>
|
||||
<item quantity="few">%d dołączone</item>
|
||||
<item quantity="many">%d dołączonych</item>
|
||||
<item quantity="other">%d dołączonych</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Wszystkie aplikacje</string>
|
||||
<string name="exclude_from_tunnel">Wyklucz</string>
|
||||
<string name="include_in_tunnel">Dołącz tylko</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Dołącz %d aplikację</item>
|
||||
<item quantity="few">Dołącz %d aplikacje</item>
|
||||
<item quantity="many">Dołącz %d aplikacji</item>
|
||||
<item quantity="other">Dołącz %d aplikacji</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Wyklucz %d aplikację</item>
|
||||
<item quantity="few">Wyklucz %d aplikacje</item>
|
||||
<item quantity="many">Wyklucz %d aplikacji</item>
|
||||
<item quantity="other">Wyklucz %d aplikacji</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">co sekundę</item>
|
||||
<item quantity="few">co %d sekundy</item>
|
||||
<item quantity="many">co %d sekund</item>
|
||||
<item quantity="other">co %d sekund</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">sekunda</item>
|
||||
<item quantity="few">sekundy</item>
|
||||
<item quantity="many">sekund</item>
|
||||
<item quantity="other">sekundy</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Używaj wszystkich aplikacji</string>
|
||||
<string name="add_peer">Dodaj Peer\'a</string>
|
||||
<string name="addresses">Adresy</string>
|
||||
<string name="applications">Aplikacje</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Zewnętrzne aplikacje nie mogą przełączać tuneli (zalecane)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Zewnętrzne aplikacje mogą przełączać tunele (zaawansowane)</string>
|
||||
<string name="allow_remote_control_intents_title">Zezwól na kontrolowanie przez zewnętrzne aplikacje</string>
|
||||
<string name="allowed_ips">Dozwolone adresy IP</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$s dla %2$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%1$s w %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Musi być dodatnia i nie większa niż 65535</string>
|
||||
<string name="bad_config_explanation_positive_number">: Musi być dodatni</string>
|
||||
<string name="bad_config_explanation_udp_port">: Musi być poprawnym numerem portu UDP</string>
|
||||
<string name="bad_config_reason_invalid_key">Nieprawidłowy klucz</string>
|
||||
<string name="bad_config_reason_invalid_number">Numer jest nieprawidłowy</string>
|
||||
<string name="bad_config_reason_invalid_value">Nieprawidłowa wartość</string>
|
||||
<string name="bad_config_reason_missing_attribute">Brakujący atrybut</string>
|
||||
<string name="bad_config_reason_missing_section">Brakująca sekcja</string>
|
||||
<string name="bad_config_reason_syntax_error">Błąd składni</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Nieznany atrybut</string>
|
||||
<string name="bad_config_reason_unknown_section">Nieznana sekcja</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Wartość poza zakresem</string>
|
||||
<string name="bad_extension_error">Plik musi być .conf lub .zip</string>
|
||||
<string name="cancel">Anuluj</string>
|
||||
<string name="config_delete_error">Nie można usunąć pliku konfiguracyjnego %s</string>
|
||||
<string name="config_exists_error">Konfiguracja dla \"%s\" już istnieje</string>
|
||||
<string name="config_file_exists_error">Plik konfiguracyjny \"%s\" już istnieje</string>
|
||||
<string name="config_not_found_error">Plik konfiguracyjny \"%s\" nie został znaleziony</string>
|
||||
<string name="config_rename_error">Nie można zmienić nazwy pliku konfiguracyjnego \"%s\"</string>
|
||||
<string name="config_save_error">Nie można zapisać konfiguracji dla \"%1$s\": %2$s</string>
|
||||
<string name="config_save_success">Pomyślnie zapisano konfigurację dla \"%s\"</string>
|
||||
<string name="create_activity_title">Utwórz tunel WireGuard</string>
|
||||
<string name="create_bin_dir_error">Nie można stworzyć tymczasowego folderu lokalnego</string>
|
||||
<string name="create_downloads_file_error">Nie można utworzyć pliku w folderze pobierania</string>
|
||||
<string name="create_empty">Utwórz od podstaw</string>
|
||||
<string name="create_from_file">Utwórz z pliku lub archiwum</string>
|
||||
<string name="create_from_qr_code">Zeskanuj kod QR</string>
|
||||
<string name="create_output_dir_error">Nie można utworzyć folderu wyjściowego</string>
|
||||
<string name="create_temp_dir_error">Nie można stworzyć tymczasowego folderu lokalnego</string>
|
||||
<string name="create_tunnel">Utwórz Tunel</string>
|
||||
<string name="dark_theme_summary_off">Obecnie używasz jasnego (dzień) motywu</string>
|
||||
<string name="dark_theme_summary_on">Obecnie używa ciemnego (nocnego) motywu</string>
|
||||
<string name="dark_theme_title">Użyj ciemnego motywu</string>
|
||||
<string name="delete">Usuń</string>
|
||||
<string name="dns_servers">Serwery DNS</string>
|
||||
<string name="edit">Edytuj</string>
|
||||
<string name="endpoint">Punkt końcowy</string>
|
||||
<string name="error_down">Błąd podczas zamykania tunelu: %s</string>
|
||||
<string name="error_fetching_apps">Błąd podczas pobierania listy aplikacji: %s</string>
|
||||
<string name="error_root">Proszę uzyskać dostęp do root\'a i spróbować ponownie</string>
|
||||
<string name="error_up">Błąd podczas włączania tunelu: %s</string>
|
||||
<string name="exclude_private_ips">Wyklucz prywatne adresy IP</string>
|
||||
<string name="generate_new_private_key">Wygeneruj nowy klucz prywatny</string>
|
||||
<string name="generic_error">Nieznany błąd \"%s\"</string>
|
||||
<string name="hint_automatic">(automatycznie)</string>
|
||||
<string name="hint_generated">(wygenerowane)</string>
|
||||
<string name="hint_optional">(opcjonalnie)</string>
|
||||
<string name="hint_optional_discouraged">(opcjonalnie, niezalecane)</string>
|
||||
<string name="hint_random">(losowy)</string>
|
||||
<string name="illegal_filename_error">Niedozwolona nazwa pliku \"%s\"</string>
|
||||
<string name="import_error">Nie można zaimportować tunelu: %s</string>
|
||||
<string name="import_from_qr_code">Importuj tunel za pomocą kodu QR</string>
|
||||
<string name="import_success">Zaimportowano \"%s\"</string>
|
||||
<string name="interface_title">Interfejs</string>
|
||||
<string name="key_contents_error">Niepoprawne znaki w kluczu</string>
|
||||
<string name="key_length_error">Niewłaściwa długość klucza</string>
|
||||
<string name="key_length_explanation_base64">: klucze base64 WireGuard\'a muszą mieć długość 44 znaków (32 bajty)</string>
|
||||
<string name="key_length_explanation_binary">: klucze WireGuard\'a muszą wynosić 32 bajty</string>
|
||||
<string name="key_length_explanation_hex">: klucze hex WireGuard\'a muszą mieć długość 64 znaków (32 bajty)</string>
|
||||
<string name="listen_port">Port nasłuchu</string>
|
||||
<string name="log_export_error">Nie można wyeksportować logu: %s</string>
|
||||
<string name="log_export_subject">Plik logu programu WireGuard dla systemu Android</string>
|
||||
<string name="log_export_success">Zapisano w \"%s\"</string>
|
||||
<string name="log_export_title">Wyeksportuj plik logu</string>
|
||||
<string name="log_saver_activity_label">Zapisz log</string>
|
||||
<string name="log_viewer_pref_summary">Logi mogą pomóc w debugowaniu</string>
|
||||
<string name="log_viewer_pref_title">Wyświetl log aplikacji</string>
|
||||
<string name="log_viewer_title">Log</string>
|
||||
<string name="logcat_error">Nie można uruchomić logcat: </string>
|
||||
<string name="module_disabler_disabled_summary">Eksperymentalny moduł jądra może poprawić wydajność</string>
|
||||
<string name="module_disabler_disabled_title">Włącz moduł jądra</string>
|
||||
<string name="module_disabler_enabled_summary">Wolniejsza implementacja w przestrzeni użytkownika może poprawić stabilność</string>
|
||||
<string name="module_disabler_enabled_title">Wyłącz moduł jądra</string>
|
||||
<string name="module_installer_error">Coś poszło nie tak. Proszę spróbować ponownie</string>
|
||||
<string name="module_installer_initial">Eksperymentalny moduł jądra może poprawić wydajność</string>
|
||||
<string name="module_installer_not_found">Brak dostępnych modułów dla twojego urządzenia</string>
|
||||
<string name="module_installer_title">Pobierz i zainstaluj moduł jądra</string>
|
||||
<string name="module_installer_working">Pobieranie i instalowanie…</string>
|
||||
<string name="module_version_error">Nie można określić wersji modułu jądra</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Włączenie jednego tunelu spowoduje wyłączenie innych</string>
|
||||
<string name="multiple_tunnels_summary_on">Wiele tuneli może być włączonych jednocześnie</string>
|
||||
<string name="multiple_tunnels_title">Zezwalaj na wiele tuneli równoległych</string>
|
||||
<string name="name">Nazwa</string>
|
||||
<string name="no_config_error">Próba przywołania tunelu bez konfiguracji</string>
|
||||
<string name="no_configs_error">Nie odnaleziono żadnych konfiguracji</string>
|
||||
<string name="no_tunnels_error">Brak tuneli</string>
|
||||
<string name="parse_error_generic">ciągu</string>
|
||||
<string name="parse_error_inet_address">Adresy IP</string>
|
||||
<string name="parse_error_inet_endpoint">punkt końcowy</string>
|
||||
<string name="parse_error_inet_network">Sieć IP</string>
|
||||
<string name="parse_error_integer">numer</string>
|
||||
<string name="parse_error_reason">Nie można przetworzyć %1$s „%2$s”</string>
|
||||
<string name="peer">Peer</string>
|
||||
<string name="permission_description">kontrolowanie tuneli WireGuard, włączanie i wyłączanie tuneli, potencjalnie błędne kierowanie ruchem internetowym</string>
|
||||
<string name="permission_label">sterowanie tunelami WireGuard</string>
|
||||
<string name="persistent_keepalive">Utrzymanie połączenia</string>
|
||||
<string name="pre_shared_key">Klucz wstępnie udostępniony</string>
|
||||
<string name="pre_shared_key_enabled">włączone</string>
|
||||
<string name="private_key">Klucz prywatny</string>
|
||||
<string name="public_key">Klucz publiczny</string>
|
||||
<string name="qr_code_hint">Wskazówka: wygeneruj za pomocą `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_off">Włączone tunele nie zostaną przywrócone przy uruchomieniu</string>
|
||||
<string name="restore_on_boot_summary_on">Włączone tunele zostaną przywrócone przy uruchomieniu</string>
|
||||
<string name="restore_on_boot_title">Przywróć przy uruchomieniu</string>
|
||||
<string name="save">Zapisz</string>
|
||||
<string name="select_all">Wybierz wszystko</string>
|
||||
<string name="settings">Ustawienia</string>
|
||||
<string name="shell_exit_status_read_error">Powłoka nie może odczytać statusu wyjścia</string>
|
||||
<string name="shell_marker_count_error">Powłoka spodziewała się 4 znaczników, otrzymano %d</string>
|
||||
<string name="shell_start_error">Nie udało się uruchomić powłoki: %d</string>
|
||||
<string name="success_application_will_restart">Ukończono pomyślnie. Aplikacja zostanie uruchomiona ponownie…</string>
|
||||
<string name="toggle_all">Przełącz wszystkie</string>
|
||||
<string name="toggle_error">Błąd podczas przełączania tunelu WireGuard: %s</string>
|
||||
<string name="tools_installer_already">wg i wg-quick są już zainstalowane</string>
|
||||
<string name="tools_installer_failure">Nie można zainstalować narzędzi wiersza poleceń (brak root\'a?)</string>
|
||||
<string name="tools_installer_initial">Zainstaluj opcjonalne narzędzia do tworzenia skryptów</string>
|
||||
<string name="tools_installer_initial_magisk">Zainstaluj opcjonalne narzędzia do tworzenia skryptów jako moduł Magisk</string>
|
||||
<string name="tools_installer_initial_system">Zainstaluj opcjonalne narzędzia do tworzenia skryptów w partycji systemowej</string>
|
||||
<string name="tools_installer_success_magisk">wg i wg-quick zostały zainstalowane jako moduł Magisk (wymagane ponowne uruchomienie)</string>
|
||||
<string name="tools_installer_success_system">wg i wg-quick zostały zainstalowane w partycji systemowej</string>
|
||||
<string name="tools_installer_title">Zainstaluj narzędzia wiersza poleceń</string>
|
||||
<string name="tools_installer_working">Instalowanie wg i wg-quick</string>
|
||||
<string name="tools_unavailable_error">Wymagane narzędzia są niedostępne</string>
|
||||
<string name="transfer">Transfer</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">odebrano: %1$s, wysłano: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">Nie można utworzyć urządzenia tun</string>
|
||||
<string name="tunnel_config_error">Nie można skonfigurować tunelu (wg-quick zwróciło %d)</string>
|
||||
<string name="tunnel_create_error">Nie można utworzyć tunelu: %s</string>
|
||||
<string name="tunnel_create_success">Pomyślnie utworzono tunel \"%s\"</string>
|
||||
<string name="tunnel_error_already_exists">Tunel \"%s\" już istnieje</string>
|
||||
<string name="tunnel_error_invalid_name">Nieprawidłowa nazwa</string>
|
||||
<string name="tunnel_list_placeholder">Dodaj tunel za pomocą niebieskiego przycisku</string>
|
||||
<string name="tunnel_name">Nazwa tunelu</string>
|
||||
<string name="tunnel_on_error">Nie można włączyć tunelu (wgTurnOn zwróciło %d)</string>
|
||||
<string name="tunnel_rename_error">Nie można zmienić nazwy tunelu: %s</string>
|
||||
<string name="tunnel_rename_success">Pomyślnie zmieniono nazwę tunelu na \"%s\"</string>
|
||||
<string name="type_name_go_userspace">Przestrzeń użytkownika Go</string>
|
||||
<string name="type_name_kernel_module">Moduł jądra</string>
|
||||
<string name="unknown_error">Nieznany błąd</string>
|
||||
<string name="version_summary">Implementacja %1$s v%2$s</string>
|
||||
<string name="version_summary_checking">Sprawdzanie wersji %s implementacji</string>
|
||||
<string name="version_summary_unknown">Nieznana %s wersja</string>
|
||||
<string name="version_title">WireGuard dla systemu Android v%s</string>
|
||||
<string name="vpn_not_authorized_error">Usługa VPN nie została autoryzowana przez użytkownika</string>
|
||||
<string name="vpn_start_error">Nie można uruchomić usługi VPN systemu Android</string>
|
||||
<string name="zip_export_error">Nie można wyeksportować tuneli: %s</string>
|
||||
<string name="zip_export_success">Zapisano w \"%s\"</string>
|
||||
<string name="zip_export_summary">Plik ZIP zostanie zapisany w folderze pobierania</string>
|
||||
<string name="zip_export_title">Wyeksportuj tunele do pliku ZIP</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Uwierzytelnij, aby wyeksportować tunele</string>
|
||||
<string name="biometric_prompt_private_key_title">Uwierzytelnij, aby zobaczyć klucz prywatny</string>
|
||||
<string name="biometric_auth_error">Błąd uwierzytelnienia</string>
|
||||
<string name="biometric_auth_error_reason">Błąd uwierzytelnienia: %s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,242 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Nu se poate șterge %d tunel: %s</item>
|
||||
<item quantity="few">Nu se pot șterge %d tunele: %s</item>
|
||||
<item quantity="other">Nu se pot șterge %d de tunele: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">%d tunel a fost șters</item>
|
||||
<item quantity="few">%d tunele șterse</item>
|
||||
<item quantity="other">%d de tunele șterse</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d tunel selectat</item>
|
||||
<item quantity="few">%d tuneluri selectate</item>
|
||||
<item quantity="other">%d de tuneluri selectate</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">%1$d din %2$d tuneluri importate</item>
|
||||
<item quantity="few">%1$d din %2$d tuneluri importate</item>
|
||||
<item quantity="other">%1$d din %2$d de tuneluri importate</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">%d tunel importat</item>
|
||||
<item quantity="few">%d tuneluri importate</item>
|
||||
<item quantity="other">%d de tuneluri importate</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d aplicație exclusă</item>
|
||||
<item quantity="few">%d aplicații excluse</item>
|
||||
<item quantity="other">%d de aplicații excluse</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d aplicație inclusă</item>
|
||||
<item quantity="few">%d aplicații incluse</item>
|
||||
<item quantity="other">%d de aplicații incluse</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d exclusă</item>
|
||||
<item quantity="few">%d excluse</item>
|
||||
<item quantity="other">%d excluse</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d inclusă</item>
|
||||
<item quantity="few">%d incluse</item>
|
||||
<item quantity="other">%d incluse</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Toate aplicațiile</string>
|
||||
<string name="exclude_from_tunnel">Excludere</string>
|
||||
<string name="include_in_tunnel">Includere numai</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Include %d aplicație</item>
|
||||
<item quantity="few">Include %d aplicații</item>
|
||||
<item quantity="other">Include %d de aplicații</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Exclude %d aplicație</item>
|
||||
<item quantity="few">Exclude %d aplicații</item>
|
||||
<item quantity="other">Exclude %d de aplicații</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">în fiecare secundă</item>
|
||||
<item quantity="few">la fiecare %d secunde</item>
|
||||
<item quantity="other">la fiecare %d secunde</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">secundă</item>
|
||||
<item quantity="few">secunde</item>
|
||||
<item quantity="other">secunde</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Utilizează toate aplicațiile</string>
|
||||
<string name="add_peer">Adăugare pereche</string>
|
||||
<string name="addresses">Adrese</string>
|
||||
<string name="applications">Aplicații</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Aplicațiile externe nu pot comuta tunelurile (recomandat)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Aplicațiile externe pot comuta tunelurile (avansat)</string>
|
||||
<string name="allow_remote_control_intents_title">Permite aplicații de control la distanță</string>
|
||||
<string name="allowed_ips">IP-uri permise</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%2$s pentru %1$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%1$s în %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Trebuie să fie pozitiv și nu mai mare decât 65535</string>
|
||||
<string name="bad_config_explanation_positive_number">: Trebuie să fie pozitiv</string>
|
||||
<string name="bad_config_explanation_udp_port">: Trebuie să fie un număr de port UDP valid</string>
|
||||
<string name="bad_config_reason_invalid_key">Cheie invalidă</string>
|
||||
<string name="bad_config_reason_invalid_number">Număr invalid</string>
|
||||
<string name="bad_config_reason_invalid_value">Valoare invalidă</string>
|
||||
<string name="bad_config_reason_missing_attribute">Atribuit lipsă</string>
|
||||
<string name="bad_config_reason_missing_section">Secțiune lipsă</string>
|
||||
<string name="bad_config_reason_syntax_error">Eroare de sintaxă</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Atribuit necunoscut</string>
|
||||
<string name="bad_config_reason_unknown_section">Secțiune necunoscută</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Valoare în afara intervalului</string>
|
||||
<string name="bad_extension_error">Fișierul trebuie să fie .conf sau .zip</string>
|
||||
<string name="cancel">Anulare</string>
|
||||
<string name="config_delete_error">Fișierul de configurare %s nu poate fi șters</string>
|
||||
<string name="config_exists_error">Configurația pentru „%s” există deja</string>
|
||||
<string name="config_file_exists_error">Fișierul de configurare „%s” există deja</string>
|
||||
<string name="config_not_found_error">Fișier de configurare „%s” negăsit</string>
|
||||
<string name="config_rename_error">Fișierul de configurare „%s” nu poate fi redenumit</string>
|
||||
<string name="config_save_error">Nu poate fi salvată configurația pentru „%1$s”: %2$s</string>
|
||||
<string name="config_save_success">Configurația pentru „%s” a fost salvată</string>
|
||||
<string name="create_activity_title">Creare tunel WireGuard</string>
|
||||
<string name="create_bin_dir_error">Nu se poate crea directorul binar local</string>
|
||||
<string name="create_downloads_file_error">Fișierul nu poate fi creat în directorul pentru descărcări</string>
|
||||
<string name="create_empty">Creare de la zero</string>
|
||||
<string name="create_from_file">Importare din fișier sau arhivă</string>
|
||||
<string name="create_from_qr_code">Scanare din cod QR</string>
|
||||
<string name="create_output_dir_error">Nu se poate crea directorul de ieșire</string>
|
||||
<string name="create_temp_dir_error">Nu se poate crea directorul temporar local</string>
|
||||
<string name="create_tunnel">Creare tunel</string>
|
||||
<string name="dark_theme_summary_off">În prezent este utilizată tema luminoasă (zi)</string>
|
||||
<string name="dark_theme_summary_on">În prezent este utilizată tema întunecată (noapte)</string>
|
||||
<string name="dark_theme_title">Utilizare temă întunecată</string>
|
||||
<string name="delete">Ștergere</string>
|
||||
<string name="dns_servers">Servere DNS</string>
|
||||
<string name="edit">Editare</string>
|
||||
<string name="endpoint">Punct final</string>
|
||||
<string name="error_down">Eroare la oprirea tunelului: %s</string>
|
||||
<string name="error_fetching_apps">Eroare la preluarea listei de aplicații: %s</string>
|
||||
<string name="error_root">Obține acces root și încearcă din nou</string>
|
||||
<string name="error_up">Eroare la pornirea tunelului: %s</string>
|
||||
<string name="exclude_private_ips">Excludere IP-uri private</string>
|
||||
<string name="generate_new_private_key">Generare cheie privată nouă</string>
|
||||
<string name="generic_error">Eroare „%s” necunoscută</string>
|
||||
<string name="hint_automatic">(auto)</string>
|
||||
<string name="hint_generated">(generată)</string>
|
||||
<string name="hint_optional">(opțională)</string>
|
||||
<string name="hint_optional_discouraged">(opțională, nerecomandată)</string>
|
||||
<string name="hint_random">(aleatorie)</string>
|
||||
<string name="illegal_filename_error">Nume nepermis de fișier „%s”</string>
|
||||
<string name="import_error">Tunelul nu poate fi importat: %s</string>
|
||||
<string name="import_from_qr_code">Importare tunel din cod QR</string>
|
||||
<string name="import_success">„%s” importat</string>
|
||||
<string name="interface_title">Interfață</string>
|
||||
<string name="key_contents_error">Caractere incorecte în cheie</string>
|
||||
<string name="key_length_error">Lungime incorectă a cheii</string>
|
||||
<string name="key_length_explanation_base64">: Cheile base64 ale WireGuard trebuie să aibă 44 de caractere (32 de octeți)</string>
|
||||
<string name="key_length_explanation_binary">: Cheile WireGuard trebuie să aibă 32 de octeți</string>
|
||||
<string name="key_length_explanation_hex">: Cheile hex WireGuard trebuie să aibă 64 de caractere (32 de octeți)</string>
|
||||
<string name="listen_port">Port de ascultare</string>
|
||||
<string name="log_export_error">Jurnalul nu poate fi exportat: %s</string>
|
||||
<string name="log_export_subject">Fișier de jurnal Android WireGuard</string>
|
||||
<string name="log_export_success">Salvat în „%s”</string>
|
||||
<string name="log_export_title">Exportare fișier de jurnal</string>
|
||||
<string name="log_saver_activity_label">Salvare jurnal</string>
|
||||
<string name="log_viewer_pref_summary">Jurnalele pot ajuta la depanare</string>
|
||||
<string name="log_viewer_pref_title">Vizualizare jurnal aplicație</string>
|
||||
<string name="log_viewer_title">Jurnal</string>
|
||||
<string name="logcat_error">Programul logcat nu poate fi executat: </string>
|
||||
<string name="module_disabler_disabled_summary">Modulul experimental de nucleu poate îmbunătăți performanța</string>
|
||||
<string name="module_disabler_disabled_title">Activează biblioteca modulului de nucleu</string>
|
||||
<string name="module_disabler_enabled_summary">Biblioteca mai lentă a spațiului utilizatorului poate îmbunătăți stabilitatea</string>
|
||||
<string name="module_disabler_enabled_title">Dezactivează biblioteca modulului de nucleu</string>
|
||||
<string name="module_installer_error">A apărut o eroare. Încearcă din nou</string>
|
||||
<string name="module_installer_initial">Modulul experimental de nucleu poate îmbunătăți performanța</string>
|
||||
<string name="module_installer_not_found">Nu sunt disponibile module pentru dispozitivul tău</string>
|
||||
<string name="module_installer_title">Descărcare și instalare modul nucleu</string>
|
||||
<string name="module_installer_working">Se descarcă și se instalează…</string>
|
||||
<string name="module_version_error">Nu se poate determina versiunea modulului de nucleu</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Pornirea unui tunel va opri celelalte tuneluri</string>
|
||||
<string name="multiple_tunnels_summary_on">Mai multe tunele pot fi pornite simultan</string>
|
||||
<string name="multiple_tunnels_title">Permite mai multe tuneluri simultane</string>
|
||||
<string name="name">Nume</string>
|
||||
<string name="no_config_error">Se încearcă pornirea unui tunel fără configurație</string>
|
||||
<string name="no_configs_error">Nu au fost găsite configurații</string>
|
||||
<string name="no_tunnels_error">Nu există tuneluri</string>
|
||||
<string name="parse_error_generic">șir</string>
|
||||
<string name="parse_error_inet_address">Adresă IP</string>
|
||||
<string name="parse_error_inet_endpoint">punct final</string>
|
||||
<string name="parse_error_inet_network">Rețea IP</string>
|
||||
<string name="parse_error_integer">număr</string>
|
||||
<string name="parse_error_reason">Nu se poate analiza %1$s „%2$s”</string>
|
||||
<string name="peer">Pereche</string>
|
||||
<string name="permission_description">controleze tuneluri WireGuard și, astfel, să activeze și să dezactiveze tuneluri în mod automat, existând posibilitatea de a dirija greșit traficul de internet</string>
|
||||
<string name="permission_label">controleze tuneluri WireGuard</string>
|
||||
<string name="persistent_keepalive">Mesaj keepalive persistent</string>
|
||||
<string name="pre_shared_key">Cheie predistribuită</string>
|
||||
<string name="pre_shared_key_enabled">activată</string>
|
||||
<string name="private_key">Cheie privată</string>
|
||||
<string name="public_key">Cheie publică</string>
|
||||
<string name="qr_code_hint">Sfat: generează cu `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_off">Tunelurile activate nu vor fi pornite odată cu pornirea dispozitivului</string>
|
||||
<string name="restore_on_boot_summary_on">Tunelurile activate vor fi pornite odată cu pornirea dispozitivului</string>
|
||||
<string name="restore_on_boot_title">Restaurare la pornire</string>
|
||||
<string name="save">Salvare</string>
|
||||
<string name="select_all">Selectare totală</string>
|
||||
<string name="settings">Setări</string>
|
||||
<string name="shell_exit_status_read_error">Interfața de comunicare nu poate citi starea de ieșire</string>
|
||||
<string name="shell_marker_count_error">Interfața de comunicare a așteptat 4 marcatori, a primit %d</string>
|
||||
<string name="shell_start_error">Interfața de comunicare nu a putut porni: %d</string>
|
||||
<string name="success_application_will_restart">Succes. Aplicația se va reporni acum…</string>
|
||||
<string name="toggle_all">Comutare toate</string>
|
||||
<string name="toggle_error">Eroare la comutarea tunelului WireGuard: %s</string>
|
||||
<string name="tools_installer_already">wg și wg-quick sunt deja instalate</string>
|
||||
<string name="tools_installer_failure">Nu se pot instala instrumentele de linie de comandă (lipsă root?)</string>
|
||||
<string name="tools_installer_initial">Instalare instrumente opționale pentru scriptare</string>
|
||||
<string name="tools_installer_initial_magisk">Instalare instrumente opționale pentru scriptare ca modul Magisk</string>
|
||||
<string name="tools_installer_initial_system">Instalare instrumente opționale pentru scriptare în partiția de sistem</string>
|
||||
<string name="tools_installer_success_magisk">wg și wg-quick instalate ca modul Magisk (este necesară repornirea)</string>
|
||||
<string name="tools_installer_success_system">wg și wg-quick instalate în partiția de sistem</string>
|
||||
<string name="tools_installer_title">Instalare instrumente de linie de comandă</string>
|
||||
<string name="tools_installer_working">Se instalează wg și wg-quick</string>
|
||||
<string name="tools_unavailable_error">Instrumentele necesare sunt indisponibile</string>
|
||||
<string name="transfer">Transferare</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">Nu se poate crea dispozitiv TUN</string>
|
||||
<string name="tunnel_config_error">Tunelul nu poate fi configurat (wg-quick a returnat %d)</string>
|
||||
<string name="tunnel_create_error">Tunelul nu poate fi creat: %s</string>
|
||||
<string name="tunnel_create_success">Tunelul „%s” a fost creat</string>
|
||||
<string name="tunnel_error_already_exists">Tunelul „%s” există deja</string>
|
||||
<string name="tunnel_error_invalid_name">Nume invalid</string>
|
||||
<string name="tunnel_list_placeholder">Adaugă un tunel folosind butonul albastru</string>
|
||||
<string name="tunnel_name">Numele tunelului</string>
|
||||
<string name="tunnel_on_error">Tunelul nu poate fi pornit (wgTurnOn a returnat %d)</string>
|
||||
<string name="tunnel_rename_error">Tunelul nu poate fi redenumit: %s</string>
|
||||
<string name="tunnel_rename_success">Tunelul a fost redenumit ca „%s”</string>
|
||||
<string name="type_name_go_userspace">Spațiu de utilizator Go</string>
|
||||
<string name="type_name_kernel_module">Modul nucleu</string>
|
||||
<string name="unknown_error">Eroare necunoscută</string>
|
||||
<string name="version_summary">Bibliotecă %1$s v%2$s</string>
|
||||
<string name="version_summary_checking">Se verifică versiunea bibliotecii %s</string>
|
||||
<string name="version_summary_unknown">Versiune %s necunoscută</string>
|
||||
<string name="version_title">WireGuard pentru Android v%s</string>
|
||||
<string name="vpn_not_authorized_error">Serviciul VPN nu este autorizat de utilizator</string>
|
||||
<string name="vpn_start_error">Serviciul VPN Android nu poate fi pornit</string>
|
||||
<string name="zip_export_error">Tunelurile nu pot fi exportate: %s</string>
|
||||
<string name="zip_export_success">Salvat în „%s”</string>
|
||||
<string name="zip_export_summary">Fișierul zip va fi salvat în dosarul pentru descărcări</string>
|
||||
<string name="zip_export_title">Exportare tuneluri în fișierul zip</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Autentifică-te pentru a exporta tunelurile</string>
|
||||
<string name="biometric_prompt_private_key_title">Autentifică-te pentru a vizualiza cheia privată</string>
|
||||
<string name="biometric_auth_error">Eroare la autentificare</string>
|
||||
<string name="biometric_auth_error_reason">Eroare la autentificare: %s</string>
|
||||
</resources>
|
||||
@@ -32,7 +32,7 @@
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d Исключенное приложение</item>
|
||||
<item quantity="few">%d Исключенных приложений</item>
|
||||
<item quantity="few">%d Исключенных приложения</item>
|
||||
<item quantity="many">%d Исключенных приложений</item>
|
||||
<item quantity="other">%d Исключенных приложений</item>
|
||||
</plurals>
|
||||
@@ -56,7 +56,7 @@
|
||||
</plurals>
|
||||
<string name="all_applications">Все приложения</string>
|
||||
<string name="exclude_from_tunnel">Исключить</string>
|
||||
<string name="include_in_tunnel">Только включить</string>
|
||||
<string name="include_in_tunnel">Только включено</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Включить %d приложение</item>
|
||||
<item quantity="few">Включить %d приложения</item>
|
||||
@@ -82,12 +82,12 @@
|
||||
<item quantity="other">секунд</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Использовать все приложения</string>
|
||||
<string name="add_peer">Добавить пира</string>
|
||||
<string name="add_peer">Добавить пир</string>
|
||||
<string name="addresses">IP-адреса</string>
|
||||
<string name="applications">Приложения</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Сторонние приложения не могут переключать туннели (рекомендуется)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Сторонние приложения могут переключать туннели (дополнительно)</string>
|
||||
<string name="allow_remote_control_intents_title">Доступ к другим приложениям</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Внешние приложения не могут переключать туннели (рекомендуется)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Внешние приложения могут переключать туннели (расширенное)</string>
|
||||
<string name="allow_remote_control_intents_title">Разрешить управление через внешние приложения</string>
|
||||
<string name="allowed_ips">Разрешенные IP-адреса</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$s из %2$s</string>
|
||||
@@ -153,18 +153,18 @@
|
||||
<string name="key_length_explanation_binary">: Ключи WireGuard должны быть 32 байта</string>
|
||||
<string name="key_length_explanation_hex">: HEX ключи WireGuard должны содержать 64 символа (32 байта)</string>
|
||||
<string name="listen_port">Порт</string>
|
||||
<string name="log_export_error">Не удалось экспортировать логи: %s</string>
|
||||
<string name="log_export_subject">Файл логов WireGuard Android</string>
|
||||
<string name="log_export_error">Не удалось экспортировать журнал: %s</string>
|
||||
<string name="log_export_subject">Файл журнала WireGuard Android</string>
|
||||
<string name="log_export_success">Сохранено в “%s”</string>
|
||||
<string name="log_export_title">Экспорт логов в файл</string>
|
||||
<string name="log_saver_activity_label">Сохранить логи</string>
|
||||
<string name="log_viewer_pref_summary">Логи могут помочь с отладкой</string>
|
||||
<string name="log_viewer_pref_title">Просмотр логов приложения</string>
|
||||
<string name="log_viewer_title">Логи</string>
|
||||
<string name="log_export_title">Экспорт журнала в файл</string>
|
||||
<string name="log_saver_activity_label">Сохранить журнал</string>
|
||||
<string name="log_viewer_pref_summary">Журналы могут помочь при отладке</string>
|
||||
<string name="log_viewer_pref_title">Просмотр журналов приложения</string>
|
||||
<string name="log_viewer_title">Журнал</string>
|
||||
<string name="logcat_error">Не удалось запустить logcat: </string>
|
||||
<string name="module_disabler_disabled_summary">Экспериментальный модуль ядра приоритетнее и улучшает производительность</string>
|
||||
<string name="module_disabler_disabled_title">Включить модуль ядра</string>
|
||||
<string name="module_disabler_enabled_summary">Пользовательское пространство немного медленнее и улучшает стабильность</string>
|
||||
<string name="module_disabler_enabled_summary">Более медленный бэкэнд пользовательского пространства может улучшить стабильность</string>
|
||||
<string name="module_disabler_enabled_title">Выключить модуль ядра</string>
|
||||
<string name="module_installer_error">Что-то пошло не так. Пожалуйста, попробуйте еще раз</string>
|
||||
<string name="module_installer_initial">Экспериментальный модуль ядра может улучшить производительность</string>
|
||||
@@ -176,7 +176,7 @@
|
||||
<string name="multiple_tunnels_summary_off">Только один туннель, выключит другие</string>
|
||||
<string name="multiple_tunnels_summary_on">Могут быть включены несколько туннелей одновременно</string>
|
||||
<string name="multiple_tunnels_title">Несколько туннелей</string>
|
||||
<string name="name">Имя</string>
|
||||
<string name="name">Название</string>
|
||||
<string name="no_config_error">Попытка поднять туннель без конфигурации</string>
|
||||
<string name="no_configs_error">Конфигурации не найдены</string>
|
||||
<string name="no_tunnels_error">Туннелей не существует</string>
|
||||
@@ -229,13 +229,13 @@
|
||||
<string name="tunnel_create_error">Не удалось создать туннель: %s</string>
|
||||
<string name="tunnel_create_success">Успешно созданный туннель “%s”</string>
|
||||
<string name="tunnel_error_already_exists">Туннель “%s” уже существует</string>
|
||||
<string name="tunnel_error_invalid_name">Неправильное имя</string>
|
||||
<string name="tunnel_error_invalid_name">Некорректное название</string>
|
||||
<string name="tunnel_list_placeholder">Добавьте туннель с помощью синей кнопки</string>
|
||||
<string name="tunnel_name">Название туннеля</string>
|
||||
<string name="tunnel_on_error">Не удалось включить туннель (wgTurnOn вернул %d)</string>
|
||||
<string name="tunnel_rename_error">Не удалось переименовать туннель: %s</string>
|
||||
<string name="tunnel_rename_success">Туннель успешно переименован в “%s”</string>
|
||||
<string name="type_name_go_userspace">Пользовательское пространство</string>
|
||||
<string name="type_name_go_userspace">Перейти в пользовательское пространство</string>
|
||||
<string name="type_name_kernel_module">Модуль ядра</string>
|
||||
<string name="unknown_error">Неизвестная ошибка</string>
|
||||
<string name="version_summary">%1$s v%2$s</string>
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">%d tüneli silinemiyor: %s</item>
|
||||
<item quantity="other">%d tünelleri silinemiyor: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">%d tüneli başarıyla silindi</item>
|
||||
<item quantity="other">%d tünelleri başarıyla silindi</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d tüneli seçildi</item>
|
||||
<item quantity="other">%d tünelleri seçildi</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">%1$d/%2$d tünel içe aktarıldı</item>
|
||||
<item quantity="other">%1$d/%2$d tünel içe aktarıldı</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">%d tünel içe aktarıldı</item>
|
||||
<item quantity="other">%d tünel içe aktarıldı</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d Hariç Tutulan Uygulama</item>
|
||||
<item quantity="other">%d Hariç Tutulan Uygulamalar</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d Dahil Edilen Uygulama</item>
|
||||
<item quantity="other">%d Dahil Edilen Uygulamalar</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d hariç tutuldu</item>
|
||||
<item quantity="other">%d hariç tutuldu</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d dahil edildi</item>
|
||||
<item quantity="other">%d dahil edildi</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Tüm Uygulamalar</string>
|
||||
<string name="exclude_from_tunnel">Hariç</string>
|
||||
<string name="include_in_tunnel">Yalnızca dahil</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">%d uygulamasını dahil et</item>
|
||||
<item quantity="other">%d uygulamalarını dahil et</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">%d uygulamasını hariç tut</item>
|
||||
<item quantity="other">%d uygulamalarını hariç tut</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">her saniye</item>
|
||||
<item quantity="other">%d saniyede bir</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">saniye</item>
|
||||
<item quantity="other">saniye</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Tüm uygulamaları kullan</string>
|
||||
<string name="add_peer">Eş ekle</string>
|
||||
<string name="addresses">Adresler</string>
|
||||
<string name="applications">Uygulamalar</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Harici uygulamalar tünelleri değiştiremez (önerilir)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Harici uygulamalar tünelleri değiştirebilir (gelişmiş)</string>
|
||||
<string name="allow_remote_control_intents_title">Uzaktan kontrol uygulamalarına izin ver</string>
|
||||
<string name="allowed_ips">İzin verilen IP\'ler</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$s\'in %2$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%2$s içinde %1$s</string>
|
||||
<string name="bad_config_explanation_pka">: Pozitif olmalı ve 65535\'ten fazla olmamalıdır</string>
|
||||
<string name="bad_config_explanation_positive_number">: Pozitif olmalıdır</string>
|
||||
<string name="bad_config_explanation_udp_port">: Geçerli bir UDP Port numarası olmalıdır</string>
|
||||
<string name="bad_config_reason_invalid_key">Geçersiz anahtar</string>
|
||||
<string name="bad_config_reason_invalid_number">Geçersiz numara</string>
|
||||
<string name="bad_config_reason_invalid_value">Geçersiz değer</string>
|
||||
<string name="bad_config_reason_missing_attribute">Eksik öznitelik</string>
|
||||
<string name="bad_config_reason_missing_section">Eksik bölüm</string>
|
||||
<string name="bad_config_reason_syntax_error">Sözdizimi hatası</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Bilinmeyen öznitelik</string>
|
||||
<string name="bad_config_reason_unknown_section">Bilinmeyen bölüm</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Aralık dışı değer</string>
|
||||
<string name="bad_extension_error">Dosya .conf veya .zip olmalıdır</string>
|
||||
<string name="cancel">İptal</string>
|
||||
<string name="config_delete_error">%s konfigürasyon dosyası silinemiyor</string>
|
||||
<string name="config_exists_error">“%s” için konfigürasyon zaten var</string>
|
||||
<string name="config_file_exists_error">“%s“ için konfigürasyon dosyası zaten var</string>
|
||||
<string name="config_not_found_error">“%s“ konfigürasyon dosyası bulunamadı</string>
|
||||
<string name="config_rename_error">“%s” konfigürasyon dosyası yeniden adlandırılamıyor</string>
|
||||
<string name="config_save_error">“%1$s” için konfigürasyon kaydedilemiyor: %2$s</string>
|
||||
<string name="config_save_success">“%s“ için konfigürasyon başarıyla kaydedildi</string>
|
||||
<string name="create_activity_title">WireGuard Tüneli Yarat</string>
|
||||
<string name="create_bin_dir_error">Yerel ikili dizin oluşturulamıyor</string>
|
||||
<string name="create_downloads_file_error">İndirilenler klasöründe dosya oluşturulamadı</string>
|
||||
<string name="create_empty">Sıfırdan oluştur</string>
|
||||
<string name="create_from_file">Dosya veya arşivden ekle</string>
|
||||
<string name="create_from_qr_code">QR kodundan ekle</string>
|
||||
<string name="create_output_dir_error">Çıktı klasörü oluşturulamıyor</string>
|
||||
<string name="create_temp_dir_error">Yerel geçici dizin oluşturulamıyor</string>
|
||||
<string name="create_tunnel">Tünel Oluştur</string>
|
||||
<string name="dark_theme_summary_off">Şu anda açık (gündüz) teması kullanılıyor</string>
|
||||
<string name="dark_theme_summary_on">Şu anda karanlık (gece) teması kullanılıyor</string>
|
||||
<string name="dark_theme_title">Koyu tema kullan</string>
|
||||
<string name="delete">Sil</string>
|
||||
<string name="dns_servers">DNS sunucuları</string>
|
||||
<string name="edit">Düzenle</string>
|
||||
<string name="endpoint">Uç nokta</string>
|
||||
<string name="error_down">Tünel kapatılırken hata oluştu: %s</string>
|
||||
<string name="error_fetching_apps">Uygulama listesi getirilirken hata oluştu: %s</string>
|
||||
<string name="error_root">Lütfen root erişimi elde edin ve tekrar deneyin</string>
|
||||
<string name="error_up">Tünel açılırken hata oluştu: %s</string>
|
||||
<string name="exclude_private_ips">Özel IP’leri hariç tut</string>
|
||||
<string name="generate_new_private_key">Yeni özel anahtar oluştur</string>
|
||||
<string name="generic_error">Bilinmeyen “%s” hatası</string>
|
||||
<string name="hint_automatic">(otomatik)</string>
|
||||
<string name="hint_generated">(oluşturuldu)</string>
|
||||
<string name="hint_optional">(isteğe bağlı)</string>
|
||||
<string name="hint_optional_discouraged">(isteğe bağlı, önerilmez)</string>
|
||||
<string name="hint_random">(rastgele)</string>
|
||||
<string name="illegal_filename_error">Geçersiz dosya ismi “%s”</string>
|
||||
<string name="import_error">Tünel içeri aktarılamıyor: %s</string>
|
||||
<string name="import_from_qr_code">Tüneli QR Kod ile İçe Aktar</string>
|
||||
<string name="import_success">İçe aktarıldı “%s”</string>
|
||||
<string name="interface_title">Arayüz</string>
|
||||
<string name="key_contents_error">Anahtardaki yanlış karakterler</string>
|
||||
<string name="key_length_error">Yanlış anahtar uzunluğu</string>
|
||||
<string name="key_length_explanation_base64">: WireGuard base64 anahtarları 44 karakter (32 bayt) olmalıdır</string>
|
||||
<string name="key_length_explanation_binary">: WireGuard anahtarları 32 bayt olmalıdır</string>
|
||||
<string name="key_length_explanation_hex">: WireGuard onaltılık anahtarları 64 karakter (32 bayt) olmalıdır</string>
|
||||
<string name="listen_port">Dinlenen port</string>
|
||||
<string name="log_export_error">Günlük dışa aktarılamıyor: %s</string>
|
||||
<string name="log_export_subject">WireGuard Android Günlük Dosyası</string>
|
||||
<string name="log_export_success">“%s” ’e kaydedildi</string>
|
||||
<string name="log_export_title">Günlük dosyasını dışa aktar</string>
|
||||
<string name="log_saver_activity_label">Günlüğü kaydet</string>
|
||||
<string name="log_viewer_pref_summary">Günlükler hata ayıklamaya yardımcı olabilir</string>
|
||||
<string name="log_viewer_pref_title">Uygulama günlüğünü görüntüle</string>
|
||||
<string name="log_viewer_title">Günlük</string>
|
||||
<string name="logcat_error">Logcat çalıştırılamıyor: </string>
|
||||
<string name="module_disabler_disabled_summary">Deneysel çekirdek modülü performansı artırabilir</string>
|
||||
<string name="module_disabler_disabled_title">Çekirdek modülü arka ucunu etkinleştir</string>
|
||||
<string name="module_disabler_enabled_summary">Daha yavaş kullanıcı alanı arka ucu kararlılığı artırabilir</string>
|
||||
<string name="module_disabler_enabled_title">Çekirdek modülü arka ucunu devre dışı bırak</string>
|
||||
<string name="module_installer_error">Bir şeyler yanlış gitti. Lütfen tekrar deneyin</string>
|
||||
<string name="module_installer_initial">Deneysel çekirdek modülü performansı artırabilir</string>
|
||||
<string name="module_installer_not_found">Cihazınız için uygun modül yok</string>
|
||||
<string name="module_installer_title">Çekirdek modülünü indir ve yükle</string>
|
||||
<string name="module_installer_working">İndiriliyor ve yükleniyor…</string>
|
||||
<string name="module_version_error">Çekirdek modülü sürümü belirlenemiyor</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Bir tüneli açmak diğerlerini kapatır</string>
|
||||
<string name="multiple_tunnels_summary_on">Aynı anda birden fazla tünel açılabilir</string>
|
||||
<string name="multiple_tunnels_title">Birden çok eşzamanlı tünele izin verin</string>
|
||||
<string name="name">İsim</string>
|
||||
<string name="no_config_error">Konfigürasyonsuz bir tünel açmaya çalışılıyor</string>
|
||||
<string name="no_configs_error">Konfigürasyon bulunamadı</string>
|
||||
<string name="no_tunnels_error">Tünel yok</string>
|
||||
<string name="parse_error_generic">dizi</string>
|
||||
<string name="parse_error_inet_address">IP adresi</string>
|
||||
<string name="parse_error_inet_endpoint">uç nokta</string>
|
||||
<string name="parse_error_inet_network">IP ağı</string>
|
||||
<string name="parse_error_integer">numara</string>
|
||||
<string name="parse_error_reason">%1$s “%2$s” ayrıştırılamıyor</string>
|
||||
<string name="peer">Eş</string>
|
||||
<string name="permission_description">WireGuard tünellerini kontrol edin, tünelleri istediğiniz zaman etkinleştirin ve devre dışı bırakın, İnternet trafiğini potansiyel olarak yanlış yönlendirin</string>
|
||||
<string name="permission_label">WireGuard tünellerini kontrol edin</string>
|
||||
<string name="persistent_keepalive">Kalıcı canlı tutma</string>
|
||||
<string name="pre_shared_key">Önceden paylaşılan anahtar</string>
|
||||
<string name="pre_shared_key_enabled">etkinleştirildi</string>
|
||||
<string name="private_key">Özel anahtar</string>
|
||||
<string name="public_key">Genel anahtar</string>
|
||||
<string name="qr_code_hint">İpucu: `qrencode -t ansiutf8 < tunnel.conf` ile oluşturun.</string>
|
||||
<string name="restore_on_boot_summary_off">Önyüklemede etkin tünelleri açmayacak</string>
|
||||
<string name="restore_on_boot_summary_on">Önyüklemede etkin tünelleri açacak</string>
|
||||
<string name="restore_on_boot_title">Cihaz açılırken başlat</string>
|
||||
<string name="save">Kaydet</string>
|
||||
<string name="select_all">Tümünü seç</string>
|
||||
<string name="settings">Ayarlar</string>
|
||||
<string name="shell_exit_status_read_error">Kabuk, çıktı durumunu okuyamıyor</string>
|
||||
<string name="shell_marker_count_error">Kabuk 4 işaret bekledi, %d aldı</string>
|
||||
<string name="shell_start_error">Kabuk başlatılamadı: %d</string>
|
||||
<string name="success_application_will_restart">Başarı. Uygulama şimdi yeniden başlayacak…</string>
|
||||
<string name="toggle_all">Tümünü Değiştir</string>
|
||||
<string name="toggle_error">WireGuard tüneli değiştirilirken hata oluştu: %s</string>
|
||||
<string name="tools_installer_already">wg ve wg-quick zaten kurulu</string>
|
||||
<string name="tools_installer_failure">Komut satırı araçları yüklenemiyor (root yok mu?)</string>
|
||||
<string name="tools_installer_initial">Komut dosyası oluşturmak için isteğe bağlı araçları yükleyin</string>
|
||||
<string name="tools_installer_initial_magisk">Magisk modülü olarak komut dosyası oluşturmak için isteğe bağlı araçları yükleyin</string>
|
||||
<string name="tools_installer_initial_system">Sistem bölümüne komut dosyası oluşturmak için isteğe bağlı araçlar yükleyin</string>
|
||||
<string name="tools_installer_success_magisk">wg ve wg-quick bir Magisk modülü olarak kuruldu (yeniden başlatma gerekir)</string>
|
||||
<string name="tools_installer_success_system">wg ve wg-quick, sistem bölümüne yüklendi</string>
|
||||
<string name="tools_installer_title">Komut satırı araçlarını yükleyin</string>
|
||||
<string name="tools_installer_working">wg ve wg-quick kuruluyor</string>
|
||||
<string name="tools_unavailable_error">Gerekli araçlar mevcut değil</string>
|
||||
<string name="transfer">Transfer</string>
|
||||
<string name="transfer_bytes">%d B</string>
|
||||
<string name="transfer_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_kibibytes">%.2f KiB</string>
|
||||
<string name="transfer_mibibytes">%.2f MiB</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">Tun cihazı oluşturulamıyor</string>
|
||||
<string name="tunnel_config_error">Tünel yapılandırılamıyor (wg-quick döndürdü: %d)</string>
|
||||
<string name="tunnel_create_error">Tünel oluşturulamıyor: %s</string>
|
||||
<string name="tunnel_create_success">Tünel başarıyla oluşturuldu “%s”</string>
|
||||
<string name="tunnel_error_already_exists">“%s” tüneli zaten mevcut</string>
|
||||
<string name="tunnel_error_invalid_name">Geçersiz isim</string>
|
||||
<string name="tunnel_list_placeholder">Mavi düğmeyi kullanarak bir tünel ekleyin</string>
|
||||
<string name="tunnel_name">Tünel İsmi</string>
|
||||
<string name="tunnel_on_error">Tünel aktif edilemiyor (wgTornOn döndürdü: %d)</string>
|
||||
<string name="tunnel_rename_error">Tünel yeniden adlandırılamıyor: %s</string>
|
||||
<string name="tunnel_rename_success">Tünel başarıyla yeniden adlandırıldı “%s”</string>
|
||||
<string name="type_name_go_userspace">Kullanıcı alanına git</string>
|
||||
<string name="type_name_kernel_module">Çekirdek modülü</string>
|
||||
<string name="unknown_error">Bilinmeyen hata</string>
|
||||
<string name="version_summary">%1$s backend v%2$s</string>
|
||||
<string name="version_summary_checking">%s arka uç sürümü kontrol ediliyor</string>
|
||||
<string name="version_summary_unknown">Bilinmeyen %s sürümü</string>
|
||||
<string name="version_title">Android için WireGuard v%s</string>
|
||||
<string name="vpn_not_authorized_error">VPN hizmeti kullanıcı tarafından yetkilendirilmemiş</string>
|
||||
<string name="vpn_start_error">Android VPN hizmeti başlatılamıyor</string>
|
||||
<string name="zip_export_error">Tüneller dışa aktarılamıyor: %s</string>
|
||||
<string name="zip_export_success">“%s” ’e kaydedildi</string>
|
||||
<string name="zip_export_summary">Zip dosyası indirilenler klasörüne kaydedilecek</string>
|
||||
<string name="zip_export_title">Tünelleri zip dosyasına aktar</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Tünelleri dışa aktarmak için kimlik doğrulama</string>
|
||||
<string name="biometric_prompt_private_key_title">Özel anahtarı görüntülemek için kimlik doğrulaması</string>
|
||||
<string name="biometric_auth_error">Kimlik doğrulama hatası</string>
|
||||
<string name="biometric_auth_error_reason">Kimlik doğrulama hatası: %s</string>
|
||||
</resources>
|
||||
@@ -27,7 +27,7 @@
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="other">对 %d 个应用生效</item>
|
||||
</plurals>
|
||||
<string name="all_applications">对全部应用生效</string>
|
||||
<string name="all_applications">全部应用程序</string>
|
||||
<string name="exclude_from_tunnel">不生效</string>
|
||||
<string name="include_in_tunnel">生效</string>
|
||||
<plurals name="include_n_applications">
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="other">無法刪除 %d 個通道: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="other">成功刪除了 %d 個通道</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="other">選擇了 %d 個通道</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="other">匯入了 %d 個通道</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="other">排除了 %d 個應用程式</item>
|
||||
</plurals>
|
||||
<string name="add_peer">新增端點</string>
|
||||
<string name="addresses">位址</string>
|
||||
<string name="allow_remote_control_intents_title">允許遠端控制應用程式</string>
|
||||
<string name="allowed_ips">允許的 IPs</string>
|
||||
<string name="bad_config_context">錯誤設定: %1$s 的 %2$s</string>
|
||||
<string name="bad_config_context_top_level">頂層錯誤設定: %s</string>
|
||||
<string name="bad_config_error">設定有誤: %1$s 在 %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: 必須是不大於 65535 的正整數</string>
|
||||
<string name="bad_config_explanation_positive_number">: 必須是正整數</string>
|
||||
<string name="bad_config_explanation_udp_port">: 必須是一個有效的 UDP 埠號</string>
|
||||
<string name="bad_config_reason_invalid_key">無效的密鑰</string>
|
||||
<string name="bad_config_reason_invalid_number">無效的號碼</string>
|
||||
<string name="bad_config_reason_invalid_value">無效值</string>
|
||||
<string name="bad_config_reason_missing_attribute">缺少屬性</string>
|
||||
<string name="bad_config_reason_missing_section">缺少章節</string>
|
||||
<string name="bad_config_reason_syntax_error">語法錯誤</string>
|
||||
<string name="bad_config_reason_unknown_attribute">未知屬性</string>
|
||||
<string name="bad_config_reason_unknown_section">未知章節</string>
|
||||
<string name="bad_config_reason_value_out_of_range">內容值超出範圍</string>
|
||||
<string name="bad_extension_error">必須是 .conf 或 .zip 的檔案</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="config_delete_error">無法刪除設定檔 %s</string>
|
||||
<string name="config_exists_error">設定「%s」已經存在</string>
|
||||
<string name="config_file_exists_error">設定檔「%s」已經存在</string>
|
||||
<string name="config_not_found_error">設定檔「%s」找不到</string>
|
||||
<string name="config_rename_error">無法改名設定檔「%s」</string>
|
||||
<string name="config_save_error">無法儲存設定「%1$s」: %2$s</string>
|
||||
<string name="config_save_success">成功儲存設定「%s」</string>
|
||||
<string name="create_activity_title">新建 WireGuard 通道</string>
|
||||
<string name="create_bin_dir_error">無法建立本地二進位目錄</string>
|
||||
<string name="create_downloads_file_error">無法在下載目錄建立檔案</string>
|
||||
<string name="create_empty">從空白開始建立</string>
|
||||
<string name="create_from_file">從檔案或壓縮檔匯入</string>
|
||||
<string name="create_from_qr_code">掃描 QR code</string>
|
||||
<string name="create_output_dir_error">無法建立輸出目錄</string>
|
||||
<string name="create_temp_dir_error">無法建立本地暫存目錄</string>
|
||||
<string name="create_tunnel">新建通道</string>
|
||||
<string name="dark_theme_summary_off">目前使用明亮(白晝)主題</string>
|
||||
<string name="dark_theme_summary_on">目前使用暗黑(夜晚)主題</string>
|
||||
<string name="dark_theme_title">使用暗黑主題</string>
|
||||
<string name="delete">刪除</string>
|
||||
<string name="dns_servers">DNS 伺服器</string>
|
||||
<string name="edit">編輯</string>
|
||||
<string name="endpoint">終端點</string>
|
||||
<string name="error_down">徹下通道錯誤: %s</string>
|
||||
<string name="error_fetching_apps">汲取應用程式清單錯誤: %s</string>
|
||||
<string name="error_root">請取得 root 存取權再試一次</string>
|
||||
<string name="error_up">起用通道錯誤: %s</string>
|
||||
<string name="exclude_private_ips">排除私有 IPs</string>
|
||||
<string name="generic_error">不明的「%s」錯誤</string>
|
||||
<string name="hint_automatic">(自動)</string>
|
||||
<string name="hint_generated">(產生的)</string>
|
||||
<string name="hint_optional">(可選的)</string>
|
||||
<string name="hint_random">(隨機)</string>
|
||||
<string name="illegal_filename_error">不合規定的檔名「%s」</string>
|
||||
<string name="import_error">沒辦法匯入通道: %s</string>
|
||||
<string name="import_from_qr_code">從 QR Code 匯入通道</string>
|
||||
<string name="import_success">匯入了「%s」</string>
|
||||
<string name="interface_title">界面</string>
|
||||
<string name="key_length_explanation_base64">: WireGuard 的 base64 密鑰必須是 44 個字元 (32 個位元組)</string>
|
||||
<string name="key_length_explanation_binary">: WireGuard 密鑰必須是 32 個位元組</string>
|
||||
<string name="key_length_explanation_hex">: WireGuard 的16進位密鑰必須是 64 個字元 (32 個位元組)</string>
|
||||
<string name="listen_port">監聽連接埠</string>
|
||||
<string name="log_export_success">儲存到「%s」</string>
|
||||
<string name="log_export_title">匯出日誌檔</string>
|
||||
<string name="save">儲存</string>
|
||||
<string name="select_all">全選</string>
|
||||
<string name="toggle_all">切換全部</string>
|
||||
</resources>
|
||||
@@ -97,10 +97,15 @@
|
||||
<string name="create_output_dir_error">Cannot create output directory</string>
|
||||
<string name="create_temp_dir_error">Cannot create local temporary directory</string>
|
||||
<string name="create_tunnel">Create Tunnel</string>
|
||||
<string name="copied_to_clipboard">%s copied to clipboard</string>
|
||||
<string name="dark_theme_summary_off">Currently using light (day) theme</string>
|
||||
<string name="dark_theme_summary_on">Currently using dark (night) theme</string>
|
||||
<string name="dark_theme_title">Use dark theme</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="tv_delete">Select tunnel to delete</string>
|
||||
<string name="tv_select_a_storage_drive">Select a storage drive</string>
|
||||
<string name="tv_no_file_picker">Please install a file management utility to browse files</string>
|
||||
<string name="tv_add_tunnel_get_started">Add a tunnel to get started</string>
|
||||
<string name="disable_config_export_title">Disable config exporting</string>
|
||||
<string name="disable_config_export_description">Disabling config exporting makes private keys less accessible</string>
|
||||
<string name="dns_servers">DNS servers</string>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="tv_primary_color">#ff212121</color>
|
||||
<color name="tv_card_background">@color/tv_primary_color</color>
|
||||
<color name="tv_card_delete_background">#b00020</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<style name="TvTheme" parent="Theme.MaterialComponents.NoActionBar">
|
||||
<item name="colorPrimary">@color/tv_primary_color</item>
|
||||
<item name="colorOnPrimary">#fffafafa</item>
|
||||
<item name="colorPrimaryDark">@color/tv_primary_color</item>
|
||||
<item name="colorPrimaryVariant">#ff484848</item>
|
||||
<item name="colorSecondary">#ff4285f4</item>
|
||||
<item name="colorOnSecondary">#ff0059c1</item>
|
||||
<item name="colorSurface">@color/tv_primary_color</item>
|
||||
<item name="colorOnSurface">#fffafafa</item>
|
||||
<item name="colorBackground">@color/tv_primary_color</item>
|
||||
<item name="colorMultiselectActiveBackground">@color/list_multiselect_background</item>
|
||||
<item name="colorControlNormal">#fffafafa</item>
|
||||
<item name="elevationOverlayEnabled">false</item>
|
||||
<item name="android:statusBarColor">@color/tv_primary_color</item>
|
||||
<item name="android:windowBackground">@color/tv_primary_color</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="textInputStyle">@style/TextInputLayoutBase</item>
|
||||
<item name="materialCardViewStyle">@style/TvTheme.MaterialCardView</item>
|
||||
</style>
|
||||
|
||||
<style name="TvTheme.MaterialCardView" parent="Widget.MaterialComponents.CardView">
|
||||
<item name="cornerRadius">4dp</item>
|
||||
<item name="cardElevation">8dp</item>
|
||||
<item name="contentPadding">8dp</item>
|
||||
<item name="cardBackgroundColor">?attr/elevationOverlayColor</item>
|
||||
</style>
|
||||
</resources>
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
buildscript {
|
||||
ext {
|
||||
wireguardVersionCode = 478
|
||||
wireguardVersionName = '1.0.20200920'
|
||||
wireguardVersionCode = 486
|
||||
wireguardVersionName = '1.0.20210211'
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user