mirror of
https://github.com/amnezia-vpn/amneziawg-android.git
synced 2026-07-03 14:05:13 +02:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e08d873cc3 | |||
| 3748a1da88 | |||
| 9597d719ac | |||
| 041ce2134f | |||
| 4c17fc51e7 | |||
| 6cf7439053 | |||
| 814ab4937d | |||
| 3d088411e2 | |||
| 39e0c861e2 | |||
| d60efcd7c7 | |||
| 4dff537d21 | |||
| 761c2ade4a | |||
| 115a87af32 | |||
| c7ecaeb145 | |||
| 8e2d63db75 | |||
| 3208bac987 | |||
| fc1f2132fe | |||
| 09125e1e31 | |||
| 6b1164ad8d | |||
| c68a5c776b | |||
| f3ac787f5a | |||
| 751be2c469 | |||
| cfb7f1b016 | |||
| 33e07628db | |||
| b1b7d1d90c | |||
| 6cb9548f72 | |||
| 8207ae1e8d | |||
| 48e0e427eb | |||
| 03e95d2dd3 | |||
| 58b14cc650 | |||
| 3fa8e09545 | |||
| 9d76b354f0 | |||
| 1856a50c56 | |||
| ba0f3ece04 | |||
| e8ad75d924 | |||
| b858284b1e | |||
| 3c6e06f8d5 | |||
| 0d33a00e72 | |||
| 830d0992a7 | |||
| e4192ea172 | |||
| 4bbb1a0fcd | |||
| 77b5937fbb | |||
| 3144d36056 | |||
| 521bbb4b4c | |||
| 0a55e10b94 | |||
| d6e5fd9301 | |||
| 2c625f56fd | |||
| 7db0fa915e | |||
| e424765a61 | |||
| 1ca4dbf1a2 | |||
| 065893e31d | |||
| ef70aa88e1 | |||
| 6a11a199ca |
@@ -15,3 +15,4 @@ build/
|
||||
*.iml
|
||||
*.jks
|
||||
keystore.properties
|
||||
gradlew.bat
|
||||
|
||||
+10
-10
@@ -8,27 +8,26 @@ allprojects {
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
agpVersion = '3.6.2'
|
||||
agpVersion = '4.0.1'
|
||||
annotationsVersion = '1.1.0'
|
||||
appcompatVersion = '1.1.0'
|
||||
bintrayPluginVersion = '1.8.4'
|
||||
biometricVersion = '1.0.1'
|
||||
cardviewVersion = '1.0.0'
|
||||
collectionVersion = '1.1.0'
|
||||
constraintLayoutVersion = '1.1.3'
|
||||
coordinatorLayoutVersion = '1.1.0'
|
||||
coreKtxVersion = '1.2.0'
|
||||
coroutinesVersion = '1.3.5'
|
||||
coreKtxVersion = '1.3.0'
|
||||
coroutinesVersion = '1.3.7'
|
||||
eddsaVersion = '0.3.0'
|
||||
fragmentVersion = '1.2.4'
|
||||
fragmentVersion = '1.2.5'
|
||||
jsr305Version = '3.0.2'
|
||||
junitVersion = '4.13'
|
||||
kotlinVersion = '1.3.71'
|
||||
materialComponentsVersion = '1.1.0'
|
||||
kotlinVersion = '1.3.72'
|
||||
materialComponentsVersion = '1.2.0-alpha06'
|
||||
mavenPluginVersion = '2.1'
|
||||
preferenceVersion = '1.1.0'
|
||||
preferenceVersion = '1.1.1'
|
||||
streamsupportVersion = '1.7.2'
|
||||
threetenabpVersion = '1.2.3'
|
||||
threetenabpVersion = '1.2.4'
|
||||
zxingEmbeddedVersion = '3.6.0'
|
||||
|
||||
groupName = 'com.wireguard.android'
|
||||
@@ -51,8 +50,9 @@ task clean(type: Delete) {
|
||||
|
||||
tasks {
|
||||
wrapper {
|
||||
gradleVersion = "6.2.2"
|
||||
gradleVersion = "6.5.1"
|
||||
distributionType = Wrapper.DistributionType.ALL
|
||||
distributionSha256Sum = "143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-1
@@ -1,5 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
distributionSha256Sum=143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -82,6 +82,7 @@ esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
@@ -129,6 +130,7 @@ fi
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
|
||||
@@ -21,6 +21,9 @@ android {
|
||||
path 'tools/CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
libraryVariants.all {
|
||||
it.generateBuildConfigProvider.configure { enabled = false }
|
||||
}
|
||||
testOptions.unitTests.all {
|
||||
testLogging {
|
||||
events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
|
||||
@@ -42,6 +45,9 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
disable('LongLogTag')
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.system.OsConstants;
|
||||
import android.util.Log;
|
||||
|
||||
import com.wireguard.android.backend.BackendException.Reason;
|
||||
@@ -193,15 +194,28 @@ public final class GoBackend implements Backend {
|
||||
for (final String excludedApplication : config.getInterface().getExcludedApplications())
|
||||
builder.addDisallowedApplication(excludedApplication);
|
||||
|
||||
for (final String includedApplication : config.getInterface().getIncludedApplications())
|
||||
builder.addAllowedApplication(includedApplication);
|
||||
|
||||
for (final InetNetwork addr : config.getInterface().getAddresses())
|
||||
builder.addAddress(addr.getAddress(), addr.getMask());
|
||||
|
||||
for (final InetAddress addr : config.getInterface().getDnsServers())
|
||||
builder.addDnsServer(addr.getHostAddress());
|
||||
|
||||
boolean sawDefaultRoute = false;
|
||||
for (final Peer peer : config.getPeers()) {
|
||||
for (final InetNetwork addr : peer.getAllowedIps())
|
||||
for (final InetNetwork addr : peer.getAllowedIps()) {
|
||||
if (addr.getMask() == 0)
|
||||
sawDefaultRoute = true;
|
||||
builder.addRoute(addr.getAddress(), addr.getMask());
|
||||
}
|
||||
}
|
||||
|
||||
// "Kill-switch" semantics
|
||||
if (!(sawDefaultRoute && config.getPeers().size() == 1)) {
|
||||
builder.allowFamily(OsConstants.AF_INET);
|
||||
builder.allowFamily(OsConstants.AF_INET6);
|
||||
}
|
||||
|
||||
builder.setMtu(config.getInterface().getMtu().orElse(1280));
|
||||
|
||||
@@ -143,12 +143,12 @@ public final class ToolsInstaller {
|
||||
extract();
|
||||
final StringBuilder script = new StringBuilder("set -ex; ");
|
||||
|
||||
script.append("trap 'rm -rf /sbin/.magisk/img/wireguard' INT TERM EXIT; ");
|
||||
script.append(String.format("rm -rf /sbin/.magisk/img/wireguard/; mkdir -p /sbin/.magisk/img/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' > /sbin/.magisk/img/wireguard/module.prop; ");
|
||||
script.append("touch /sbin/.magisk/img/wireguard/auto_mount; ");
|
||||
script.append("trap 'rm -rf /data/adb/moduleswireguard' 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; ");
|
||||
for (final String name : EXECUTABLES) {
|
||||
final File destination = new File("/sbin/.magisk/img/wireguard" + INSTALL_DIR, name);
|
||||
final File destination = new File("/data/adb/modules/wireguard" + INSTALL_DIR, name);
|
||||
script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; chcon 'u:object_r:system_file:s0' '%s' || true; ",
|
||||
new File(localBinaryDir, name), destination, destination, destination));
|
||||
}
|
||||
@@ -191,7 +191,7 @@ public final class ToolsInstaller {
|
||||
synchronized (lock) {
|
||||
if (installAsMagiskModule == null) {
|
||||
try {
|
||||
installAsMagiskModule = rootShell.run(null, "[ -d /sbin/.magisk/mirror -a -d /sbin/.magisk/img -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
|
||||
installAsMagiskModule = rootShell.run(null, "[ -d /data/adb/modules -a ! -f /cache/.disable_magisk ]") == OsConstants.EXIT_SUCCESS;
|
||||
} catch (final Exception ignored) {
|
||||
installAsMagiskModule = false;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ public class BadConfigException extends Exception {
|
||||
DNS("DNS"),
|
||||
ENDPOINT("Endpoint"),
|
||||
EXCLUDED_APPLICATIONS("ExcludedApplications"),
|
||||
INCLUDED_APPLICATIONS("IncludedApplications"),
|
||||
LISTEN_PORT("ListenPort"),
|
||||
MTU("MTU"),
|
||||
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
|
||||
|
||||
@@ -17,10 +17,8 @@ import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -187,7 +185,7 @@ public final class Config {
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static final class Builder {
|
||||
// Defaults to an empty set.
|
||||
private final Set<Peer> peers = new LinkedHashSet<>();
|
||||
private final ArrayList<Peer> peers = new ArrayList<>();
|
||||
// No default; must be provided before building.
|
||||
@Nullable private Interface interfaze;
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ public final class Interface {
|
||||
private final Set<InetNetwork> addresses;
|
||||
private final Set<InetAddress> dnsServers;
|
||||
private final Set<String> excludedApplications;
|
||||
private final Set<String> includedApplications;
|
||||
private final KeyPair keyPair;
|
||||
private final Optional<Integer> listenPort;
|
||||
private final Optional<Integer> mtu;
|
||||
@@ -52,6 +53,7 @@ public final class Interface {
|
||||
addresses = Collections.unmodifiableSet(new LinkedHashSet<>(builder.addresses));
|
||||
dnsServers = Collections.unmodifiableSet(new LinkedHashSet<>(builder.dnsServers));
|
||||
excludedApplications = Collections.unmodifiableSet(new LinkedHashSet<>(builder.excludedApplications));
|
||||
includedApplications = Collections.unmodifiableSet(new LinkedHashSet<>(builder.includedApplications));
|
||||
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
|
||||
listenPort = builder.listenPort;
|
||||
mtu = builder.mtu;
|
||||
@@ -81,6 +83,9 @@ public final class Interface {
|
||||
case "excludedapplications":
|
||||
builder.parseExcludedApplications(attribute.getValue());
|
||||
break;
|
||||
case "includedapplications":
|
||||
builder.parseIncludedApplications(attribute.getValue());
|
||||
break;
|
||||
case "listenport":
|
||||
builder.parseListenPort(attribute.getValue());
|
||||
break;
|
||||
@@ -106,6 +111,7 @@ public final class Interface {
|
||||
return addresses.equals(other.addresses)
|
||||
&& dnsServers.equals(other.dnsServers)
|
||||
&& excludedApplications.equals(other.excludedApplications)
|
||||
&& includedApplications.equals(other.includedApplications)
|
||||
&& keyPair.equals(other.keyPair)
|
||||
&& listenPort.equals(other.listenPort)
|
||||
&& mtu.equals(other.mtu);
|
||||
@@ -141,6 +147,16 @@ public final class Interface {
|
||||
return excludedApplications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of applications included exclusively for using the interface.
|
||||
*
|
||||
* @return a set of package names
|
||||
*/
|
||||
public Set<String> getIncludedApplications() {
|
||||
// The collection is already immutable.
|
||||
return includedApplications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public/private key pair used by the interface.
|
||||
*
|
||||
@@ -174,6 +190,7 @@ public final class Interface {
|
||||
hash = 31 * hash + addresses.hashCode();
|
||||
hash = 31 * hash + dnsServers.hashCode();
|
||||
hash = 31 * hash + excludedApplications.hashCode();
|
||||
hash = 31 * hash + includedApplications.hashCode();
|
||||
hash = 31 * hash + keyPair.hashCode();
|
||||
hash = 31 * hash + listenPort.hashCode();
|
||||
hash = 31 * hash + mtu.hashCode();
|
||||
@@ -213,6 +230,8 @@ public final class Interface {
|
||||
}
|
||||
if (!excludedApplications.isEmpty())
|
||||
sb.append("ExcludedApplications = ").append(Attribute.join(excludedApplications)).append('\n');
|
||||
if (!includedApplications.isEmpty())
|
||||
sb.append("IncludedApplications = ").append(Attribute.join(includedApplications)).append('\n');
|
||||
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
|
||||
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
|
||||
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
|
||||
@@ -240,6 +259,8 @@ public final class Interface {
|
||||
private final Set<InetAddress> dnsServers = new LinkedHashSet<>();
|
||||
// Defaults to an empty set.
|
||||
private final Set<String> excludedApplications = new LinkedHashSet<>();
|
||||
// Defaults to an empty set.
|
||||
private final Set<String> includedApplications = new LinkedHashSet<>();
|
||||
// No default; must be provided before building.
|
||||
@Nullable private KeyPair keyPair;
|
||||
// Defaults to not present.
|
||||
@@ -271,6 +292,9 @@ public final class Interface {
|
||||
if (keyPair == null)
|
||||
throw new BadConfigException(Section.INTERFACE, Location.PRIVATE_KEY,
|
||||
Reason.MISSING_ATTRIBUTE, null);
|
||||
if (!includedApplications.isEmpty() && !excludedApplications.isEmpty())
|
||||
throw new BadConfigException(Section.INTERFACE, Location.INCLUDED_APPLICATIONS,
|
||||
Reason.INVALID_KEY, null);
|
||||
return new Interface(this);
|
||||
}
|
||||
|
||||
@@ -284,6 +308,16 @@ public final class Interface {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder includeApplication(final String application) {
|
||||
includedApplications.add(application);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder includeApplications(final Collection<String> applications) {
|
||||
includedApplications.addAll(applications);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder parseAddresses(final CharSequence addresses) throws BadConfigException {
|
||||
try {
|
||||
for (final String address : Attribute.split(addresses))
|
||||
@@ -308,6 +342,10 @@ public final class Interface {
|
||||
return excludeApplications(Lists.of(Attribute.split(apps)));
|
||||
}
|
||||
|
||||
public Builder parseIncludedApplications(final CharSequence apps) {
|
||||
return includeApplications(Lists.of(Attribute.split(apps)));
|
||||
}
|
||||
|
||||
public Builder parseListenPort(final String listenPort) throws BadConfigException {
|
||||
try {
|
||||
return setListenPort(Integer.parseInt(listenPort));
|
||||
|
||||
@@ -14,7 +14,7 @@ target_link_libraries(libwg-quick.so -ldl)
|
||||
|
||||
file(GLOB WG_SOURCES wireguard-tools/src/*.c ndk-compat/compat.c)
|
||||
add_executable(libwg.so ${WG_SOURCES})
|
||||
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/")
|
||||
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/linux/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/")
|
||||
target_compile_options(libwg.so PUBLIC -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\")
|
||||
|
||||
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go" VERBATIM COMMAND make
|
||||
|
||||
@@ -20,11 +20,11 @@ export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
|
||||
export GOOS := android
|
||||
export CGO_ENABLED := 1
|
||||
|
||||
GO_VERSION := 1.14.1
|
||||
GO_VERSION := 1.14.4
|
||||
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 := 6632f9d53fd95632e431e8c34295349cca3f0a124e3a28b760ae5c42b32816e3
|
||||
GO_HASH_linux-amd64 := 2f49eb17ce8b48c680cdb166ffd7389702c0dec6effa090c324804a5cac8a7f8
|
||||
GO_HASH_darwin-amd64 := 3fa7ed8dc44fdd50c0bfe72676250cceca527d59950aef20af906a670cf88de2
|
||||
GO_HASH_linux-amd64 := aed845e4185a0b2a3c3d5e1d0a35491702c55889192bb9c30e67a3de6849c067
|
||||
|
||||
default: $(DESTDIR)/libwg-go.so
|
||||
|
||||
|
||||
@@ -11,10 +11,6 @@ import "C"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/ipc"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"bytes"
|
||||
"log"
|
||||
"math"
|
||||
@@ -24,6 +20,12 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/ipc"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
type AndroidLogger struct {
|
||||
@@ -149,7 +151,11 @@ func wgGetSocketV4(tunnelHandle int32) int32 {
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
fd, err := handle.device.PeekLookAtSocketFd4()
|
||||
bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd)
|
||||
if bind == nil {
|
||||
return -1
|
||||
}
|
||||
fd, err := bind.PeekLookAtSocketFd4()
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
@@ -162,7 +168,11 @@ func wgGetSocketV6(tunnelHandle int32) int32 {
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
fd, err := handle.device.PeekLookAtSocketFd6()
|
||||
bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd)
|
||||
if bind == nil {
|
||||
return -1
|
||||
}
|
||||
fd, err := bind.PeekLookAtSocketFd4()
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module golang.zx2c4.com/wireguard/android
|
||||
|
||||
go 1.13
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df // indirect
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 // indirect
|
||||
golang.org/x/sys v0.0.0-20200321134203-328b4cd54aae
|
||||
golang.zx2c4.com/wireguard v0.0.20200320
|
||||
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
|
||||
)
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df h1:lDWgvUvNnaTnNBc/dwOty86cFeKoKWbwy2wQj0gIxbU=
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 h1:1+zQlQqEEhUeStBTi653GZAnAuivZq/2hz+Iz+OP7rg=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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/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-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200321134203-328b4cd54aae h1:3tcmuaB7wwSZtelmiv479UjUB+vviwABz7a133ZwOKQ=
|
||||
golang.org/x/sys v0.0.0-20200321134203-328b4cd54aae/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/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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.zx2c4.com/wireguard v0.0.20200320 h1:1vE6zVeO7fix9cJX1Z9ZQ+ikPIIx7vIyU0o0tLDD88g=
|
||||
golang.zx2c4.com/wireguard v0.0.20200320/go.mod h1:lDian4Sw4poJ04SgHh35nzMVwGSYlPumkdnHcucAQoY=
|
||||
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=
|
||||
|
||||
Submodule tunnel/tools/wireguard-tools updated: a8063adc8a...eb4665ecf0
+2
-3
@@ -21,8 +21,8 @@ android {
|
||||
}
|
||||
}
|
||||
compileSdkVersion 29
|
||||
dataBinding.enabled true
|
||||
viewBinding.enabled true
|
||||
buildFeatures.dataBinding = true
|
||||
buildFeatures.viewBinding = true
|
||||
defaultConfig {
|
||||
applicationId 'com.wireguard.android'
|
||||
minSdkVersion 21
|
||||
@@ -68,7 +68,6 @@ dependencies {
|
||||
implementation project(":tunnel")
|
||||
implementation "androidx.annotation:annotation:$annotationsVersion"
|
||||
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
||||
implementation "androidx.cardview:cardview:$cardviewVersion"
|
||||
implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$coordinatorLayoutVersion"
|
||||
implementation "androidx.biometric:biometric:$biometricVersion"
|
||||
|
||||
Vendored
+3
-3
@@ -2,9 +2,6 @@
|
||||
# escalates them as errors.
|
||||
-dontwarn sun.misc.Unsafe
|
||||
|
||||
# Retain some information to keep stacktraces usable
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# Fragment 1.2.4 allows Fragment classes to be obfuscated but
|
||||
# databinding references in XML seem to not be rewritten to
|
||||
# match, so we preserve the names as 1.2.3 did.
|
||||
@@ -12,3 +9,6 @@
|
||||
-keep public class <1> {
|
||||
public <init>();
|
||||
}
|
||||
|
||||
# Don't obfuscate
|
||||
-dontobfuscate
|
||||
|
||||
@@ -112,5 +112,8 @@
|
||||
android:name="android.service.quicksettings.ACTIVE_TILE"
|
||||
android:value="false" />
|
||||
</service>
|
||||
|
||||
<meta-data android:name="android.content.APP_RESTRICTIONS"
|
||||
android:resource="@xml/app_restrictions" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -9,8 +9,9 @@ import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.ActionBar
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.wireguard.android.R
|
||||
@@ -55,16 +56,15 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.main_activity)
|
||||
actionBar = supportActionBar
|
||||
isTwoPaneLayout = findViewById<View>(R.id.master_detail_wrapper) is LinearLayout
|
||||
isTwoPaneLayout = findViewById<View?>(R.id.master_detail_wrapper) != null
|
||||
supportFragmentManager.addOnBackStackChangedListener(this)
|
||||
onBackStackChanged()
|
||||
// Dispatch insets on back stack change
|
||||
// This is required to ensure replaced fragments are also able to consume insets
|
||||
findViewById<View>(R.id.master_detail_wrapper).setOnApplyWindowInsetsListener { _, insets ->
|
||||
val fragmentManager = supportFragmentManager
|
||||
fragmentManager.addOnBackStackChangedListener {
|
||||
fragmentManager.fragments.forEach {
|
||||
it.requireView().dispatchApplyWindowInsets(insets)
|
||||
findViewById<View>(R.id.main_activity_container).setOnApplyWindowInsetsListener { _, insets ->
|
||||
supportFragmentManager.addOnBackStackChangedListener {
|
||||
supportFragmentManager.fragments.forEach {
|
||||
ViewCompat.dispatchApplyWindowInsets(it.requireView(), WindowInsetsCompat.toWindowInsetsCompat(insets))
|
||||
}
|
||||
}
|
||||
insets
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.preference.PreferenceFragmentCompat
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.backend.WgQuickBackend
|
||||
import com.wireguard.android.util.AdminKnobs
|
||||
import com.wireguard.android.util.ModuleLoader
|
||||
import java.util.ArrayList
|
||||
import java.util.Arrays
|
||||
@@ -87,6 +88,10 @@ class SettingsActivity : ThemeChangeAwareActivity() {
|
||||
val remoteApps = preferenceManager.findPreference<Preference>("allow_remote_control_intents")
|
||||
remoteApps?.parent?.removePreference(remoteApps)
|
||||
}
|
||||
if (AdminKnobs.disableConfigExport) {
|
||||
val zipExporter = preferenceManager.findPreference<Preference>("zip_exporter")
|
||||
zipExporter?.parent?.removePreference(zipExporter)
|
||||
}
|
||||
val wgQuickOnlyPrefs = arrayOf(
|
||||
preferenceManager.findPreference("tools_installer"),
|
||||
preferenceManager.findPreference("restore_on_boot"),
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.wireguard.android.widget.ToggleSwitch.OnBeforeCheckedChangeListener
|
||||
import com.wireguard.config.Attribute
|
||||
import com.wireguard.config.InetNetwork
|
||||
import java9.util.Optional
|
||||
import java.net.InetAddress
|
||||
|
||||
/**
|
||||
* Static methods for use by generated code in the Android data binding library.
|
||||
@@ -135,13 +136,30 @@ object BindingAdapters {
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:text")
|
||||
fun setText(view: TextView, text: Optional<*>) {
|
||||
view.text = text.map { it.toString() }.orElse("")
|
||||
fun setOptionalText(view: TextView, text: Optional<*>?) {
|
||||
view.text = text?.map { it.toString() }?.orElse("") ?: ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:text")
|
||||
fun setText(view: TextView, networks: Iterable<InetNetwork?>?) {
|
||||
fun setInetNetworkSetText(view: TextView, networks: Iterable<InetNetwork?>?) {
|
||||
view.text = if (networks != null) Attribute.join(networks) else ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:text")
|
||||
fun setInetAddressSetText(view: TextView, addresses: Iterable<InetAddress?>?) {
|
||||
view.text = if (addresses != null) Attribute.join(addresses.map { it?.hostAddress }) else ""
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun tryParseInt(s: String?): Int {
|
||||
if (s == null)
|
||||
return 0
|
||||
return try {
|
||||
Integer.parseInt(s)
|
||||
} catch (_: Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -17,8 +17,10 @@ import java.lang.ref.WeakReference
|
||||
/**
|
||||
* A generic `RecyclerView.Adapter` backed by a `ObservableKeyedArrayList`.
|
||||
*/
|
||||
class ObservableKeyedRecyclerViewAdapter<K, E : Keyed<out K>> internal constructor(context: Context, private val layoutId: Int,
|
||||
list: ObservableKeyedArrayList<K, E>?) : RecyclerView.Adapter<ObservableKeyedRecyclerViewAdapter.ViewHolder>() {
|
||||
class ObservableKeyedRecyclerViewAdapter<K, E : Keyed<out K>> internal constructor(
|
||||
context: Context, private val layoutId: Int,
|
||||
list: ObservableKeyedArrayList<K, E>?
|
||||
) : RecyclerView.Adapter<ObservableKeyedRecyclerViewAdapter.ViewHolder>() {
|
||||
private val callback = OnListChangedCallback(this)
|
||||
private val layoutInflater: LayoutInflater = LayoutInflater.from(context)
|
||||
private var list: ObservableKeyedArrayList<K, E>? = null
|
||||
|
||||
@@ -12,13 +12,13 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.FrameLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.activity.TunnelCreatorActivity
|
||||
import com.wireguard.android.util.requireTargetFragment
|
||||
import com.wireguard.android.util.resolveAttribute
|
||||
|
||||
class AddTunnelsSheet : BottomSheetDialogFragment() {
|
||||
@@ -81,10 +81,6 @@ class AddTunnelsSheet : BottomSheetDialogFragment() {
|
||||
behavior?.removeBottomSheetCallback(bottomSheetCallback)
|
||||
}
|
||||
|
||||
private fun requireTargetFragment(): Fragment {
|
||||
return requireNotNull(targetFragment) { "A target fragment should always be set" }
|
||||
}
|
||||
|
||||
private fun onRequestCreateConfig() {
|
||||
startActivity(Intent(activity, TunnelCreatorActivity::class.java))
|
||||
}
|
||||
|
||||
@@ -5,23 +5,30 @@
|
||||
package com.wireguard.android.fragment
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.databinding.Observable
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.wireguard.android.Application
|
||||
import com.wireguard.android.BR
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.databinding.AppListDialogFragmentBinding
|
||||
import com.wireguard.android.databinding.ObservableKeyedArrayList
|
||||
import com.wireguard.android.model.ApplicationData
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import com.wireguard.android.util.requireTargetFragment
|
||||
|
||||
class AppListDialogFragment : DialogFragment() {
|
||||
private val appData: ObservableKeyedArrayList<String, ApplicationData> = ObservableKeyedArrayList()
|
||||
private var currentlyExcludedApps = emptyList<String>()
|
||||
private val appData = ObservableKeyedArrayList<String, ApplicationData>()
|
||||
private var currentlySelectedApps = emptyList<String>()
|
||||
private var initiallyExcluded = false
|
||||
private var button: Button? = null
|
||||
private var tabs: TabLayout? = null
|
||||
|
||||
private fun loadData() {
|
||||
val activity = activity ?: return
|
||||
@@ -33,7 +40,14 @@ class AppListDialogFragment : DialogFragment() {
|
||||
val applicationData: MutableList<ApplicationData> = ArrayList()
|
||||
resolveInfos.forEach {
|
||||
val packageName = it.activityInfo.packageName
|
||||
applicationData.add(ApplicationData(it.loadIcon(pm), it.loadLabel(pm).toString(), packageName, currentlyExcludedApps.contains(packageName)))
|
||||
val appData = ApplicationData(it.loadIcon(pm), it.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
|
||||
applicationData.add(appData)
|
||||
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
|
||||
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
|
||||
if (propertyId == BR.selected)
|
||||
setButtonText()
|
||||
}
|
||||
})
|
||||
}
|
||||
applicationData.sortWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
|
||||
applicationData
|
||||
@@ -52,17 +66,37 @@ class AppListDialogFragment : DialogFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val excludedApps = requireArguments().getStringArrayList(KEY_EXCLUDED_APPS)
|
||||
currentlyExcludedApps = (excludedApps ?: emptyList())
|
||||
require(requireTargetFragment() is AppSelectionListener) { "${requireTargetFragment()} must implement AppSelectionListener" }
|
||||
currentlySelectedApps = (arguments?.getStringArrayList(KEY_SELECTED_APPS) ?: emptyList())
|
||||
initiallyExcluded = arguments?.getBoolean(KEY_IS_EXCLUDED) ?: true
|
||||
}
|
||||
|
||||
private fun setButtonText() {
|
||||
val numSelected = appData.count { it.isSelected }
|
||||
button?.text = if (numSelected == 0)
|
||||
getString(R.string.use_all_applications)
|
||||
else when (tabs?.selectedTabPosition) {
|
||||
0 -> resources.getQuantityString(R.plurals.exclude_n_applications, numSelected, numSelected)
|
||||
1 -> resources.getQuantityString(R.plurals.include_n_applications, numSelected, numSelected)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val alertDialogBuilder = AlertDialog.Builder(requireActivity())
|
||||
alertDialogBuilder.setTitle(R.string.excluded_applications)
|
||||
val binding = AppListDialogFragmentBinding.inflate(requireActivity().layoutInflater, null, false)
|
||||
binding.executePendingBindings()
|
||||
alertDialogBuilder.setView(binding.root)
|
||||
alertDialogBuilder.setPositiveButton(R.string.set_exclusions) { _, _ -> setExclusionsAndDismiss() }
|
||||
tabs = binding.tabs
|
||||
tabs?.apply {
|
||||
selectTab(binding.tabs.getTabAt(if (initiallyExcluded) 0 else 1))
|
||||
addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) = Unit
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) = Unit
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) = setButtonText()
|
||||
})
|
||||
}
|
||||
alertDialogBuilder.setPositiveButton(" ") { _, _ -> setSelectionAndDismiss() }
|
||||
alertDialogBuilder.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
alertDialogBuilder.setNeutralButton(R.string.toggle_all) { _, _ -> }
|
||||
binding.fragment = this
|
||||
@@ -70,39 +104,40 @@ class AppListDialogFragment : DialogFragment() {
|
||||
loadData()
|
||||
val dialog = alertDialogBuilder.create()
|
||||
dialog.setOnShowListener {
|
||||
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
|
||||
val selectedItems = appData
|
||||
.filter { it.isExcludedFromTunnel }
|
||||
|
||||
val excludeAll = selectedItems.isEmpty()
|
||||
button = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
setButtonText()
|
||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener { _ ->
|
||||
val selectAll = appData.none { it.isSelected }
|
||||
appData.forEach {
|
||||
it.isExcludedFromTunnel = excludeAll
|
||||
it.isSelected = selectAll
|
||||
}
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun setExclusionsAndDismiss() {
|
||||
val excludedApps: MutableList<String> = ArrayList()
|
||||
private fun setSelectionAndDismiss() {
|
||||
val selectedApps: MutableList<String> = ArrayList()
|
||||
for (data in appData) {
|
||||
if (data.isExcludedFromTunnel) {
|
||||
excludedApps.add(data.packageName)
|
||||
if (data.isSelected) {
|
||||
selectedApps.add(data.packageName)
|
||||
}
|
||||
}
|
||||
(targetFragment as AppExclusionListener?)!!.onExcludedAppsSelected(excludedApps)
|
||||
(requireTargetFragment() as AppSelectionListener).onSelectedAppsSelected(selectedApps, tabs?.selectedTabPosition == 0)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
interface AppExclusionListener {
|
||||
fun onExcludedAppsSelected(excludedApps: List<String>)
|
||||
interface AppSelectionListener {
|
||||
fun onSelectedAppsSelected(selectedApps: List<String>, isExcluded: Boolean)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_EXCLUDED_APPS = "excludedApps"
|
||||
fun <T> newInstance(excludedApps: ArrayList<String?>?, target: T): AppListDialogFragment where T : Fragment?, T : AppExclusionListener? {
|
||||
private const val KEY_SELECTED_APPS = "selected_apps"
|
||||
private const val KEY_IS_EXCLUDED = "is_excluded"
|
||||
fun <T> newInstance(selectedApps: ArrayList<String?>?, isExcluded: Boolean, target: T): AppListDialogFragment where T : Fragment?, T : AppSelectionListener? {
|
||||
val extras = Bundle()
|
||||
extras.putStringArrayList(KEY_EXCLUDED_APPS, excludedApps)
|
||||
extras.putStringArrayList(KEY_SELECTED_APPS, selectedApps)
|
||||
extras.putBoolean(KEY_IS_EXCLUDED, isExcluded)
|
||||
val fragment = AppListDialogFragment()
|
||||
fragment.setTargetFragment(target, 0)
|
||||
fragment.arguments = extras
|
||||
|
||||
@@ -23,9 +23,10 @@ import com.wireguard.android.Application
|
||||
import com.wireguard.android.R
|
||||
import com.wireguard.android.backend.Tunnel
|
||||
import com.wireguard.android.databinding.TunnelEditorFragmentBinding
|
||||
import com.wireguard.android.fragment.AppListDialogFragment.AppExclusionListener
|
||||
import com.wireguard.android.fragment.AppListDialogFragment.AppSelectionListener
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
import com.wireguard.android.util.BiometricAuthenticator
|
||||
import com.wireguard.android.util.AdminKnobs
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import com.wireguard.android.viewmodel.ConfigProxy
|
||||
import com.wireguard.android.widget.EdgeToEdge.setUpRoot
|
||||
@@ -35,7 +36,7 @@ import com.wireguard.config.Config
|
||||
/**
|
||||
* Fragment for editing a WireGuard configuration.
|
||||
*/
|
||||
class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
|
||||
class TunnelEditorFragment : BaseFragment(), AppSelectionListener {
|
||||
private var haveShownKeys = false
|
||||
private var binding: TunnelEditorFragmentBinding? = null
|
||||
private var tunnel: ObservableTunnel? = null
|
||||
@@ -88,11 +89,20 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onExcludedAppsSelected(excludedApps: List<String>) {
|
||||
requireNotNull(binding) { "Tried to set excluded apps while no view was loaded" }
|
||||
binding!!.config!!.`interface`.excludedApplications.apply {
|
||||
clear()
|
||||
addAll(excludedApps)
|
||||
override fun onSelectedAppsSelected(selectedApps: List<String>, isExcluded: Boolean) {
|
||||
requireNotNull(binding) { "Tried to set excluded/included apps while no view was loaded" }
|
||||
if (isExcluded) {
|
||||
binding!!.config!!.`interface`.includedApplications.clear()
|
||||
binding!!.config!!.`interface`.excludedApplications.apply {
|
||||
clear()
|
||||
addAll(selectedApps)
|
||||
}
|
||||
} else {
|
||||
binding!!.config!!.`interface`.excludedApplications.clear()
|
||||
binding!!.config!!.`interface`.includedApplications.apply {
|
||||
clear()
|
||||
addAll(selectedApps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,10 +160,16 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onRequestSetExcludedApplications(view: View?) {
|
||||
fun onRequestSetExcludedIncludedApplications(view: View?) {
|
||||
if (binding != null) {
|
||||
val excludedApps = ArrayList(binding!!.config!!.`interface`.excludedApplications)
|
||||
val fragment = AppListDialogFragment.newInstance(excludedApps, this)
|
||||
var isExcluded = true
|
||||
var selectedApps = ArrayList(binding!!.config!!.`interface`.excludedApplications)
|
||||
if (selectedApps.isEmpty()) {
|
||||
selectedApps = ArrayList(binding!!.config!!.`interface`.includedApplications)
|
||||
if (selectedApps.isNotEmpty())
|
||||
isExcluded = false
|
||||
}
|
||||
val fragment = AppListDialogFragment.newInstance(selectedApps, isExcluded, this)
|
||||
fragment.show(parentFragmentManager, null)
|
||||
}
|
||||
}
|
||||
@@ -237,6 +253,7 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
|
||||
val edit = view as? EditText ?: return
|
||||
if (edit.inputType == InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) return
|
||||
if (!haveShownKeys && edit.text.isNotEmpty()) {
|
||||
if (AdminKnobs.disableConfigExport) return
|
||||
showingAuthenticator = true
|
||||
BiometricAuthenticator.authenticate(R.string.biometric_prompt_private_key_title, this) {
|
||||
showingAuthenticator = false
|
||||
|
||||
@@ -17,6 +17,8 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
@@ -314,6 +316,11 @@ class TunnelListFragment : BaseFragment() {
|
||||
return when (item.itemId) {
|
||||
R.id.menu_action_delete -> {
|
||||
val copyCheckedItems = HashSet(checkedItems)
|
||||
binding?.createFab?.apply {
|
||||
visibility = View.VISIBLE
|
||||
scaleX = 1f
|
||||
scaleY = 1f
|
||||
}
|
||||
Application.getTunnelManager().tunnels.thenAccept { tunnels ->
|
||||
val tunnelsToDelete = ArrayList<ObservableTunnel>()
|
||||
for (position in copyCheckedItems) tunnelsToDelete.add(tunnels[position])
|
||||
@@ -343,14 +350,16 @@ class TunnelListFragment : BaseFragment() {
|
||||
if (activity != null) {
|
||||
resources = activity!!.resources
|
||||
}
|
||||
animateFab(binding?.createFab, false)
|
||||
mode.menuInflater.inflate(R.menu.tunnel_list_action_mode, menu)
|
||||
binding!!.tunnelList.adapter!!.notifyDataSetChanged()
|
||||
binding?.tunnelList?.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode) {
|
||||
actionMode = null
|
||||
resources = null
|
||||
animateFab(binding?.createFab, true)
|
||||
checkedItems.clear()
|
||||
binding!!.tunnelList.adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
@@ -391,6 +400,26 @@ class TunnelListFragment : BaseFragment() {
|
||||
mode.title = resources!!.getQuantityString(R.plurals.delete_title, count, count)
|
||||
}
|
||||
}
|
||||
|
||||
private fun animateFab(view: View?, show: Boolean) {
|
||||
view ?: return
|
||||
val animation = AnimationUtils.loadAnimation(
|
||||
context, if (show) R.anim.scale_up else R.anim.scale_down
|
||||
)
|
||||
animation.setAnimationListener(object : Animation.AnimationListener {
|
||||
override fun onAnimationRepeat(animation: Animation?) {
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation?) {
|
||||
if (!show) view.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onAnimationStart(animation: Animation?) {
|
||||
if (show) view.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
view.startAnimation(animation)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -10,13 +10,13 @@ import androidx.databinding.Bindable
|
||||
import com.wireguard.android.BR
|
||||
import com.wireguard.android.databinding.Keyed
|
||||
|
||||
class ApplicationData(val icon: Drawable, val name: String, val packageName: String, isExcludedFromTunnel: Boolean) : BaseObservable(), Keyed<String> {
|
||||
class ApplicationData(val icon: Drawable, val name: String, val packageName: String, isSelected: Boolean) : BaseObservable(), Keyed<String> {
|
||||
override val key = name
|
||||
|
||||
@get:Bindable
|
||||
var isExcludedFromTunnel = isExcludedFromTunnel
|
||||
var isSelected = isSelected
|
||||
set(value) {
|
||||
field = value
|
||||
notifyPropertyChanged(BR.excludedFromTunnel)
|
||||
notifyPropertyChanged(BR.selected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,14 +93,14 @@ class ObservableTunnel internal constructor(
|
||||
@get:Bindable
|
||||
var statistics: Statistics? = null
|
||||
get() {
|
||||
if (field == null || field!!.isStale)
|
||||
if (field == null || field?.isStale != false)
|
||||
manager.getTunnelStatistics(this).whenComplete(ExceptionLoggers.E)
|
||||
return field
|
||||
}
|
||||
private set
|
||||
|
||||
val statisticsAsync: CompletionStage<Statistics>
|
||||
get() = if (statistics == null || statistics!!.isStale)
|
||||
get() = if (statistics == null || statistics?.isStale != false)
|
||||
manager.getTunnelStatistics(this)
|
||||
else
|
||||
CompletableFuture.completedFuture(statistics)
|
||||
|
||||
+17
-8
@@ -18,11 +18,18 @@ import java9.util.concurrent.CompletableFuture
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
|
||||
private var state = if (Application.getBackend() is WgQuickBackend) State.ENABLED else State.DISABLED
|
||||
private var state = State.UNKNOWN
|
||||
|
||||
override fun getSummary() = context.getString(state.summaryResourceId)
|
||||
init {
|
||||
isVisible = false
|
||||
Application.getBackendAsync().thenAccept { backend ->
|
||||
setState(if (backend is WgQuickBackend) State.ENABLED else State.DISABLED)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTitle() = context.getString(state.titleResourceId)
|
||||
override fun getSummary() = if (state == State.UNKNOWN) "" else context.getString(state.summaryResourceId)
|
||||
|
||||
override fun getTitle() = if (state == State.UNKNOWN) "" else context.getString(state.titleResourceId)
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
override fun onClick() {
|
||||
@@ -51,13 +58,15 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
|
||||
if (this.state == state) return
|
||||
this.state = state
|
||||
if (isEnabled != state.shouldEnableView) isEnabled = state.shouldEnableView
|
||||
if (isVisible != state.visible) isVisible = state.visible
|
||||
notifyChanged()
|
||||
}
|
||||
|
||||
private enum class State(val titleResourceId: Int, val summaryResourceId: Int, val shouldEnableView: Boolean) {
|
||||
ENABLED(R.string.module_disabler_enabled_title, R.string.module_disabler_enabled_summary, true),
|
||||
DISABLED(R.string.module_disabler_disabled_title, R.string.module_disabler_disabled_summary, true),
|
||||
ENABLING(R.string.module_disabler_disabled_title, R.string.success_application_will_restart, false),
|
||||
DISABLING(R.string.module_disabler_enabled_title, R.string.success_application_will_restart, false);
|
||||
private enum class State(val titleResourceId: Int, val summaryResourceId: Int, val shouldEnableView: Boolean, val visible: Boolean) {
|
||||
UNKNOWN(0, 0, false, false),
|
||||
ENABLED(R.string.module_disabler_enabled_title, R.string.module_disabler_enabled_summary, true, true),
|
||||
DISABLED(R.string.module_disabler_disabled_title, R.string.module_disabler_disabled_summary, true, true),
|
||||
ENABLING(R.string.module_disabler_disabled_title, R.string.success_application_will_restart, false, true),
|
||||
DISABLING(R.string.module_disabler_enabled_title, R.string.success_application_will_restart, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.wireguard.android.R
|
||||
import com.wireguard.android.model.ObservableTunnel
|
||||
import com.wireguard.android.util.BiometricAuthenticator
|
||||
import com.wireguard.android.util.DownloadsFileSaver
|
||||
import com.wireguard.android.util.AdminKnobs
|
||||
import com.wireguard.android.util.ErrorMessages
|
||||
import com.wireguard.android.util.FragmentUtils
|
||||
import java9.util.concurrent.CompletableFuture
|
||||
@@ -82,6 +83,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
||||
override fun getTitle() = context.getString(R.string.zip_export_title)
|
||||
|
||||
override fun onClick() {
|
||||
if (AdminKnobs.disableConfigExport) return
|
||||
val prefActivity = FragmentUtils.getPrefActivity(this)
|
||||
val fragment = prefActivity.supportFragmentManager.fragments.first()
|
||||
BiometricAuthenticator.authenticate(R.string.biometric_prompt_zip_exporter_title, fragment) {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.android.util
|
||||
|
||||
import android.content.RestrictionsManager
|
||||
import androidx.core.content.getSystemService
|
||||
import com.wireguard.android.Application
|
||||
|
||||
object AdminKnobs {
|
||||
private val restrictions: RestrictionsManager? = Application.get().getSystemService()
|
||||
val disableConfigExport: Boolean
|
||||
get() = restrictions?.applicationRestrictions?.getBoolean("disable_config_export", false) ?: false
|
||||
}
|
||||
@@ -8,9 +8,14 @@ package com.wireguard.android.util
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
fun Context.resolveAttribute(@AttrRes attrRes: Int): Int {
|
||||
val typedValue = TypedValue()
|
||||
theme.resolveAttribute(attrRes, typedValue, true)
|
||||
return typedValue.data
|
||||
}
|
||||
|
||||
fun Fragment.requireTargetFragment(): Fragment {
|
||||
return requireNotNull(targetFragment) { "A target fragment should always be set for $this" }
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ class InterfaceProxy : BaseObservable, Parcelable {
|
||||
@get:Bindable
|
||||
val excludedApplications: ObservableList<String> = ObservableArrayList()
|
||||
|
||||
@get:Bindable
|
||||
val includedApplications: ObservableList<String> = ObservableArrayList()
|
||||
|
||||
@get:Bindable
|
||||
var addresses: String = ""
|
||||
set(value) {
|
||||
@@ -70,6 +73,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
|
||||
addresses = parcel.readString() ?: ""
|
||||
dnsServers = parcel.readString() ?: ""
|
||||
parcel.readStringList(excludedApplications)
|
||||
parcel.readStringList(includedApplications)
|
||||
listenPort = parcel.readString() ?: ""
|
||||
mtu = parcel.readString() ?: ""
|
||||
privateKey = parcel.readString() ?: ""
|
||||
@@ -80,6 +84,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
|
||||
val dnsServerStrings = other.dnsServers.map { it.hostAddress }
|
||||
dnsServers = Attribute.join(dnsServerStrings)
|
||||
excludedApplications.addAll(other.excludedApplications)
|
||||
includedApplications.addAll(other.includedApplications)
|
||||
listenPort = other.listenPort.map { it.toString() }.orElse("")
|
||||
mtu = other.mtu.map { it.toString() }.orElse("")
|
||||
val keyPair = other.keyPair
|
||||
@@ -103,6 +108,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
|
||||
if (addresses.isNotEmpty()) builder.parseAddresses(addresses)
|
||||
if (dnsServers.isNotEmpty()) builder.parseDnsServers(dnsServers)
|
||||
if (excludedApplications.isNotEmpty()) builder.excludeApplications(excludedApplications)
|
||||
if (includedApplications.isNotEmpty()) builder.includeApplications(includedApplications)
|
||||
if (listenPort.isNotEmpty()) builder.parseListenPort(listenPort)
|
||||
if (mtu.isNotEmpty()) builder.parseMtu(mtu)
|
||||
if (privateKey.isNotEmpty()) builder.parsePrivateKey(privateKey)
|
||||
@@ -113,6 +119,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
|
||||
dest.writeString(addresses)
|
||||
dest.writeString(dnsServers)
|
||||
dest.writeStringList(excludedApplications)
|
||||
dest.writeStringList(includedApplications)
|
||||
dest.writeString(listenPort)
|
||||
dest.writeString(mtu)
|
||||
dest.writeString(privateKey)
|
||||
|
||||
@@ -12,7 +12,7 @@ import androidx.core.view.marginRight
|
||||
import androidx.core.view.marginTop
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
|
||||
/**
|
||||
* A utility for edge-to-edge display. It provides several features needed to make the app
|
||||
@@ -27,7 +27,7 @@ object EdgeToEdge {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setUpScrollingContent(scrollingContent: ViewGroup, fab: ExtendedFloatingActionButton?) {
|
||||
fun setUpScrollingContent(scrollingContent: ViewGroup, fab: FloatingActionButton?) {
|
||||
val originalPaddingLeft = scrollingContent.paddingLeft
|
||||
val originalPaddingRight = scrollingContent.paddingRight
|
||||
val originalPaddingBottom = scrollingContent.paddingBottom
|
||||
@@ -50,7 +50,7 @@ object EdgeToEdge {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setUpFAB(fab: ExtendedFloatingActionButton) {
|
||||
fun setUpFAB(fab: FloatingActionButton) {
|
||||
val originalMarginLeft = fab.marginLeft
|
||||
val originalMarginRight = fab.marginRight
|
||||
val originalMarginBottom = fab.marginBottom
|
||||
|
||||
@@ -10,14 +10,14 @@ import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import com.wireguard.android.R
|
||||
|
||||
class MultiselectableRelativeLayout : RelativeLayout {
|
||||
class MultiselectableRelativeLayout @JvmOverloads constructor(
|
||||
context: Context? = null,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
defStyleRes: Int = 0
|
||||
) : RelativeLayout(context, attrs, defStyleAttr, defStyleRes) {
|
||||
private var multiselected = false
|
||||
|
||||
constructor(context: Context?) : super(context) {}
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
|
||||
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
|
||||
|
||||
override fun onCreateDrawableState(extraSpace: Int): IntArray {
|
||||
if (multiselected) {
|
||||
val drawableState = super.onCreateDrawableState(extraSpace + 1)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<scale
|
||||
android:duration="300"
|
||||
android:fromXScale="1.0"
|
||||
android:fromYScale="1.0"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toXScale="0"
|
||||
android:toYScale="0" />
|
||||
</set>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<scale
|
||||
android:duration="300"
|
||||
android:fromXScale="0"
|
||||
android:fromYScale="0"
|
||||
android:interpolator="@android:anim/linear_interpolator"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:toXScale="1.0"
|
||||
android:toYScale="1.0" />
|
||||
</set>
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main_activity_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activity.MainActivity">
|
||||
|
||||
@@ -18,30 +18,50 @@
|
||||
type="com.wireguard.android.databinding.ObservableKeyedArrayList<String, ApplicationData>" />
|
||||
</data>
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:minHeight="200dp">
|
||||
android:orientation="vertical">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}"
|
||||
tools:visibility="gone" />
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
style="@style/Widget.MaterialComponents.TabLayout.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/app_list"
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/exclude_from_tunnel" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/include_in_tunnel" />
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:items="@{appData}"
|
||||
app:layout="@{@layout/app_list_item}"
|
||||
tools:itemCount="10"
|
||||
tools:listitem="@layout/app_list_item" />
|
||||
|
||||
</FrameLayout>
|
||||
android:minHeight="200dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="@{appData.isEmpty() ? View.VISIBLE : View.GONE}"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/app_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:items="@{appData}"
|
||||
app:layout="@{@layout/app_list_item}"
|
||||
tools:itemCount="10"
|
||||
tools:listitem="@layout/app_list_item" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/list_item_background"
|
||||
android:gravity="center_vertical"
|
||||
android:onClick="@{(view) -> item.setExcludedFromTunnel(!item.excludedFromTunnel)}"
|
||||
android:onClick="@{(view) -> item.setSelected(!item.selected)}"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
@@ -51,10 +51,10 @@
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/excluded_checkbox"
|
||||
android:id="@+id/selected_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="@={item.excludedFromTunnel}"
|
||||
android:checked="@={item.selected}"
|
||||
tools:checked="true" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
tools:itemCount="20"
|
||||
tools:listitem="@layout/log_viewer_entry" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/share_fab"
|
||||
style="@style/Widget.MaterialComponents.ExtendedFloatingActionButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:icon="@drawable/ic_action_share_white" />
|
||||
app:srcCompat="@drawable/ic_action_share_white" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/master_detail_wrapper"
|
||||
android:id="@+id/main_activity_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
|
||||
@@ -22,131 +22,242 @@
|
||||
type="com.wireguard.config.Config" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical">
|
||||
android:focusable="true">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/tunnel_detail_card"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:cardBackgroundColor="?attr/elevationOverlayColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="2dp"
|
||||
app:contentPadding="8dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/tunnel_detail_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/interface_title"
|
||||
style="@style/SectionText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/interface_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.wireguard.android.widget.ToggleSwitch
|
||||
android:id="@+id/tunnel_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:checked="@{tunnel.state == State.UP}"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/interface_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/interface_name_label"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/interface_name_text"
|
||||
android:text="@string/name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/interface_title" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/interface_name_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{tunnel.name}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/interface_name_label"
|
||||
tools:text="wg0" />
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/interface_title"
|
||||
style="@style/SectionText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/interface_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/public_key_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/public_key_text"
|
||||
android:text="@string/public_key"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/interface_name_text" />
|
||||
<com.wireguard.android.widget.ToggleSwitch
|
||||
android:id="@+id/tunnel_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
app:checked="@{tunnel.state == State.UP}"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/interface_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/public_key_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/public_key_description"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:singleLine="true"
|
||||
android:text="@{config.interface.keyPair.publicKey.toBase64}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/public_key_label"
|
||||
tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" />
|
||||
<TextView
|
||||
android:id="@+id/interface_name_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/interface_name_text"
|
||||
android:text="@string/name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/interface_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/addresses_text"
|
||||
android:text="@string/addresses"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/public_key_text" />
|
||||
<TextView
|
||||
android:id="@+id/interface_name_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/name"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{tunnel.name}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/interface_name_label"
|
||||
tools:text="wg0" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/addresses"
|
||||
android:text="@{config.interface.addresses}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/addresses_label"
|
||||
tools:text="fc00:bbbb:bbbb:bb11::3:368b/128" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<TextView
|
||||
android:id="@+id/public_key_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/public_key_text"
|
||||
android:text="@string/public_key"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/interface_name_text" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/peers_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:divider="@null"
|
||||
android:orientation="vertical"
|
||||
app:items="@{config.peers}"
|
||||
app:layout="@{@layout/tunnel_detail_peer}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tunnel_detail_card"
|
||||
tools:ignore="UselessLeaf" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<TextView
|
||||
android:id="@+id/public_key_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/public_key"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:singleLine="true"
|
||||
android:text="@{config.interface.keyPair.publicKey.toBase64}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/public_key_label"
|
||||
tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/addresses_text"
|
||||
android:text="@string/addresses"
|
||||
android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/public_key_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/addresses_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/addresses"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{config.interface.addresses}"
|
||||
android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/addresses_label"
|
||||
tools:text="fc00:bbbb:bbbb:bb11::3:368b/128" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dns_servers_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/dns_servers_text"
|
||||
android:text="@string/dns_servers"
|
||||
android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/addresses_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dns_servers_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/dns_servers"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{config.interface.dnsServers}"
|
||||
android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/dns_servers_label"
|
||||
tools:text="8.8.8.8, 8.8.4.4" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/listen_port_label"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/listen_port_text"
|
||||
android:text="@string/listen_port"
|
||||
android:visibility="@{config.interface.listenPort.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintEnd_toStartOf="@id/mtu_label"
|
||||
app:layout_constraintHorizontal_weight="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dns_servers_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/listen_port_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/listen_port"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{config.interface.listenPort}"
|
||||
android:visibility="@{config.interface.listenPort.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintEnd_toStartOf="@id/mtu_label"
|
||||
app:layout_constraintHorizontal_weight="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/listen_port_label"
|
||||
tools:text="51820" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mtu_label"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/mtu_text"
|
||||
android:text="@string/mtu"
|
||||
android:visibility="@{config.interface.mtu.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="0.5"
|
||||
app:layout_constraintLeft_toRightOf="@id/listen_port_label"
|
||||
app:layout_constraintStart_toEndOf="@id/listen_port_label"
|
||||
app:layout_constraintTop_toBottomOf="@id/dns_servers_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mtu_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/mtu"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{config.interface.mtu}"
|
||||
android:visibility="@{config.interface.mtu.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="0.5"
|
||||
app:layout_constraintStart_toEndOf="@id/listen_port_label"
|
||||
app:layout_constraintStart_toStartOf="@+id/mtu_label"
|
||||
app:layout_constraintTop_toBottomOf="@+id/mtu_label"
|
||||
tools:text="1500" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/applications_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/applications_text"
|
||||
android:text="@string/applications"
|
||||
android:visibility="@{config.interface.includedApplications.isEmpty() && config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/listen_port_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/applications_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/applications"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{config.interface.includedApplications.isEmpty() ? @plurals/n_excluded_applications(config.interface.excludedApplications.size(), config.interface.excludedApplications.size()) : @plurals/n_included_applications(config.interface.includedApplications.size(), config.interface.includedApplications.size())}"
|
||||
android:visibility="@{config.interface.includedApplications.isEmpty() && config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/applications_label"
|
||||
tools:text="8 excluded" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/peers_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:divider="@null"
|
||||
android:orientation="vertical"
|
||||
app:items="@{config.peers}"
|
||||
app:layout="@{@layout/tunnel_detail_peer}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tunnel_detail_card"
|
||||
tools:ignore="UselessLeaf" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
</layout>
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="?attr/elevationOverlayColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="2dp"
|
||||
app:contentPadding="8dp">
|
||||
android:layout_margin="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -49,7 +45,7 @@
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/public_key_description"
|
||||
android:contentDescription="@string/public_key"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
@@ -59,6 +55,32 @@
|
||||
app:layout_constraintTop_toBottomOf="@+id/public_key_label"
|
||||
tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pre_shared_key_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/pre_shared_key_text"
|
||||
android:text="@string/pre_shared_key"
|
||||
android:visibility="@{item.preSharedKey.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/public_key_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pre_shared_key_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/pre_shared_key"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:text="@string/pre_shared_key_enabled"
|
||||
android:visibility="@{item.preSharedKey.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pre_shared_key_label"
|
||||
tools:text="8VyS8W8XeMcBWfKp1GuG3/fZlnUQFkqMNbrdmZtVQIM=" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/allowed_ips_label"
|
||||
android:layout_width="match_parent"
|
||||
@@ -66,15 +88,19 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/allowed_ips_text"
|
||||
android:text="@string/allowed_ips"
|
||||
android:visibility="@{item.allowedIps.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/public_key_text" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/pre_shared_key_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/allowed_ips_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/allowed_ips"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{item.allowedIps}"
|
||||
android:visibility="@{item.allowedIps.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/allowed_ips_label"
|
||||
tools:text="0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3" />
|
||||
@@ -86,6 +112,7 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/endpoint_text"
|
||||
android:text="@string/endpoint"
|
||||
android:visibility="@{item.endpoint.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/allowed_ips_text" />
|
||||
|
||||
@@ -94,11 +121,38 @@
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/endpoint"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{item.endpoint}"
|
||||
android:visibility="@{item.endpoint.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/endpoint_label"
|
||||
tools:text="192.168.0.1:51820" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/persistent_keepalive_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:labelFor="@+id/persistent_keepalive_text"
|
||||
android:text="@string/persistent_keepalive"
|
||||
android:visibility="@{item.persistentKeepalive.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/endpoint_text" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/persistent_keepalive_text"
|
||||
style="@style/DetailText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/persistent_keepalive"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:text="@{@plurals/persistent_keepalive_seconds_unit(item.persistentKeepalive.orElse(0), item.persistentKeepalive.orElse(0))}"
|
||||
android:visibility="@{item.persistentKeepalive.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/persistent_keepalive_label"
|
||||
tools:text="every 3 seconds" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/transfer_label"
|
||||
android:layout_width="match_parent"
|
||||
@@ -109,7 +163,7 @@
|
||||
android:text="@string/transfer"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/endpoint_text"
|
||||
app:layout_constraintTop_toBottomOf="@+id/persistent_keepalive_text"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
@@ -118,6 +172,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/transfer_label"
|
||||
android:contentDescription="@string/transfer"
|
||||
android:onClick="@{ClipboardUtils::copyTextView}"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/transfer_label"
|
||||
|
||||
@@ -45,11 +45,7 @@
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="?attr/elevationOverlayColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="2dp"
|
||||
app:contentPadding="8dp">
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -220,8 +216,8 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:onClick="@{fragment::onRequestSetExcludedApplications}"
|
||||
android:text="@{@plurals/set_excluded_applications(config.interface.excludedApplications.size, config.interface.excludedApplications.size)}"
|
||||
android:onClick="@{fragment::onRequestSetExcludedIncludedApplications}"
|
||||
android:text="@{config.interface.includedApplications.size > 0 ? @plurals/set_included_applications(config.interface.includedApplications.size, config.interface.includedApplications.size) : config.interface.excludedApplications.size > 0 ? @plurals/set_excluded_applications(config.interface.excludedApplications.size, config.interface.excludedApplications.size) : @string/all_applications}"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
<import type="com.wireguard.android.widget.KeyInputFilter" />
|
||||
|
||||
<import type="com.wireguard.android.databinding.BindingAdapters" />
|
||||
|
||||
<variable
|
||||
name="collection"
|
||||
type="androidx.databinding.ObservableList<com.wireguard.android.viewmodel.PeerProxy>" />
|
||||
@@ -27,11 +29,7 @@
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:cardBackgroundColor="?attr/elevationOverlayColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="2dp"
|
||||
app:contentPadding="8dp">
|
||||
android:layout_marginBottom="4dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -108,6 +106,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:hint="@string/persistent_keepalive"
|
||||
app:suffixText="@{@plurals/persistent_keepalive_seconds_suffix(BindingAdapters.tryParseInt(item.persistentKeepalive))}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/pre_shared_key_label_layout">
|
||||
@@ -118,7 +117,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/hint_optional_discouraged"
|
||||
android:inputType="number"
|
||||
android:text="@={item.persistentKeepalive}" />
|
||||
android:text="@={item.persistentKeepalive}"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
@@ -159,7 +158,7 @@
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/excluded_checkbox"
|
||||
android:id="@+id/selected_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="4dp"
|
||||
|
||||
@@ -66,14 +66,13 @@
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/create_fab"
|
||||
style="@style/Widget.MaterialComponents.ExtendedFloatingActionButton.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:icon="@drawable/ic_action_add_white" />
|
||||
app:srcCompat="@drawable/ic_action_add_white" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</layout>
|
||||
|
||||
@@ -24,14 +24,47 @@
|
||||
<item quantity="one">%d ausgeschlossene Anwendung</item>
|
||||
<item quantity="other">%d ausgeschlossene Anwendungen</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d einbezogene Anwendung</item>
|
||||
<item quantity="other">%d einbezogene Anwendungen</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d ausgeschlossen</item>
|
||||
<item quantity="other">%d ausgeschlossen</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d einbezogen</item>
|
||||
<item quantity="other">%d einbezogen</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Alle Anwendungen</string>
|
||||
<string name="exclude_from_tunnel">Ausschließen</string>
|
||||
<string name="include_in_tunnel">Nur einbeziehen</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">%d App einbeziehen</item>
|
||||
<item quantity="other">%d App einbeziehen</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">%d App ausschließen</item>
|
||||
<item quantity="other">%d App ausschließen</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">jede Sekunde</item>
|
||||
<item quantity="other">alle %d Sekunden</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">Sekunde</item>
|
||||
<item quantity="other">Sekunden</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Alle Apps verwenden</string>
|
||||
<string name="add_peer">Teilnehmer hinzufügen</string>
|
||||
<string name="addresses">Adressen</string>
|
||||
<string name="applications">Anwendungen</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Externe Apps dürfen keine Tunnel umschalten (empfohlen)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Externe Apps dürfen Tunnel umschalten (erweitert)</string>
|
||||
<string name="allow_remote_control_intents_title">Erlaube Steuerung über externe Apps</string>
|
||||
<string name="allowed_ips">Erlaubte IPs</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$ss %2$s</string>
|
||||
<string name="bad_config_context">%2$s des %1$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%1$s in %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Muss positiv sein und nicht größer als 65535</string>
|
||||
@@ -40,8 +73,8 @@
|
||||
<string name="bad_config_reason_invalid_key">Ungültiger Schlüssel</string>
|
||||
<string name="bad_config_reason_invalid_number">Ungültige Zahl</string>
|
||||
<string name="bad_config_reason_invalid_value">Ungültiger Wert</string>
|
||||
<string name="bad_config_reason_missing_attribute">Attribut fehlt</string>
|
||||
<string name="bad_config_reason_missing_section">Fehlende Sektion</string>
|
||||
<string name="bad_config_reason_missing_attribute">Fehlendes Attribut</string>
|
||||
<string name="bad_config_reason_missing_section">Fehlender Abschnitt</string>
|
||||
<string name="bad_config_reason_syntax_error">Syntaxfehler</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Unbekanntes Attribut</string>
|
||||
<string name="bad_config_reason_unknown_section">Unbekannter Abschnitt</string>
|
||||
@@ -56,27 +89,26 @@
|
||||
<string name="config_save_error">Konfiguration für „%1$s“ kann nicht gespeichert werden: %2$s</string>
|
||||
<string name="config_save_success">Konfiguration für „%s ” erfolgreich gespeichert</string>
|
||||
<string name="create_activity_title">WireGuard-Tunnel erstellen</string>
|
||||
<string name="create_bin_dir_error">Lokales Anwendungsverzeichnis konnte nicht erstellt werden</string>
|
||||
<string name="create_downloads_file_error">Datei konnte im Download-Verzeichnis nicht erstellt werden</string>
|
||||
<string name="create_bin_dir_error">Lokales Anwendungsverzeichnis kann nicht erstellt werden</string>
|
||||
<string name="create_downloads_file_error">Datei kann im Download-Verzeichnis nicht erstellt werden</string>
|
||||
<string name="create_empty">Neu erstellen</string>
|
||||
<string name="create_from_file">Aus Datei oder Archiv importieren</string>
|
||||
<string name="create_from_qr_code">Vom QR-Code scannen</string>
|
||||
<string name="create_from_qr_code">Von QR-Code scannen</string>
|
||||
<string name="create_output_dir_error">Konnte das Ausgabeverzeichnis nicht erstellen</string>
|
||||
<string name="create_temp_dir_error">Lokales temporäres Verzeichnis konnte nicht erstellt werden</string>
|
||||
<string name="create_temp_dir_error">Lokales temporäres Verzeichnis kann nicht erstellt werden</string>
|
||||
<string name="create_tunnel">Tunnel erstellen</string>
|
||||
<string name="dark_theme_summary_off">Helles (Tag) Design in Verwendung</string>
|
||||
<string name="dark_theme_summary_on">Dunkles (Nacht) Design in Verwendung</string>
|
||||
<string name="dark_theme_summary_off">Verwende helles Design (Tag)</string>
|
||||
<string name="dark_theme_summary_on">Verwende dunkles Design (Nacht)</string>
|
||||
<string name="dark_theme_title">Dunkles Design verwenden</string>
|
||||
<string name="delete">Entfernen</string>
|
||||
<string name="dns_servers">DNS-Server</string>
|
||||
<string name="edit">Bearbeiten</string>
|
||||
<string name="endpoint">Endpunkt</string>
|
||||
<string name="error_down">Fehler beim Herunterfahren des Tunnels: %s</string>
|
||||
<string name="error_down">Fehler beim Abschalten des Tunnels: %s</string>
|
||||
<string name="error_fetching_apps">Fehler beim Abrufen der App-Liste: %s</string>
|
||||
<string name="error_root">Bitte root-Zugriff anfordern und erneut versuchen</string>
|
||||
<string name="error_up">Fehler beim Starten des Tunnels: %s</string>
|
||||
<string name="exclude_private_ips">Private IPs ausschließen</string>
|
||||
<string name="excluded_applications">Ausgeschlossene Anwendungen</string>
|
||||
<string name="generate_new_private_key">Neuen privaten Schlüssel generieren</string>
|
||||
<string name="generic_error">Unbekannter „%s“ Fehler</string>
|
||||
<string name="hint_automatic">(auto)</string>
|
||||
@@ -88,38 +120,38 @@
|
||||
<string name="import_error">Kann Tunnel nicht importieren: %s</string>
|
||||
<string name="import_from_qr_code">Tunnel aus QR-Code importieren</string>
|
||||
<string name="import_success">„%s” importiert</string>
|
||||
<string name="interface_title">Schnittstelle</string>
|
||||
<string name="key_contents_error">Falsche Zeichen in Schlüssel</string>
|
||||
<string name="interface_title">Interface</string>
|
||||
<string name="key_contents_error">Unzulässige Zeichen im Schlüssel</string>
|
||||
<string name="key_length_error">Falsche Schlüssellänge</string>
|
||||
<string name="key_length_explanation_base64">: WireGuard base64-Schlüssel müssen 44 Zeichen enthalten (32 Bytes)</string>
|
||||
<string name="key_length_explanation_binary">: WireGuard-Schlüssel müssen 32 Bytes groß sein</string>
|
||||
<string name="key_length_explanation_hex">: WireGuard Hex-Schlüssel müssen 64 Zeichen (32 Bytes) groß sein</string>
|
||||
<string name="listen_port">Eingangs-Port</string>
|
||||
<string name="log_export_error">Fehler beim Exportieren des Logs: %s</string>
|
||||
<string name="log_export_subject">WireGuard Android Log Datei</string>
|
||||
<string name="log_export_error">Konnte Protokoll nicht exportieren: %s</string>
|
||||
<string name="log_export_subject">WireGuard Android Protokolldatei</string>
|
||||
<string name="log_export_success">Gespeichert in „%s”</string>
|
||||
<string name="log_export_title">Logdatei exportieren</string>
|
||||
<string name="log_saver_activity_label">Log speichern</string>
|
||||
<string name="log_viewer_pref_summary">Logs können beim Debuggen helfen</string>
|
||||
<string name="log_viewer_pref_title">Protokoll der Anwendung anzeigen</string>
|
||||
<string name="log_viewer_title">Loggen</string>
|
||||
<string name="log_saver_activity_label">Protokoll speichern</string>
|
||||
<string name="log_viewer_pref_summary">Protokolle können beim Debuggen helfen</string>
|
||||
<string name="log_viewer_pref_title">Anwendungs-Protokoll anzeigen</string>
|
||||
<string name="log_viewer_title">Protokoll</string>
|
||||
<string name="logcat_error">Konnte logcat nicht ausführen: </string>
|
||||
<string name="module_disabler_disabled_summary">Das experimentelle Kernelmodul kann die Leistung verbessern</string>
|
||||
<string name="module_disabler_disabled_title">Kernelmodul-Backend aktivieren</string>
|
||||
<string name="module_disabler_enabled_summary">Das langsamere Userspace-Backend kann die Stabilität verbessern</string>
|
||||
<string name="module_disabler_enabled_title">Kernelmodul-Backend deaktivieren</string>
|
||||
<string name="module_installer_error">Es ist etwas schief gelaufen. Bitte versuchen Sie es später erneut</string>
|
||||
<string name="module_installer_error">Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut</string>
|
||||
<string name="module_installer_initial">Das experimentelle Kernelmodul kann die Leistung verbessern</string>
|
||||
<string name="module_installer_not_found">Für Ihr Gerät sind keine Module verfügbar</string>
|
||||
<string name="module_installer_title">Kernelmodul herunterladen und installieren</string>
|
||||
<string name="module_installer_working">Herunterladen und Installieren…</string>
|
||||
<string name="module_installer_working">Lade herunter und installiere…</string>
|
||||
<string name="module_version_error">Konnte Version des Kernel-Moduls nicht ermitteln</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Einschalten eines Tunnels wird andere ausschalten</string>
|
||||
<string name="multiple_tunnels_summary_on">Mehrere Tunnel können gleichzeitig aktiviert werden</string>
|
||||
<string name="multiple_tunnels_title">Erlaube mehrere Tunnel gleichzeitig</string>
|
||||
<string name="multiple_tunnels_summary_off">Das einschalten eines Tunnels wird andere ausschalten</string>
|
||||
<string name="multiple_tunnels_summary_on">Mehrere Tunnel können gleichzeitig aktiviert sein</string>
|
||||
<string name="multiple_tunnels_title">Erlaube mehrere gleichzeitige Tunnel</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="no_config_error">Versucht einen Tunnel ohne Konfiguration zu starten</string>
|
||||
<string name="no_config_error">Es wurde versucht, einen Tunnel ohne Konfiguration zu starten</string>
|
||||
<string name="no_configs_error">Keine Konfigurationen gefunden</string>
|
||||
<string name="no_tunnels_error">Keine Tunnel vorhanden</string>
|
||||
<string name="parse_error_generic">String (Zeichenkette)</string>
|
||||
@@ -133,16 +165,15 @@
|
||||
<string name="permission_label">WireGuard-Tunnel steuern</string>
|
||||
<string name="persistent_keepalive">Dauerhafte Erhaltung</string>
|
||||
<string name="pre_shared_key">Vorab geteilter Schlüssel</string>
|
||||
<string name="pre_shared_key_enabled">aktiviert</string>
|
||||
<string name="private_key">Privater Schlüssel</string>
|
||||
<string name="public_key">Öffentlicher Schlüssel</string>
|
||||
<string name="public_key_description">Öffentlicher Schlüssel</string>
|
||||
<string name="qr_code_hint">Tipp: Mit `qrencode -t ansiutf8 < tunnel.conf` generieren.</string>
|
||||
<string name="restore_on_boot_summary_off">Wird aktivierte Tunnel beim Systemstart nicht automatisch starten</string>
|
||||
<string name="restore_on_boot_summary_on">Wird aktivierte Tunnel beim Systemstart automatisch wieder starten</string>
|
||||
<string name="restore_on_boot_summary_off">Aktivierte Tunnel beim Systemstart nicht automatisch starten</string>
|
||||
<string name="restore_on_boot_summary_on">Aktivierte Tunnel beim Systemstart automatisch wieder starten</string>
|
||||
<string name="restore_on_boot_title">Beim Neustart wiederherstellen</string>
|
||||
<string name="save">Speichern</string>
|
||||
<string name="select_all">Alle auswählen</string>
|
||||
<string name="set_exclusions">Ausnahmen festlegen</string>
|
||||
<string name="settings">Einstellungen</string>
|
||||
<string name="shell_exit_status_read_error">Shell kann den Exit-Status nicht lesen</string>
|
||||
<string name="shell_marker_count_error">Die Shell erwartete 4 Marker, erhielt aber %d</string>
|
||||
@@ -191,4 +222,8 @@
|
||||
<string name="zip_export_success">Gespeichert unter “%s”</string>
|
||||
<string name="zip_export_summary">Zip-Datei wird im Download-Verzeichnis gespeichert</string>
|
||||
<string name="zip_export_title">Tunnel als Zip-Datei exportieren</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Authentifizieren, um Tunnel zu exportieren</string>
|
||||
<string name="biometric_prompt_private_key_title">Authentifizieren, um privaten Schlüssel anzuzeigen</string>
|
||||
<string name="biometric_auth_error">Authentifizierungsfehler</string>
|
||||
<string name="biometric_auth_error_reason">Authentifizierungsfehler: %s</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Impossible de supprimer %d tunnel : %s</item>
|
||||
<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="other">Supprimé avec succès %d tunnels</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d tunnel sélectionné</item>
|
||||
<item quantity="other">%d tunnels sélectionnés</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">%1$d de %2$d tunnels importés</item>
|
||||
<item quantity="other">%1$d de %2$d tunnels importés</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">%d tunnel importé</item>
|
||||
<item quantity="other">%d tunnels importés</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d application exclue</item>
|
||||
<item quantity="other">%d applications exclues</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d application incluse</item>
|
||||
<item quantity="other">%d applications incluses</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d exclue</item>
|
||||
<item quantity="other">%d exclues</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d incluse</item>
|
||||
<item quantity="other">%d incluses</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Toutes les Applications</string>
|
||||
<string name="exclude_from_tunnel">Exclure</string>
|
||||
<string name="include_in_tunnel">Inclure uniquement</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Inclure %d application</item>
|
||||
<item quantity="other">Inclure %d applications</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Exclure %d application</item>
|
||||
<item quantity="other">Exclure %d applications</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">chaque seconde</item>
|
||||
<item quantity="other">tous les %d secondes</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">seconde</item>
|
||||
<item quantity="other">secondes</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Utiliser toutes les applications</string>
|
||||
<string name="add_peer">Ajouter un pair</string>
|
||||
<string name="addresses">Adresses</string>
|
||||
<string name="applications">Applications</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Les applications externes ne peuvent pas activer les tunnels (recommandé)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Les applications externes peuvent activer les tunnels (avancés)</string>
|
||||
<string name="allow_remote_control_intents_title">Autoriser les applications de contrôle à distance</string>
|
||||
<string name="allowed_ips">Adresses IP autorisées</string>
|
||||
<string name="app_name">WireGuard</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 dans %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Doit être positif et ne pas dépasser 65535</string>
|
||||
<string name="bad_config_explanation_positive_number">: Doit être positif</string>
|
||||
<string name="bad_config_explanation_udp_port">: Doit être un numéro de port UDP valide</string>
|
||||
<string name="bad_config_reason_invalid_key">Clef invalide</string>
|
||||
<string name="bad_config_reason_invalid_number">Numéro invalide</string>
|
||||
<string name="bad_config_reason_invalid_value">Valeur invalide</string>
|
||||
<string name="bad_config_reason_missing_attribute">Attribut manquant</string>
|
||||
<string name="bad_config_reason_missing_section">Section manquante</string>
|
||||
<string name="bad_config_reason_syntax_error">Erreur de syntaxe</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Attribut inconnu</string>
|
||||
<string name="bad_config_reason_unknown_section">Section inconnue</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Valeur hors limite</string>
|
||||
<string name="bad_extension_error">Le fichier doit être .conf ou .zip</string>
|
||||
<string name="cancel">Annuler</string>
|
||||
<string name="config_delete_error">Impossible de supprimer le fichier de configuration %s</string>
|
||||
<string name="config_exists_error">La configuration de « %s » existe déjà</string>
|
||||
<string name="config_file_exists_error">Le fichier de configuration « %s » existe déjà</string>
|
||||
<string name="config_not_found_error">Fichier de configuration «%s» introuvable</string>
|
||||
<string name="config_rename_error">Impossible de renommer le fichier de configuration «%s»</string>
|
||||
<string name="config_save_error">Impossible d’enregistrer la configuration pour «%1$s» : %2$s</string>
|
||||
<string name="config_save_success">Configuration enregistrée avec succès pour “%s”</string>
|
||||
<string name="create_activity_title">Créer un tunnel WireGuard</string>
|
||||
<string name="create_bin_dir_error">Impossible de créer le répertoire binaire local</string>
|
||||
<string name="create_downloads_file_error">Impossible de créer le fichier dans le répertoire des téléchargements</string>
|
||||
<string name="create_empty">Créer à partir de zéro</string>
|
||||
<string name="create_from_file">Importer depuis un fichier ou une archive</string>
|
||||
<string name="create_from_qr_code">Créer avec un scan de QR code</string>
|
||||
<string name="create_output_dir_error">Impossible de créer le répertoire de sortie</string>
|
||||
<string name="create_temp_dir_error">Impossible de créer le répertoire temporaire local</string>
|
||||
<string name="create_tunnel">Créer un tunnel</string>
|
||||
<string name="dark_theme_summary_off">Utilisation en cours du thème clair (jour)</string>
|
||||
<string name="dark_theme_summary_on">Utilisation en cours du thème sombre (nuit)</string>
|
||||
<string name="dark_theme_title">Utilisez le thème sombre</string>
|
||||
<string name="delete">Supprimer</string>
|
||||
<string name="dns_servers">Serveurs DNS</string>
|
||||
<string name="edit">Modifier</string>
|
||||
<string name="endpoint">Point de terminaison</string>
|
||||
<string name="error_down">Erreur lors de la désactivation du tunnel : %s</string>
|
||||
<string name="error_fetching_apps">Erreur lors de la récupération de la liste d\'applications : %s</string>
|
||||
<string name="error_root">Veuillez obtenir l\'accès root et essayez à nouveau</string>
|
||||
<string name="error_up">Erreur lors de la mise en place du tunnel : %s</string>
|
||||
<string name="exclude_private_ips">Exclure les IPs privées</string>
|
||||
<string name="generate_new_private_key">Générer une nouvelle clé privée</string>
|
||||
<string name="generic_error">Erreur inconnue « %s »</string>
|
||||
<string name="hint_automatic">(auto)</string>
|
||||
<string name="hint_generated">(généré)</string>
|
||||
<string name="hint_optional">(facultatif)</string>
|
||||
<string name="hint_optional_discouraged">(facultatif, non recommandé)</string>
|
||||
<string name="hint_random">(aléatoire)</string>
|
||||
<string name="illegal_filename_error">Nom de fichier invalide “%s”</string>
|
||||
<string name="import_error">Impossible d\'importer le tunnel : %s</string>
|
||||
<string name="import_from_qr_code">Importer un tunnel depuis un QR-code</string>
|
||||
<string name="import_success">Importé «%s »</string>
|
||||
<string name="interface_title">Interface</string>
|
||||
<string name="key_contents_error">Mauvais caractères dans la clé</string>
|
||||
<string name="key_length_error">Longueur de la clé incorrecte</string>
|
||||
<string name="key_length_explanation_base64">: Les clés base64 WireGuard doivent comporter 44 caractères (32 octets)</string>
|
||||
<string name="key_length_explanation_binary">: Les clés WireGuard doivent comporter 32 octets</string>
|
||||
<string name="key_length_explanation_hex">: Les clés hexadécimales WireGuard doivent comporter 64 caractères (32 octets)</string>
|
||||
<string name="listen_port">Port d\'écoute</string>
|
||||
<string name="log_export_error">Impossible d\'exporter le journal : %s</string>
|
||||
<string name="log_export_subject">Fichier journal d\'Android WireGuard</string>
|
||||
<string name="log_export_success">Enregistré dans « %s »</string>
|
||||
<string name="log_export_title">Exporter le fichier journal</string>
|
||||
<string name="log_saver_activity_label">Enregistrer le journal</string>
|
||||
<string name="log_viewer_pref_summary">Les journaux peuvent aider au débogage</string>
|
||||
<string name="log_viewer_pref_title">Afficher le journal de l\'application</string>
|
||||
<string name="log_viewer_title">Journal</string>
|
||||
<string name="logcat_error">Impossible d\'exécuter logcat : </string>
|
||||
<string name="module_disabler_disabled_summary">Le module expérimental du noyau peut améliorer les performances</string>
|
||||
<string name="module_disabler_disabled_title">Activer le backend du module du noyau</string>
|
||||
<string name="module_disabler_enabled_summary">Le backend plus lent de l\'espace utilisateur peut améliorer la stabilité</string>
|
||||
<string name="module_disabler_enabled_title">Désactiver le backend du module du noyau</string>
|
||||
<string name="module_installer_error">Une erreur est survenue. Veuillez réessayer</string>
|
||||
<string name="module_installer_initial">Le module expérimental du noyau peut améliorer les performances</string>
|
||||
<string name="module_installer_not_found">Aucun module n\'est disponible pour votre appareil</string>
|
||||
<string name="module_installer_title">Télécharger et installer le module du noyau</string>
|
||||
<string name="module_installer_working">Téléchargement et installation en cours…</string>
|
||||
<string name="module_version_error">Impossible de déterminer la version du module noyau</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Activer un tunnel éteindra les autres</string>
|
||||
<string name="multiple_tunnels_summary_on">Plusieurs tunnels peuvent être activés simultanément</string>
|
||||
<string name="multiple_tunnels_title">Autoriser plusieurs tunnels simultanés</string>
|
||||
<string name="name">Nom</string>
|
||||
<string name="no_config_error">Tentative d\'établir un tunnel sans configuration</string>
|
||||
<string name="no_configs_error">Aucune configuration trouvée</string>
|
||||
<string name="no_tunnels_error">Aucun tunnel existant</string>
|
||||
<string name="parse_error_generic">chaîne de caractères</string>
|
||||
<string name="parse_error_inet_address">Adresse IP</string>
|
||||
<string name="parse_error_inet_endpoint">point de terminaison</string>
|
||||
<string name="parse_error_inet_network">Réseau IP</string>
|
||||
<string name="parse_error_integer">nombre</string>
|
||||
<string name="parse_error_reason">Impossible d\'analyser %1$s “%2$s”</string>
|
||||
<string name="peer">Pair</string>
|
||||
<string name="permission_description">contrôler les tunnels WireGuard, activer et désactiver les tunnels à volonté, potentiellement détourner le trafic Internet</string>
|
||||
<string name="permission_label">contrôler les tunnels WireGuard</string>
|
||||
<string name="persistent_keepalive">Maintien de connexion permanente</string>
|
||||
<string name="pre_shared_key">Clé pré-partagée</string>
|
||||
<string name="pre_shared_key_enabled">activée</string>
|
||||
<string name="private_key">Clé privée</string>
|
||||
<string name="public_key">Clé publique</string>
|
||||
<string name="qr_code_hint">Astuce : générez avec \"qrencode -t ansiutf8 < tunnel.conf\".</string>
|
||||
<string name="restore_on_boot_summary_off">N\'affichera pas les tunnels activés au démarrage</string>
|
||||
<string name="restore_on_boot_summary_on">Les tunnels activés seront affichés au démarrage</string>
|
||||
<string name="restore_on_boot_title">Restaurer au démarrage</string>
|
||||
<string name="save">Enregistrer</string>
|
||||
<string name="select_all">Tout sélectionner</string>
|
||||
<string name="settings">Paramètres</string>
|
||||
<string name="shell_exit_status_read_error">L\'interpréteur de commande ne peut pas lire l\'état de sortie</string>
|
||||
<string name="shell_marker_count_error">L\'interpréteur de commandes attendait 4 marqueurs, %d reçus</string>
|
||||
<string name="shell_start_error">L\'interpréteur de commande n\'a pas pu démarrer : %d</string>
|
||||
<string name="success_application_will_restart">Succès. L\'application va redémarrer maintenant…</string>
|
||||
<string name="toggle_all">Tout basculer</string>
|
||||
<string name="toggle_error">Erreur lors de l\'activation du tunnel WireGuard : %s</string>
|
||||
<string name="tools_installer_already">wg et wg-quick sont déjà installés</string>
|
||||
<string name="tools_installer_failure">Impossible d\'installer les outils en ligne de commande (pas de root?)</string>
|
||||
<string name="tools_installer_initial">Installer les outils optionnels pour le script</string>
|
||||
<string name="tools_installer_initial_magisk">Installer les outils optionnels pour le script en tant que module Magisk</string>
|
||||
<string name="tools_installer_initial_system">Installer les outils optionnels pour le script dans la partition système</string>
|
||||
<string name="tools_installer_success_magisk">wg et wg-quick installés en tant que module Magisk (redémarrage requis)</string>
|
||||
<string name="tools_installer_success_system">wg et wg-quick installés dans la partition système</string>
|
||||
<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_bytes">%d Octets</string>
|
||||
<string name="transfer_gibibytes">%.2f Go</string>
|
||||
<string name="transfer_kibibytes">%.2f Ko</string>
|
||||
<string name="transfer_mibibytes">%.2f Mo</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f To</string>
|
||||
<string name="tun_create_error">Impossible de créer le périphérique tun</string>
|
||||
<string name="tunnel_config_error">Impossible de configurer le tunnel (wg-quick a retourné %d)</string>
|
||||
<string name="tunnel_create_error">Impossible de créer le tunnel : %s</string>
|
||||
<string name="tunnel_create_success">Tunnel «%s » créé avec succès</string>
|
||||
<string name="tunnel_error_already_exists">Le tunnel « %s » existe déjà</string>
|
||||
<string name="tunnel_error_invalid_name">Nom invalide</string>
|
||||
<string name="tunnel_list_placeholder">Ajouter un tunnel en utilisant le bouton bleu</string>
|
||||
<string name="tunnel_name">Nom du tunnel</string>
|
||||
<string name="tunnel_on_error">Impossible d\'activer le tunnel (wgTurnOn a retourné %d)</string>
|
||||
<string name="tunnel_rename_error">Impossible de renommer le tunnel : %s</string>
|
||||
<string name="tunnel_rename_success">Tunnel renommé avec succès en «%s »</string>
|
||||
<string name="type_name_go_userspace">Nom de l\'espace utilisateur</string>
|
||||
<string name="type_name_kernel_module">Module noyau</string>
|
||||
<string name="unknown_error">Erreur inconnue</string>
|
||||
<string name="version_summary">%1$s backend v%2$s</string>
|
||||
<string name="version_summary_checking">Vérification de la version %s du backend</string>
|
||||
<string name="version_summary_unknown">Version %s inconnue</string>
|
||||
<string name="version_title">WireGuard pour Android v%s</string>
|
||||
<string name="vpn_not_authorized_error">Service VPN non autorisé par l\'utilisateur</string>
|
||||
<string name="vpn_start_error">Impossible de démarrer le service VPN Android</string>
|
||||
<string name="zip_export_error">Impossible d\'exporter les tunnels : %s</string>
|
||||
<string name="zip_export_success">Enregistré dans « %s »</string>
|
||||
<string name="zip_export_summary">L\'archive zip sera sauvegardée dans le dossier de téléchargement</string>
|
||||
<string name="zip_export_title">Exporter les tunnels vers le fichier zip</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">S\'authentifier pour exporter des tunnels</string>
|
||||
<string name="biometric_prompt_private_key_title">S\'authentifier pour voir la clé privée</string>
|
||||
<string name="biometric_auth_error">Échec de l\'authentification</string>
|
||||
<string name="biometric_auth_error_reason">Échec de l\'authentification : %s</string>
|
||||
</resources>
|
||||
@@ -72,7 +72,6 @@
|
||||
<string name="error_root">कृपया रूट एक्सेस प्राप्त करें और पुनः प्रयास करें</string>
|
||||
<string name="error_up">टनल को लाने में त्रुटि: %s</string>
|
||||
<string name="exclude_private_ips">निजी आईपी को छोड़ दें</string>
|
||||
<string name="excluded_applications">निकाले गए ऐप्स</string>
|
||||
<string name="generic_error">अज्ञात “%s” त्रुटि</string>
|
||||
<string name="hint_automatic">(ऑटो)</string>
|
||||
<string name="hint_generated">(उत्पन्न)</string>
|
||||
@@ -121,14 +120,12 @@
|
||||
<string name="pre_shared_key">प्री-शेयर्ड कीस</string>
|
||||
<string name="private_key">निजी कीस</string>
|
||||
<string name="public_key">सार्वजनिक कीस</string>
|
||||
<string name="public_key_description">सार्वजनिक कीस</string>
|
||||
<string name="qr_code_hint">सुझाव: `qrencode -t ansiutf8 < tunnel.conf` के साथ उत्पन्न करो</string>
|
||||
<string name="restore_on_boot_summary_on">बूट पर सक्षम टनलस को लाएगा</string>
|
||||
<string name="restore_on_boot_summary_off">बूट पर सक्षम टनलस को नहीं लाएगा</string>
|
||||
<string name="restore_on_boot_title">बूट पर पुनर्स्थापित करें</string>
|
||||
<string name="save">सहेजें</string>
|
||||
<string name="select_all">सभी का चयन करे</string>
|
||||
<string name="set_exclusions">बहिष्करण सेट करें</string>
|
||||
<string name="settings">सेटिंग्स</string>
|
||||
<string name="shell_exit_status_read_error">शेल बाहर निकलने की स्थिति नहीं पढ़ सकता</string>
|
||||
<string name="shell_marker_count_error">शेल ने 4 मार्करों की अपेक्षा की, %d प्राप्त किया</string>
|
||||
|
||||
@@ -1,112 +1,143 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Tidak dapat menghapus %d tunel: %s</item>
|
||||
<item quantity="other">Tidak dapat menghapus %d tunel: %s</item>
|
||||
<item quantity="other">Tidak dapat menghapus %d terowongan: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">Berhasil menghapus tunel %d</item>
|
||||
<item quantity="other">Berhasil menghapus tunel %d</item>
|
||||
<item quantity="other">Berhasil menghapus terowongan %d</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d tunnel dipilih</item>
|
||||
<item quantity="other">%d tunel dipilih</item>
|
||||
<item quantity="other">%d terowongan dipilih</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">Mengimpor tunel %d dari %d</item>
|
||||
<item quantity="other">Mengimpor tunel %d dari %d</item>
|
||||
<item quantity="other">Mengimpor %1$d terowongan dari %2$d</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">Mengimpor tunel %d</item>
|
||||
<item quantity="other">Mengimpor tunel %d</item>
|
||||
<item quantity="other">Mengimpor %d terowongan</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d Aplikasi dikecualikan</item>
|
||||
<item quantity="other">%d Aplikasi dikecualikan</item>
|
||||
<item quantity="other">%d Aplikasi Dikecualikan</item>
|
||||
</plurals>
|
||||
<string name="add_peer">Tambahkan peer</string>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="other">%d Aplikasi Dikecualikan</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="other">%d dikecualikan</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="other">%d termasuk</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Semua aplikasi</string>
|
||||
<string name="exclude_from_tunnel">Kecualikan</string>
|
||||
<string name="include_in_tunnel">Berlaku hanya untuk</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="other">Aplikasi %d yang disertakan</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="other">Aplikasi %d yang disertakan</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="other">setiap 10 detik</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="other">detik</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Gunakan semua aplikasi</string>
|
||||
<string name="add_peer">Tambahkan rekan</string>
|
||||
<string name="addresses">Alamat</string>
|
||||
<string name="applications">Aplikasi</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Apl eksternal tidak dapat mengalihkan tunnel (disarankan)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Apl eksternal dapat mengalihkan tunnel (lanjutan)</string>
|
||||
<string name="allow_remote_control_intents_title">Izinkan apl kendali jarak jauh</string>
|
||||
<string name="allowed_ips">IP diizinkan</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$s\'s %2$s</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 di %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Harus positif dan tidak lebih dari 65535</string>
|
||||
<string name="bad_config_explanation_positive_number">: Angka harus positif</string>
|
||||
<string name="bad_config_explanation_udp_port">: Harus nomor port UDP yang valid</string>
|
||||
<string name="bad_config_reason_invalid_key">Kunci tidak valid</string>
|
||||
<string name="bad_config_reason_invalid_number">Angka tidak valid</string>
|
||||
<string name="bad_config_reason_invalid_value">Nilai tidak valid</string>
|
||||
<string name="bad_config_reason_missing_attribute">Atribut yang hilang</string>
|
||||
<string name="bad_config_reason_missing_section">Bagian yang hilang</string>
|
||||
<string name="bad_config_reason_syntax_error">Kesalahan sintaks</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Atribut tidak diketahui</string>
|
||||
<string name="bad_config_reason_unknown_section">Bagian tidak diketahui</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Nilai di luar jangkauan</string>
|
||||
<string name="bad_extension_error">File harus .conf atau .zip</string>
|
||||
<string name="cancel">Kembali</string>
|
||||
<string name="config_delete_error">Tidak dapat menghapus file konfigurasi %s</string>
|
||||
<string name="config_exists_error">Konfigurasi untuk “%s” sudah ada</string>
|
||||
<string name="config_file_exists_error">Konfigurasi file “%s” sudah ada</string>
|
||||
<string name="config_not_found_error">Konfigurasi file “%s” tidak ditemukan</string>
|
||||
<string name="config_rename_error">Nama konfigurasi “%s” Tidak bisa diganti</string>
|
||||
<string name="bad_config_explanation_positive_number">: Harus positif</string>
|
||||
<string name="bad_config_explanation_udp_port">: Harus nomor porta UDP yang sah</string>
|
||||
<string name="bad_config_reason_invalid_key">Kunci tidak sah</string>
|
||||
<string name="bad_config_reason_invalid_number">Bilngan tidak sah</string>
|
||||
<string name="bad_config_reason_invalid_value">Nilai tidak sah</string>
|
||||
<string name="bad_config_reason_missing_attribute">Atribut hilang</string>
|
||||
<string name="bad_config_reason_missing_section">Bagian hilang</string>
|
||||
<string name="bad_config_reason_syntax_error">Galat sintaks</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Atribut tak diketahui</string>
|
||||
<string name="bad_config_reason_unknown_section">Bagian tak diketahui</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Nilai di luar rentang</string>
|
||||
<string name="bad_extension_error">Berkas harus .conf atau .zip</string>
|
||||
<string name="cancel">Batalkan</string>
|
||||
<string name="config_delete_error">Tidak dapat menghapus berkas konfigurasi %s</string>
|
||||
<string name="config_exists_error">Sudah ada konfigurasi untuk “%s”</string>
|
||||
<string name="config_file_exists_error">Sudah ada konfigurasi berkas “%s”</string>
|
||||
<string name="config_not_found_error">Tidak menemukan konfigurasi berkas “%s”</string>
|
||||
<string name="config_rename_error">Tidak bisa mengganti nama konfigurasi “%s”</string>
|
||||
<string name="config_save_error">Konfigurasi “%1$s”: %2$s tidak bisa disimpan</string>
|
||||
<string name="config_save_success">Konfigurasi “%s” berhasil disimpan</string>
|
||||
<string name="create_activity_title">Buat tunel WireGuard</string>
|
||||
<string name="create_bin_dir_error">Tidak dapat membuat direktori biner lokal</string>
|
||||
<string name="create_empty">Buat dari awal</string>
|
||||
<string name="create_output_dir_error">Tidak dapat membuat direktori keluaran</string>
|
||||
<string name="create_downloads_file_error">Tidak dapat membuat file di direktori download</string>
|
||||
<string name="create_empty">Buat dari awal</string>
|
||||
<string name="create_from_file">Impor dari berkas atau arsip</string>
|
||||
<string name="create_from_qr_code">Pindai dari kode QR</string>
|
||||
<string name="create_output_dir_error">Tidak dapat membuat direktori keluaran</string>
|
||||
<string name="create_temp_dir_error">Tidak dapat membuat direktori lokal sementara</string>
|
||||
<string name="create_tunnel">Buat tunel</string>
|
||||
<string name="dark_theme_summary_off">Saat ini menggunakan tema terang (siang)</string>
|
||||
<string name="dark_theme_summary_on">Saat ini menggunakan tema gelap (malam)</string>
|
||||
<string name="dark_theme_title">Gunakan tema gelap</string>
|
||||
<string name="delete">Hapus</string>
|
||||
<string name="toggle_all">Matikan semua</string>
|
||||
<string name="dns_servers">Server DNS</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="endpoint">Titik akhir</string>
|
||||
<string name="error_down">Kesalahan mengurangi tunel: %s</string>
|
||||
<string name="endpoint">Endpoint</string>
|
||||
<string name="error_down">Kesalahan pada tunel: %s</string>
|
||||
<string name="error_fetching_apps">Kesalahan mengambil daftar aplikasi: %s</string>
|
||||
<string name="error_root">Izinkan akses root dan coba lagi</string>
|
||||
<string name="error_up">Kesalahan menambahkan tunel: %s</string>
|
||||
<string name="error_up">Kesalahan pada tunel: %s</string>
|
||||
<string name="exclude_private_ips">Kecualikan IP pribadi</string>
|
||||
<string name="excluded_applications">Kecualikan aplikasi</string>
|
||||
<string name="generate_new_private_key">Buat kunci privat baru</string>
|
||||
<string name="generic_error">Eror “%s” Tidak diketahui</string>
|
||||
<string name="hint_automatic">(otomatis)</string>
|
||||
<string name="hint_generated">(generate)</string>
|
||||
<string name="hint_optional">(pilihan)</string>
|
||||
<string name="hint_optional_discouraged">(opsional, tidak disarankan)</string>
|
||||
<string name="hint_random">(acak)</string>
|
||||
<string name="illegal_filename_error">Nama file “%s” ilegal</string>
|
||||
<string name="import_error">Tunel %s tidak bisa diimpor</string>
|
||||
<string name="import_from_qr_code">Mengimpor tunel dari kode QR</string>
|
||||
<string name="import_success">“%s” Sudah diimpor</string>
|
||||
<string name="interface_title">Antarmuka</string>
|
||||
<string name="key_contents_error">Karakter buruk pada kunci</string>
|
||||
<string name="key_length_error">Panjang kunci salah</string>
|
||||
<string name="key_length_explanation_base64">: Kunci WireGuard base64 harus terdiri dari 44 karakter (32 bit)</string>
|
||||
<string name="key_length_explanation_binary">: Kunci WireGuard harus terdiri dari 32 bit</string>
|
||||
<string name="key_length_explanation_hex">: Kunci hex WireGuard Harus terdiri dari 64 karakter (32 bit)</string>
|
||||
<string name="listen_port">Isi port</string>
|
||||
<string name="log_export_error">Log tidak bisa diekspor: %s</string>
|
||||
<string name="log_export_subject">Berkas Log WireGuard Android</string>
|
||||
<string name="log_export_success">Simpan ke “%s”</string>
|
||||
<string name="log_export_title">Ekspor file log</string>
|
||||
<string name="log_saver_activity_label">Simpan log</string>
|
||||
<string name="log_viewer_pref_summary">Log dapat membantu dengan pengawakutuan</string>
|
||||
<string name="log_viewer_pref_title">Lihat log aplikasi</string>
|
||||
<string name="log_viewer_title">Log</string>
|
||||
<string name="logcat_error">Tidak bisa menjalankan logcat: </string>
|
||||
<string name="module_version_error">Tidak dapat menentukan versi modul kernel</string>
|
||||
<string name="module_installer_not_found">Tidak tersedia modul untuk perangkat anda</string>
|
||||
<string name="module_disabler_disabled_summary">Modul kernel eksperimental dapat meningkatkan kinerja</string>
|
||||
<string name="module_disabler_disabled_title">Aktifkan backend modul kernel</string>
|
||||
<string name="module_disabler_enabled_summary">Backend userspace yang lebih lambat dapat meningkatkan stabilitas</string>
|
||||
<string name="module_disabler_enabled_title">Nonaktifkan backend modul kernel</string>
|
||||
<string name="module_installer_error">Ada yang salah. Silakan coba lagi</string>
|
||||
<string name="module_installer_initial">Modul kernel eksperimental dapat meningkatkan kinerja</string>
|
||||
<string name="module_installer_not_found">Tidak tersedia modul untuk perangkat anda</string>
|
||||
<string name="module_installer_title">Unduh dan pasang modul kernel</string>
|
||||
<string name="module_installer_working">Mengunduh and memasang…</string>
|
||||
<string name="module_installer_error">Ada yang salah. Silakan coba lagi</string>
|
||||
<string name="module_disabler_disabled_title">Aktifkan backend modul kernel</string>
|
||||
<string name="module_disabler_disabled_summary">Modul kernel eksperimental dapat meningkatkan kinerja</string>
|
||||
<string name="module_disabler_enabled_title">Nonaktifkan backend modul kernel</string>
|
||||
<string name="module_disabler_enabled_summary">Backend userspace yang lebih lambat dapat meningkatkan stabilitas</string>
|
||||
<string name="success_application_will_restart">Berhasil. Sekarang aplikasi akan memulai ulang…</string>
|
||||
<string name="module_version_error">Tidak dapat menentukan versi modul kernel</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_title">Izinkan beberapa sekaligus tunel</string>
|
||||
<string name="multiple_tunnels_summary_on">Beberapa tunel dapat dihidupkan secara bersamaan</string>
|
||||
<string name="multiple_tunnels_summary_off">Menyalakan satu tunel akan mematikan semuanya</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="multiple_tunnels_summary_on">Beberapa tunel dapat dihidupkan secara bersamaan</string>
|
||||
<string name="multiple_tunnels_title">Izinkan beberapa sekaligus tunel</string>
|
||||
<string name="name">Nama</string>
|
||||
<string name="no_config_error">Lihat tunel tanpa konfigurasi</string>
|
||||
<string name="no_configs_error">Tidak ditemukan konfigurasi</string>
|
||||
<string name="no_tunnels_error">Tidak ada tunel</string>
|
||||
@@ -116,24 +147,26 @@
|
||||
<string name="parse_error_inet_network">Jaringan IP</string>
|
||||
<string name="parse_error_integer">angka</string>
|
||||
<string name="parse_error_reason">%1$s “%2$s” Tidak dapat diuraikan</string>
|
||||
<string name="peer">Peer</string>
|
||||
<string name="peer">Rekan</string>
|
||||
<string name="permission_description">mengontrol terowongan WireGuard, mengaktifkan dan menonaktifkannya sesuka hati, berpotensi salah melalu lintas Internet</string>
|
||||
<string name="permission_label">Kontrol tunel WireGuard</string>
|
||||
<string name="persistent_keepalive">Keepalive persisten</string>
|
||||
<string name="pre_shared_key">Kunci Pra-bersama</string>
|
||||
<string name="pre_shared_key_enabled">diaktifkan</string>
|
||||
<string name="private_key">Kunci pribadi</string>
|
||||
<string name="public_key">Kunci publik</string>
|
||||
<string name="public_key_description">Kunci publik</string>
|
||||
<string name="qr_code_hint">Tips: generate dengan `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_on">Tunel yang diaktifkan akan dimunculkan saat boot</string>
|
||||
<string name="restore_on_boot_summary_off">Tunel yang diaktifkan tidak akan ditampilkan saat boot</string>
|
||||
<string name="restore_on_boot_summary_on">Tunel yang diaktifkan akan dimunculkan saat boot</string>
|
||||
<string name="restore_on_boot_title">Pulihkan saat boot</string>
|
||||
<string name="save">Simpan</string>
|
||||
<string name="select_all">Pilih semua</string>
|
||||
<string name="set_exclusions">Tetapkan pengecualian</string>
|
||||
<string name="settings">Pengaturan</string>
|
||||
<string name="shell_exit_status_read_error">Shell tidak dapat membaca status keluar</string>
|
||||
<string name="shell_marker_count_error">Shell diharapkan 4 nilai, diterima %d</string>
|
||||
<string name="shell_start_error">Gagal memulai shell: %d</string>
|
||||
<string name="success_application_will_restart">Berhasil. Sekarang aplikasi akan memulai ulang…</string>
|
||||
<string name="toggle_all">Matikan semua</string>
|
||||
<string name="toggle_error">Tunel WireGuard %s gagal dialihkan</string>
|
||||
<string name="tools_installer_already">wg and wg-quick sudah terpasang</string>
|
||||
<string name="tools_installer_failure">Tidak dapat memasang alat command-line (tidak root?)</string>
|
||||
@@ -146,11 +179,11 @@
|
||||
<string name="tools_installer_working">Memasang wg and wg-quick</string>
|
||||
<string name="tools_unavailable_error">Alat yang diperlukan tidak tersedia</string>
|
||||
<string name="transfer">Transfer</string>
|
||||
<string name="transfer_rx_tx">rx: %1$s, tx: %2$s</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_gibibytes">%.2f GiB</string>
|
||||
<string name="transfer_rx_tx">trm: %1$s, krm: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">Tidak dapat membuat perangkat tun</string>
|
||||
<string name="tunnel_config_error">Tidak bisa mengkonfigurasikan tunel (wg-quick %d dikembalikan)</string>
|
||||
@@ -176,6 +209,8 @@
|
||||
<string name="zip_export_success">Disimpan ke “%s”</string>
|
||||
<string name="zip_export_summary">File Zip akan disimpan di folder download</string>
|
||||
<string name="zip_export_title">Ekspor tunel ke file zip</string>
|
||||
<string name="key_length_error">Panjang kunci salah</string>
|
||||
<string name="key_contents_error">Karakter buruk pada kunci</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Otentikasi untuk mengekspor terowongan</string>
|
||||
<string name="biometric_prompt_private_key_title">Otentikasi untuk melihat kunci privat</string>
|
||||
<string name="biometric_auth_error">Otentikasi gagal</string>
|
||||
<string name="biometric_auth_error_reason">Otentikasi gagal: %s</string>
|
||||
</resources>
|
||||
|
||||
@@ -24,8 +24,41 @@
|
||||
<item quantity="one">%d applicazione esclusa</item>
|
||||
<item quantity="other">%d applicazioni escluse</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d applicazione esclusa</item>
|
||||
<item quantity="other">%d applicazioni incluse</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d escluse</item>
|
||||
<item quantity="other">%d escluse</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d escluse</item>
|
||||
<item quantity="other">%d incluse</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Tutte le applicazioni</string>
|
||||
<string name="exclude_from_tunnel">Escludi</string>
|
||||
<string name="include_in_tunnel">Includi solo</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Includi %d applicazione</item>
|
||||
<item quantity="other">Includi %d applicazioni</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Escludi %d applicazione</item>
|
||||
<item quantity="other">Escludi %d applicazioni</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">ogni secondo</item>
|
||||
<item quantity="other">ogni %d secondi</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">secondo</item>
|
||||
<item quantity="other">secondi</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Utilizza tutte le applicazioni</string>
|
||||
<string name="add_peer">Aggiungi peer</string>
|
||||
<string name="addresses">Indirizzi</string>
|
||||
<string name="applications">Applicazioni</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Le applicazioni esterne non possono attivare tunnel (consigliato)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Le applicazioni esterne possono attivare tunnel (avanzato)</string>
|
||||
<string name="allow_remote_control_intents_title">Consenti applicazioni di controllo remoto</string>
|
||||
@@ -76,7 +109,6 @@
|
||||
<string name="error_root">Accedi come root e riprova</string>
|
||||
<string name="error_up">Errore di attivazione del tunnel: %s</string>
|
||||
<string name="exclude_private_ips">Escludi IP privati</string>
|
||||
<string name="excluded_applications">Applicazioni escluse</string>
|
||||
<string name="generate_new_private_key">Genera nuova chiave privata</string>
|
||||
<string name="generic_error">Errore “%s” sconosciuto</string>
|
||||
<string name="hint_automatic">(auto)</string>
|
||||
@@ -133,16 +165,15 @@
|
||||
<string name="permission_label">controlla tunnel WireGuard</string>
|
||||
<string name="persistent_keepalive">Tieni sempre attivo</string>
|
||||
<string name="pre_shared_key">Chiave condivisa (PSK)</string>
|
||||
<string name="pre_shared_key_enabled">abilitata</string>
|
||||
<string name="private_key">Chiave privata</string>
|
||||
<string name="public_key">Chiave pubblica</string>
|
||||
<string name="public_key_description">La chiave pubblica</string>
|
||||
<string name="qr_code_hint">Suggerimento: genera con `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_off">Non attiverà i tunnel configurati all\'avvio</string>
|
||||
<string name="restore_on_boot_summary_on">Attiverà i tunnel configurati all\'avvio</string>
|
||||
<string name="restore_on_boot_title">Ripristina all\'avvio</string>
|
||||
<string name="save">Salva</string>
|
||||
<string name="select_all">Seleziona tutto</string>
|
||||
<string name="set_exclusions">Imposta esclusioni</string>
|
||||
<string name="settings">Impostazioni</string>
|
||||
<string name="shell_exit_status_read_error">La shell non riesce a leggere lo stato di uscita</string>
|
||||
<string name="shell_marker_count_error">La shell si aspettava 4 marker, ne ha ricevuti %d</string>
|
||||
@@ -191,4 +222,8 @@
|
||||
<string name="zip_export_success">Salvato in “%s”</string>
|
||||
<string name="zip_export_summary">Il file zip verrà salvato nella cartella di download</string>
|
||||
<string name="zip_export_title">Esporta i tunnel in un file zip</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Autenticati per esportare le chiavi i tunnel</string>
|
||||
<string name="biometric_prompt_private_key_title">Autenticati per visualizzare le chiavi private</string>
|
||||
<string name="biometric_auth_error">Autenticazione non riuscita</string>
|
||||
<string name="biometric_auth_error_reason">Autenticazione non riuscita: %s</string>
|
||||
</resources>
|
||||
|
||||
@@ -18,8 +18,34 @@
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="other">除外アプリ %d 個</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="other">トンネリング対象アプリ %d 個</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="other">対象外アプリ %d 個</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<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="other">%d アプリが対象</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="other">%d アプリを除外</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="other">%d 秒ごと</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<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>
|
||||
@@ -70,7 +96,6 @@
|
||||
<string name="error_root">root 権限を取得して再試行してください</string>
|
||||
<string name="error_up">トンネル起動時エラー: %s</string>
|
||||
<string name="exclude_private_ips">プライベート IP アドレスを除外</string>
|
||||
<string name="excluded_applications">対象外とするアプリケーション</string>
|
||||
<string name="generate_new_private_key">新しい秘密鍵を生成する</string>
|
||||
<string name="generic_error">未知の “%s” エラー</string>
|
||||
<string name="hint_automatic">(自動)</string>
|
||||
@@ -127,22 +152,21 @@
|
||||
<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="public_key_description">公開鍵</string>
|
||||
<string name="qr_code_hint">Tip: `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="set_exclusions">対象外アプリを設定</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_all">すべての状態を切り替え</string>
|
||||
<string name="toggle_error">WireGuard トンネルの状態切り替え時にエラー: %s</string>
|
||||
<string name="tools_installer_already">wg および wg-quick はインストール済みです</string>
|
||||
<string name="tools_installer_failure">コマンドラインツールをインストールできません(root権限がない?)</string>
|
||||
@@ -185,4 +209,8 @@
|
||||
<string name="zip_export_success">“%s” に保存</string>
|
||||
<string name="zip_export_summary">Zip ファイルはダウンロードフォルダに保存されます</string>
|
||||
<string name="zip_export_title">トンネル設定を zip ファイルにエクスポート</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>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
<!-- Theme variables -->
|
||||
<color name="list_multiselect_background">#1aeeeeee</color>
|
||||
<color name="status_bar_color">#21242424</color>
|
||||
<color name="navigation_bar_color">#aa242424</color>
|
||||
<color name="status_bar_color">@color/primary_color</color>
|
||||
<color name="navigation_bar_color">#aa212121</color>
|
||||
|
||||
<!-- Log viewer tag colors -->
|
||||
<color name="debug_tag_color">#aaaaaa</color>
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
<resources>
|
||||
<plurals name="delete_error">
|
||||
<item quantity="one">Не удалось удалить %d туннель: %s</item>
|
||||
<item quantity="few">Не удалось удалить %d туннелей: %s</item>
|
||||
<item quantity="few">Не удалось удалить %d туннеля: %s</item>
|
||||
<item quantity="many">Не удалось удалить %d туннелей: %s</item>
|
||||
<item quantity="other">Не удалось удалить %d туннелей: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<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>
|
||||
<plurals name="delete_title">
|
||||
<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>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">Импортирован %1$d из %2$d туннелей</item>
|
||||
<item quantity="few">Импортировано %1$d из %2$d туннелей</item>
|
||||
<item quantity="few">Импортировано %1$d из %2$d туннеля</item>
|
||||
<item quantity="many">Импортировано %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="few">Импортировано %d туннелей</item>
|
||||
<item quantity="few">Импортировано %d туннеля</item>
|
||||
<item quantity="many">Импортировано %d туннелей</item>
|
||||
<item quantity="other">Импортировано %d туннелей</item>
|
||||
</plurals>
|
||||
@@ -36,8 +36,55 @@
|
||||
<item quantity="many">%d Исключенных приложений</item>
|
||||
<item quantity="other">%d Исключенных приложений</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d Включенное приложение</item>
|
||||
<item quantity="few">%d Включенных приложений</item>
|
||||
<item quantity="many">%d Включенных приложений</item>
|
||||
<item quantity="other">%d Включенных приложений</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d исключен</item>
|
||||
<item quantity="few">%d исключено</item>
|
||||
<item quantity="many">%d исключено</item>
|
||||
<item quantity="other">%d исключено</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d влючен</item>
|
||||
<item quantity="few">%d включено</item>
|
||||
<item quantity="many">%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="few">Включить %d приложения</item>
|
||||
<item quantity="many">Включить %d приложений</item>
|
||||
<item quantity="other">Включить %d приложений</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Исключить %d приложение</item>
|
||||
<item quantity="few">Исключить %d приложения</item>
|
||||
<item quantity="many">Исключить %d приложений</item>
|
||||
<item quantity="other">Исключить %d приложений</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">каждую %d секунду</item>
|
||||
<item quantity="few">каждые %d секунды</item>
|
||||
<item quantity="many">каждые %d секунд</item>
|
||||
<item quantity="other">каждые %d секунд</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">секунда</item>
|
||||
<item quantity="few">секунд</item>
|
||||
<item quantity="many">секунд</item>
|
||||
<item quantity="other">секунд</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Использовать все приложения</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>
|
||||
@@ -72,7 +119,7 @@
|
||||
<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_from_qr_code">Сканировать QR-код</string>
|
||||
<string name="create_output_dir_error">Не удалось создать выходной каталог</string>
|
||||
<string name="create_temp_dir_error">Не удалось создать временный локальный каталог</string>
|
||||
<string name="create_tunnel">Создать туннель</string>
|
||||
@@ -88,12 +135,11 @@
|
||||
<string name="error_root">Пожалуйста, получите root-доступ и попробуйте снова</string>
|
||||
<string name="error_up">Ошибка при запуске туннеля: %s</string>
|
||||
<string name="exclude_private_ips">Исключить частные IP-адреса</string>
|
||||
<string name="excluded_applications">Исключенные приложения</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_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>
|
||||
@@ -129,7 +175,7 @@
|
||||
<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="multiple_tunnels_title">Несколько туннелей</string>
|
||||
<string name="name">Имя</string>
|
||||
<string name="no_config_error">Попытка поднять туннель без конфигурации</string>
|
||||
<string name="no_configs_error">Конфигурации не найдены</string>
|
||||
@@ -145,16 +191,15 @@
|
||||
<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="public_key_description">Публичный ключ</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="set_exclusions">ОК</string>
|
||||
<string name="settings">Настройки</string>
|
||||
<string name="shell_exit_status_read_error">Shell не может прочитать статус выхода</string>
|
||||
<string name="shell_marker_count_error">Shell ожидает 4 маркера, получено %d</string>
|
||||
@@ -203,4 +248,8 @@
|
||||
<string name="zip_export_success">Сохранено в “%s”</string>
|
||||
<string name="zip_export_summary">Zip-архив будет сохранен в папке загрузок</string>
|
||||
<string name="zip_export_title">Экспорт туннелей в zip-архив</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">%d tunela ni bilo mogoče izbrisati: %s</item>
|
||||
<item quantity="two">%d tunelov ni bilo mogoče izbrisati: %s</item>
|
||||
<item quantity="few">%d tunelov ni bilo mogoče izbrisati: %s</item>
|
||||
<item quantity="other">%d tunelov ni bilo mogoče izbrisati: %s</item>
|
||||
</plurals>
|
||||
<plurals name="delete_success">
|
||||
<item quantity="one">%d tunel uspešno izbrisan</item>
|
||||
<item quantity="two">%d tunela uspešno izbrisana</item>
|
||||
<item quantity="few">%d tuneli uspešno izbrisani</item>
|
||||
<item quantity="other">%d tunelov uspešno izbrisanih</item>
|
||||
</plurals>
|
||||
<plurals name="delete_title">
|
||||
<item quantity="one">%d tunel izbran</item>
|
||||
<item quantity="two">%d tunela izbrana</item>
|
||||
<item quantity="few">%d tuneli izbrani</item>
|
||||
<item quantity="other">%d tunelov izbranih</item>
|
||||
</plurals>
|
||||
<plurals name="import_partial_success">
|
||||
<item quantity="one">%1$d tunel od %2$d uvožen</item>
|
||||
<item quantity="two">%1$d tunela od %2$d uvožena</item>
|
||||
<item quantity="few">%1$d tuneli od %2$d uvoženi</item>
|
||||
<item quantity="other">%1$d tunelov od %2$d uvoženih</item>
|
||||
</plurals>
|
||||
<plurals name="import_total_success">
|
||||
<item quantity="one">%d tunel uvožen</item>
|
||||
<item quantity="two">%d tunela uvožena</item>
|
||||
<item quantity="few">%d tuneli uvoženi</item>
|
||||
<item quantity="other">%d tunelov uvoženih</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="one">%d izvzeta aplikacija</item>
|
||||
<item quantity="two">%d izvzeti aplikaciji</item>
|
||||
<item quantity="few">%d izvzete aplikacije</item>
|
||||
<item quantity="other">%d izvzetih aplikacij</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d vključena aplikacija</item>
|
||||
<item quantity="two">%d vključeni aplikaciji</item>
|
||||
<item quantity="few">%d vključene aplikacije</item>
|
||||
<item quantity="other">%d vključenih aplikacij</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d izvzeta</item>
|
||||
<item quantity="two">%d izvzeti</item>
|
||||
<item quantity="few">%d izvzete</item>
|
||||
<item quantity="other">%d izvzetih</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d vključena</item>
|
||||
<item quantity="two">%d vključeni</item>
|
||||
<item quantity="few">%d vključene</item>
|
||||
<item quantity="other">%d vključenih</item>
|
||||
</plurals>
|
||||
<string name="all_applications">Vse aplikacije</string>
|
||||
<string name="exclude_from_tunnel">Izvzemi</string>
|
||||
<string name="include_in_tunnel">Vključi samo za</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Vključi za %d aplikacijo</item>
|
||||
<item quantity="two">Vključi za %d aplikaciji</item>
|
||||
<item quantity="few">Vključi za %d aplikacije</item>
|
||||
<item quantity="other">Vključi za %d aplikacij</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Izvzemi %d aplikacijo</item>
|
||||
<item quantity="two">Izvzemi %d aplikaciji</item>
|
||||
<item quantity="few">Izvzemi %d aplikacije</item>
|
||||
<item quantity="other">Izvzemi %d aplikacij</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">vsako %d sekundo</item>
|
||||
<item quantity="two">vsaki %d sekundi</item>
|
||||
<item quantity="few">vsake %d sekunde</item>
|
||||
<item quantity="other">vsakih %d sekund</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">sekunda</item>
|
||||
<item quantity="two">sekundi</item>
|
||||
<item quantity="few">sekunde</item>
|
||||
<item quantity="other">sekund</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Vse aplikacije</string>
|
||||
<string name="add_peer">Dodaj vrstnike</string>
|
||||
<string name="addresses">Naslovi</string>
|
||||
<string name="applications">Aplikacije</string>
|
||||
<string name="allow_remote_control_intents_summary_off">Zunanjim aplikacijam ni dovoljeno preklapljati tunelov (priporočeno)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">Zunanje aplikacije lahko preklapljajo tunele (napredno)</string>
|
||||
<string name="allow_remote_control_intents_title">Dovoljeno upravljanje preko zunanjih aplikacij</string>
|
||||
<string name="allowed_ips">Dovoljeni naslovi IP</string>
|
||||
<string name="app_name">WireGuard</string>
|
||||
<string name="bad_config_context">%1$s-ov %2$s</string>
|
||||
<string name="bad_config_context_top_level">%s</string>
|
||||
<string name="bad_config_error">%1$s v %2$s</string>
|
||||
<string name="bad_config_explanation_pka">: Mora biti pozitivno in ne večje od 65535</string>
|
||||
<string name="bad_config_explanation_positive_number">: Mora biti pozitivno</string>
|
||||
<string name="bad_config_explanation_udp_port">: Mora biti veljavna številka vrat UDP</string>
|
||||
<string name="bad_config_reason_invalid_key">Neveljaven ključ</string>
|
||||
<string name="bad_config_reason_invalid_number">Neveljavno število</string>
|
||||
<string name="bad_config_reason_invalid_value">Neveljavna vrednost</string>
|
||||
<string name="bad_config_reason_missing_attribute">Manjka atribut</string>
|
||||
<string name="bad_config_reason_missing_section">Manjka odsek</string>
|
||||
<string name="bad_config_reason_syntax_error">Sintaktična napaka</string>
|
||||
<string name="bad_config_reason_unknown_attribute">Neznan atribut</string>
|
||||
<string name="bad_config_reason_unknown_section">Neznani odsek</string>
|
||||
<string name="bad_config_reason_value_out_of_range">Vrednost je zunaj veljavnega območja</string>
|
||||
<string name="bad_extension_error">Datoteka mora biti .conf ali .zip</string>
|
||||
<string name="cancel">Prekliči</string>
|
||||
<string name="config_delete_error">Konfiguracijske datoteke %s ni bilo mogoče izbrisati</string>
|
||||
<string name="config_exists_error">Konfiguracija za „%s“ že obstaja</string>
|
||||
<string name="config_file_exists_error">Konfiguracijska datoteka za „%s“ že obstaja</string>
|
||||
<string name="config_not_found_error">Konfiguracijske datoteke za „%s“ ni bilo mogoče najti</string>
|
||||
<string name="config_rename_error">Konfiguracijske datoteke „%s“ ni bilo mogoče preimenovati</string>
|
||||
<string name="config_save_error">Konfiguracijske datoteke za „%1$s“ ni bilo mogoče shraniti: %2$s</string>
|
||||
<string name="config_save_success">Konfiguracijska datoteka za „%s“ uspešno shranjena</string>
|
||||
<string name="create_activity_title">Ustvarite tunel WireGuard</string>
|
||||
<string name="create_bin_dir_error">Lokalnega imenika za aplikacijo ni bilo mogoče ustvariti</string>
|
||||
<string name="create_downloads_file_error">Datoteke v mapi prenosov ni bilo mogoče ustvariti</string>
|
||||
<string name="create_empty">Ustvari na novo</string>
|
||||
<string name="create_from_file">Uvozi iz datoteke ali arhiva</string>
|
||||
<string name="create_from_qr_code">Skreniraj kodo QR</string>
|
||||
<string name="create_output_dir_error">Izhodnega imenika ni bilo mogoče ustvariti</string>
|
||||
<string name="create_temp_dir_error">Lokalnega začasnega imenika ni bilo mogoče ustvariti</string>
|
||||
<string name="create_tunnel">Ustvari tunel</string>
|
||||
<string name="dark_theme_summary_off">V uporabi svetla (dnevna) tema</string>
|
||||
<string name="dark_theme_summary_on">V uporabi temna (nočna) tema</string>
|
||||
<string name="dark_theme_title">Uporabi temno temo</string>
|
||||
<string name="delete">Izbriši</string>
|
||||
<string name="dns_servers">Strežniki DNS</string>
|
||||
<string name="edit">Uredi</string>
|
||||
<string name="endpoint">Končna točka</string>
|
||||
<string name="error_down">Napaka pri zaključevanju tunela: %s</string>
|
||||
<string name="error_fetching_apps">Napaka pri poizvedovanju seznama aplikacij: %s</string>
|
||||
<string name="error_root">Prosim omogočite dostop root in poskusite ponovno</string>
|
||||
<string name="error_up">Napaka pri vzpostavitvi tunela: %s</string>
|
||||
<string name="exclude_private_ips">Izvzemi zasebne naslove IP</string>
|
||||
<string name="generate_new_private_key">Izdelaj nov zasebni ključ</string>
|
||||
<string name="generic_error">Neznana napaka „%s“</string>
|
||||
<string name="hint_automatic">(samodejno)</string>
|
||||
<string name="hint_generated">(izdelano)</string>
|
||||
<string name="hint_optional">(izbirno)</string>
|
||||
<string name="hint_optional_discouraged">(izbirno, ni priporočljivo)</string>
|
||||
<string name="hint_random">(naključno)</string>
|
||||
<string name="illegal_filename_error">Neveljavno ime datoteke „%s“</string>
|
||||
<string name="import_error">Tunela ni bilo mogoče uvoziti: %s</string>
|
||||
<string name="import_from_qr_code">Uvozi tunel iz kode QR</string>
|
||||
<string name="import_success">„%s“ uvožen</string>
|
||||
<string name="interface_title">Vmesnik</string>
|
||||
<string name="key_contents_error">Napačni znaki v ključu</string>
|
||||
<string name="key_length_error">Napačna dolžina ključa</string>
|
||||
<string name="key_length_explanation_base64">: WireGuardovi ključi base64 morajo vsebovati 44 znakov (32 bajtov)</string>
|
||||
<string name="key_length_explanation_binary">: WireGuardovi ključi morajo biti veliki 32 bajtov</string>
|
||||
<string name="key_length_explanation_hex">: WireGuardovi ključi hex morajo biti veliki 64 znakov (32 bajtov)</string>
|
||||
<string name="listen_port">Vrata poslušanja</string>
|
||||
<string name="log_export_error">Dnevnika ni bilo mogoče izvoziti: %s</string>
|
||||
<string name="log_export_subject">Dnevniška datoteka WireGuard za Android</string>
|
||||
<string name="log_export_success">Shranjeno v „%s“</string>
|
||||
<string name="log_export_title">Izvozi dnevniško datoteko</string>
|
||||
<string name="log_saver_activity_label">Shrani dnevnik</string>
|
||||
<string name="log_viewer_pref_summary">Dnevniki lahko pomagajo pri razhroščevanju</string>
|
||||
<string name="log_viewer_pref_title">Prikaži dnevnik aplikacije</string>
|
||||
<string name="log_viewer_title">Dnevnik</string>
|
||||
<string name="logcat_error">Ukaza logcat ni bilo mogoče izvesti: </string>
|
||||
<string name="module_disabler_disabled_summary">Eksperimentalni modul jedra lahko izboljša zmogljivost</string>
|
||||
<string name="module_disabler_disabled_title">Omogoči zaledje za modul jedra</string>
|
||||
<string name="module_disabler_enabled_summary">Počasnejše uporabniško zaledje lahko izboljša stabilnost</string>
|
||||
<string name="module_disabler_enabled_title">Onemogoči zaledje za modul jedra</string>
|
||||
<string name="module_installer_error">Nekaj je šlo narobe, prosimo poskusite znova</string>
|
||||
<string name="module_installer_initial">Eksperimentalni modul jedra lahko izboljša zmogljivost</string>
|
||||
<string name="module_installer_not_found">Za vašo napravo ni razpoložljivih modulov</string>
|
||||
<string name="module_installer_title">Prenesi in namesti modul jedra</string>
|
||||
<string name="module_installer_working">Prenašanje in nameščanje …</string>
|
||||
<string name="module_version_error">Verzije modula jedra ni bilo mogoče določiti</string>
|
||||
<string name="mtu">MTU</string>
|
||||
<string name="multiple_tunnels_summary_off">Vklop enega tunela bo izklopil druge</string>
|
||||
<string name="multiple_tunnels_summary_on">Več tunelov je lahko aktiviranih sočasno</string>
|
||||
<string name="multiple_tunnels_title">Dovoli več sočasnih tunelov</string>
|
||||
<string name="name">Ime</string>
|
||||
<string name="no_config_error">Poskus vzpostavitve tunela brez konfiguracije</string>
|
||||
<string name="no_configs_error">Ni najdenih konfiguracij</string>
|
||||
<string name="no_tunnels_error">Ni tunelov</string>
|
||||
<string name="parse_error_generic">niz</string>
|
||||
<string name="parse_error_inet_address">Naslov IP</string>
|
||||
<string name="parse_error_inet_endpoint">končna točka</string>
|
||||
<string name="parse_error_inet_network">Omrežje IP</string>
|
||||
<string name="parse_error_integer">število</string>
|
||||
<string name="parse_error_reason">Ni mogoče razčleniti %1$s „%2$s“</string>
|
||||
<string name="peer">Vrstnik</string>
|
||||
<string name="permission_description">upravljanje tunelov WireGuard, aktivacija in deaktivacija tunela, zaradi česar bo internetni promet mogoče napačno usmerjen</string>
|
||||
<string name="permission_label">upravljanje tunelov WireGuard</string>
|
||||
<string name="persistent_keepalive">Trajno ohranjanje povezave</string>
|
||||
<string name="pre_shared_key">Ključ v skupni rabi</string>
|
||||
<string name="pre_shared_key_enabled">omogočeno</string>
|
||||
<string name="private_key">Zasebni ključ</string>
|
||||
<string name="public_key">Javni ključ</string>
|
||||
<string name="qr_code_hint">Namig: izdelajte z `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_off">Pri zagonu telefona omogočeni tuneli ne bodo aktivirani</string>
|
||||
<string name="restore_on_boot_summary_on">Pri zagonu telefona bodo omogočeni tuneli aktivirani</string>
|
||||
<string name="restore_on_boot_title">Ponovna vzpostavitev ob zagonu</string>
|
||||
<string name="save">Shrani</string>
|
||||
<string name="select_all">Izberi vse</string>
|
||||
<string name="settings">Nastavitve</string>
|
||||
<string name="shell_exit_status_read_error">Lupina ne more prebrati izhodnega statusa</string>
|
||||
<string name="shell_marker_count_error">Lupina je pričakovala 4 oznake, dobila pa je %d</string>
|
||||
<string name="shell_start_error">Lupina se ni mogla zagnati: %d</string>
|
||||
<string name="success_application_will_restart">Uspešno. Aplikacija se bo znova zagnala …</string>
|
||||
<string name="toggle_all">Preklopi vse</string>
|
||||
<string name="toggle_error">Napaka pri preklopu tunela WireGuard: %s</string>
|
||||
<string name="tools_installer_already">wg in wg-quick sta že nameščena</string>
|
||||
<string name="tools_installer_failure">Orodij ukazne vrstice ni bilo mogoče namestiti (ni dostopa root?)</string>
|
||||
<string name="tools_installer_initial">Namestitev izbirnih orodij za skripte</string>
|
||||
<string name="tools_installer_initial_magisk">Namestitev izbirnih orodij za skripte kot modula Magisk</string>
|
||||
<string name="tools_installer_initial_system">Namestitev izbirnih orodij za skripte na sistemsko particijo</string>
|
||||
<string name="tools_installer_success_magisk">wg in wg-quick kot modul Magisk nameščen (zahtevan ponovni zagon)</string>
|
||||
<string name="tools_installer_success_system">wg und wg-quick nameščena na sistemsko particijo</string>
|
||||
<string name="tools_installer_title">Namesti orodja za ukazno vrstico</string>
|
||||
<string name="tools_installer_working">Nameščam wg in wg-quick</string>
|
||||
<string name="tools_unavailable_error">Zahtevana orodja niso na voljo</string>
|
||||
<string name="transfer">Prenos</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">prejeto: %1$s, poslano: %2$s</string>
|
||||
<string name="transfer_tibibytes">%.2f TiB</string>
|
||||
<string name="tun_create_error">Naprave tun ni bilo mogoče ustvariti</string>
|
||||
<string name="tunnel_config_error">Tunela ni bilo mogoče nastaviti (wg-quick je vrnil %d)</string>
|
||||
<string name="tunnel_create_error">Tunela ni bilo mogoče ustvariti: %s</string>
|
||||
<string name="tunnel_create_success">Tunel „%s“ uspešno ustvarjen</string>
|
||||
<string name="tunnel_error_already_exists">Tunel „%s“ že obstaja</string>
|
||||
<string name="tunnel_error_invalid_name">Neveljavno ime</string>
|
||||
<string name="tunnel_list_placeholder">Dodaj tunel s klikom na modri gumb</string>
|
||||
<string name="tunnel_name">Ime tunela</string>
|
||||
<string name="tunnel_on_error">Tunela ni bilo mogoče vključiti (wgTurnOn je vrnil %d)</string>
|
||||
<string name="tunnel_rename_error">Tunela ni bilo mogoče preimenovati: %s</string>
|
||||
<string name="tunnel_rename_success">Tunel uspešno preimenovan v „%s“</string>
|
||||
<string name="type_name_go_userspace">Uporabniški prostor Go</string>
|
||||
<string name="type_name_kernel_module">Modul jedra</string>
|
||||
<string name="unknown_error">Neznana napaka</string>
|
||||
<string name="version_summary">Zaledje %1$s v%2$s</string>
|
||||
<string name="version_summary_checking">Preverjam verzijo zaledja %s</string>
|
||||
<string name="version_summary_unknown">Neznana verzija %s</string>
|
||||
<string name="version_title">WireGuard za Android v%s</string>
|
||||
<string name="vpn_not_authorized_error">Uporabnik ni odobril storitve VPN</string>
|
||||
<string name="vpn_start_error">Storitve Android VPN ni bilo mogoče zagnati</string>
|
||||
<string name="zip_export_error">Tunelov ni bilo mogoče izvoziti: %s</string>
|
||||
<string name="zip_export_success">Shranjeno v „%s“</string>
|
||||
<string name="zip_export_summary">Datoteka zip je bila shranjena v mapo Prenosi</string>
|
||||
<string name="zip_export_title">Izvozi tunele v datoteko zip</string>
|
||||
<string name="biometric_prompt_zip_exporter_title">Za izvoz tunelov se prijavite</string>
|
||||
<string name="biometric_prompt_private_key_title">Za ogled zasebnega ključa se prijavite</string>
|
||||
<string name="biometric_auth_error">Napaka pri overovljanju</string>
|
||||
<string name="biometric_auth_error_reason">Napaka pri overovljanju: %s</string>
|
||||
</resources>
|
||||
@@ -20,7 +20,7 @@
|
||||
<item name="android:windowBackground">@color/primary_color</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.MaterialComponents.ActionBar</item>
|
||||
<item name="textInputStyle">@style/TextInputLayoutBase</item>
|
||||
<item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<item name="android:windowBackground">@color/primary_color</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.MaterialComponents.ActionBar</item>
|
||||
<item name="textInputStyle">@style/TextInputLayoutBase</item>
|
||||
<item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -16,10 +16,36 @@
|
||||
<item quantity="other">导入了 %d 项</item>
|
||||
</plurals>
|
||||
<plurals name="set_excluded_applications">
|
||||
<item quantity="other">%d 个排除应用</item>
|
||||
<item quantity="other">对 %d 个应用不生效</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="other">对 %d 个应用生效</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="other">对 %d 个应用不生效</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<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="other">设定 %d 个应用</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="other">设定 %d 个应用</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="other">每隔 %d 秒</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="other">秒</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">不设定过滤</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>
|
||||
@@ -70,7 +96,6 @@
|
||||
<string name="error_root">请获取 root 权限并重试</string>
|
||||
<string name="error_up">建立连接时出错:%s</string>
|
||||
<string name="exclude_private_ips">排除局域网</string>
|
||||
<string name="excluded_applications">排除的应用</string>
|
||||
<string name="generate_new_private_key">生成新的私钥</string>
|
||||
<string name="generic_error">未知的 “%s” 错误</string>
|
||||
<string name="hint_automatic">(自动)</string>
|
||||
@@ -127,16 +152,15 @@
|
||||
<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="public_key_description">公钥</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="set_exclusions">确定</string>
|
||||
<string name="settings">设置</string>
|
||||
<string name="shell_exit_status_read_error">Shell 无法读取退出状态</string>
|
||||
<string name="shell_marker_count_error">Shell 应获取 4 个标记,获取到 %d 个</string>
|
||||
@@ -184,5 +208,9 @@
|
||||
<string name="zip_export_error">无法导出隧道配置:%s</string>
|
||||
<string name="zip_export_success">已保存至 “%s”</string>
|
||||
<string name="zip_export_summary">zip 压缩包将保存至下载文件夹</string>
|
||||
<string name="zip_export_title">导出隧道配置为 zip 压缩包</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>
|
||||
|
||||
@@ -24,8 +24,41 @@
|
||||
<item quantity="one">%d Excluded Application</item>
|
||||
<item quantity="other">%d Excluded Applications</item>
|
||||
</plurals>
|
||||
<plurals name="set_included_applications">
|
||||
<item quantity="one">%d Included Application</item>
|
||||
<item quantity="other">%d Included Applications</item>
|
||||
</plurals>
|
||||
<plurals name="n_excluded_applications">
|
||||
<item quantity="one">%d excluded</item>
|
||||
<item quantity="other">%d excluded</item>
|
||||
</plurals>
|
||||
<plurals name="n_included_applications">
|
||||
<item quantity="one">%d included</item>
|
||||
<item quantity="other">%d included</item>
|
||||
</plurals>
|
||||
<string name="all_applications">All Applications</string>
|
||||
<string name="exclude_from_tunnel">Exclude</string>
|
||||
<string name="include_in_tunnel">Include only</string>
|
||||
<plurals name="include_n_applications">
|
||||
<item quantity="one">Include %d app</item>
|
||||
<item quantity="other">Include %d apps</item>
|
||||
</plurals>
|
||||
<plurals name="exclude_n_applications">
|
||||
<item quantity="one">Exclude %d app</item>
|
||||
<item quantity="other">Exclude %d apps</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_unit">
|
||||
<item quantity="one">every second</item>
|
||||
<item quantity="other">every %d seconds</item>
|
||||
</plurals>
|
||||
<plurals name="persistent_keepalive_seconds_suffix">
|
||||
<item quantity="one">second</item>
|
||||
<item quantity="other">seconds</item>
|
||||
</plurals>
|
||||
<string name="use_all_applications">Use all apps</string>
|
||||
<string name="add_peer">Add peer</string>
|
||||
<string name="addresses">Addresses</string>
|
||||
<string name="applications">Applications</string>
|
||||
<string name="allow_remote_control_intents_summary_off">External apps may not toggle tunnels (recommended)</string>
|
||||
<string name="allow_remote_control_intents_summary_on">External apps may toggle tunnels (advanced)</string>
|
||||
<string name="allow_remote_control_intents_title">Allow remote control apps</string>
|
||||
@@ -68,6 +101,8 @@
|
||||
<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="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>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="endpoint">Endpoint</string>
|
||||
@@ -76,7 +111,6 @@
|
||||
<string name="error_root">Please obtain root access and try again</string>
|
||||
<string name="error_up">Error bringing up tunnel: %s</string>
|
||||
<string name="exclude_private_ips">Exclude private IPs</string>
|
||||
<string name="excluded_applications">Excluded Applications</string>
|
||||
<string name="generate_new_private_key">Generate new private key</string>
|
||||
<string name="generic_error">Unknown “%s” error</string>
|
||||
<string name="hint_automatic">(auto)</string>
|
||||
@@ -133,16 +167,15 @@
|
||||
<string name="permission_label">control WireGuard tunnels</string>
|
||||
<string name="persistent_keepalive">Persistent keepalive</string>
|
||||
<string name="pre_shared_key">Pre-shared key</string>
|
||||
<string name="pre_shared_key_enabled">enabled</string>
|
||||
<string name="private_key">Private key</string>
|
||||
<string name="public_key">Public key</string>
|
||||
<string name="public_key_description">Public key</string>
|
||||
<string name="qr_code_hint">Tip: generate with `qrencode -t ansiutf8 < tunnel.conf`.</string>
|
||||
<string name="restore_on_boot_summary_off">Will not bring up enabled tunnels at boot</string>
|
||||
<string name="restore_on_boot_summary_on">Will bring up enabled tunnels at boot</string>
|
||||
<string name="restore_on_boot_title">Restore on boot</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="select_all">Select all</string>
|
||||
<string name="set_exclusions">Set Exclusions</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="shell_exit_status_read_error">Shell cannot read exit status</string>
|
||||
<string name="shell_marker_count_error">Shell expected 4 markers, received %d</string>
|
||||
|
||||
@@ -19,8 +19,15 @@
|
||||
<item name="android:windowBackground">@color/primary_color</item>
|
||||
<item name="alertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item>
|
||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.MaterialComponents.ActionBar</item>
|
||||
<item name="textInputStyle">@style/TextInputLayoutBase</item>
|
||||
<item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.MaterialCardView" parent="Widget.MaterialComponents.CardView">
|
||||
<item name="cornerRadius">4dp</item>
|
||||
<item name="cardElevation">4dp</item>
|
||||
<item name="contentPadding">8dp</item>
|
||||
<item name="cardBackgroundColor">?attr/elevationOverlayColor</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog.Alert">
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<!--
|
||||
~ Copyright © 2020 WireGuard LLC. All Rights Reserved.
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<restriction
|
||||
android:defaultValue="false"
|
||||
android:description="@string/disable_config_export_description"
|
||||
android:key="disable_config_export"
|
||||
android:restrictionType="bool"
|
||||
android:title="@string/disable_config_export_title" />
|
||||
</restrictions>
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
buildscript {
|
||||
ext {
|
||||
wireguardVersionCode = 472
|
||||
wireguardVersionName = '1.0.20200401'
|
||||
wireguardVersionCode = 475
|
||||
wireguardVersionName = '1.0.20200724'
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user