From 0a7f8f489625d90b8969f112d80059d6757d5e8d Mon Sep 17 00:00:00 2001
From: pacien
Date: Thu, 9 Aug 2018 00:09:39 +0200
Subject: Refactor configuration activity
---
app/build.gradle | 5 +
app/src/main/AndroidManifest.xml | 2 +-
.../org/pacien/tincapp/activities/BaseActivity.kt | 16 ++-
.../pacien/tincapp/activities/ConfigureActivity.kt | 145 ---------------------
.../org/pacien/tincapp/activities/StartActivity.kt | 4 +-
.../pacien/tincapp/activities/StatusActivity.kt | 3 +-
.../tincapp/activities/common/ProgressModal.kt | 49 +++++++
.../activities/configure/ConfigureActivity.kt | 35 +++++
.../activities/configure/PathInfoFragment.kt | 40 ++++++
.../tincapp/activities/configure/ToolsFragment.kt | 53 ++++++++
.../configure/tools/ConfigurationTool.kt | 64 +++++++++
.../tools/EncryptDecryptPrivateKeysTool.kt | 49 +++++++
.../configure/tools/GenerateConfigTool.kt | 51 ++++++++
.../activities/configure/tools/JoinNetworkTool.kt | 83 ++++++++++++
.../java/org/pacien/tincapp/context/AppPaths.kt | 12 +-
.../java/org/pacien/tincapp/utils/ProgressModal.kt | 49 -------
app/src/main/res/layout/configure_activity.xml | 53 ++++++++
...configure_tools_dialog_encrypt_decrypt_keys.xml | 51 ++++++++
.../configure_tools_dialog_network_generate.xml | 51 ++++++++
.../layout/configure_tools_dialog_network_join.xml | 78 +++++++++++
.../main/res/layout/configure_tools_fragment.xml | 73 +++++++++++
.../layout/configure_tools_path_info_fragment.xml | 74 +++++++++++
.../res/layout/dialog_encrypt_decrypt_keys.xml | 51 --------
.../main/res/layout/dialog_network_generate.xml | 51 --------
app/src/main/res/layout/dialog_network_join.xml | 66 ----------
app/src/main/res/layout/page_configure.xml | 121 -----------------
app/src/main/res/values-ja/strings.xml | 2 +-
app/src/main/res/values-nb-rNO/strings.xml | 2 +-
app/src/main/res/values-zh-rCN/strings.xml | 48 +++----
app/src/main/res/values-zh-rHK/strings.xml | 48 +++----
app/src/main/res/values-zh-rTW/strings.xml | 48 +++----
app/src/main/res/values/strings.xml | 55 ++++----
32 files changed, 936 insertions(+), 596 deletions(-)
delete mode 100644 app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/common/ProgressModal.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/ConfigureActivity.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/PathInfoFragment.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/ToolsFragment.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/tools/ConfigurationTool.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/tools/EncryptDecryptPrivateKeysTool.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/tools/GenerateConfigTool.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/configure/tools/JoinNetworkTool.kt
delete mode 100644 app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt
create mode 100644 app/src/main/res/layout/configure_activity.xml
create mode 100644 app/src/main/res/layout/configure_tools_dialog_encrypt_decrypt_keys.xml
create mode 100644 app/src/main/res/layout/configure_tools_dialog_network_generate.xml
create mode 100644 app/src/main/res/layout/configure_tools_dialog_network_join.xml
create mode 100644 app/src/main/res/layout/configure_tools_fragment.xml
create mode 100644 app/src/main/res/layout/configure_tools_path_info_fragment.xml
delete mode 100644 app/src/main/res/layout/dialog_encrypt_decrypt_keys.xml
delete mode 100644 app/src/main/res/layout/dialog_network_generate.xml
delete mode 100644 app/src/main/res/layout/dialog_network_join.xml
delete mode 100644 app/src/main/res/layout/page_configure.xml
diff --git a/app/build.gradle b/app/build.gradle
index ade3cba..d475102 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -19,6 +19,7 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
apply plugin: 'com.github.triplet.play'
def keystorePropertiesFile = rootProject.file("keystore.properties")
@@ -63,6 +64,10 @@ android {
path 'CMakeLists.txt'
}
}
+
+ dataBinding {
+ enabled = true
+ }
}
dependencies {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 517097e..ed9ddf0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -49,7 +49,7 @@
diff --git a/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt
index 4dc2381..af71544 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt
@@ -19,19 +19,18 @@
package org.pacien.tincapp.activities
import android.os.Bundle
+import android.support.annotation.LayoutRes
import android.support.annotation.StringRes
import android.support.design.widget.Snackbar
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
-import android.view.Menu
-import android.view.MenuItem
+import android.view.*
import kotlinx.android.synthetic.main.base.*
import org.pacien.tincapp.R
import org.pacien.tincapp.context.App
import org.pacien.tincapp.context.AppInfo
import org.pacien.tincapp.context.AppPaths
import org.pacien.tincapp.context.CrashRecorder
-import org.pacien.tincapp.utils.ProgressModal
/**
* @author pacien
@@ -105,10 +104,13 @@ abstract class BaseActivity : AppCompatActivity() {
.show()
}
- protected fun notify(@StringRes msg: Int) = Snackbar.make(activity_base, msg, Snackbar.LENGTH_LONG).show()
- protected fun notify(msg: String) = Snackbar.make(activity_base, msg, Snackbar.LENGTH_LONG).show()
- protected fun showProgressDialog(@StringRes msg: Int): AlertDialog = ProgressModal.show(this, getString(msg))
- protected fun showErrorDialog(msg: String): AlertDialog = AlertDialog.Builder(this)
+ fun inflate(@LayoutRes layout: Int) = layoutInflater.inflate(layout, main_content, false)!!
+ fun inflate(inflateFunc: (LayoutInflater, ViewGroup, Boolean) -> View) = inflateFunc(layoutInflater, main_content, false)
+
+ fun notify(@StringRes msg: Int) = Snackbar.make(activity_base, msg, Snackbar.LENGTH_LONG).show()
+ fun notify(msg: String) = Snackbar.make(activity_base, msg, Snackbar.LENGTH_LONG).show()
+
+ fun showErrorDialog(msg: String): AlertDialog = AlertDialog.Builder(this)
.setTitle(R.string.title_error).setMessage(msg)
.setPositiveButton(R.string.action_close) { _, _ -> Unit }.show()
}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt
deleted file mode 100644
index 2aab304..0000000
--- a/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
- * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.pacien.tincapp.activities
-
-import android.content.Intent
-import android.os.Bundle
-import android.support.annotation.StringRes
-import android.support.v7.app.AlertDialog
-import android.view.View
-import com.google.zxing.integration.android.IntentIntegrator
-import com.google.zxing.integration.android.IntentResult
-import java8.util.concurrent.CompletableFuture
-import kotlinx.android.synthetic.main.base.*
-import kotlinx.android.synthetic.main.dialog_encrypt_decrypt_keys.view.*
-import kotlinx.android.synthetic.main.dialog_network_generate.view.*
-import kotlinx.android.synthetic.main.dialog_network_join.view.*
-import kotlinx.android.synthetic.main.page_configure.*
-import org.pacien.tincapp.R
-import org.pacien.tincapp.commands.Tinc
-import org.pacien.tincapp.commands.TincApp
-import org.pacien.tincapp.context.AppPaths
-import org.pacien.tincapp.extensions.Java.exceptionallyAccept
-import java.util.regex.Pattern
-
-/**
- * @author pacien
- */
-class ConfigureActivity : BaseActivity() {
- companion object {
- private val NETWORK_NAME_PATTERN = Pattern.compile("^[^\\x00/]*$")
- }
-
- private var joinDialog: View? = null
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
- ?.let(IntentResult::getContents)
- ?.let(String::trim)
- ?.let { joinDialog?.invitation_url?.setText(it) }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- supportActionBar!!.setDisplayHomeAsUpEnabled(true)
- layoutInflater.inflate(R.layout.page_configure, main_content)
- writeContent()
- }
-
- fun scanCode(@Suppress("UNUSED_PARAMETER") v: View) {
- IntentIntegrator(this).initiateScan()
- }
-
- fun openGenerateConfDialog(@Suppress("UNUSED_PARAMETER") v: View) {
- val genDialog = layoutInflater.inflate(R.layout.dialog_network_generate, main_content, false)
- AlertDialog.Builder(this).setTitle(R.string.title_new_network).setView(genDialog)
- .setPositiveButton(R.string.action_create) { _, _ ->
- generateConf(
- genDialog.new_net_name.text.toString(),
- genDialog.new_node_name.text.toString(),
- genDialog.new_passphrase.text.toString())
- }.setNegativeButton(R.string.action_cancel) { _, _ -> Unit }.show()
- }
-
- fun openJoinNetworkDialog(@Suppress("UNUSED_PARAMETER") v: View) {
- joinDialog = layoutInflater.inflate(R.layout.dialog_network_join, main_content, false)
- AlertDialog.Builder(this).setTitle(R.string.title_join_network).setView(joinDialog)
- .setPositiveButton(R.string.action_join) { _, _ ->
- joinNetwork(
- joinDialog!!.net_name.text.toString(),
- joinDialog!!.invitation_url.text.toString(),
- joinDialog!!.join_passphrase.text.toString())
- }.setNegativeButton(R.string.action_cancel) { _, _ -> Unit }.show()
- }
-
- fun openEncryptDecryptPrivateKeyDialog(@Suppress("UNUSED_PARAMETER") v: View) {
- val encryptDecryptDialog = layoutInflater.inflate(R.layout.dialog_encrypt_decrypt_keys, main_content, false)
- AlertDialog.Builder(this).setTitle(R.string.title_private_keys_encryption).setView(encryptDecryptDialog)
- .setPositiveButton(R.string.action_apply) { _, _ ->
- encryptDecryptPrivateKeys(
- encryptDecryptDialog!!.enc_dec_net_name.text.toString(),
- encryptDecryptDialog.enc_dec_current_passphrase.text.toString(),
- encryptDecryptDialog.enc_dec_new_passphrase.text.toString())
- }.setNegativeButton(R.string.action_cancel) { _, _ -> Unit }.show()
- }
-
- private fun writeContent() {
- text_configuration_directory.text = AppPaths.confDir().absolutePath
- text_log_directory.text = AppPaths.cacheDir().absolutePath
- text_tinc_binary.text = AppPaths.tinc().absolutePath
- }
-
- private fun generateConf(netName: String, nodeName: String, passphrase: String? = null) = execAction(
- R.string.message_generating_configuration,
- validateNetName(netName)
- .thenCompose { Tinc.init(netName, nodeName) }
- .thenCompose { TincApp.removeScripts(netName) }
- .thenCompose { TincApp.generateIfaceCfgTemplate(netName) }
- .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) })
-
- private fun joinNetwork(netName: String, url: String, passphrase: String? = null) = execAction(
- R.string.message_joining_network,
- validateNetName(netName)
- .thenCompose { Tinc.join(netName, url) }
- .thenCompose { TincApp.removeScripts(netName) }
- .thenCompose { TincApp.generateIfaceCfg(netName) }
- .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) })
-
- private fun encryptDecryptPrivateKeys(netName: String, currentPassphrase: String, newPassphrase: String) = execAction(
- R.string.message_encrypting_decrypting_private_keys,
- validateNetName(netName)
- .thenCompose { TincApp.setPassphrase(netName, currentPassphrase, newPassphrase) })
-
- private fun execAction(@StringRes label: Int, action: CompletableFuture) {
- showProgressDialog(label).let { progressDialog ->
- action
- .whenComplete { _, _ -> progressDialog.dismiss() }
- .thenAccept { notify(R.string.message_network_configuration_written) }
- .exceptionallyAccept { runOnUiThread { showErrorDialog(it.cause!!.localizedMessage) } }
- }
- }
-
- private fun validateNetName(netName: String): CompletableFuture =
- if (NETWORK_NAME_PATTERN.matcher(netName).matches())
- CompletableFuture.completedFuture(Unit)
- else
- CompletableFuture.failedFuture(IllegalArgumentException(resources.getString(R.string.message_invalid_network_name)))
-}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
index 50e002f..70302e5 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
@@ -35,6 +35,8 @@ import kotlinx.android.synthetic.main.dialog_decrypt_keys.view.*
import kotlinx.android.synthetic.main.fragment_list_view.*
import kotlinx.android.synthetic.main.fragment_network_list_header.*
import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.common.ProgressModal
+import org.pacien.tincapp.activities.configure.ConfigureActivity
import org.pacien.tincapp.context.AppPaths
import org.pacien.tincapp.extensions.Android.setElements
import org.pacien.tincapp.intent.Actions
@@ -127,7 +129,7 @@ class StartActivity : BaseActivity() {
}
private fun startVpn(netName: String, passphrase: String? = null) {
- connectDialog = showProgressDialog(R.string.message_starting_vpn)
+ connectDialog = ProgressModal.show(this@StartActivity, getString(R.string.message_starting_vpn))
TincVpnService.connect(netName, passphrase)
}
}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
index 68e008e..88ce222 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
@@ -34,6 +34,7 @@ import kotlinx.android.synthetic.main.dialog_node_details.view.*
import kotlinx.android.synthetic.main.fragment_list_view.*
import kotlinx.android.synthetic.main.fragment_network_status_header.*
import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.common.ProgressModal
import org.pacien.tincapp.commands.Executor
import org.pacien.tincapp.commands.Tinc
import org.pacien.tincapp.data.VpnInterfaceConfiguration
@@ -127,7 +128,7 @@ class StatusActivity : BaseActivity(), AdapterView.OnItemClickListener, SwipeRef
fun stopVpn(@Suppress("UNUSED_PARAMETER") i: MenuItem? = null) {
refreshTimer?.cancel()
list_wrapper.isRefreshing = false
- shutdownDialog = showProgressDialog(R.string.message_disconnecting_vpn)
+ shutdownDialog = ProgressModal.show(this, getString(R.string.message_disconnecting_vpn))
TincVpnService.disconnect()
}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/common/ProgressModal.kt b/app/src/main/java/org/pacien/tincapp/activities/common/ProgressModal.kt
new file mode 100644
index 0000000..d4310a1
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/common/ProgressModal.kt
@@ -0,0 +1,49 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.common
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.support.v7.app.AlertDialog
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.TextView
+import org.pacien.tincapp.R
+
+/**
+ * An indefinite progress dialog replacing the deprecated `android.app.ProgressDialog`.
+ *
+ * @author pacien
+ */
+object ProgressModal {
+ fun show(context: Activity, text: String): AlertDialog {
+ return AlertDialog.Builder(context)
+ .setView(newDialogView(context.layoutInflater, text))
+ .setCancelable(false)
+ .show()
+ }
+
+ @SuppressLint("InflateParams")
+ private fun newDialogView(inflater: LayoutInflater, text: String): View {
+ val view = inflater.inflate(R.layout.common_progress_dialog, null)
+ val textView: TextView = view.findViewById(R.id.common_progress_dialog_text)
+ textView.text = text
+ return view
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/ConfigureActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/ConfigureActivity.kt
new file mode 100644
index 0000000..d154ff7
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/ConfigureActivity.kt
@@ -0,0 +1,35 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure
+
+import android.os.Bundle
+import kotlinx.android.synthetic.main.base.*
+import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.BaseActivity
+
+/**
+ * @author pacien
+ */
+class ConfigureActivity : BaseActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ supportActionBar!!.setDisplayHomeAsUpEnabled(true)
+ layoutInflater.inflate(R.layout.configure_activity, main_content)
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/PathInfoFragment.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/PathInfoFragment.kt
new file mode 100644
index 0000000..dae4413
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/PathInfoFragment.kt
@@ -0,0 +1,40 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure
+
+import android.app.Fragment
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.pacien.tincapp.context.AppPaths
+import org.pacien.tincapp.databinding.ConfigureToolsPathInfoFragmentBinding
+
+/**
+ * @author pacien
+ */
+class PathInfoFragment : Fragment() {
+ private val appPaths = AppPaths
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ val binding = ConfigureToolsPathInfoFragmentBinding.inflate(inflater, container, false)
+ binding.appPaths = appPaths
+ return binding.root
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/ToolsFragment.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/ToolsFragment.kt
new file mode 100644
index 0000000..0ad2f19
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/ToolsFragment.kt
@@ -0,0 +1,53 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure
+
+import android.app.Fragment
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.pacien.tincapp.activities.BaseActivity
+import org.pacien.tincapp.activities.configure.tools.EncryptDecryptPrivateKeysTool
+import org.pacien.tincapp.activities.configure.tools.GenerateConfigTool
+import org.pacien.tincapp.activities.configure.tools.JoinNetworkTool
+import org.pacien.tincapp.databinding.ConfigureToolsFragmentBinding
+
+/**
+ * @author pacien
+ */
+class ToolsFragment : Fragment() {
+ private val parentActivity by lazy { activity as BaseActivity }
+ private val generateConfigTool by lazy { GenerateConfigTool(parentActivity) }
+ private val joinNetworkTool by lazy { JoinNetworkTool(this, parentActivity) }
+ private val encryptDecryptPrivateKeysTool by lazy { EncryptDecryptPrivateKeysTool(parentActivity) }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ val binding = ConfigureToolsFragmentBinding.inflate(inflater, container, false)
+ binding.generateConfigAction = generateConfigTool::openGenerateConfDialog
+ binding.joinNetworkAction = joinNetworkTool::openJoinNetworkDialog
+ binding.encryptDecryptPrivateKeysAction = encryptDecryptPrivateKeysTool::openEncryptDecryptPrivateKeyDialog
+ return binding.root
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ joinNetworkTool.onActivityResult(requestCode, resultCode, data)
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/tools/ConfigurationTool.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/ConfigurationTool.kt
new file mode 100644
index 0000000..41d1f55
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/ConfigurationTool.kt
@@ -0,0 +1,64 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure.tools
+
+import android.app.AlertDialog
+import android.support.annotation.LayoutRes
+import android.support.annotation.StringRes
+import android.view.View
+import java8.util.concurrent.CompletableFuture
+import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.BaseActivity
+import org.pacien.tincapp.activities.common.ProgressModal
+import org.pacien.tincapp.extensions.Java.exceptionallyAccept
+import java.util.regex.Pattern
+
+/**
+ * @author pacien
+ */
+abstract class ConfigurationTool(private val parentActivity: BaseActivity) {
+ private val networkNamePattern by lazy { Pattern.compile("^[^\\x00/]*$")!! }
+
+ protected fun showDialog(@LayoutRes layout: Int, @StringRes title: Int, @StringRes applyButton: Int, applyAction: (View) -> Unit) =
+ showDialog(parentActivity.inflate(layout), title, applyButton, applyAction)
+
+ protected fun showDialog(view: View, @StringRes title: Int, @StringRes applyButton: Int, applyAction: (View) -> Unit) {
+ AlertDialog.Builder(parentActivity)
+ .setTitle(title)
+ .setView(view)
+ .setPositiveButton(applyButton) { _, _ -> applyAction(view) }
+ .setNegativeButton(R.string.action_cancel) { _, _ -> Unit }
+ .show()
+ }
+
+ protected fun execAction(@StringRes label: Int, action: CompletableFuture) {
+ ProgressModal.show(parentActivity, parentActivity.getString(label)).let { progressDialog ->
+ action
+ .whenComplete { _, _ -> progressDialog.dismiss() }
+ .thenAccept { parentActivity.notify(R.string.message_network_configuration_written) }
+ .exceptionallyAccept { parentActivity.runOnUiThread { parentActivity.showErrorDialog(it.cause!!.localizedMessage) } }
+ }
+ }
+
+ protected fun validateNetName(netName: String): CompletableFuture =
+ if (networkNamePattern.matcher(netName).matches())
+ CompletableFuture.completedFuture(Unit)
+ else
+ CompletableFuture.failedFuture(IllegalArgumentException(parentActivity.getString(R.string.message_invalid_network_name)))
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/tools/EncryptDecryptPrivateKeysTool.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/EncryptDecryptPrivateKeysTool.kt
new file mode 100644
index 0000000..cd55111
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/EncryptDecryptPrivateKeysTool.kt
@@ -0,0 +1,49 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure.tools
+
+import kotlinx.android.synthetic.main.configure_tools_dialog_encrypt_decrypt_keys.view.*
+import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.BaseActivity
+import org.pacien.tincapp.commands.TincApp
+
+/**
+ * @author pacien
+ */
+class EncryptDecryptPrivateKeysTool(parentActivity: BaseActivity) : ConfigurationTool(parentActivity) {
+ fun openEncryptDecryptPrivateKeyDialog() =
+ showDialog(
+ R.layout.configure_tools_dialog_encrypt_decrypt_keys,
+ R.string.configure_tools_private_keys_encryption_title,
+ R.string.configure_tools_private_keys_encryption_action
+ ) { dialog ->
+ encryptDecryptPrivateKeys(
+ dialog.enc_dec_net_name.text.toString(),
+ dialog.enc_dec_current_passphrase.text.toString(),
+ dialog.enc_dec_new_passphrase.text.toString()
+ )
+ }
+
+ private fun encryptDecryptPrivateKeys(netName: String, currentPassphrase: String, newPassphrase: String) =
+ execAction(
+ R.string.configure_tools_private_keys_encryption_encrypting,
+ validateNetName(netName)
+ .thenCompose { TincApp.setPassphrase(netName, currentPassphrase, newPassphrase) }
+ )
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/tools/GenerateConfigTool.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/GenerateConfigTool.kt
new file mode 100644
index 0000000..2f0ef49
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/GenerateConfigTool.kt
@@ -0,0 +1,51 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure.tools
+
+import kotlinx.android.synthetic.main.configure_tools_dialog_network_generate.view.*
+import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.BaseActivity
+import org.pacien.tincapp.commands.Tinc
+import org.pacien.tincapp.commands.TincApp
+
+/**
+ * @author pacien
+ */
+class GenerateConfigTool(parentActivity: BaseActivity) : ConfigurationTool(parentActivity) {
+ fun openGenerateConfDialog() =
+ showDialog(
+ R.layout.configure_tools_dialog_network_generate,
+ R.string.configure_tools_generate_config_title,
+ R.string.configure_tools_generate_config_action
+ ) { dialog ->
+ generateConf(
+ dialog.new_net_name.text.toString(),
+ dialog.new_node_name.text.toString(),
+ dialog.new_passphrase.text.toString()
+ )
+ }
+
+ private fun generateConf(netName: String, nodeName: String, passphrase: String? = null) = execAction(
+ R.string.configure_tools_generate_config_generating,
+ validateNetName(netName)
+ .thenCompose { Tinc.init(netName, nodeName) }
+ .thenCompose { TincApp.removeScripts(netName) }
+ .thenCompose { TincApp.generateIfaceCfgTemplate(netName) }
+ .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) })
+}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/configure/tools/JoinNetworkTool.kt b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/JoinNetworkTool.kt
new file mode 100644
index 0000000..82a4380
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/configure/tools/JoinNetworkTool.kt
@@ -0,0 +1,83 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.pacien.tincapp.activities.configure.tools
+
+import android.app.Fragment
+import android.content.Intent
+import android.view.View
+import com.google.zxing.integration.android.IntentIntegrator
+import com.google.zxing.integration.android.IntentResult
+import kotlinx.android.synthetic.main.configure_tools_dialog_network_join.view.*
+import org.pacien.tincapp.R
+import org.pacien.tincapp.activities.BaseActivity
+import org.pacien.tincapp.commands.Tinc
+import org.pacien.tincapp.commands.TincApp
+import org.pacien.tincapp.databinding.ConfigureToolsDialogNetworkJoinBinding
+
+/**
+ * @author pacien
+ */
+class JoinNetworkTool(parentFragment: Fragment, private val parentActivity: BaseActivity) : ConfigurationTool(parentActivity) {
+ private val scanner by lazy { IntentIntegrator(parentFragment) }
+ private var joinDialog: View? = null
+
+ fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
+ ?.let(IntentResult::getContents)
+ ?.let(String::trim)
+ ?.let { joinDialog?.invitation_url?.setText(it) }
+ }
+
+ fun openJoinNetworkDialog() =
+ makeJoinDialog().let { newDialog ->
+ joinDialog = newDialog
+ showDialog(
+ newDialog,
+ R.string.configure_tools_join_network_title,
+ R.string.configure_tools_join_network_action
+ ) { dialog ->
+ joinNetwork(
+ dialog.net_name.text.toString(),
+ dialog.invitation_url.text.toString(),
+ dialog.join_passphrase.text.toString()
+ )
+ }
+ }
+
+ private fun makeJoinDialog() =
+ parentActivity.inflate { inflater, parent, attachToRoot ->
+ ConfigureToolsDialogNetworkJoinBinding.inflate(inflater, parent, attachToRoot)
+ .apply { scanAction = this@JoinNetworkTool::scanCode }
+ .root
+ }
+
+ private fun scanCode() {
+ scanner.initiateScan()
+ }
+
+ private fun joinNetwork(netName: String, url: String, passphrase: String? = null) =
+ execAction(
+ R.string.configure_tools_join_network_joining,
+ validateNetName(netName)
+ .thenCompose { Tinc.join(netName, url) }
+ .thenCompose { TincApp.removeScripts(netName) }
+ .thenCompose { TincApp.generateIfaceCfg(netName) }
+ .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) }
+ )
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt b/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt
index 0b85565..1efb7cf 100644
--- a/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt
+++ b/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt
@@ -43,13 +43,15 @@ object AppPaths {
private const val NET_DEFAULT_ED25519_PRIVATE_KEY_FILE = "ed25519_key.priv"
private const val NET_DEFAULT_RSA_PRIVATE_KEY_FILE = "rsa_key.priv"
+ private val context by lazy { App.getContext() }
+
fun storageAvailable() =
Environment.getExternalStorageState().let { it == Environment.MEDIA_MOUNTED && it != Environment.MEDIA_MOUNTED_READ_ONLY }
- private fun internalCacheDir() = App.getContext().cacheDir!!
- fun cacheDir() = App.getContext().externalCacheDir!!
- fun confDir() = App.getContext().getExternalFilesDir(null)!!
- private fun binDir() = File(App.getContext().applicationInfo.nativeLibraryDir)
+ private fun internalCacheDir() = context.cacheDir!!
+ fun cacheDir() = context.externalCacheDir!!
+ fun confDir() = context.getExternalFilesDir(null)!!
+ private fun binDir() = File(context.applicationInfo.nativeLibraryDir)
fun confDir(netName: String) = File(confDir(), netName)
fun hostsDir(netName: String) = File(confDir(netName), NET_HOSTS_DIR)
@@ -57,7 +59,7 @@ object AppPaths {
fun tincConfFile(netName: String) = File(confDir(netName), NET_TINC_CONF_FILE)
fun invitationFile(netName: String) = File(confDir(netName), NET_INVITATION_FILE)
fun logFile(netName: String) = File(cacheDir(), String.format(LOGFILE_FORMAT, netName))
- fun pidFile(netName: String) = File(App.getContext().cacheDir, String.format(PIDFILE_FORMAT, netName))
+ fun pidFile(netName: String) = File(context.cacheDir, String.format(PIDFILE_FORMAT, netName))
fun appLogFile() = File(cacheDir(), APPLOG_FILE)
fun crashFlagFile() = File(internalCacheDir(), CRASHFLAG_FILE)
diff --git a/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt b/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt
deleted file mode 100644
index 53eb651..0000000
--- a/app/src/main/java/org/pacien/tincapp/utils/ProgressModal.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
- * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.pacien.tincapp.utils
-
-import android.annotation.SuppressLint
-import android.app.Activity
-import android.support.v7.app.AlertDialog
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.TextView
-import org.pacien.tincapp.R
-
-/**
- * An indefinite progress dialog replacing the deprecated `android.app.ProgressDialog`.
- *
- * @author pacien
- */
-object ProgressModal {
- fun show(context: Activity, text: String): AlertDialog {
- return AlertDialog.Builder(context)
- .setView(newDialogView(context.layoutInflater, text))
- .setCancelable(false)
- .show()
- }
-
- @SuppressLint("InflateParams")
- private fun newDialogView(inflater: LayoutInflater, text: String): View {
- val view = inflater.inflate(R.layout.common_progress_dialog, null)
- val textView: TextView = view.findViewById(R.id.common_progress_dialog_text)
- textView.text = text
- return view
- }
-}
diff --git a/app/src/main/res/layout/configure_activity.xml b/app/src/main/res/layout/configure_activity.xml
new file mode 100644
index 0000000..6097384
--- /dev/null
+++ b/app/src/main/res/layout/configure_activity.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/configure_tools_dialog_encrypt_decrypt_keys.xml b/app/src/main/res/layout/configure_tools_dialog_encrypt_decrypt_keys.xml
new file mode 100644
index 0000000..1e8e64a
--- /dev/null
+++ b/app/src/main/res/layout/configure_tools_dialog_encrypt_decrypt_keys.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/configure_tools_dialog_network_generate.xml b/app/src/main/res/layout/configure_tools_dialog_network_generate.xml
new file mode 100644
index 0000000..614cc16
--- /dev/null
+++ b/app/src/main/res/layout/configure_tools_dialog_network_generate.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/configure_tools_dialog_network_join.xml b/app/src/main/res/layout/configure_tools_dialog_network_join.xml
new file mode 100644
index 0000000..9171284
--- /dev/null
+++ b/app/src/main/res/layout/configure_tools_dialog_network_join.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/configure_tools_fragment.xml b/app/src/main/res/layout/configure_tools_fragment.xml
new file mode 100644
index 0000000..bb67b45
--- /dev/null
+++ b/app/src/main/res/layout/configure_tools_fragment.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/configure_tools_path_info_fragment.xml b/app/src/main/res/layout/configure_tools_path_info_fragment.xml
new file mode 100644
index 0000000..376fa3d
--- /dev/null
+++ b/app/src/main/res/layout/configure_tools_path_info_fragment.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_encrypt_decrypt_keys.xml b/app/src/main/res/layout/dialog_encrypt_decrypt_keys.xml
deleted file mode 100644
index 47433e4..0000000
--- a/app/src/main/res/layout/dialog_encrypt_decrypt_keys.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/dialog_network_generate.xml b/app/src/main/res/layout/dialog_network_generate.xml
deleted file mode 100644
index 5e3d42c..0000000
--- a/app/src/main/res/layout/dialog_network_generate.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/dialog_network_join.xml b/app/src/main/res/layout/dialog_network_join.xml
deleted file mode 100644
index 65d772d..0000000
--- a/app/src/main/res/layout/dialog_network_join.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/page_configure.xml b/app/src/main/res/layout/page_configure.xml
deleted file mode 100644
index c86ff76..0000000
--- a/app/src/main/res/layout/page_configure.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-