diff options
Diffstat (limited to 'ui')
109 files changed, 1039 insertions, 334 deletions
diff --git a/ui/build.gradle b/ui/build.gradle index 1ac42e58..61c06f2a 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' @@ -12,16 +14,17 @@ group groupName final def keystorePropertiesFile = rootProject.file("keystore.properties") android { - compileSdkVersion 31 + compileSdk 33 buildFeatures { buildConfig = true dataBinding = true viewBinding = true } + namespace = 'com.wireguard.android' defaultConfig { applicationId 'eu.m7n.wireguard.android' minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 33 versionCode wireguardVersionCode versionName wireguardVersionName buildConfigField 'int', 'MIN_SDK_VERSION', "$minSdkVersion.apiLevel" @@ -59,6 +62,9 @@ android { } } buildTypes { + all { + buildConfigField("boolean", "IS_GOOGLE_PLAY", (System.getenv("WG_BUILD_FOR_GOOGLE_PLAY") == "true").toString()) + } release { if (keystorePropertiesFile.exists()) signingConfig signingConfigs.release minifyEnabled true @@ -69,10 +75,9 @@ android { versionNameSuffix "-debug" } } - lintOptions { - disable('LongLogTag') - warning('MissingTranslation') - warning('ImpliedQuantity') + lint { + disable 'LongLogTag' + warning 'MissingTranslation', 'ImpliedQuantity' } } @@ -96,14 +101,11 @@ dependencies { coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugarVersion" } -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { options.compilerArgs << '-Xlint:unchecked' options.deprecation = true } -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 - useIR = true - } +tasks.withType(KotlinCompile).configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8 } diff --git a/ui/src/main/AndroidManifest.xml b/ui/src/main/AndroidManifest.xml index 4dd38cb2..2f83ba86 100644 --- a/ui/src/main/AndroidManifest.xml +++ b/ui/src/main/AndroidManifest.xml @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - package="com.wireguard.android" android:installLocation="internalOnly"> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission @@ -21,6 +22,9 @@ <uses-feature android:name="android.hardware.camera.any" android:required="false" /> + <uses-feature + android:name="android.hardware.camera" + android:required="false" /> <permission android:name="${applicationId}.permission.CONTROL_TUNNELS" @@ -33,6 +37,7 @@ android:name=".Application" android:allowBackup="false" android:banner="@mipmap/banner" + android:enableOnBackInvokedCallback="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" @@ -44,7 +49,7 @@ android:theme="@style/NoBackgroundTheme" android:excludeFromRecents="true"/> - <activity android:name=".activity.MainActivity"> + <activity android:name=".activity.MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -58,7 +63,8 @@ <activity android:name=".activity.TvMainActivity" - android:theme="@style/TvTheme"> + android:theme="@style/TvTheme" + android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> @@ -82,7 +88,8 @@ <activity android:name=".activity.LogViewerActivity" - android:label="@string/log_viewer_title"> + android:label="@string/log_viewer_title" + android:exported="false"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> @@ -94,7 +101,7 @@ android:exported="false" android:grantUriPermissions="true" /> - <receiver android:name=".BootShutdownReceiver"> + <receiver android:name=".BootShutdownReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.ACTION_SHUTDOWN" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> @@ -103,7 +110,8 @@ <receiver android:name=".model.TunnelManager$IntentReceiver" - android:permission="${applicationId}.permission.CONTROL_TUNNELS"> + android:permission="${applicationId}.permission.CONTROL_TUNNELS" + android:exported="true"> <intent-filter> <action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" /> <action android:name="com.wireguard.android.action.SET_TUNNEL_UP" /> @@ -114,7 +122,8 @@ <service android:name=".QuickTileService" android:icon="@drawable/ic_tile" - android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> + android:permission="android.permission.BIND_QUICK_SETTINGS_TILE" + android:exported="true"> <intent-filter> <action android:name="android.service.quicksettings.action.QS_TILE" /> @@ -135,5 +144,10 @@ <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent> + + <intent> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> + </intent> </queries> </manifest> diff --git a/ui/src/main/java/com/wireguard/android/Application.kt b/ui/src/main/java/com/wireguard/android/Application.kt index d9dcb637..cac1f8d8 100644 --- a/ui/src/main/java/com/wireguard/android/Application.kt +++ b/ui/src/main/java/com/wireguard/android/Application.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android @@ -16,6 +16,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.preferencesDataStoreFile +import com.google.android.material.color.DynamicColors import com.wireguard.android.backend.Backend import com.wireguard.android.backend.GoBackend import com.wireguard.android.backend.WgQuickBackend @@ -64,11 +65,9 @@ class Application : android.app.Application() { private suspend fun determineBackend(): Backend { var backend: Backend? = null - var didStartRootShell = false if (UserKnobs.enableKernelModule.first() && WgQuickBackend.hasKernelSupport()) { try { - if (!didStartRootShell) - rootShell.start() + rootShell.start() val wgQuickBackend = WgQuickBackend(applicationContext, rootShell, toolsInstaller) wgQuickBackend.setMultipleTunnels(UserKnobs.multipleTunnels.first()) backend = wgQuickBackend @@ -88,6 +87,7 @@ class Application : android.app.Application() { override fun onCreate() { Log.i(TAG, USER_AGENT) super.onCreate() + DynamicColors.applyToActivitiesIfAvailable(this) rootShell = RootShell(applicationContext) toolsInstaller = ToolsInstaller(applicationContext, rootShell) preferencesDataStore = PreferenceDataStoreFactory.create { applicationContext.preferencesDataStoreFile("settings") } diff --git a/ui/src/main/java/com/wireguard/android/BootShutdownReceiver.kt b/ui/src/main/java/com/wireguard/android/BootShutdownReceiver.kt index b8bb4f6a..23775f44 100644 --- a/ui/src/main/java/com/wireguard/android/BootShutdownReceiver.kt +++ b/ui/src/main/java/com/wireguard/android/BootShutdownReceiver.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android diff --git a/ui/src/main/java/com/wireguard/android/QuickTileService.kt b/ui/src/main/java/com/wireguard/android/QuickTileService.kt index 8b35f9b4..ed208c50 100644 --- a/ui/src/main/java/com/wireguard/android/QuickTileService.kt +++ b/ui/src/main/java/com/wireguard/android/QuickTileService.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android diff --git a/ui/src/main/java/com/wireguard/android/activity/BaseActivity.kt b/ui/src/main/java/com/wireguard/android/activity/BaseActivity.kt index bdf0f8d4..8f0855ea 100644 --- a/ui/src/main/java/com/wireguard/android/activity/BaseActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/BaseActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity @@ -10,6 +10,7 @@ import androidx.databinding.CallbackRegistry.NotifierCallback import androidx.lifecycle.lifecycleScope import com.wireguard.android.Application import com.wireguard.android.model.ObservableTunnel +import kotlinx.coroutines.launch /** * Base class for activities that need to remember the currently-selected tunnel. @@ -30,6 +31,8 @@ abstract class BaseActivity : ThemeChangeAwareActivity() { } override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Restore the saved tunnel if there is one; otherwise grab it from the arguments. val savedTunnelName = when { savedInstanceState != null -> savedInstanceState.getString(KEY_SELECTED_TUNNEL) @@ -37,10 +40,9 @@ abstract class BaseActivity : ThemeChangeAwareActivity() { else -> null } if (savedTunnelName != null) - lifecycleScope.launchWhenCreated { selectedTunnel = Application.getTunnelManager().getTunnels()[savedTunnelName] } - - // The selected tunnel must be set before the superclass method recreates fragments. - super.onCreate(savedInstanceState) + lifecycleScope.launch { + selectedTunnel = Application.getTunnelManager().getTunnels()[savedTunnelName] + } } override fun onSaveInstanceState(outState: Bundle) { diff --git a/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt b/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt index dd100cf9..fe75be35 100644 --- a/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/activity/MainActivity.kt b/ui/src/main/java/com/wireguard/android/activity/MainActivity.kt index aac08e18..1566c129 100644 --- a/ui/src/main/java/com/wireguard/android/activity/MainActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/MainActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity @@ -9,6 +9,8 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.activity.OnBackPressedCallback +import androidx.activity.addCallback import androidx.appcompat.app.ActionBar import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentTransaction @@ -26,27 +28,29 @@ import com.wireguard.android.model.ObservableTunnel class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener { private var actionBar: ActionBar? = null private var isTwoPaneLayout = false + private var backPressedCallback: OnBackPressedCallback? = null - override fun onBackPressed() { + private fun handleBackPressed() { val backStackEntries = supportFragmentManager.backStackEntryCount // If the two-pane layout does not have an editor open, going back should exit the app. if (isTwoPaneLayout && backStackEntries <= 1) { finish() return } - // Deselect the current tunnel on navigating back from the detail pane to the one-pane list. - if (!isTwoPaneLayout && backStackEntries == 1) { + + if (backStackEntries >= 1) supportFragmentManager.popBackStack() + + // Deselect the current tunnel on navigating back from the detail pane to the one-pane list. + if (backStackEntries == 1) selectedTunnel = null - return - } - super.onBackPressed() } override fun onBackStackChanged() { + val backStackEntries = supportFragmentManager.backStackEntryCount + backPressedCallback?.isEnabled = backStackEntries >= 1 if (actionBar == null) return // Do not show the home menu when the two-pane layout is at the detail view (see above). - val backStackEntries = supportFragmentManager.backStackEntryCount val minBackStackEntries = if (isTwoPaneLayout) 2 else 1 actionBar!!.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries) } @@ -57,6 +61,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener actionBar = supportActionBar isTwoPaneLayout = findViewById<View?>(R.id.master_detail_wrapper) != null supportFragmentManager.addOnBackStackChangedListener(this) + backPressedCallback = onBackPressedDispatcher.addCallback(this) { handleBackPressed() } onBackStackChanged() } @@ -69,7 +74,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener return when (item.itemId) { android.R.id.home -> { // The back arrow in the action bar should act the same as the back button. - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } R.id.menu_action_edit -> { diff --git a/ui/src/main/java/com/wireguard/android/activity/SettingsActivity.kt b/ui/src/main/java/com/wireguard/android/activity/SettingsActivity.kt index df025163..aa768e0b 100644 --- a/ui/src/main/java/com/wireguard/android/activity/SettingsActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/SettingsActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity diff --git a/ui/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.kt b/ui/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.kt index 2158858b..06f621c4 100644 --- a/ui/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/ThemeChangeAwareActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity diff --git a/ui/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.kt b/ui/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.kt index 28d5da3a..b3fccee3 100644 --- a/ui/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/TunnelCreatorActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity diff --git a/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt b/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt index ebf059a5..ee95ce40 100644 --- a/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity diff --git a/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt b/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt index 7b0737e8..ae98f442 100644 --- a/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ @@ -16,12 +16,14 @@ import android.os.storage.StorageVolume import android.util.Log import android.view.View import android.widget.Toast +import androidx.activity.addCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import androidx.core.view.forEach import androidx.databinding.DataBindingUtil +import androidx.databinding.Observable import androidx.databinding.ObservableBoolean import androidx.databinding.ObservableField import androidx.lifecycle.lifecycleScope @@ -185,6 +187,17 @@ class TvMainActivity : AppCompatActivity() { binding.tunnelList.requestFocus() } } + + val backPressedCallback = onBackPressedDispatcher.addCallback(this) { handleBackPressed() } + val updateBackPressedCallback = object : Observable.OnPropertyChangedCallback() { + override fun onPropertyChanged(sender: Observable?, propertyId: Int) { + backPressedCallback.isEnabled = isDeleting.get() || filesRoot.get()?.isNotEmpty() == true + } + } + isDeleting.addOnPropertyChangedCallback(updateBackPressedCallback) + filesRoot.addOnPropertyChangedCallback(updateBackPressedCallback) + backPressedCallback.isEnabled = false + binding.executePendingBindings() setContentView(binding.root) @@ -298,7 +311,7 @@ class TvMainActivity : AppCompatActivity() { } } - override fun onBackPressed() { + private fun handleBackPressed() { when { isDeleting.get() -> { isDeleting.set(false) @@ -313,7 +326,6 @@ class TvMainActivity : AppCompatActivity() { binding.tunnelList.requestFocus() } } - else -> super.onBackPressed() } } diff --git a/ui/src/main/java/com/wireguard/android/configStore/ConfigStore.kt b/ui/src/main/java/com/wireguard/android/configStore/ConfigStore.kt index 5b66f830..7336e78f 100644 --- a/ui/src/main/java/com/wireguard/android/configStore/ConfigStore.kt +++ b/ui/src/main/java/com/wireguard/android/configStore/ConfigStore.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.configStore diff --git a/ui/src/main/java/com/wireguard/android/configStore/FileConfigStore.kt b/ui/src/main/java/com/wireguard/android/configStore/FileConfigStore.kt index 1099382d..30a2674f 100644 --- a/ui/src/main/java/com/wireguard/android/configStore/FileConfigStore.kt +++ b/ui/src/main/java/com/wireguard/android/configStore/FileConfigStore.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.configStore diff --git a/ui/src/main/java/com/wireguard/android/databinding/BindingAdapters.kt b/ui/src/main/java/com/wireguard/android/databinding/BindingAdapters.kt index 9c8a0dc2..d823fa8d 100644 --- a/ui/src/main/java/com/wireguard/android/databinding/BindingAdapters.kt +++ b/ui/src/main/java/com/wireguard/android/databinding/BindingAdapters.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.databinding diff --git a/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt b/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt index d1a1352b..93333cb6 100644 --- a/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt +++ b/ui/src/main/java/com/wireguard/android/databinding/ItemChangeListener.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.databinding diff --git a/ui/src/main/java/com/wireguard/android/databinding/Keyed.kt b/ui/src/main/java/com/wireguard/android/databinding/Keyed.kt index 1122f552..f91581d0 100644 --- a/ui/src/main/java/com/wireguard/android/databinding/Keyed.kt +++ b/ui/src/main/java/com/wireguard/android/databinding/Keyed.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.databinding diff --git a/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedArrayList.kt b/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedArrayList.kt index 9963255a..947644b3 100644 --- a/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedArrayList.kt +++ b/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedArrayList.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.databinding diff --git a/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.kt b/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.kt index 003ff74e..91223ad1 100644 --- a/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.kt +++ b/ui/src/main/java/com/wireguard/android/databinding/ObservableKeyedRecyclerViewAdapter.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.databinding diff --git a/ui/src/main/java/com/wireguard/android/databinding/ObservableSortedKeyedArrayList.kt b/ui/src/main/java/com/wireguard/android/databinding/ObservableSortedKeyedArrayList.kt index a8738627..a09d726f 100644 --- a/ui/src/main/java/com/wireguard/android/databinding/ObservableSortedKeyedArrayList.kt +++ b/ui/src/main/java/com/wireguard/android/databinding/ObservableSortedKeyedArrayList.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.databinding diff --git a/ui/src/main/java/com/wireguard/android/fragment/AddTunnelsSheet.kt b/ui/src/main/java/com/wireguard/android/fragment/AddTunnelsSheet.kt index c56462d6..f54f88f2 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/AddTunnelsSheet.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/AddTunnelsSheet.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment diff --git a/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt index f6f57ddb..627a9728 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt @@ -1,11 +1,15 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment import android.Manifest import android.app.Dialog +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.content.pm.PackageManager.PackageInfoFlags +import android.os.Build import android.os.Bundle import android.widget.Button import android.widget.Toast @@ -15,6 +19,7 @@ import androidx.databinding.Observable import androidx.fragment.app.DialogFragment import androidx.fragment.app.setFragmentResult import androidx.lifecycle.lifecycleScope +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.tabs.TabLayout import com.wireguard.android.BR import com.wireguard.android.R @@ -40,7 +45,7 @@ class AppListDialogFragment : DialogFragment() { try { val applicationData: MutableList<ApplicationData> = ArrayList() withContext(Dispatchers.IO) { - val packageInfos = pm.getPackagesHoldingPermissions(arrayOf(Manifest.permission.INTERNET), 0) + val packageInfos = getPackagesHoldingPermissions(pm, arrayOf(Manifest.permission.INTERNET)) packageInfos.forEach { val packageName = it.packageName val appInfo = it.applicationInfo @@ -59,6 +64,7 @@ class AppListDialogFragment : DialogFragment() { appData.clear() appData.addAll(applicationData) } + setButtonText() } catch (e: Throwable) { withContext(Dispatchers.Main.immediate) { val error = ErrorMessages[e] @@ -76,6 +82,15 @@ class AppListDialogFragment : DialogFragment() { initiallyExcluded = arguments?.getBoolean(KEY_IS_EXCLUDED) ?: true } + private fun getPackagesHoldingPermissions(pm: PackageManager, permissions: Array<String>): List<PackageInfo> { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + pm.getPackagesHoldingPermissions(permissions, PackageInfoFlags.of(0L)) + } else { + @Suppress("DEPRECATION") + pm.getPackagesHoldingPermissions(permissions, 0) + } + } + private fun setButtonText() { val numSelected = appData.count { it.isSelected } button?.text = if (numSelected == 0) @@ -88,7 +103,7 @@ class AppListDialogFragment : DialogFragment() { } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val alertDialogBuilder = AlertDialog.Builder(requireActivity()) + val alertDialogBuilder = MaterialAlertDialogBuilder(requireActivity()) val binding = AppListDialogFragmentBinding.inflate(requireActivity().layoutInflater, null, false) binding.executePendingBindings() alertDialogBuilder.setView(binding.root) diff --git a/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt index 783f5722..569a6217 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment diff --git a/ui/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.kt index d20f21c6..97f2ec73 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/ConfigNamingDialogFragment.kt @@ -1,18 +1,15 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment import android.app.Dialog -import android.content.DialogInterface import android.os.Bundle -import android.view.inputmethod.InputMethodManager -import androidx.appcompat.app.AlertDialog -import androidx.core.content.getSystemService +import android.view.WindowManager import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope -import com.google.android.material.textfield.TextInputEditText +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.wireguard.android.Application import com.wireguard.android.R import com.wireguard.android.databinding.ConfigNamingDialogFragmentBinding @@ -26,7 +23,6 @@ import java.nio.charset.StandardCharsets class ConfigNamingDialogFragment : DialogFragment() { private var binding: ConfigNamingDialogFragmentBinding? = null private var config: Config? = null - private var imm: InputMethodManager? = null private fun createTunnelAndDismiss() { val binding = binding ?: return @@ -41,12 +37,6 @@ class ConfigNamingDialogFragment : DialogFragment() { } } } - - override fun dismiss() { - setKeyboardVisible(false) - super.dismiss() - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configText = requireArguments().getString(KEY_CONFIG_TEXT) @@ -63,45 +53,18 @@ class ConfigNamingDialogFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val activity = requireActivity() - imm = activity.getSystemService() - val alertDialogBuilder = AlertDialog.Builder(activity) + val alertDialogBuilder = MaterialAlertDialogBuilder(activity) alertDialogBuilder.setTitle(R.string.import_from_qr_code) binding = ConfigNamingDialogFragmentBinding.inflate(activity.layoutInflater, null, false) binding?.apply { executePendingBindings() alertDialogBuilder.setView(root) } - alertDialogBuilder.setPositiveButton(R.string.create_tunnel, null) + alertDialogBuilder.setPositiveButton(R.string.create_tunnel) { _, _ -> createTunnelAndDismiss() } alertDialogBuilder.setNegativeButton(R.string.cancel) { _, _ -> dismiss() } - return alertDialogBuilder.create().apply { - setOnShowListener { - findViewById<TextInputEditText>(R.id.tunnel_name_text)?.apply { - setOnFocusChangeListener { v, _ -> - v.post { - imm?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT) - } - } - requestFocus() - } - } - } - } - - override fun onResume() { - super.onResume() - val dialog = dialog as AlertDialog? - if (dialog != null) { - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener { createTunnelAndDismiss() } - setKeyboardVisible(true) - } - } - - private fun setKeyboardVisible(visible: Boolean) { - if (visible) { - imm!!.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0) - } else if (binding != null) { - imm!!.hideSoftInputFromWindow(binding!!.tunnelNameText.windowToken, 0) - } + val dialog = alertDialogBuilder.create() + dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) + return dialog } companion object { diff --git a/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt index 7046cb96..e7c1262e 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt @@ -1,16 +1,20 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment import android.os.Bundle +import android.util.Log; import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.core.view.MenuProvider import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.wireguard.android.R import com.wireguard.android.backend.Tunnel @@ -18,24 +22,27 @@ import com.wireguard.android.databinding.TunnelDetailFragmentBinding import com.wireguard.android.databinding.TunnelDetailPeerBinding import com.wireguard.android.model.ObservableTunnel import com.wireguard.android.util.QuantityFormatter +import com.wireguard.android.viewmodel.ConfigDetail import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import java.time.Duration +import java.time.LocalDateTime +import java.time.ZoneId /** * Fragment that shows details about a specific tunnel. */ -class TunnelDetailFragment : BaseFragment() { +class TunnelDetailFragment : BaseFragment(), MenuProvider { private var binding: TunnelDetailFragmentBinding? = null private var lastState = Tunnel.State.TOGGLE private var timerActive = true - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return false } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.tunnel_detail, menu) + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.tunnel_detail, menu) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, @@ -46,6 +53,11 @@ class TunnelDetailFragment : BaseFragment() { return binding?.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + override fun onDestroyView() { binding = null super.onDestroyView() @@ -70,7 +82,9 @@ class TunnelDetailFragment : BaseFragment() { } else { lifecycleScope.launch { try { - binding.config = newTunnel.getConfigAsync() + var config = newTunnel.getConfigDetailAsync() + binding.config = config + Log.i(TAG, "onSelectedTunnelChanged " + config + ", " + config.config) } catch (_: Throwable) { binding.config = null } @@ -99,6 +113,7 @@ class TunnelDetailFragment : BaseFragment() { val state = tunnel.state if (state != Tunnel.State.UP && lastState == state) return lastState = state + var now = LocalDateTime.now(ZoneId.of("UTC")) try { val statistics = tunnel.getStatisticsAsync() for (i in 0 until binding.peersLayout.childCount) { @@ -110,11 +125,20 @@ class TunnelDetailFragment : BaseFragment() { if (rx == 0L && tx == 0L) { peer.transferLabel.visibility = View.GONE peer.transferText.visibility = View.GONE - continue + } else { + peer.transferText.text = getString(R.string.transfer_rx_tx, QuantityFormatter.formatBytes(rx), QuantityFormatter.formatBytes(tx)) + peer.transferLabel.visibility = View.VISIBLE + peer.transferText.visibility = View.VISIBLE + } + val lastHandshake:LocalDateTime? = statistics.peerLastHandshake(publicKey) + if (lastHandshake == null) { + peer.lastHandshakeLabel.visibility = View.GONE + peer.lastHandshakeText.visibility = View.GONE + } else { + peer.lastHandshakeText.text = getString(R.string.last_handshake_ago, QuantityFormatter.formatDuration(Duration.between(lastHandshake, now))) + peer.lastHandshakeLabel.visibility = View.VISIBLE + peer.lastHandshakeText.visibility = View.VISIBLE } - peer.transferText.text = getString(R.string.transfer_rx_tx, QuantityFormatter.formatBytes(rx), QuantityFormatter.formatBytes(tx)) - peer.transferLabel.visibility = View.VISIBLE - peer.transferText.visibility = View.VISIBLE } } catch (e: Throwable) { for (i in 0 until binding.peersLayout.childCount) { @@ -122,7 +146,13 @@ class TunnelDetailFragment : BaseFragment() { ?: continue peer.transferLabel.visibility = View.GONE peer.transferText.visibility = View.GONE + peer.lastHandshakeLabel.visibility = View.GONE + peer.lastHandshakeText.visibility = View.GONE } } } + + companion object { + private const val TAG = "WireGuard/TunnelDetailFragment" + } } diff --git a/ui/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.kt index 6c6f53f9..f37475c2 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/TunnelEditorFragment.kt @@ -1,10 +1,11 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment import android.content.Context +import android.os.Build import android.os.Bundle import android.text.InputType import android.util.Log @@ -16,10 +17,16 @@ import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.view.inputmethod.InputMethodManager +import android.widget.ArrayAdapter +import android.widget.AutoCompleteTextView import android.widget.EditText +import android.widget.Filter import android.widget.Toast +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar +import com.google.android.material.textfield.TextInputLayout import com.wireguard.android.Application import com.wireguard.android.R import com.wireguard.android.backend.Tunnel @@ -29,17 +36,33 @@ import com.wireguard.android.util.AdminKnobs import com.wireguard.android.util.BiometricAuthenticator import com.wireguard.android.util.ErrorMessages import com.wireguard.android.viewmodel.ConfigProxy +import com.wireguard.android.viewmodel.Constants import com.wireguard.config.Config import kotlinx.coroutines.launch /** * Fragment for editing a WireGuard configuration. */ -class TunnelEditorFragment : BaseFragment() { +class TunnelEditorFragment : BaseFragment(), MenuProvider { private var haveShownKeys = false private var binding: TunnelEditorFragmentBinding? = null private var tunnel: ObservableTunnel? = null + private class MaterialSpinnerAdapter<T>(context: Context, resource: Int, private val objects: List<T>) : ArrayAdapter<T>(context, resource, objects) { + private val _filter: Filter by lazy { + object : Filter() { + override fun performFiltering(constraint: CharSequence?): FilterResults { + return FilterResults() + } + + override fun publishResults(constraint: CharSequence?, results: FilterResults?) { + } + } + } + + override fun getFilter(): Filter = _filter + } + private fun onConfigLoaded(config: Config) { binding?.config = ConfigProxy(config) } @@ -65,11 +88,10 @@ class TunnelEditorFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.config_editor, menu) + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.config_editor, menu) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, @@ -80,9 +102,21 @@ class TunnelEditorFragment : BaseFragment() { executePendingBindings() privateKeyTextLayout.setEndIconOnClickListener { config?.`interface`?.generateKeyPair() } } + + var httpProxyMenu = binding?.root?.findViewById<TextInputLayout>(R.id.http_proxy_menu) + var httpProxyItems = listOf(Constants.HTTP_PROXY_NONE, Constants.HTTP_PROXY_MANUAL, Constants.HTTP_PROXY_PAC) + var httpProxyAdapter = MaterialSpinnerAdapter(requireContext(), R.layout.http_proxy_menu_item, httpProxyItems) + var httpProxyMenuText = httpProxyMenu?.editText as? AutoCompleteTextView + httpProxyMenuText?.setAdapter(httpProxyAdapter) + return binding?.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + override fun onDestroyView() { activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) binding = null @@ -105,8 +139,8 @@ class TunnelEditorFragment : BaseFragment() { selectedTunnel = tunnel } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.menu_action_save) { + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + if (menuItem.itemId == R.id.menu_action_save) { binding ?: return false val newConfig = try { binding!!.config!!.resolve() @@ -152,7 +186,7 @@ class TunnelEditorFragment : BaseFragment() { } return true } - return super.onOptionsItemSelected(item) + return false } @Suppress("UNUSED_PARAMETER") @@ -265,7 +299,12 @@ class TunnelEditorFragment : BaseFragment() { onSelectedTunnelChanged(null, selectedTunnel) } else { tunnel = selectedTunnel - val config: ConfigProxy = savedInstanceState.getParcelable(KEY_LOCAL_CONFIG)!! + val config: ConfigProxy = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + savedInstanceState.getParcelable(KEY_LOCAL_CONFIG, ConfigProxy::class.java)!! + } else { + @Suppress("DEPRECATION") + savedInstanceState.getParcelable(KEY_LOCAL_CONFIG)!! + } val originalName = savedInstanceState.getString(KEY_ORIGINAL_NAME) if (tunnel != null && tunnel!!.name != originalName) onSelectedTunnelChanged(null, tunnel) else binding!!.config = config } diff --git a/ui/src/main/java/com/wireguard/android/fragment/TunnelListFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/TunnelListFragment.kt index 390a6396..53098eb8 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/TunnelListFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/TunnelListFragment.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.fragment diff --git a/ui/src/main/java/com/wireguard/android/model/ApplicationData.kt b/ui/src/main/java/com/wireguard/android/model/ApplicationData.kt index c4cb168b..f3892424 100644 --- a/ui/src/main/java/com/wireguard/android/model/ApplicationData.kt +++ b/ui/src/main/java/com/wireguard/android/model/ApplicationData.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.model diff --git a/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt b/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt index 252e8759..e38e473f 100644 --- a/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt +++ b/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.model @@ -7,12 +7,20 @@ package com.wireguard.android.model import android.util.Log import androidx.databinding.BaseObservable import androidx.databinding.Bindable +import com.wireguard.android.Application import com.wireguard.android.BR +import com.wireguard.android.backend.Dhcp import com.wireguard.android.backend.Statistics import com.wireguard.android.backend.Tunnel import com.wireguard.android.databinding.Keyed import com.wireguard.android.util.applicationScope +import com.wireguard.android.viewmodel.ConfigDetail +import com.wireguard.android.viewmodel.PeerDetail import com.wireguard.config.Config +import com.wireguard.config.InetEndpoint +import com.wireguard.config.InetNetwork +import com.wireguard.crypto.Key +import java.util.Optional import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -55,7 +63,18 @@ class ObservableTunnel internal constructor( } fun onStateChanged(state: Tunnel.State): Tunnel.State { - if (state != Tunnel.State.UP) onStatisticsChanged(null) + if (state != Tunnel.State.UP) { + onStatisticsChanged(null) + onDhcpChanged(null) + Application.getCoroutineScope().launch { + onPeersReset() + } + } else { + configDetail?.peers?.forEach { + var endpoint: InetEndpoint? = it.peer?.endpoint?.orElse(null) + it.endpoint = Optional.ofNullable(endpoint?.getResolved()?.get()) + } + } this.state = state notifyPropertyChanged(BR.state) return state @@ -68,6 +87,7 @@ class ObservableTunnel internal constructor( this@ObservableTunnel.state } + private var configDetail: ConfigDetail? = if (config != null) ConfigDetail(config) else null @get:Bindable var config = config @@ -86,7 +106,11 @@ class ObservableTunnel internal constructor( private set suspend fun getConfigAsync(): Config = withContext(Dispatchers.Main.immediate) { - config ?: manager.getTunnelConfig(this@ObservableTunnel) + config ?: manager.getTunnelConfig(this@ObservableTunnel).config!! + } + + suspend fun getConfigDetailAsync(): ConfigDetail = withContext(Dispatchers.Main.immediate) { + configDetail ?: manager.getTunnelConfig(this@ObservableTunnel) } suspend fun setConfigAsync(config: Config): Config = withContext(Dispatchers.Main.immediate) { @@ -98,10 +122,11 @@ class ObservableTunnel internal constructor( } } - fun onConfigChanged(config: Config?): Config? { + fun onConfigChanged(config: Config?): ConfigDetail? { + this.configDetail = ConfigDetail(config) this.config = config notifyPropertyChanged(BR.config) - return config + return configDetail } @@ -137,6 +162,106 @@ class ObservableTunnel internal constructor( } + @get:Bindable + var dhcp: Dhcp? = null + private set + + override fun onDhcpChange(newDhcp: Dhcp) { + onDhcpChanged(newDhcp) + } + + fun onDhcpChanged(dhcp: Dhcp?): Dhcp? { + this.dhcp = dhcp + notifyPropertyChanged(BR.dhcp) + return dhcp + } + + // Remove dynamic peers, and reset static peers + fun onPeersReset() { + Log.i(TAG, "ObservableTunnel onPeersReset") + var toRemove: MutableList<PeerDetail> = ArrayList() + + configDetail?.peers?.forEach { + if (it.peer == null) { + toRemove.add(it) + } else { + it.endpoint = Optional.empty() + } + } + + toRemove.forEach { + Log.i(TAG, "ObservableTunnel remove " + it) + configDetail?.peers?.remove(it) + } + } + + override fun onEndpointChange(publicKey: Key, newEndpoint: InetEndpoint?) { + Application.getCoroutineScope().launch { + onEndpointChanged(publicKey, newEndpoint) + } + } + + private fun onEndpointChanged(publicKey: Key, newEndpoint: InetEndpoint?) { + + Log.i(TAG, "ObservableTunnel onEndpointChange " + newEndpoint) + var peer: PeerDetail? = null + + configDetail?.peers?.forEach { + if (it.publicKey.equals(publicKey) == true) { + Log.i(TAG, "ObservableTunnel peer " + it + ", " + it.peer) + peer = it; + } + } + + if (peer == null) { + Log.i(TAG, "ObservableTunnel create peer " + publicKey) + peer = PeerDetail(publicKey) + configDetail?.peers?.add(peer) + } + + var peer2: PeerDetail = peer!! + + if (newEndpoint != null) { + peer2.endpoint = newEndpoint.getResolved() + } else { + var peer3 = peer2.peer + peer2.endpoint = if (peer3 != null) peer3.endpoint else Optional.empty() + } + } + + fun lookupPeer(publicKey: Key): PeerDetail { + configDetail?.peers?.forEach { + if (it.publicKey.equals(publicKey) == true) { + Log.i(TAG, "ObservableTunnel peer " + it + ", " + it.peer) + return it + } + } + + Log.i(TAG, "ObservableTunnel create peer " + publicKey) + var peer: PeerDetail = PeerDetail(publicKey) + configDetail?.peers?.add(peer) + + return peer + } + + override fun onAllowedIpsChange(publicKey: Key, addNetworks: List<InetNetwork>?, removeNetworks: List<InetNetwork>?) { + Application.getCoroutineScope().launch { + onAllowedIpsChanged(publicKey, addNetworks, removeNetworks) + } + } + + private fun onAllowedIpsChanged(publicKey: Key, addNetworks: List<InetNetwork>?, removeNetworks: List<InetNetwork>?) { + var peer: PeerDetail = lookupPeer(publicKey) + + removeNetworks?.let() { + peer.allowedIps.removeAll(removeNetworks) + } + addNetworks?.let() { + peer.allowedIps.addAll(addNetworks) + } + } + + suspend fun deleteAsync() = manager.delete(this) diff --git a/ui/src/main/java/com/wireguard/android/model/TunnelComparator.kt b/ui/src/main/java/com/wireguard/android/model/TunnelComparator.kt index 0baa44e8..e6b46a54 100644 --- a/ui/src/main/java/com/wireguard/android/model/TunnelComparator.kt +++ b/ui/src/main/java/com/wireguard/android/model/TunnelComparator.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt b/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt index ec796164..77d69f70 100644 --- a/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt +++ b/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.model @@ -24,6 +24,7 @@ import com.wireguard.android.databinding.ObservableSortedKeyedArrayList import com.wireguard.android.util.ErrorMessages import com.wireguard.android.util.UserKnobs import com.wireguard.android.util.applicationScope +import com.wireguard.android.viewmodel.ConfigDetail import com.wireguard.config.Config import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers @@ -94,7 +95,7 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { applicationScope.launch { UserKnobs.setLastUsedTunnel(value?.name) } } - suspend fun getTunnelConfig(tunnel: ObservableTunnel): Config = withContext(Dispatchers.Main.immediate) { + suspend fun getTunnelConfig(tunnel: ObservableTunnel): ConfigDetail = withContext(Dispatchers.Main.immediate) { tunnel.onConfigChanged(withContext(Dispatchers.IO) { configStore.load(tunnel.name) })!! } @@ -155,7 +156,7 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { tunnel.onConfigChanged(withContext(Dispatchers.IO) { getBackend().setState(tunnel, tunnel.state, config) configStore.save(tunnel.name, config) - })!! + })!!.config!! } suspend fun setTunnelName(tunnel: ObservableTunnel, name: String): String = withContext(Dispatchers.Main.immediate) { diff --git a/ui/src/main/java/com/wireguard/android/preference/DonatePreference.kt b/ui/src/main/java/com/wireguard/android/preference/DonatePreference.kt new file mode 100644 index 00000000..57202c81 --- /dev/null +++ b/ui/src/main/java/com/wireguard/android/preference/DonatePreference.kt @@ -0,0 +1,38 @@ +/* + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.wireguard.android.preference + +import android.app.AlertDialog +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.util.AttributeSet +import androidx.preference.Preference +import com.wireguard.android.BuildConfig +import com.wireguard.android.R + +class DonatePreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) { + override fun getSummary() = context.getString(R.string.donate_summary) + + override fun getTitle() = context.getString(R.string.donate_title) + + override fun onClick() { + if (BuildConfig.IS_GOOGLE_PLAY) { + AlertDialog.Builder(context) + .setTitle(R.string.donate_title) + .setMessage(R.string.donate_google_play_disappointment) + .show() + return + } + val intent = Intent(Intent.ACTION_VIEW) + intent.data = Uri.parse("https://www.wireguard.com/donations/") + try { + context.startActivity(intent) + } catch (ignored: ActivityNotFoundException) { + } + } +}
\ No newline at end of file diff --git a/ui/src/main/java/com/wireguard/android/preference/KernelModuleEnablerPreference.kt b/ui/src/main/java/com/wireguard/android/preference/KernelModuleEnablerPreference.kt index 15f1dcec..20de8e93 100644 --- a/ui/src/main/java/com/wireguard/android/preference/KernelModuleEnablerPreference.kt +++ b/ui/src/main/java/com/wireguard/android/preference/KernelModuleEnablerPreference.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.preference diff --git a/ui/src/main/java/com/wireguard/android/preference/PreferencesPreferenceDataStore.kt b/ui/src/main/java/com/wireguard/android/preference/PreferencesPreferenceDataStore.kt index 3f1a7223..1a491684 100644 --- a/ui/src/main/java/com/wireguard/android/preference/PreferencesPreferenceDataStore.kt +++ b/ui/src/main/java/com/wireguard/android/preference/PreferencesPreferenceDataStore.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt b/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt index 7c6283ba..dac80e88 100644 --- a/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt +++ b/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.preference diff --git a/ui/src/main/java/com/wireguard/android/preference/VersionPreference.kt b/ui/src/main/java/com/wireguard/android/preference/VersionPreference.kt index 27065d28..31c751d2 100644 --- a/ui/src/main/java/com/wireguard/android/preference/VersionPreference.kt +++ b/ui/src/main/java/com/wireguard/android/preference/VersionPreference.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.preference diff --git a/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt b/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt index 65880303..ced95b69 100644 --- a/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt +++ b/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.preference diff --git a/ui/src/main/java/com/wireguard/android/util/AdminKnobs.kt b/ui/src/main/java/com/wireguard/android/util/AdminKnobs.kt index c7a683a3..430e904d 100644 --- a/ui/src/main/java/com/wireguard/android/util/AdminKnobs.kt +++ b/ui/src/main/java/com/wireguard/android/util/AdminKnobs.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt b/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt index d187a4c8..fe36898f 100644 --- a/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt +++ b/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/util/ClipboardUtils.kt b/ui/src/main/java/com/wireguard/android/util/ClipboardUtils.kt index 65fdf078..6a0d54ba 100644 --- a/ui/src/main/java/com/wireguard/android/util/ClipboardUtils.kt +++ b/ui/src/main/java/com/wireguard/android/util/ClipboardUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.util diff --git a/ui/src/main/java/com/wireguard/android/util/DownloadsFileSaver.kt b/ui/src/main/java/com/wireguard/android/util/DownloadsFileSaver.kt index 6a7256e0..8538e75e 100644 --- a/ui/src/main/java/com/wireguard/android/util/DownloadsFileSaver.kt +++ b/ui/src/main/java/com/wireguard/android/util/DownloadsFileSaver.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.util diff --git a/ui/src/main/java/com/wireguard/android/util/ErrorMessages.kt b/ui/src/main/java/com/wireguard/android/util/ErrorMessages.kt index 60c6b878..466009f0 100644 --- a/ui/src/main/java/com/wireguard/android/util/ErrorMessages.kt +++ b/ui/src/main/java/com/wireguard/android/util/ErrorMessages.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.util @@ -114,6 +114,8 @@ object ErrorMessages { return resources.getString(R.string.bad_config_explanation_udp_port) } else if (bce.location == BadConfigException.Location.MTU) { return resources.getString(R.string.bad_config_explanation_positive_number) + } else if (bce.location == BadConfigException.Location.HTTP_PROXY) { + return resources.getString(R.string.bad_config_explanation_http_proxy) } else if (bce.location == BadConfigException.Location.PERSISTENT_KEEPALIVE) { return resources.getString(R.string.bad_config_explanation_pka) } diff --git a/ui/src/main/java/com/wireguard/android/util/Extensions.kt b/ui/src/main/java/com/wireguard/android/util/Extensions.kt index f653cb61..98f94af9 100644 --- a/ui/src/main/java/com/wireguard/android/util/Extensions.kt +++ b/ui/src/main/java/com/wireguard/android/util/Extensions.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/util/QrCodeFromFileScanner.kt b/ui/src/main/java/com/wireguard/android/util/QrCodeFromFileScanner.kt index 3e54a52a..135fc1f3 100644 --- a/ui/src/main/java/com/wireguard/android/util/QrCodeFromFileScanner.kt +++ b/ui/src/main/java/com/wireguard/android/util/QrCodeFromFileScanner.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2022 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt b/ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt index 4a9ffed4..f9abd590 100644 --- a/ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt +++ b/ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,8 @@ package com.wireguard.android.util import com.wireguard.android.Application import com.wireguard.android.R +import java.time.Duration + object QuantityFormatter { fun formatBytes(bytes: Long): String { val context = Application.get().applicationContext @@ -19,4 +21,58 @@ object QuantityFormatter { else -> context.getString(R.string.transfer_tibibytes, bytes / (1024.0 * 1024.0 * 1024.0) / 1024.0) } } -}
\ No newline at end of file + + fun formatDuration(duration: Duration): String { + val context = Application.get().applicationContext + val str = formatHours(duration.getSeconds()) + return when { + str != "" -> str + else -> context.getString(R.string.duration_seconds, 0) + } + } + + fun formatHours(seconds: Long): String { + val context = Application.get().applicationContext + val hours = seconds / 3600 + val restSeconds = seconds % 3600 + val str = formatMinutes(restSeconds) + + return when { + hours > 0 -> context.getString(R.string.duration_hours, hours) + if (str != "") ", " + str else "" + else -> str + } + } + + fun formatDays(seconds: Long): String { + val context = Application.get().applicationContext + val days = seconds / 3600 / 24 + val restSeconds = seconds % (3600 * 24) + val str = formatHours(restSeconds) + + return when { + days > 0 -> context.getString(R.string.duration_days, days) + if (str != "") ", " + str else "" + else -> str + } + } + + fun formatMinutes(seconds: Long): String { + val context = Application.get().applicationContext + val minutes = seconds / 60 + val restSeconds = seconds % 60 + val str = formatSeconds(restSeconds) + + return when { + minutes > 0 -> context.getString(R.string.duration_minutes, minutes) + if (str != "") ", " + str else "" + else -> str + } + } + + fun formatSeconds(seconds: Long): String { + val context = Application.get().applicationContext + + return when { + seconds > 0 -> context.getString(R.string.duration_seconds, seconds) + else -> "" + } + } +} diff --git a/ui/src/main/java/com/wireguard/android/util/TunnelImporter.kt b/ui/src/main/java/com/wireguard/android/util/TunnelImporter.kt index 64993cda..e66691e8 100644 --- a/ui/src/main/java/com/wireguard/android/util/TunnelImporter.kt +++ b/ui/src/main/java/com/wireguard/android/util/TunnelImporter.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/util/UserKnobs.kt b/ui/src/main/java/com/wireguard/android/util/UserKnobs.kt index 224c1e1a..52672e45 100644 --- a/ui/src/main/java/com/wireguard/android/util/UserKnobs.kt +++ b/ui/src/main/java/com/wireguard/android/util/UserKnobs.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ diff --git a/ui/src/main/java/com/wireguard/android/viewmodel/ConfigDetail.kt b/ui/src/main/java/com/wireguard/android/viewmodel/ConfigDetail.kt new file mode 100644 index 00000000..af95a86a --- /dev/null +++ b/ui/src/main/java/com/wireguard/android/viewmodel/ConfigDetail.kt @@ -0,0 +1,22 @@ +package com.wireguard.android.viewmodel + +import androidx.databinding.ObservableArrayList +import androidx.databinding.ObservableList + +import com.wireguard.config.Config + +class ConfigDetail { + val config: Config? + val peers: ObservableList<PeerDetail> = ObservableArrayList() + + constructor(other: Config?) { + config = other + if (other != null) { + other.peers.forEach { + val detail = PeerDetail(it) + peers.add(detail) + detail.bind(this) + } + } + } +} diff --git a/ui/src/main/java/com/wireguard/android/viewmodel/ConfigProxy.kt b/ui/src/main/java/com/wireguard/android/viewmodel/ConfigProxy.kt index ccfbce34..e29de2dd 100644 --- a/ui/src/main/java/com/wireguard/android/viewmodel/ConfigProxy.kt +++ b/ui/src/main/java/com/wireguard/android/viewmodel/ConfigProxy.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.viewmodel @@ -18,7 +18,7 @@ class ConfigProxy : Parcelable { val peers: ObservableList<PeerProxy> = ObservableArrayList() private constructor(parcel: Parcel) { - `interface` = parcel.readParcelable(InterfaceProxy::class.java.classLoader)!! + `interface` = InterfaceProxy.CREATOR.createFromParcel(parcel) parcel.readTypedList(peers, PeerProxy.CREATOR) peers.forEach { it.bind(this) } } diff --git a/ui/src/main/java/com/wireguard/android/viewmodel/InterfaceProxy.kt b/ui/src/main/java/com/wireguard/android/viewmodel/InterfaceProxy.kt index 2792f749..16c3e6a3 100644 --- a/ui/src/main/java/com/wireguard/android/viewmodel/InterfaceProxy.kt +++ b/ui/src/main/java/com/wireguard/android/viewmodel/InterfaceProxy.kt @@ -1,9 +1,11 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.viewmodel +import android.net.Uri +import android.os.Build import android.os.Parcel import android.os.Parcelable import androidx.databinding.BaseObservable @@ -18,6 +20,12 @@ import com.wireguard.crypto.Key import com.wireguard.crypto.KeyFormatException import com.wireguard.crypto.KeyPair +object Constants { + const val HTTP_PROXY_NONE = "None" + const val HTTP_PROXY_MANUAL = "Manual" + const val HTTP_PROXY_PAC = "Proxy Auto-Config" +} + class InterfaceProxy : BaseObservable, Parcelable { @get:Bindable val excludedApplications: ObservableList<String> = ObservableArrayList() @@ -54,6 +62,44 @@ class InterfaceProxy : BaseObservable, Parcelable { } @get:Bindable + var httpProxyMenu: String = "" + set(value) { + field = value + notifyPropertyChanged(BR.httpProxyMenu) + notifyPropertyChanged(BR.httpProxyManualVisibility) + notifyPropertyChanged(BR.httpProxyPacVisibility) + } + + @get:Bindable + var httpProxyManualVisibility: Int = 0 + get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) android.view.View.GONE else (if (httpProxyMenu == Constants.HTTP_PROXY_MANUAL) android.view.View.VISIBLE else android.view.View.GONE) + + @get:Bindable + var httpProxyHostname: String = "" + set(value) { + field = value + notifyPropertyChanged(BR.httpProxyHostname) + } + + @get:Bindable + var httpProxyPort: String = "" + set(value) { + field = value + notifyPropertyChanged(BR.httpProxyPort) + } + + @get:Bindable + var httpProxyPac: String = "" + set(value) { + field = value + notifyPropertyChanged(BR.httpProxyPac) + } + + @get:Bindable + var httpProxyPacVisibility: Int = 0 + get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) android.view.View.GONE else (if (httpProxyMenu == Constants.HTTP_PROXY_PAC) android.view.View.VISIBLE else android.view.View.GONE) + + @get:Bindable var privateKey: String = "" set(value) { field = value @@ -76,6 +122,10 @@ class InterfaceProxy : BaseObservable, Parcelable { parcel.readStringList(includedApplications) listenPort = parcel.readString() ?: "" mtu = parcel.readString() ?: "" + httpProxyMenu = parcel.readString() ?: "" + httpProxyHostname = parcel.readString() ?: "" + httpProxyPort = parcel.readString() ?: "" + httpProxyPac = parcel.readString() ?: "" privateKey = parcel.readString() ?: "" } @@ -87,6 +137,10 @@ class InterfaceProxy : BaseObservable, Parcelable { includedApplications.addAll(other.includedApplications) listenPort = other.listenPort.map { it.toString() }.orElse("") mtu = other.mtu.map { it.toString() }.orElse("") + httpProxyHostname = other.httpProxy.map { if (it.getHost().startsWith('[') && it.getHost().endsWith(']')) it.getHost().substring(1, it.getHost().length-1) else it.getHost() }.orElse("") + httpProxyPort = other.httpProxy.map { if (it.getPort() <= 0) "8080" else it.getPort().toString() }.orElse("") + httpProxyPac = other.httpProxy.map { it.getPacFileUrl().toString() }.orElse("") + httpProxyMenu = other.httpProxy.map { if (it.getPacFileUrl() != null && it.getPacFileUrl() != Uri.EMPTY) Constants.HTTP_PROXY_PAC else if (it.getHost() != "") Constants.HTTP_PROXY_MANUAL else Constants.HTTP_PROXY_NONE }.orElse(Constants.HTTP_PROXY_NONE) val keyPair = other.keyPair privateKey = keyPair.privateKey.toBase64() } @@ -111,6 +165,20 @@ class InterfaceProxy : BaseObservable, Parcelable { if (includedApplications.isNotEmpty()) builder.includeApplications(includedApplications) if (listenPort.isNotEmpty()) builder.parseListenPort(listenPort) if (mtu.isNotEmpty()) builder.parseMtu(mtu) + if (Constants.HTTP_PROXY_MANUAL.equals(httpProxyMenu) && httpProxyHostname.isNotEmpty()) { + var httpProxy: String + if (httpProxyHostname.contains(":")) { + httpProxy = "[" + httpProxyHostname + "]" + } else { + httpProxy = httpProxyHostname + } + if (httpProxyPort.isNotEmpty()) { + httpProxy += ":" + httpProxyPort; + } + builder.parseHttpProxy(httpProxy) + } else if (Constants.HTTP_PROXY_PAC.equals(httpProxyMenu) && httpProxyPac.isNotEmpty()) { + builder.parseHttpProxy("pac:" + httpProxyPac) + } if (privateKey.isNotEmpty()) builder.parsePrivateKey(privateKey) return builder.build() } @@ -122,6 +190,10 @@ class InterfaceProxy : BaseObservable, Parcelable { dest.writeStringList(includedApplications) dest.writeString(listenPort) dest.writeString(mtu) + dest.writeString(httpProxyMenu) + dest.writeString(httpProxyHostname) + dest.writeString(httpProxyPort) + dest.writeString(httpProxyPac) dest.writeString(privateKey) } diff --git a/ui/src/main/java/com/wireguard/android/viewmodel/PeerDetail.kt b/ui/src/main/java/com/wireguard/android/viewmodel/PeerDetail.kt new file mode 100644 index 00000000..80b32fd5 --- /dev/null +++ b/ui/src/main/java/com/wireguard/android/viewmodel/PeerDetail.kt @@ -0,0 +1,85 @@ +package com.wireguard.android.viewmodel + +import android.util.Log +import androidx.databinding.BaseObservable +import androidx.databinding.Bindable +import androidx.databinding.Observable +import androidx.databinding.ObservableList +import androidx.databinding.ObservableArrayList + +import com.wireguard.android.BR +import com.wireguard.config.InetEndpoint +import com.wireguard.config.InetNetwork +import com.wireguard.config.Peer +import com.wireguard.crypto.Key; + +import java.util.Optional; + +import kotlin.collections.LinkedHashSet + + +class PeerDetail : BaseObservable { + var peer: Peer? + private var owner: ConfigDetail? = null + + @get:Bindable + var publicKey: Key + + @get:Bindable + var allowedIps: ObservableList<InetNetwork> = ObservableArrayList<InetNetwork>() + + @get:Bindable + var endpoint: Optional<InetEndpoint> = Optional.empty() + get() { + if (!field.isEmpty()) { + return field + } else { + return Optional.ofNullable(peer?.endpoint?.get()) + } + } + + set(value) { + Log.i(TAG, "notifyPropertyChanged endpoint " + this + ", " + value) + field = value + notifyPropertyChanged(BR.endpoint) + } + + @get:Bindable + var persistentKeepalive: Optional<Int> = Optional.empty() + + constructor(other: Peer) { + peer = other + publicKey = other.getPublicKey() + allowedIps.addAll(other.getAllowedIps()) + endpoint = other.getEndpoint(); + persistentKeepalive = other.getPersistentKeepalive() + } + + constructor(publicKey: Key) { + peer = null + this.publicKey = publicKey + } + + fun bind(owner: ConfigDetail) { + this.owner = owner + } + + override fun addOnPropertyChangedCallback (callback: Observable.OnPropertyChangedCallback) { + Log.i(TAG, "addOnPropertyChangedCallback " + this + ", " + callback) + super.addOnPropertyChangedCallback(callback) + } + + /** + * Converts the {@code Peer} into a string suitable for debugging purposes. The {@code Peer} is + * identified by its public key and (if known) its endpoint. + * + * @return a concise single-line identifier for the {@code Peer} + */ + override fun toString(): String { + return "(Peer " + publicKey.toBase64() + ")" + } + + companion object { + private const val TAG = "WireGuard/PeerDetail" + } +} diff --git a/ui/src/main/java/com/wireguard/android/viewmodel/PeerProxy.kt b/ui/src/main/java/com/wireguard/android/viewmodel/PeerProxy.kt index d1cb1046..4bf2ce9c 100644 --- a/ui/src/main/java/com/wireguard/android/viewmodel/PeerProxy.kt +++ b/ui/src/main/java/com/wireguard/android/viewmodel/PeerProxy.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.viewmodel diff --git a/ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.kt b/ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.kt index 6f941c86..bf42166d 100644 --- a/ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.kt +++ b/ui/src/main/java/com/wireguard/android/widget/KeyInputFilter.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.widget diff --git a/ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.kt b/ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.kt index 38aee443..511cd287 100644 --- a/ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.kt +++ b/ui/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.widget diff --git a/ui/src/main/java/com/wireguard/android/widget/NameInputFilter.kt b/ui/src/main/java/com/wireguard/android/widget/NameInputFilter.kt index a047dab4..7af514d9 100644 --- a/ui/src/main/java/com/wireguard/android/widget/NameInputFilter.kt +++ b/ui/src/main/java/com/wireguard/android/widget/NameInputFilter.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.widget diff --git a/ui/src/main/java/com/wireguard/android/widget/SlashDrawable.kt b/ui/src/main/java/com/wireguard/android/widget/SlashDrawable.kt index 2ebf4fd8..8fcee9df 100644 --- a/ui/src/main/java/com/wireguard/android/widget/SlashDrawable.kt +++ b/ui/src/main/java/com/wireguard/android/widget/SlashDrawable.kt @@ -1,6 +1,6 @@ /* * Copyright © 2018 The Android Open Source Project - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.widget diff --git a/ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.kt b/ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.kt index 0b5fa09f..fe415fd5 100644 --- a/ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.kt +++ b/ui/src/main/java/com/wireguard/android/widget/ToggleSwitch.kt @@ -1,6 +1,6 @@ /* * Copyright © 2013 The Android Open Source Project - * Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + * Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.widget diff --git a/ui/src/main/res/drawable/ic_action_add_white.xml b/ui/src/main/res/drawable/ic_action_add_white.xml index 18fe19db..1ea440df 100644 --- a/ui/src/main/res/drawable/ic_action_add_white.xml +++ b/ui/src/main/res/drawable/ic_action_add_white.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:tint="?attr/colorControlNormal" + android:viewportWidth="24" + android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnSecondary" + android:fillColor="#FFFFFFFF" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_delete.xml b/ui/src/main/res/drawable/ic_action_delete.xml index 51517c42..73eb7352 100644 --- a/ui/src/main/res/drawable/ic_action_delete.xml +++ b/ui/src/main/res/drawable/ic_action_delete.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnPrimary" + android:fillColor="#FFFFFFFF" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_edit.xml b/ui/src/main/res/drawable/ic_action_edit.xml index 8d8acf85..d40c78d9 100644 --- a/ui/src/main/res/drawable/ic_action_edit.xml +++ b/ui/src/main/res/drawable/ic_action_edit.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnPrimary" + android:fillColor="#FFFFFFFF" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_edit_white.xml b/ui/src/main/res/drawable/ic_action_edit_white.xml deleted file mode 100644 index 212fc72c..00000000 --- a/ui/src/main/res/drawable/ic_action_edit_white.xml +++ /dev/null @@ -1,9 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="?attr/colorOnSecondary" - android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" /> -</vector> diff --git a/ui/src/main/res/drawable/ic_action_generate.xml b/ui/src/main/res/drawable/ic_action_generate.xml index 7324eae4..51d26aed 100644 --- a/ui/src/main/res/drawable/ic_action_generate.xml +++ b/ui/src/main/res/drawable/ic_action_generate.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="#FF000000" + android:fillColor="#FFFFFFFF" android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_open_white.xml b/ui/src/main/res/drawable/ic_action_open.xml index 91075680..c9fd6fba 100644 --- a/ui/src/main/res/drawable/ic_action_open_white.xml +++ b/ui/src/main/res/drawable/ic_action_open.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnSecondary" + android:fillColor="#FFFFFFFF" android:pathData="M6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6L6,2zM13,9L13,3.5L18.5,9L13,9z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_save.xml b/ui/src/main/res/drawable/ic_action_save.xml index ed98e85a..6e618edb 100644 --- a/ui/src/main/res/drawable/ic_action_save.xml +++ b/ui/src/main/res/drawable/ic_action_save.xml @@ -2,9 +2,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnPrimary" + android:fillColor="#FFFFFFFF" android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_scan_qr_code_white.xml b/ui/src/main/res/drawable/ic_action_scan_qr_code.xml index a5ede695..4522ae46 100644 --- a/ui/src/main/res/drawable/ic_action_scan_qr_code_white.xml +++ b/ui/src/main/res/drawable/ic_action_scan_qr_code.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnSecondary" + android:fillColor="#FFFFFFFF" android:pathData="M4,4H10V10H4V4M20,4V10H14V4H20M14,15H16V13H14V11H16V13H18V11H20V13H18V15H20V18H18V20H16V18H13V20H11V16H14V15M16,15V18H18V15H16M4,20V14H10V20H4M6,6V8H8V6H6M16,6V8H18V6H16M6,16V18H8V16H6M4,11H6V13H4V11M9,11H13V15H11V13H9V11M11,6H13V10H11V6M2,2V6H0V2A2,2 0 0,1 2,0H6V2H2M22,0A2,2 0 0,1 24,2V6H22V2H18V0H22M2,18V22H6V24H2A2,2 0 0,1 0,22V18H2M22,22V18H24V22A2,2 0 0,1 22,24H18V22H22Z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_select_all.xml b/ui/src/main/res/drawable/ic_action_select_all.xml index 43f5f15e..490ca715 100644 --- a/ui/src/main/res/drawable/ic_action_select_all.xml +++ b/ui/src/main/res/drawable/ic_action_select_all.xml @@ -2,9 +2,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?attr/colorOnPrimary" + android:fillColor="#FFFFFFFF" android:pathData="M3 5L5 5 5 3C3.9 3 3 3.9 3 5Zm0 8l2 0 0 -2 -2 0 0 2zm4 8l2 0 0 -2 -2 0 0 2zM3 9L5 9 5 7 3 7 3 9Zm10 -6l-2 0 0 2 2 0 0 -2zm6 0l0 2 2 0C21 3.9 20.1 3 19 3ZM5 21L5 19 3 19c0 1.1 0.9 2 2 2zm-2 -4l2 0 0 -2 -2 0 0 2zM9 3L7 3 7 5 9 5 9 3Zm2 18l2 0 0 -2 -2 0 0 2zm8 -8l2 0 0 -2 -2 0 0 2zm0 8c1.1 0 2 -0.9 2 -2l-2 0 0 2zm0 -12l2 0 0 -2 -2 0 0 2zm0 8l2 0 0 -2 -2 0 0 2zm-4 4l2 0 0 -2 -2 0 0 2zm0 -16l2 0 0 -2 -2 0 0 2zM7 17L17 17 17 7 7 7 7 17Zm2 -8l6 0 0 6 -6 0 0 -6z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_action_share_white.xml b/ui/src/main/res/drawable/ic_action_share_white.xml index 70843cf3..04ee5b74 100644 --- a/ui/src/main/res/drawable/ic_action_share_white.xml +++ b/ui/src/main/res/drawable/ic_action_share_white.xml @@ -1,6 +1,7 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path diff --git a/ui/src/main/res/drawable/ic_arrow_back.xml b/ui/src/main/res/drawable/ic_arrow_back.xml index 0d549893..0df5dc6c 100644 --- a/ui/src/main/res/drawable/ic_arrow_back.xml +++ b/ui/src/main/res/drawable/ic_arrow_back.xml @@ -1,14 +1,15 @@ <!-- - ~ Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + ~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. ~ SPDX-License-Identifier: Apache-2.0 --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="#000000" + android:fillColor="#FFFFFFFF" android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z" /> </vector> diff --git a/ui/src/main/res/drawable/ic_settings.xml b/ui/src/main/res/drawable/ic_settings.xml index 6d1cfa71..af9f2634 100644 --- a/ui/src/main/res/drawable/ic_settings.xml +++ b/ui/src/main/res/drawable/ic_settings.xml @@ -1,9 +1,10 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" + android:tint="?attr/colorControlNormal" android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="?android:attr/colorForeground" + android:fillColor="#FFFFFFFF" android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" /> </vector> diff --git a/ui/src/main/res/drawable/tv_logo_banner.xml b/ui/src/main/res/drawable/tv_logo_banner.xml index 646967d6..734702f3 100644 --- a/ui/src/main/res/drawable/tv_logo_banner.xml +++ b/ui/src/main/res/drawable/tv_logo_banner.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + ~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. ~ SPDX-License-Identifier: Apache-2.0 --> diff --git a/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml b/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml index 68f186b6..9ed57ac6 100644 --- a/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml +++ b/ui/src/main/res/layout/add_tunnels_bottom_sheet.xml @@ -20,7 +20,7 @@ android:text="@string/create_from_file" android:textAlignment="viewStart" android:textColor="?attr/colorOnSurface" - app:icon="@drawable/ic_action_open_white" + app:icon="@drawable/ic_action_open" app:iconPadding="@dimen/bottom_sheet_icon_padding" app:iconTint="?attr/colorSecondary" app:layout_constraintBottom_toTopOf="@+id/create_from_qrcode" @@ -44,7 +44,7 @@ android:text="@string/create_from_qr_code" android:textAlignment="viewStart" android:textColor="?attr/colorOnSurface" - app:icon="@drawable/ic_action_scan_qr_code_white" + app:icon="@drawable/ic_action_scan_qr_code" app:iconPadding="@dimen/bottom_sheet_icon_padding" app:iconTint="?attr/colorSecondary" app:layout_constraintBottom_toBottomOf="@+id/create_empty" diff --git a/ui/src/main/res/layout/config_naming_dialog_fragment.xml b/ui/src/main/res/layout/config_naming_dialog_fragment.xml index 0fd88c6c..88deb976 100644 --- a/ui/src/main/res/layout/config_naming_dialog_fragment.xml +++ b/ui/src/main/res/layout/config_naming_dialog_fragment.xml @@ -3,7 +3,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> <data> - <import type="com.wireguard.android.widget.NameInputFilter" /> </data> @@ -24,7 +23,9 @@ android:hint="@string/tunnel_name" android:imeOptions="actionDone" android:inputType="textNoSuggestions|textVisiblePassword" - app:filter="@{NameInputFilter.newInstance()}" /> + app:filter="@{NameInputFilter.newInstance()}"> + <requestFocus/> + </com.google.android.material.textfield.TextInputEditText> </com.google.android.material.textfield.TextInputLayout> diff --git a/ui/src/main/res/layout/http_proxy_menu_item.xml b/ui/src/main/res/layout/http_proxy_menu_item.xml new file mode 100644 index 00000000..8ad5c026 --- /dev/null +++ b/ui/src/main/res/layout/http_proxy_menu_item.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:ellipsize="end" + android:maxLines="1" +/> diff --git a/ui/src/main/res/layout/log_viewer_activity.xml b/ui/src/main/res/layout/log_viewer_activity.xml index c3780470..2a377a15 100644 --- a/ui/src/main/res/layout/log_viewer_activity.xml +++ b/ui/src/main/res/layout/log_viewer_activity.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + ~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. ~ SPDX-License-Identifier: Apache-2.0 --> diff --git a/ui/src/main/res/layout/log_viewer_entry.xml b/ui/src/main/res/layout/log_viewer_entry.xml index 73680f0c..38e71d35 100644 --- a/ui/src/main/res/layout/log_viewer_entry.xml +++ b/ui/src/main/res/layout/log_viewer_entry.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + ~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. ~ SPDX-License-Identifier: Apache-2.0 --> diff --git a/ui/src/main/res/layout/tunnel_detail_fragment.xml b/ui/src/main/res/layout/tunnel_detail_fragment.xml index 8e34f082..59112d5e 100644 --- a/ui/src/main/res/layout/tunnel_detail_fragment.xml +++ b/ui/src/main/res/layout/tunnel_detail_fragment.xml @@ -5,6 +5,8 @@ <data> + <import type="android.os.Build" /> + <import type="com.wireguard.android.backend.Tunnel.State" /> <import type="com.wireguard.android.util.ClipboardUtils" /> @@ -19,7 +21,7 @@ <variable name="config" - type="com.wireguard.config.Config" /> + type="com.wireguard.android.viewmodel.ConfigDetail" /> </data> <ScrollView @@ -117,7 +119,7 @@ android:nextFocusForward="@id/addresses_text" android:onClick="@{ClipboardUtils::copyTextView}" android:singleLine="true" - android:text="@{config.interface.keyPair.publicKey.toBase64}" + android:text="@{config.config.interface.keyPair.publicKey.toBase64}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/public_key_label" tools:text="wOs2eguFEohqIZxlSJ1CAT9584tc6ejj9hfGFsoBVkA=" /> @@ -129,7 +131,7 @@ 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}" + android:visibility="@{config.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" /> @@ -140,13 +142,40 @@ android:layout_height="wrap_content" android:contentDescription="@string/addresses" android:nextFocusUp="@id/public_key_text" + android:nextFocusDown="@id/dhcp_addresses_text" + android:nextFocusForward="@id/dhcp_addresses_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.config.interface.addresses}" + android:visibility="@{config.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/dhcp_addresses_label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/dhcp_addresses_text" + android:text="@string/dhcp_addresses" + android:visibility="@{tunnel.dhcp == null ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/addresses_text" /> + + <TextView + android:id="@+id/dhcp_addresses_text" + style="@style/DetailText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:contentDescription="@string/dhcp_addresses" + android:nextFocusUp="@id/addresses_text" android:nextFocusDown="@id/dns_servers_text" android:nextFocusForward="@id/dns_servers_text" android:onClick="@{ClipboardUtils::copyTextView}" - android:text="@{config.interface.addresses}" - android:visibility="@{config.interface.addresses.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:text="@{tunnel.dhcp.addresses}" + android:visibility="@{tunnel.dhcp == null ? android.view.View.GONE : android.view.View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/addresses_label" + app:layout_constraintTop_toBottomOf="@+id/dhcp_addresses_label" tools:text="fc00:bbbb:bbbb:bb11::3:368b/128" /> <TextView @@ -156,9 +185,9 @@ 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}" + android:visibility="@{config.config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/addresses_text" /> + app:layout_constraintTop_toBottomOf="@id/dhcp_addresses_text" /> <TextView android:id="@+id/dns_servers_text" @@ -166,12 +195,12 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:contentDescription="@string/dns_servers" - android:nextFocusUp="@id/addresses_text" + android:nextFocusUp="@id/dhcp_addresses_text" android:nextFocusDown="@id/dns_search_domains_text" android:nextFocusForward="@id/dns_search_domains_text" android:onClick="@{ClipboardUtils::copyTextView}" - android:text="@{config.interface.dnsServers}" - android:visibility="@{config.interface.dnsServers.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:text="@{config.config.interface.dnsServers}" + android:visibility="@{config.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" /> @@ -183,7 +212,7 @@ android:layout_marginTop="8dp" android:labelFor="@+id/dns_search_domain_text" android:text="@string/dns_search_domains" - android:visibility="@{config.interface.dnsSearchDomains.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:visibility="@{config.config.interface.dnsSearchDomains.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/dns_servers_text" /> @@ -197,8 +226,8 @@ android:nextFocusDown="@id/listen_port_text" android:nextFocusForward="@id/listen_port_text" android:onClick="@{ClipboardUtils::copyTextView}" - android:text="@{config.interface.dnsSearchDomains}" - android:visibility="@{config.interface.dnsSearchDomains.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:text="@{config.config.interface.dnsSearchDomains}" + android:visibility="@{config.config.interface.dnsSearchDomains.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/dns_search_domains_label" tools:text="zx2c4.com" /> @@ -210,7 +239,7 @@ android:layout_marginTop="8dp" android:labelFor="@+id/listen_port_text" android:text="@string/listen_port" - android:visibility="@{!config.interface.listenPort.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:visibility="@{!config.config.interface.listenPort.isPresent() ? 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" @@ -224,11 +253,11 @@ android:contentDescription="@string/listen_port" android:nextFocusRight="@id/mtu_text" android:nextFocusUp="@id/dns_search_domains_text" - android:nextFocusDown="@id/applications_text" + android:nextFocusDown="@id/http_proxy_text" android:nextFocusForward="@id/mtu_text" android:onClick="@{ClipboardUtils::copyTextView}" - android:text="@{config.interface.listenPort}" - android:visibility="@{!config.interface.listenPort.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:text="@{config.config.interface.listenPort}" + android:visibility="@{!config.config.interface.listenPort.isPresent() ? 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" @@ -242,7 +271,7 @@ android:layout_marginTop="8dp" android:labelFor="@+id/mtu_text" android:text="@string/mtu" - android:visibility="@{!config.interface.mtu.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:visibility="@{!config.config.interface.mtu.isPresent() ? 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" @@ -257,10 +286,10 @@ android:contentDescription="@string/mtu" android:nextFocusLeft="@id/listen_port_text" android:nextFocusUp="@id/dns_servers_text" - android:nextFocusForward="@id/applications_text" + android:nextFocusForward="@id/http_proxy_text" android:onClick="@{ClipboardUtils::copyTextView}" - android:text="@{config.interface.mtu}" - android:visibility="@{!config.interface.mtu.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:text="@{config.config.interface.mtu}" + android:visibility="@{!config.config.interface.mtu.isPresent() ? 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" @@ -268,6 +297,40 @@ app:layout_constraintTop_toBottomOf="@+id/mtu_label" tools:text="1500" /> + <androidx.constraintlayout.widget.Barrier + android:id="@+id/listen_port_mtu_barrier" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:barrierDirection="bottom" + app:constraint_referenced_ids="listen_port_text,mtu_text" /> + + <TextView + android:id="@+id/http_proxy_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:labelFor="@+id/http_proxy_text" + android:text="@string/http_proxy" + android:visibility="@{(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || !config.config.interface.httpProxy.isPresent()) ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/listen_port_mtu_barrier" /> + + <TextView + android:id="@+id/http_proxy_text" + style="@style/DetailText" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:contentDescription="@string/http_proxy" + android:nextFocusUp="@id/listen_port_text" + android:nextFocusDown="@id/applications_text" + android:nextFocusForward="@id/applications_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:text="@{config.config.interface.httpProxy}" + android:visibility="@{(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || !config.config.interface.httpProxy.isPresent()) ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintTop_toBottomOf="@id/http_proxy_label" + app:layout_constraintStart_toStartOf="parent" + tools:text="http://example.com:8888" /> + <TextView android:id="@+id/applications_label" android:layout_width="match_parent" @@ -275,9 +338,9 @@ 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" /> + android:visibility="@{config.config.interface.includedApplications.isEmpty() && config.config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" + app:layout_constraintTop_toBottomOf="@+id/http_proxy_text" + app:layout_constraintStart_toStartOf="parent" /> <TextView android:id="@+id/applications_text" @@ -289,10 +352,10 @@ android:nextFocusDown="@id/peers_layout" android:nextFocusForward="@id/peers_layout" 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" + android:text="@{config.config.interface.includedApplications.isEmpty() ? @plurals/n_excluded_applications(config.config.interface.excludedApplications.size(), config.config.interface.excludedApplications.size()) : @plurals/n_included_applications(config.config.interface.includedApplications.size(), config.config.interface.includedApplications.size())}" + android:visibility="@{config.config.interface.includedApplications.isEmpty() && config.config.interface.excludedApplications.isEmpty() ? android.view.View.GONE : android.view.View.VISIBLE}" app:layout_constraintTop_toBottomOf="@+id/applications_label" + app:layout_constraintStart_toStartOf="parent" tools:text="8 excluded" /> </androidx.constraintlayout.widget.ConstraintLayout> </com.google.android.material.card.MaterialCardView> @@ -304,6 +367,7 @@ android:layout_marginTop="8dp" android:divider="@null" android:orientation="vertical" + app:fragment="@{fragment}" app:items="@{config.peers}" app:layout="@{@layout/tunnel_detail_peer}" app:layout_constraintStart_toStartOf="parent" diff --git a/ui/src/main/res/layout/tunnel_detail_peer.xml b/ui/src/main/res/layout/tunnel_detail_peer.xml index 0fbee8f1..b4a07003 100644 --- a/ui/src/main/res/layout/tunnel_detail_peer.xml +++ b/ui/src/main/res/layout/tunnel_detail_peer.xml @@ -9,7 +9,7 @@ <variable name="item" - type="com.wireguard.config.Peer" /> + type="com.wireguard.android.viewmodel.PeerDetail" /> </data> <com.google.android.material.card.MaterialCardView @@ -64,7 +64,7 @@ android:layout_marginTop="8dp" android:labelFor="@+id/pre_shared_key_text" android:text="@string/pre_shared_key" - android:visibility="@{!item.preSharedKey.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:visibility="@{!item.peer.preSharedKey.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/public_key_text" /> @@ -81,7 +81,7 @@ android:nextFocusForward="@id/allowed_ips_text" android:singleLine="true" android:text="@string/pre_shared_key_enabled" - android:visibility="@{!item.preSharedKey.isPresent() ? android.view.View.GONE : android.view.View.VISIBLE}" + android:visibility="@{!item.peer.preSharedKey.isPresent() ? 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=" /> @@ -194,6 +194,34 @@ app:layout_constraintTop_toBottomOf="@+id/transfer_label" tools:text="1024 MB" tools:visibility="visible" /> + + <TextView + android:id="@+id/last_handshake_label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/persistent_keepalive_text" + android:layout_marginTop="8dp" + android:labelFor="@+id/last_handshake_text" + android:text="@string/last_handshake" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/transfer_text" + tools:visibility="visible" /> + + <TextView + android:id="@+id/last_handshake_text" + style="@style/DetailText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/last_handshake_label" + android:contentDescription="@string/last_handshake" + android:nextFocusUp="@id/transfer_text" + android:onClick="@{ClipboardUtils::copyTextView}" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/last_handshake_label" + tools:text="29 seconds ago" + tools:visibility="visible" /> </androidx.constraintlayout.widget.ConstraintLayout> </com.google.android.material.card.MaterialCardView> </layout> diff --git a/ui/src/main/res/layout/tunnel_editor_fragment.xml b/ui/src/main/res/layout/tunnel_editor_fragment.xml index 59572b32..789c839b 100644 --- a/ui/src/main/res/layout/tunnel_editor_fragment.xml +++ b/ui/src/main/res/layout/tunnel_editor_fragment.xml @@ -5,6 +5,8 @@ <data> + <import type="android.os.Build" /> + <import type="com.wireguard.android.util.ClipboardUtils" /> <import type="com.wireguard.android.widget.KeyInputFilter" /> @@ -210,7 +212,7 @@ android:imeOptions="actionNext" android:inputType="textNoSuggestions|textVisiblePassword" android:nextFocusUp="@id/addresses_label_text" - android:nextFocusDown="@id/set_excluded_applications" + android:nextFocusDown="@id/http_proxy_hostname_text" android:nextFocusForward="@id/mtu_text" android:text="@={config.interface.dnsServers}" /> </com.google.android.material.textfield.TextInputLayout> @@ -235,19 +237,112 @@ android:imeOptions="actionDone" android:inputType="number" android:nextFocusUp="@id/listen_port_text" - android:nextFocusDown="@id/set_excluded_applications" - android:nextFocusForward="@id/set_excluded_applications" + android:nextFocusDown="@id/http_proxy_hostname_text" + android:nextFocusForward="@id/http_proxy_hostname_text" android:text="@={config.interface.mtu}" android:textAlignment="center" /> </com.google.android.material.textfield.TextInputLayout> + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/http_proxy_menu" + style="@style/ExposedDropDownMenu" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/http_proxy" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/dns_servers_label_layout"> + + <com.google.android.material.textfield.MaterialAutoCompleteTextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="none" + android:text="@={config.interface.httpProxyMenu}" + /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/http_proxy_hostname_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/http_proxy_hostname" + android:visibility="@{config.interface.httpProxyManualVisibility}" + app:layout_constraintEnd_toStartOf="@id/http_proxy_port_label_layout" + app:layout_constraintHorizontal_chainStyle="spread" + app:layout_constraintHorizontal_weight="0.7" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/http_proxy_menu"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/http_proxy_hostname_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/mtu_text" + android:nextFocusDown="@id/set_excluded_applications" + android:nextFocusForward="@id/http_proxy_port_text" + android:text="@={config.interface.httpProxyHostname}" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/http_proxy_port_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/http_proxy_port" + android:visibility="@{config.interface.httpProxyManualVisibility}" + app:expandedHintEnabled="false" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="0.3" + app:layout_constraintStart_toEndOf="@id/http_proxy_hostname_label_layout" + app:layout_constraintTop_toBottomOf="@id/http_proxy_menu"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/http_proxy_port_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionDone" + android:nextFocusUp="@id/mtu_text" + android:nextFocusDown="@id/http_proxy_pac_label_layout" + android:nextFocusForward="@id/http_proxy_pac_label_layout" + android:text="@={config.interface.httpProxyPort}" + android:textAlignment="center" /> + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/http_proxy_pac_label_layout" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:hint="@string/http_proxy_pac" + android:visibility="@{config.interface.httpProxyPacVisibility}" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/http_proxy_hostname_label_layout"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/http_proxy_pac_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="actionNext" + android:inputType="textNoSuggestions|textVisiblePassword" + android:nextFocusUp="@id/http_proxy_hostname_text" + android:nextFocusDown="@id/set_excluded_applications" + android:nextFocusForward="@id/set_excluded_applications" + android:text="@={config.interface.httpProxyPac}" /> + </com.google.android.material.textfield.TextInputLayout> + <com.google.android.material.button.MaterialButton android:id="@+id/set_excluded_applications" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="4dp" - android:nextFocusUp="@id/dns_servers_text" + android:nextFocusUp="@id/http_proxy_hostname_text" android:nextFocusDown="@id/peers_layout" android:nextFocusForward="@id/peers_layout" android:onClick="@{fragment::onRequestSetExcludedIncludedApplications}" @@ -256,7 +351,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/mtu_label_layout" + app:layout_constraintTop_toBottomOf="@id/http_proxy_pac_label_layout" app:rippleColor="?attr/colorSecondary" tools:text="4 excluded applications" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/ui/src/main/res/values-ca-rES/strings.xml b/ui/src/main/res/values-ca-rES/strings.xml index 06ec2c50..7db86fd0 100644 --- a/ui/src/main/res/values-ca-rES/strings.xml +++ b/ui/src/main/res/values-ca-rES/strings.xml @@ -142,9 +142,9 @@ <string name="log_viewer_pref_title">Mostra el registre d\'aplicació</string> <string name="log_viewer_title">Registre</string> <string name="logcat_error">No es pot executar logcat: </string> - <string name="module_enabler_disabled_summary">El mòdul experimental del kernel pot millorar el rendiment</string> - <string name="module_enabler_disabled_title">Activa el backend del mòdul del kernel</string> - <string name="module_enabler_enabled_title">Desactiva el backend del mòdul del kernel</string> + <string name="module_disabler_disabled_summary">El mòdul experimental del kernel pot millorar el rendiment</string> + <string name="module_disabler_disabled_title">Activa el backend del mòdul del kernel</string> + <string name="module_disabler_enabled_title">Desactiva el backend del mòdul del kernel</string> <string name="module_installer_error">Alguna cosa ha anat malament. Si us plau, prova de nou</string> <string name="module_installer_not_found">El vostre dispositiu no té mòduls disponibles</string> <string name="module_installer_title">Descàrega i instala el mòdul kernel</string> diff --git a/ui/src/main/res/values-cs-rCZ/strings.xml b/ui/src/main/res/values-cs-rCZ/strings.xml index 3b50d711..a52e0a9f 100644 --- a/ui/src/main/res/values-cs-rCZ/strings.xml +++ b/ui/src/main/res/values-cs-rCZ/strings.xml @@ -119,9 +119,9 @@ <string name="log_viewer_pref_title">Zobrazit log aplikace</string> <string name="log_viewer_title">Log</string> <string name="logcat_error">Nelze spustit logcat: </string> - <string name="module_enabler_disabled_summary">Experimentální kernel modul může zlepšit výkon</string> - <string name="module_enabler_disabled_title">Povolit backend kernel modulu</string> - <string name="module_enabler_enabled_title">Vypnout backend kernel modulu</string> + <string name="module_disabler_disabled_summary">Experimentální kernel modul může zlepšit výkon</string> + <string name="module_disabler_disabled_title">Povolit backend kernel modulu</string> + <string name="module_disabler_enabled_title">Vypnout backend kernel modulu</string> <string name="module_installer_error">Něco se pokazilo. Zkuste to prosím znovu</string> <string name="module_installer_initial">Experimentální kernel modul může zlepšit výkon</string> <string name="module_installer_not_found">Pro toto zařízení nejsou dostupné žádné moduly</string> diff --git a/ui/src/main/res/values-de/strings.xml b/ui/src/main/res/values-de/strings.xml index db012dbf..57edd1da 100644 --- a/ui/src/main/res/values-de/strings.xml +++ b/ui/src/main/res/values-de/strings.xml @@ -142,10 +142,10 @@ <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_enabler_disabled_summary">Das experimentelle Kernelmodul kann die Leistung verbessern</string> - <string name="module_enabler_disabled_title">Kernelmodul-Backend aktivieren</string> - <string name="module_enabler_enabled_summary">Das langsamere Userspace-Backend kann die Stabilität verbessern</string> - <string name="module_enabler_enabled_title">Kernelmodul-Backend deaktivieren</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 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> diff --git a/ui/src/main/res/values-es-rES/strings.xml b/ui/src/main/res/values-es-rES/strings.xml index da5b89fb..478a5a7d 100644 --- a/ui/src/main/res/values-es-rES/strings.xml +++ b/ui/src/main/res/values-es-rES/strings.xml @@ -142,10 +142,10 @@ <string name="log_viewer_pref_title">Ver registro de aplicación</string> <string name="log_viewer_title">Registro</string> <string name="logcat_error">No se puede ejecutar logcat: </string> - <string name="module_enabler_disabled_summary">El módulo experimental del kernel puede mejorar el rendimiento</string> - <string name="module_enabler_disabled_title">Habilitar backend del módulo del kernel</string> - <string name="module_enabler_enabled_summary">El backend más lento del espacio de usuario puede mejorar la estabilidad</string> - <string name="module_enabler_enabled_title">Desactivar backend del módulo del kernel</string> + <string name="module_disabler_disabled_summary">El módulo experimental del kernel puede mejorar el rendimiento</string> + <string name="module_disabler_disabled_title">Habilitar backend del módulo del kernel</string> + <string name="module_disabler_enabled_summary">El backend más lento del espacio de usuario puede mejorar la estabilidad</string> + <string name="module_disabler_enabled_title">Desactivar backend del módulo del kernel</string> <string name="module_installer_error">Ocurrió un error. Intente de nuevo</string> <string name="module_installer_initial">El módulo experimental del kernel puede mejorar el rendimiento</string> <string name="module_installer_not_found">No hay módulos disponibles para tu dispositivo</string> diff --git a/ui/src/main/res/values-fa-rIR/strings.xml b/ui/src/main/res/values-fa-rIR/strings.xml index cc3df4de..b1f3793b 100644 --- a/ui/src/main/res/values-fa-rIR/strings.xml +++ b/ui/src/main/res/values-fa-rIR/strings.xml @@ -97,6 +97,7 @@ <string name="create_output_dir_error">نمیتوان دایرکتوری خروجی را ایجاد کرد</string> <string name="create_temp_dir_error">نمیتوان دایرکتوری موقت محلی را ساخت</string> <string name="create_tunnel">ساختن تونل</string> + <string name="copied_to_clipboard">متن در کلیپبورد کپی شد</string> <string name="dark_theme_summary_off">اکنون از پوسته روشن(روز) استفاده میشود</string> <string name="dark_theme_summary_on">اکنون از پوسته تاریک(شب) استفاده میشود</string> <string name="dark_theme_title">استفاده از پوسته تاریک</string> @@ -142,10 +143,10 @@ <string name="log_viewer_pref_title">نمایش گزارش رویداد برنامه</string> <string name="log_viewer_title">گزارش رویداد</string> <string name="logcat_error">نمیتوان logcat را اجرا کرد: </string> - <string name="module_enabler_disabled_summary">ماژول آزمایشیِ کرنل می تواند کارایی را افزایش دهد</string> - <string name="module_enabler_disabled_title">فعالسازی ماژول کرنل ِبک اند</string> - <string name="module_enabler_enabled_summary">فضای کاربری کند ممکن است پایداری را بهبود ببخشد</string> - <string name="module_enabler_enabled_title">غیرفعالسازی پسزمینه واحد هسته</string> + <string name="module_disabler_disabled_summary">ماژول آزمایشیِ کرنل می تواند کارایی را افزایش دهد</string> + <string name="module_disabler_disabled_title">فعالسازی ماژول کرنل ِبک اند</string> + <string name="module_disabler_enabled_summary">فضای کاربری کند ممکن است پایداری را بهبود ببخشد</string> + <string name="module_disabler_enabled_title">غیرفعالسازی پسزمینه واحد هسته</string> <string name="module_installer_error">مشکلی پیش آمد. لطفا دوباره تلاش کنید</string> <string name="module_installer_initial">ماژول آزمایشیِ کرنل می تواند کارایی را افزایش دهد</string> <string name="module_installer_not_found">هیچ واحدی برای دستگاه شما در دسترس نیست</string> diff --git a/ui/src/main/res/values-fr/strings.xml b/ui/src/main/res/values-fr/strings.xml index 33f413b1..17abc8ab 100644 --- a/ui/src/main/res/values-fr/strings.xml +++ b/ui/src/main/res/values-fr/strings.xml @@ -142,10 +142,10 @@ <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_enabler_disabled_summary">Le module expérimental du noyau peut améliorer les performances</string> - <string name="module_enabler_disabled_title">Activer le backend du module du noyau</string> - <string name="module_enabler_enabled_summary">Le backend plus lent de l\'espace utilisateur peut améliorer la stabilité</string> - <string name="module_enabler_enabled_title">Désactiver le backend du module du noyau</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> diff --git a/ui/src/main/res/values-hi-rIN/strings.xml b/ui/src/main/res/values-hi-rIN/strings.xml index b614b475..e16d69ea 100644 --- a/ui/src/main/res/values-hi-rIN/strings.xml +++ b/ui/src/main/res/values-hi-rIN/strings.xml @@ -132,10 +132,10 @@ <string name="log_viewer_pref_title">एप्लिकेशन लॉग देखें</string> <string name="log_viewer_title">लॉग</string> <string name="logcat_error">लॉगकैट चलाने में असमर्थ: </string> - <string name="module_enabler_disabled_summary">प्रयोगात्मक कर्नेल मॉड्यूल प्रदर्शन में सुधार कर सकता है</string> - <string name="module_enabler_disabled_title">कर्नेल मॉड्यूल बैकएंड सक्षम करें</string> - <string name="module_enabler_enabled_summary">धीमे यूजरस्पेस बैकएंड में स्थिरता में सुधार हो सकता है</string> - <string name="module_enabler_enabled_title">कर्नेल मॉड्यूल बैकएंड को अक्षम करें</string> + <string name="module_disabler_disabled_summary">प्रयोगात्मक कर्नेल मॉड्यूल प्रदर्शन में सुधार कर सकता है</string> + <string name="module_disabler_disabled_title">कर्नेल मॉड्यूल बैकएंड सक्षम करें</string> + <string name="module_disabler_enabled_summary">धीमे यूजरस्पेस बैकएंड में स्थिरता में सुधार हो सकता है</string> + <string name="module_disabler_enabled_title">कर्नेल मॉड्यूल बैकएंड को अक्षम करें</string> <string name="module_installer_error">कुछ गलत हो गया। कृपया पुन: प्रयास करें</string> <string name="module_installer_initial">प्रयोगात्मक कर्नेल मॉड्यूल प्रदर्शन में सुधार कर सकता है</string> <string name="module_installer_not_found">आपके डिवाइस के लिए कोई मॉड्यूल उपलब्ध नहीं हैं</string> diff --git a/ui/src/main/res/values-in/strings.xml b/ui/src/main/res/values-in/strings.xml index 7852ffd6..e8e664de 100644 --- a/ui/src/main/res/values-in/strings.xml +++ b/ui/src/main/res/values-in/strings.xml @@ -129,10 +129,10 @@ <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_enabler_disabled_summary">Modul kernel eksperimental dapat meningkatkan kinerja</string> - <string name="module_enabler_disabled_title">Aktifkan backend modul kernel</string> - <string name="module_enabler_enabled_summary">Backend userspace yang lebih lambat dapat meningkatkan stabilitas</string> - <string name="module_enabler_enabled_title">Nonaktifkan backend modul kernel</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> diff --git a/ui/src/main/res/values-it/strings.xml b/ui/src/main/res/values-it/strings.xml index 519d4b52..7b9a2d3f 100644 --- a/ui/src/main/res/values-it/strings.xml +++ b/ui/src/main/res/values-it/strings.xml @@ -142,10 +142,10 @@ <string name="log_viewer_pref_title">Visualizza log dell\'applicazione</string> <string name="log_viewer_title">Log</string> <string name="logcat_error">Impossibile eseguire logcat: </string> - <string name="module_enabler_disabled_summary">Il modulo sperimentale del kernel può migliorare le prestazioni</string> - <string name="module_enabler_disabled_title">Abilita il backend del modulo del kernel</string> - <string name="module_enabler_enabled_summary">Il backend in userspace più lento potrebbe migliorare la stabilità</string> - <string name="module_enabler_enabled_title">Disabilita il backend del modulo del kernel</string> + <string name="module_disabler_disabled_summary">Il modulo sperimentale del kernel può migliorare le prestazioni</string> + <string name="module_disabler_disabled_title">Abilita il backend del modulo del kernel</string> + <string name="module_disabler_enabled_summary">Il backend in userspace più lento potrebbe migliorare la stabilità</string> + <string name="module_disabler_enabled_title">Disabilita il backend del modulo del kernel</string> <string name="module_installer_error">Qualcosa non ha funzionato. Riprova</string> <string name="module_installer_initial">Il modulo sperimentale del kernel può migliorare le prestazioni</string> <string name="module_installer_not_found">Nessun modulo disponibile per il tuo dispositivo</string> diff --git a/ui/src/main/res/values-ja/strings.xml b/ui/src/main/res/values-ja/strings.xml index e10a05a8..7aa5531a 100644 --- a/ui/src/main/res/values-ja/strings.xml +++ b/ui/src/main/res/values-ja/strings.xml @@ -129,10 +129,10 @@ <string name="log_viewer_pref_title">アプリケーションログを表示</string> <string name="log_viewer_title">ログ</string> <string name="logcat_error">logcat を実行できません: </string> - <string name="module_enabler_disabled_summary">カーネルモジュールは実験的ですがパフォーマンスが向上する可能性があります。</string> - <string name="module_enabler_disabled_title">カーネルモジュールバックエンドの有効化</string> - <string name="module_enabler_enabled_summary">ユーザースペースバックエンドは低速ですが安定しています。</string> - <string name="module_enabler_enabled_title">カーネルモジュールバックエンドの無効化</string> + <string name="module_disabler_disabled_summary">カーネルモジュールは実験的ですがパフォーマンスが向上する可能性があります。</string> + <string name="module_disabler_disabled_title">カーネルモジュールバックエンドの有効化</string> + <string name="module_disabler_enabled_summary">ユーザースペースバックエンドは低速ですが安定しています。</string> + <string name="module_disabler_enabled_title">カーネルモジュールバックエンドの無効化</string> <string name="module_installer_error">失敗しました. 再度実行してみてください</string> <string name="module_installer_initial">実験的カーネルモジュールはパフォーマンスが向上する場合があります</string> <string name="module_installer_not_found">このデバイス用のモジュールは利用できません</string> diff --git a/ui/src/main/res/values-ko-rKR/strings.xml b/ui/src/main/res/values-ko-rKR/strings.xml index c975945a..a2890b26 100644 --- a/ui/src/main/res/values-ko-rKR/strings.xml +++ b/ui/src/main/res/values-ko-rKR/strings.xml @@ -129,10 +129,10 @@ <string name="log_viewer_pref_title">앱 로그 보기</string> <string name="log_viewer_title">로그</string> <string name="logcat_error">logcat을 실행할 수 없음: </string> - <string name="module_enabler_disabled_summary">아직 실험중이 커널 모듈을 사용하면 성능이 향상될 수 있음</string> - <string name="module_enabler_disabled_title">커널 모듈 백엔드 활성화하기</string> - <string name="module_enabler_enabled_summary">사용자공간 백엔드를 사용하면 느리지만 안정성이 좋아짐</string> - <string name="module_enabler_enabled_title">커널 모듈 백엔드를 비활성화하기</string> + <string name="module_disabler_disabled_summary">아직 실험중이 커널 모듈을 사용하면 성능이 향상될 수 있음</string> + <string name="module_disabler_disabled_title">커널 모듈 백엔드 활성화하기</string> + <string name="module_disabler_enabled_summary">사용자공간 백엔드를 사용하면 느리지만 안정성이 좋아짐</string> + <string name="module_disabler_enabled_title">커널 모듈 백엔드를 비활성화하기</string> <string name="module_installer_error">문제가 발생했습니다. 다시 시도하십시오</string> <string name="module_installer_initial">아직 실험중이 커널 모듈을 사용하면 성능이 향상될 수 있음</string> <string name="module_installer_not_found">이 기기에서 사용가능한 모듈이 없음</string> diff --git a/ui/src/main/res/values-no-rNO/strings.xml b/ui/src/main/res/values-no-rNO/strings.xml index b0616f4e..f9c2c979 100644 --- a/ui/src/main/res/values-no-rNO/strings.xml +++ b/ui/src/main/res/values-no-rNO/strings.xml @@ -142,10 +142,10 @@ <string name="log_viewer_pref_title">Vis programlogg</string> <string name="log_viewer_title">Logg</string> <string name="logcat_error">Kan ikke kjøre logcat: </string> - <string name="module_enabler_disabled_summary">Den eksperimentelle kjernemodulen kan gi bedre ytelse</string> - <string name="module_enabler_disabled_title">Aktiver backend for kjerne-modul</string> - <string name="module_enabler_enabled_summary">Backend i userspace er litt tregere men kan gi bedre stabilitet</string> - <string name="module_enabler_enabled_title">Deaktiver backend for kjerne-modul</string> + <string name="module_disabler_disabled_summary">Den eksperimentelle kjernemodulen kan gi bedre ytelse</string> + <string name="module_disabler_disabled_title">Aktiver backend for kjerne-modul</string> + <string name="module_disabler_enabled_summary">Backend i userspace er litt tregere men kan gi bedre stabilitet</string> + <string name="module_disabler_enabled_title">Deaktiver backend for kjerne-modul</string> <string name="module_installer_error">Noe gikk galt. Vennligst prøv igjen</string> <string name="module_installer_initial">Den eksperimentelle kjernemodulen kan gi bedre ytelse</string> <string name="module_installer_not_found">Ingen moduler er tilgjengelige for din enhet</string> diff --git a/ui/src/main/res/values-pa-rIN/strings.xml b/ui/src/main/res/values-pa-rIN/strings.xml index 1d7ac096..ed7e96ba 100644 --- a/ui/src/main/res/values-pa-rIN/strings.xml +++ b/ui/src/main/res/values-pa-rIN/strings.xml @@ -142,10 +142,10 @@ <string name="log_viewer_pref_title">ਐਪਲੀਕੇਸ਼ਨ ਲਾਗ ਵੇਖੋ</string> <string name="log_viewer_title">ਲਾਗ</string> <string name="logcat_error">logcat ਚਲਾਉਣ ਲਈ ਅਸਮਰੱਥ: </string> - <string name="module_enabler_disabled_summary">ਤਜਰਬੇ ਅਧੀਨ ਕਰਨਲ ਮੋਡੀਊਲ ਕਾਰਗੁਜ਼ਾਰੀ ਸੁਧਾਰ ਸਕਦਾ ਹੈ</string> - <string name="module_enabler_disabled_title">ਕਰਨਲ ਮੋਡੀਊਲ ਬੈਕਐਂਡ ਸਮਰੱਥ ਕਰੋ</string> - <string name="module_enabler_enabled_summary">ਹੌਲੀ ਵਰਤੋਂਕਾਰ-ਸਪੇਸ ਬੈਂਕਡ ਸਥਿਰਤਾ ਸੁਧਾਰ ਕਰ ਸਕਦਾ ਹੈ</string> - <string name="module_enabler_enabled_title">ਕਰਨਲ ਮੋਡੀਊਲ ਬੈਕਐਂਡ ਅਸਮਰੱਥ ਕਰੋ</string> + <string name="module_disabler_disabled_summary">ਤਜਰਬੇ ਅਧੀਨ ਕਰਨਲ ਮੋਡੀਊਲ ਕਾਰਗੁਜ਼ਾਰੀ ਸੁਧਾਰ ਸਕਦਾ ਹੈ</string> + <string name="module_disabler_disabled_title">ਕਰਨਲ ਮੋਡੀਊਲ ਬੈਕਐਂਡ ਸਮਰੱਥ ਕਰੋ</string> + <string name="module_disabler_enabled_summary">ਹੌਲੀ ਵਰਤੋਂਕਾਰ-ਸਪੇਸ ਬੈਂਕਡ ਸਥਿਰਤਾ ਸੁਧਾਰ ਕਰ ਸਕਦਾ ਹੈ</string> + <string name="module_disabler_enabled_title">ਕਰਨਲ ਮੋਡੀਊਲ ਬੈਕਐਂਡ ਅਸਮਰੱਥ ਕਰੋ</string> <string name="module_installer_error">ਕੁਝ ਗਲਤ ਵਾਪਰ ਗਿਆ। ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ</string> <string name="module_installer_initial">ਤਜਰਬੇ ਅਧੀਨ ਕਰਨਲ ਮੋਡੀਊਲ ਕਾਰਗੁਜ਼ਾਰੀ ਸੁਧਾਰ ਸਕਦਾ ਹੈ</string> <string name="module_installer_not_found">ਤੁਹਾਡੇ ਡਿਵਾਈਸ ਲਈ ਕੋਈ ਮੋਡੀਊਲ ਮੌਜੂਦ ਨਹੀਂ ਹਨ</string> diff --git a/ui/src/main/res/values-pl-rPL/strings.xml b/ui/src/main/res/values-pl-rPL/strings.xml index 119bdc74..b739035e 100644 --- a/ui/src/main/res/values-pl-rPL/strings.xml +++ b/ui/src/main/res/values-pl-rPL/strings.xml @@ -168,10 +168,10 @@ <string name="log_viewer_pref_title">Wyświetl log aplikacji</string> <string name="log_viewer_title">Log</string> <string name="logcat_error">Nie można uruchomić narzędzia logcat: </string> - <string name="module_enabler_disabled_summary">Eksperymentalny moduł jądra może poprawić wydajność</string> - <string name="module_enabler_disabled_title">Włącz moduł jądra</string> - <string name="module_enabler_enabled_summary">Wolniejsza implementacja w przestrzeni użytkownika może poprawić stabilność</string> - <string name="module_enabler_enabled_title">Wyłącz moduł jądra</string> + <string name="module_disabler_disabled_summary">Eksperymentalny moduł jądra może poprawić wydajność</string> + <string name="module_disabler_disabled_title">Włącz moduł jądra</string> + <string name="module_disabler_enabled_summary">Wolniejsza implementacja w przestrzeni użytkownika może poprawić stabilność</string> + <string name="module_disabler_enabled_title">Wyłącz moduł jądra</string> <string name="module_installer_error">Coś poszło nie tak. Proszę spróbować ponownie</string> <string name="module_installer_initial">Eksperymentalny moduł jądra może poprawić wydajność</string> <string name="module_installer_not_found">Brak dostępnych modułów dla tego urządzenia</string> diff --git a/ui/src/main/res/values-pt-rPT/strings.xml b/ui/src/main/res/values-pt-rPT/strings.xml index fc1f19cb..b609cf2b 100644 --- a/ui/src/main/res/values-pt-rPT/strings.xml +++ b/ui/src/main/res/values-pt-rPT/strings.xml @@ -142,10 +142,10 @@ <string name="log_viewer_pref_title">Ver log da aplicação</string> <string name="log_viewer_title">Log</string> <string name="logcat_error">Não foi possível executar o logcat: </string> - <string name="module_enabler_disabled_summary">O módulo experimental de kernel pode melhorar o desempenho</string> - <string name="module_enabler_disabled_title">Habilitar módulo backend do kernel</string> - <string name="module_enabler_enabled_summary">O backend do userspace mais lento pode aumentar a estabilidade</string> - <string name="module_enabler_enabled_title">Desabilitar módulo backend do kernel</string> + <string name="module_disabler_disabled_summary">O módulo experimental de kernel pode melhorar o desempenho</string> + <string name="module_disabler_disabled_title">Habilitar módulo backend do kernel</string> + <string name="module_disabler_enabled_summary">O backend do userspace mais lento pode aumentar a estabilidade</string> + <string name="module_disabler_enabled_title">Desabilitar módulo backend do kernel</string> <string name="module_installer_error">Ocorreu um erro. Por favor, tente novamente</string> <string name="module_installer_initial">O módulo experimental do kernel pode melhorar o desempenho</string> <string name="module_installer_not_found">Não há módulos disponíveis para o seu dispositivo</string> diff --git a/ui/src/main/res/values-ro-rRO/strings.xml b/ui/src/main/res/values-ro-rRO/strings.xml index 5caa3cae..e0249364 100644 --- a/ui/src/main/res/values-ro-rRO/strings.xml +++ b/ui/src/main/res/values-ro-rRO/strings.xml @@ -155,10 +155,10 @@ <string name="log_viewer_pref_title">Vizualizare jurnal aplicație</string> <string name="log_viewer_title">Jurnal</string> <string name="logcat_error">Programul logcat nu poate fi executat: </string> - <string name="module_enabler_disabled_summary">Modulul experimental de nucleu poate îmbunătăți performanța</string> - <string name="module_enabler_disabled_title">Activează biblioteca modulului de nucleu</string> - <string name="module_enabler_enabled_summary">Biblioteca mai lentă a spațiului utilizatorului poate îmbunătăți stabilitatea</string> - <string name="module_enabler_enabled_title">Dezactivează biblioteca modulului de nucleu</string> + <string name="module_disabler_disabled_summary">Modulul experimental de nucleu poate îmbunătăți performanța</string> + <string name="module_disabler_disabled_title">Activează biblioteca modulului de nucleu</string> + <string name="module_disabler_enabled_summary">Biblioteca mai lentă a spațiului utilizatorului poate îmbunătăți stabilitatea</string> + <string name="module_disabler_enabled_title">Dezactivează biblioteca modulului de nucleu</string> <string name="module_installer_error">A apărut o eroare. Încearcă din nou</string> <string name="module_installer_initial">Modulul experimental de nucleu poate îmbunătăți performanța</string> <string name="module_installer_not_found">Nu sunt disponibile module pentru dispozitivul tău</string> diff --git a/ui/src/main/res/values-ru/strings.xml b/ui/src/main/res/values-ru/strings.xml index b15436de..3fc6c911 100644 --- a/ui/src/main/res/values-ru/strings.xml +++ b/ui/src/main/res/values-ru/strings.xml @@ -168,10 +168,10 @@ <string name="log_viewer_pref_title">Просмотр журналов приложения</string> <string name="log_viewer_title">Журнал</string> <string name="logcat_error">Не удалось запустить logcat: </string> - <string name="module_enabler_disabled_summary">Экспериментальный модуль ядра может улучшить производительность</string> - <string name="module_enabler_disabled_title">Включить бэкэнд модуля ядра</string> - <string name="module_enabler_enabled_summary">Пользовательское пространство немного медленнее и улучшает стабильность</string> - <string name="module_enabler_enabled_title">Отключить бэкэнд модуля ядра</string> + <string name="module_disabler_disabled_summary">Экспериментальный модуль ядра может улучшить производительность</string> + <string name="module_disabler_disabled_title">Включить бэкэнд модуля ядра</string> + <string name="module_disabler_enabled_summary">Пользовательское пространство немного медленнее и улучшает стабильность</string> + <string name="module_disabler_enabled_title">Отключить бэкэнд модуля ядра</string> <string name="module_installer_error">Что-то пошло не так. Пожалуйста, попробуйте еще раз</string> <string name="module_installer_initial">Экспериментальный модуль ядра может улучшить производительность</string> <string name="module_installer_not_found">Для вашего устройства нет доступных модулей</string> diff --git a/ui/src/main/res/values-sk-rSK/strings.xml b/ui/src/main/res/values-sk-rSK/strings.xml index 30ba9f98..3479091f 100644 --- a/ui/src/main/res/values-sk-rSK/strings.xml +++ b/ui/src/main/res/values-sk-rSK/strings.xml @@ -77,7 +77,7 @@ <string name="log_saver_activity_label">Uložiť denník udalostí</string> <string name="log_viewer_pref_summary">Denník udalosti môžu byt nápomocné pri ladení aplikácie</string> <string name="log_viewer_pref_title">Zobraziť denník udalostí aplikácie</string> - <string name="module_enabler_enabled_summary">Pomalšie užívatelské prostredie môže zlepšiť stabilitu</string> + <string name="module_disabler_enabled_summary">Pomalšie užívatelské prostredie môže zlepšiť stabilitu</string> <string name="module_installer_error">Niečo sa pokazilo. Prosím, skúste znova</string> <string name="module_installer_not_found">Pre vaše zariadenie nie sú k dispozícii žiadne moduly</string> <string name="module_installer_title">Stiahni a nainštaluj kernel modul</string> diff --git a/ui/src/main/res/values-sl/strings.xml b/ui/src/main/res/values-sl/strings.xml index 8c98bc12..87b548e1 100644 --- a/ui/src/main/res/values-sl/strings.xml +++ b/ui/src/main/res/values-sl/strings.xml @@ -166,10 +166,10 @@ <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_enabler_disabled_summary">Eksperimentalni modul jedra lahko izboljša zmogljivost</string> - <string name="module_enabler_disabled_title">Omogoči zaledje za modul jedra</string> - <string name="module_enabler_enabled_summary">Počasnejše uporabniško zaledje lahko izboljša stabilnost</string> - <string name="module_enabler_enabled_title">Onemogoči zaledje za modul jedra</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> diff --git a/ui/src/main/res/values-sv-rSE/strings.xml b/ui/src/main/res/values-sv-rSE/strings.xml index 16765166..686bd338 100644 --- a/ui/src/main/res/values-sv-rSE/strings.xml +++ b/ui/src/main/res/values-sv-rSE/strings.xml @@ -114,10 +114,10 @@ <string name="log_viewer_pref_title">Visa applikationslogg</string> <string name="log_viewer_title">Logg</string> <string name="logcat_error">Kunde inte köra logcat: </string> - <string name="module_enabler_disabled_summary">Den experimentella kärnmodulen kan förbättra prestanda</string> - <string name="module_enabler_disabled_title">Aktivera backend för kärnmodul</string> - <string name="module_enabler_enabled_summary">Den långsammare backend för användarrymden kan förbättra stabiliteten</string> - <string name="module_enabler_enabled_title">Inaktivera backend för kärnmodul</string> + <string name="module_disabler_disabled_summary">Den experimentella kärnmodulen kan förbättra prestanda</string> + <string name="module_disabler_disabled_title">Aktivera backend för kärnmodul</string> + <string name="module_disabler_enabled_summary">Den långsammare backend för användarrymden kan förbättra stabiliteten</string> + <string name="module_disabler_enabled_title">Inaktivera backend för kärnmodul</string> <string name="module_installer_error">Något gick fel. Vänligen försök igen</string> <string name="module_installer_initial">Den experimentella kärnmodulen kan förbättra prestanda</string> <string name="module_installer_not_found">Inga moduler finns tillgängliga för din enhet</string> diff --git a/ui/src/main/res/values-tr-rTR/strings.xml b/ui/src/main/res/values-tr-rTR/strings.xml index b05d395d..89642b86 100644 --- a/ui/src/main/res/values-tr-rTR/strings.xml +++ b/ui/src/main/res/values-tr-rTR/strings.xml @@ -142,10 +142,10 @@ <string name="log_viewer_pref_title">Uygulama günlüğünü görüntüle</string> <string name="log_viewer_title">Günlük</string> <string name="logcat_error">Logcat çalıştırılamıyor: </string> - <string name="module_enabler_disabled_summary">Deneysel çekirdek modülü performansı artırabilir</string> - <string name="module_enabler_disabled_title">Çekirdek modülü arka ucunu etkinleştir</string> - <string name="module_enabler_enabled_summary">Daha yavaş kullanıcı alanı arka ucu kararlılığı artırabilir</string> - <string name="module_enabler_enabled_title">Çekirdek modülü arka ucunu devre dışı bırak</string> + <string name="module_disabler_disabled_summary">Deneysel çekirdek modülü performansı artırabilir</string> + <string name="module_disabler_disabled_title">Çekirdek modülü arka ucunu etkinleştir</string> + <string name="module_disabler_enabled_summary">Daha yavaş kullanıcı alanı arka ucu kararlılığı artırabilir</string> + <string name="module_disabler_enabled_title">Çekirdek modülü arka ucunu devre dışı bırak</string> <string name="module_installer_error">Bir şeyler yanlış gitti. Lütfen tekrar deneyin</string> <string name="module_installer_initial">Deneysel çekirdek modülü performansı artırabilir</string> <string name="module_installer_not_found">Cihazınız için uygun modül yok</string> diff --git a/ui/src/main/res/values-uk-rUA/strings.xml b/ui/src/main/res/values-uk-rUA/strings.xml index 4ecdb781..252595f0 100644 --- a/ui/src/main/res/values-uk-rUA/strings.xml +++ b/ui/src/main/res/values-uk-rUA/strings.xml @@ -168,10 +168,10 @@ <string name="log_viewer_pref_title">Переглянути журнал програми</string> <string name="log_viewer_title">Журнал</string> <string name="logcat_error">Не вдалося запустити logcat: </string> - <string name="module_enabler_disabled_summary">Експериментальний модуль ядра може підвищити продуктивність</string> - <string name="module_enabler_disabled_title">Увімкнути модуль ядра</string> - <string name="module_enabler_enabled_summary">Користувацький простір повільніший, проте може покращити стабільність</string> - <string name="module_enabler_enabled_title">Вимкнути модуль ядра</string> + <string name="module_disabler_disabled_summary">Експериментальний модуль ядра може підвищити продуктивність</string> + <string name="module_disabler_disabled_title">Увімкнути модуль ядра</string> + <string name="module_disabler_enabled_summary">Користувацький простір повільніший, проте може покращити стабільність</string> + <string name="module_disabler_enabled_title">Вимкнути модуль ядра</string> <string name="module_installer_error">Щось пішло не так. Спробуйте ще раз</string> <string name="module_installer_initial">Експериментальний модуль ядра може підвищити продуктивність</string> <string name="module_installer_not_found">Немає доступних модулів для вашого пристрою</string> diff --git a/ui/src/main/res/values-vi-rVN/strings.xml b/ui/src/main/res/values-vi-rVN/strings.xml new file mode 100644 index 00000000..582a81aa --- /dev/null +++ b/ui/src/main/res/values-vi-rVN/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="all_applications">Tất cả các ứng dụng</string> + <string name="exclude_from_tunnel">Ngoại trừ</string> +</resources> diff --git a/ui/src/main/res/values-zh-rCN/strings.xml b/ui/src/main/res/values-zh-rCN/strings.xml index 60e84c7e..24c5b6c3 100644 --- a/ui/src/main/res/values-zh-rCN/strings.xml +++ b/ui/src/main/res/values-zh-rCN/strings.xml @@ -129,10 +129,10 @@ <string name="log_viewer_pref_title">查看应用日志</string> <string name="log_viewer_title">日志</string> <string name="logcat_error">无法运行 logcat: </string> - <string name="module_enabler_disabled_summary">内核空间的模块性能较强,但可能不稳定</string> - <string name="module_enabler_disabled_title">启用内核模块</string> - <string name="module_enabler_enabled_summary">用户空间的模块性能较弱,但稳定性更好</string> - <string name="module_enabler_enabled_title">停用内核模块</string> + <string name="module_disabler_disabled_summary">内核空间的模块性能较强,但可能不稳定</string> + <string name="module_disabler_disabled_title">启用内核模块</string> + <string name="module_disabler_enabled_summary">用户空间的模块性能较弱,但稳定性更好</string> + <string name="module_disabler_enabled_title">停用内核模块</string> <string name="module_installer_error">发生错误,请重试</string> <string name="module_installer_initial">使用内核模块可以提升性能(实验性)</string> <string name="module_installer_not_found">没有可用于此设备的模块</string> diff --git a/ui/src/main/res/values-zh-rTW/strings.xml b/ui/src/main/res/values-zh-rTW/strings.xml index f4150e2c..2f58e445 100644 --- a/ui/src/main/res/values-zh-rTW/strings.xml +++ b/ui/src/main/res/values-zh-rTW/strings.xml @@ -129,8 +129,8 @@ <string name="log_viewer_pref_title">檢視應用程式日誌</string> <string name="log_viewer_title">日誌</string> <string name="logcat_error">無法執行 logcat: </string> - <string name="module_enabler_disabled_summary">使用還在實驗階段的 kernel module 以便改善效能</string> - <string name="module_enabler_disabled_title">啟用 kernel module</string> + <string name="module_disabler_disabled_summary">使用還在實驗階段的 kernel module 以便改善效能</string> + <string name="module_disabler_disabled_title">啟用 kernel module</string> <string name="save">儲存</string> <string name="select_all">全選</string> <string name="toggle_all">切換全部</string> diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml index fb6fad4b..116f68f9 100644 --- a/ui/src/main/res/values/strings.xml +++ b/ui/src/main/res/values/strings.xml @@ -70,6 +70,7 @@ <string name="bad_config_explanation_pka">: Must be positive and no more than 65535</string> <string name="bad_config_explanation_positive_number">: Must be positive</string> <string name="bad_config_explanation_udp_port">: Must be a valid UDP port number</string> + <string name="bad_config_explanation_http_proxy">: Must be valid proxy hostname and port</string> <string name="bad_config_reason_invalid_key">Invalid key</string> <string name="bad_config_reason_invalid_number">Invalid number</string> <string name="bad_config_reason_invalid_value">Invalid value</string> @@ -104,14 +105,22 @@ <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="dhcp_addresses">DHCP Addresses</string> <string name="tv_delete">Select tunnel to delete</string> <string name="tv_select_a_storage_drive">Select a storage drive</string> <string name="tv_no_file_picker">Please install a file management utility to browse files</string> <string name="tv_add_tunnel_get_started">Add a tunnel to get started</string> + <string name="donate_title">♥ Donate to the WireGuard Project</string> + <string name="donate_summary">Every contribution helps</string> + <string name="donate_google_play_disappointment">Thank you for supporting the WireGuard Project!\n\nUnfortunately, due to Google\'s policies, we\'re not allowed to link to the part of the project webpage where you can make a donation. Hopefully you can figure this out!\n\nThanks again for your contribution.</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="dns_search_domains">Search domains</string> + <string name="duration_days">%d days</string> + <string name="duration_hours">%d hours</string> + <string name="duration_minutes">%d minutes</string> + <string name="duration_seconds">%d seconds</string> <string name="edit">Edit</string> <string name="endpoint">Endpoint</string> <string name="error_down">Error bringing down tunnel: %s</string> @@ -126,6 +135,10 @@ <string name="hint_optional">(optional)</string> <string name="hint_optional_discouraged">(optional, not recommended)</string> <string name="hint_random">(random)</string> + <string name="http_proxy">Proxy</string> + <string name="http_proxy_hostname">Proxy hostname</string> + <string name="http_proxy_pac">Proxy Auto-Config URL</string> + <string name="http_proxy_port">Proxy port</string> <string name="illegal_filename_error">Illegal file name “%s”</string> <string name="import_error">Unable to import tunnel: %s</string> <string name="import_from_qr_code">Import Tunnel from QR Code</string> @@ -136,6 +149,8 @@ <string name="key_length_explanation_base64">: WireGuard base64 keys must be 44 characters (32 bytes)</string> <string name="key_length_explanation_binary">: WireGuard keys must be 32 bytes</string> <string name="key_length_explanation_hex">: WireGuard hex keys must be 64 characters (32 bytes)</string> + <string name="last_handshake">Latest handshake</string> + <string name="last_handshake_ago">%s ago</string> <string name="listen_port">Listen port</string> <string name="log_export_error">Unable to export log: %s</string> <string name="log_export_subject">WireGuard Android Log File</string> diff --git a/ui/src/main/res/values/styles.xml b/ui/src/main/res/values/styles.xml index b90f111f..da3c2cb7 100644 --- a/ui/src/main/res/values/styles.xml +++ b/ui/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="WireGuardTheme" parent="Theme.MaterialComponents.DayNight"> + <style name="WireGuardTheme" parent="Theme.Material3.DayNight"> <item name="colorPrimary">@color/primary_color</item> <item name="colorOnPrimary">@color/color_control_normal</item> <item name="colorPrimaryDark">@color/primary_color</item> @@ -17,9 +17,6 @@ <item name="elevationOverlayEnabled">true</item> <item name="android:statusBarColor">@color/status_bar_color</item> <item name="android:windowBackground">@color/primary_color</item> - <item name="alertDialogTheme">@style/AppTheme.Dialog</item> - <item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item> - <item name="textInputStyle">@style/TextInputLayoutBase</item> <item name="materialCardViewStyle">@style/AppTheme.MaterialCardView</item> </style> @@ -32,12 +29,6 @@ <item name="cardBackgroundColor">?attr/elevationOverlayColor</item> </style> - <style name="AppTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog.Alert"> - <item name="colorPrimary">@color/secondary_color</item> - <item name="colorSecondary">@color/secondary_color</item> - <item name="android:windowBackground">?attr/colorBackground</item> - </style> - <style name="BottomSheetDialogTheme" parent="ThemeOverlay.MaterialComponents.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <item name="android:navigationBarColor">?attr/colorBackground</item> @@ -71,11 +62,7 @@ <item name="colorControlActivated">@color/color_control_normal</item> </style> - <style name="TextInputLayoutBase" parent="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> + <style name="ExposedDropDownMenu" parent="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"> <item name="boxStrokeColor">?attr/colorSecondary</item> - <item name="hintTextColor">?attr/colorOnPrimary</item> - <item name="materialThemeOverlay"> - @style/ThemeOverlay.AppTheme.TextInputEditText.OutlinedBox - </item> </style> </resources> diff --git a/ui/src/main/res/values/tv_styles.xml b/ui/src/main/res/values/tv_styles.xml index c5477f6a..536ca752 100644 --- a/ui/src/main/res/values/tv_styles.xml +++ b/ui/src/main/res/values/tv_styles.xml @@ -16,12 +16,26 @@ <item name="elevationOverlayEnabled">false</item> <item name="android:statusBarColor">@color/tv_primary_color</item> <item name="android:windowBackground">@color/tv_primary_color</item> - <item name="alertDialogTheme">@style/AppTheme.Dialog</item> - <item name="materialAlertDialogTheme">@style/AppTheme.Dialog</item> + <item name="alertDialogTheme">@style/TvTheme.Dialog</item> + <item name="materialAlertDialogTheme">@style/TvTheme.Dialog</item> <item name="textInputStyle">@style/TextInputLayoutBase</item> <item name="materialCardViewStyle">@style/TvTheme.MaterialCardView</item> </style> + <style name="TextInputLayoutBase" parent="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> + <item name="boxStrokeColor">?attr/colorSecondary</item> + <item name="hintTextColor">?attr/colorOnPrimary</item> + <item name="materialThemeOverlay"> + @style/ThemeOverlay.AppTheme.TextInputEditText.OutlinedBox + </item> + </style> + + <style name="TvTheme.Dialog" parent="Theme.MaterialComponents.DayNight.Dialog.Alert"> + <item name="colorPrimary">@color/secondary_color</item> + <item name="colorSecondary">@color/secondary_color</item> + <item name="android:windowBackground">?attr/colorBackground</item> + </style> + <style name="TvTheme.MaterialCardView" parent="Widget.MaterialComponents.CardView"> <item name="cornerRadius">4dp</item> <item name="cardElevation">8dp</item> diff --git a/ui/src/main/res/xml/app_restrictions.xml b/ui/src/main/res/xml/app_restrictions.xml index fefa8a80..2eaa7bc5 100644 --- a/ui/src/main/res/xml/app_restrictions.xml +++ b/ui/src/main/res/xml/app_restrictions.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright © 2017-2021 WireGuard LLC. All Rights Reserved. + ~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved. ~ SPDX-License-Identifier: Apache-2.0 --> diff --git a/ui/src/main/res/xml/preferences.xml b/ui/src/main/res/xml/preferences.xml index 5c9505d4..aa89f27c 100644 --- a/ui/src/main/res/xml/preferences.xml +++ b/ui/src/main/res/xml/preferences.xml @@ -40,4 +40,6 @@ android:summaryOff="@string/allow_remote_control_intents_summary_off" android:summaryOn="@string/allow_remote_control_intents_summary_on" android:title="@string/allow_remote_control_intents_title" /> + <com.wireguard.android.preference.DonatePreference + android:singleLineTitle="false" /> </androidx.preference.PreferenceScreen> |