Skip to content

Commit

Permalink
UI improvements (#74)
Browse files Browse the repository at this point in the history
* Fixed connected peers status in PeersActivity.
* Fixed display of new generated public key in SettingsActivity.
* Made more reliable display of connectivity state on main screen.
* Added a note about not configured peers. Changed all dialog buttons to greenish color.
* Click on a version row now opens URL of the project on GitHub.
* Changed the wording of no peer notification.
  • Loading branch information
Revertron authored Jan 8, 2025
1 parent 94db1fa commit 055a74e
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ object ConfigurationProxy {
json.put("IfMTU", 65535)

if (json.getJSONArray("MulticastInterfaces").get(0) is String) {
var ar = JSONArray()
val ar = JSONArray()
ar.put(0, JSONObject("""
{
"Regex": ".*",
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class DnsActivity : AppCompatActivity() {
addServerButton.setOnClickListener {
val view = inflater.inflate(R.layout.dialog_add_dns_server, null)
val input = view.findViewById<TextInputEditText>(R.id.addDnsInput)
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.dns_add_server_dialog_title))
builder.setView(view)
builder.setPositiveButton(getString(R.string.add)) { _, _ ->
Expand Down Expand Up @@ -128,7 +128,7 @@ class DnsActivity : AppCompatActivity() {
view.findViewById<ImageButton>(R.id.deletePeerButton).tag = i

view.findViewById<ImageButton>(R.id.deletePeerButton).setOnClickListener { button ->
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.dns_remove_title, server))
builder.setPositiveButton(getString(R.string.remove)) { dialog, _ ->
servers.removeAt(button.tag as Int)
Expand Down Expand Up @@ -176,7 +176,7 @@ class DnsActivity : AppCompatActivity() {
}
}
view.setOnLongClickListener {
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.dns_server_info_dialog_title))
builder.setMessage("${infoPair.first}\n\n${infoPair.second}")
builder.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.core.app.NotificationCompat
import androidx.preference.PreferenceManager

const val PREF_KEY_ENABLED = "enabled"
const val PREF_KEY_PEERS_NOTE = "peers_note"
const val MAIN_CHANNEL_ID = "Yggdrasil Service"

class GlobalApplication: Application(), YggStateReceiver.StateReceiver {
Expand Down
65 changes: 55 additions & 10 deletions app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package eu.neilalexander.yggdrasil

import android.app.Activity
import android.app.AlertDialog
import android.content.*
import android.graphics.Color
import android.net.Uri
import android.net.VpnService
import android.os.Bundle
import android.view.ContextThemeWrapper
import android.widget.Switch
import android.widget.TextView
import android.widget.Toast
Expand All @@ -18,6 +21,7 @@ import eu.neilalexander.yggdrasil.PacketTunnelProvider.Companion.STATE_INTENT
import mobile.Mobile
import org.json.JSONArray

const val APP_WEB_URL = "https://github.com/yggdrasil-network/yggdrasil-android"

class MainActivity : AppCompatActivity() {
private lateinit var enabledSwitch: Switch
Expand All @@ -29,6 +33,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var dnsLabel: TextView
private lateinit var dnsRow: LinearLayoutCompat
private lateinit var settingsRow: LinearLayoutCompat
private lateinit var versionRow: LinearLayoutCompat

private fun start() {
val intent = Intent(this, PacketTunnelProvider::class.java)
Expand Down Expand Up @@ -57,6 +62,7 @@ class MainActivity : AppCompatActivity() {
dnsLabel = findViewById(R.id.dnsValue)
dnsRow = findViewById(R.id.dnsTableRow)
settingsRow = findViewById(R.id.settingsTableRow)
versionRow = findViewById(R.id.versionTableRow)

enabledLabel.setTextColor(Color.GRAY)

Expand Down Expand Up @@ -104,6 +110,11 @@ class MainActivity : AppCompatActivity() {
startActivity(intent)
}

versionRow.isClickable = true
versionRow.setOnClickListener {
openUrlInBrowser(APP_WEB_URL)
}

ipAddressLabel.setOnLongClickListener {
val clipboard: ClipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("ip", ipAddressLabel.text)
Expand Down Expand Up @@ -152,15 +163,16 @@ class MainActivity : AppCompatActivity() {
override fun onReceive(context: Context?, intent: Intent) {
when (intent.getStringExtra("type")) {
"state" -> {
enabledLabel.text = if (intent.getBooleanExtra("started", false)) {
var count = 0
if (intent.hasExtra("peers")) {
val peers = intent.getStringExtra("peers")
if (peers != null && peers != "null") {
val peerState = JSONArray(peers)
count = peerState.length()
}
val peerState = JSONArray(intent.getStringExtra("peers") ?: "[]")
var count = 0
for (i in 0..<peerState.length()) {
val peer = peerState.getJSONObject(i)
if (peer.getString("IP").isNotEmpty()) {
count += 1
}
}
enabledLabel.text = if (intent.getBooleanExtra("started", false)) {
showPeersNoteIfNeeded(peerState.length())
if (count == 0) {
enabledLabel.setTextColor(Color.RED)
getString(R.string.main_no_connectivity)
Expand All @@ -175,8 +187,7 @@ class MainActivity : AppCompatActivity() {
ipAddressLabel.text = intent.getStringExtra("ip") ?: "N/A"
subnetLabel.text = intent.getStringExtra("subnet") ?: "N/A"
if (intent.hasExtra("peers")) {
val peerState = JSONArray(intent.getStringExtra("peers") ?: "[]")
peersLabel.text = when (val count = peerState.length()) {
peersLabel.text = when (count) {
0 -> getString(R.string.main_no_peers)
1 -> getString(R.string.main_one_peer)
else -> getString(R.string.main_many_peers, count)
Expand All @@ -189,4 +200,38 @@ class MainActivity : AppCompatActivity() {
}
}
}

private fun showPeersNoteIfNeeded(peerCount: Int) {
if (peerCount > 0) return
val preferences = PreferenceManager.getDefaultSharedPreferences(this@MainActivity.baseContext)
if (!preferences.getBoolean(PREF_KEY_PEERS_NOTE, false)) {
this@MainActivity.runOnUiThread {
val builder: AlertDialog.Builder =
AlertDialog.Builder(ContextThemeWrapper(this@MainActivity, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.main_add_some_peers_title))
builder.setMessage(getString(R.string.main_add_some_peers_message))
builder.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
dialog.dismiss()
}
builder.show()
}
// Mark this note as shown
preferences.edit().apply {
putBoolean(PREF_KEY_PEERS_NOTE, true)
commit()
}
}
}

fun openUrlInBrowser(url: String) {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(url)
}
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// Handle the exception if no browser is found
Toast.makeText(this, getText(R.string.no_browser_found_toast), Toast.LENGTH_SHORT).show()
}
}
}
35 changes: 25 additions & 10 deletions app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.ContextThemeWrapper
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.widget.*
import android.widget.EditText
import android.widget.ImageButton
import android.widget.Switch
import android.widget.TableLayout
import android.widget.TableRow
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doOnTextChanged
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.android.material.textfield.TextInputEditText
import org.json.JSONArray
import org.json.JSONObject


class PeersActivity : AppCompatActivity() {
private lateinit var config: ConfigurationProxy
private lateinit var inflater: LayoutInflater
Expand Down Expand Up @@ -99,7 +105,7 @@ class PeersActivity : AppCompatActivity() {
addPeerButton.setOnClickListener {
val view = inflater.inflate(R.layout.dialog_addpeer, null)
val input = view.findViewById<TextInputEditText>(R.id.addPeerInput)
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.peers_add_peer))
builder.setView(view)
builder.setPositiveButton(getString(R.string.peers_add)) { dialog, _ ->
Expand Down Expand Up @@ -153,7 +159,7 @@ class PeersActivity : AppCompatActivity() {
view.findViewById<ImageButton>(R.id.deletePeerButton).tag = i

view.findViewById<ImageButton>(R.id.deletePeerButton).setOnClickListener { button ->
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.peers_remove_title, peer))
builder.setPositiveButton(getString(R.string.peers_remove)) { dialog, _ ->
config.updateJSON { json ->
Expand All @@ -180,16 +186,25 @@ class PeersActivity : AppCompatActivity() {
connectedTableLabel.text = getString(R.string.peers_no_connected_title)
}
else -> {
connectedTableLayout.visibility = View.VISIBLE
connectedTableLabel.text = getString(R.string.peers_connected_title)

var connected = false
connectedTableLayout.removeAllViewsInLayout()
for (peer in peers) {
val view = inflater.inflate(R.layout.peers_connected, null)
val ip = peer.getString("IP")
view.findViewById<TextView>(R.id.addressLabel).text = ip
view.findViewById<TextView>(R.id.detailsLabel).text = peer.getString("URI")
connectedTableLayout.addView(view)
// Only connected peers have IPs
if (ip.isNotEmpty()) {
view.findViewById<TextView>(R.id.addressLabel).text = ip
view.findViewById<TextView>(R.id.detailsLabel).text = peer.getString("URI")
connectedTableLayout.addView(view)
connected = true
}
}
if (connected) {
connectedTableLayout.visibility = View.VISIBLE
connectedTableLabel.text = getString(R.string.peers_connected_title)
} else {
connectedTableLayout.visibility = View.GONE
connectedTableLabel.text = getString(R.string.peers_no_connected_title)
}
}
}
Expand Down
14 changes: 10 additions & 4 deletions app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class SettingsActivity : AppCompatActivity() {
private lateinit var deviceNameEntry: EditText
private lateinit var publicKeyLabel: TextView
private lateinit var resetConfigurationRow: LinearLayoutCompat
private var publicKeyReset = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -69,7 +70,7 @@ class SettingsActivity : AppCompatActivity() {

resetConfigurationRow.setOnClickListener {
val view = inflater.inflate(R.layout.dialog_resetconfig, null)
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
builder.setTitle(getString(R.string.settings_warning_title))
builder.setView(view)
builder.setPositiveButton(getString(R.string.settings_reset)) { dialog, _ ->
Expand All @@ -85,12 +86,13 @@ class SettingsActivity : AppCompatActivity() {

findViewById<View>(R.id.resetKeysRow).setOnClickListener {
config.resetKeys()
publicKeyReset = true
updateView()
}

findViewById<View>(R.id.setKeysRow).setOnClickListener {
val view = inflater.inflate(R.layout.dialog_set_keys, null)
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog))
val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs))
val privateKey = view.findViewById<EditText>(R.id.private_key)
builder.setTitle(getString(R.string.set_keys))
builder.setView(view)
Expand Down Expand Up @@ -125,7 +127,11 @@ class SettingsActivity : AppCompatActivity() {
deviceNameEntry.setText("", TextView.BufferType.EDITABLE)
}

publicKeyLabel.text = json.optString("PublicKey")
var key = json.optString("PrivateKey")
if (key.isNotEmpty()) {
key = key.substring(key.length / 2)
}
publicKeyLabel.text = key
}

override fun onResume() {
Expand All @@ -145,7 +151,7 @@ class SettingsActivity : AppCompatActivity() {
// To be able to get public key from running Yggdrasil we use this receiver, as we don't have this field in config
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
if (intent.hasExtra("pubkey")) {
if (intent.hasExtra("pubkey") && !publicKeyReset) {
val tree = intent.getStringExtra("pubkey")
if (tree != null && tree != "null") {
publicKeyLabel.text = intent.getStringExtra("pubkey")
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,9 @@

</androidx.appcompat.widget.LinearLayoutCompat>

<androidx.appcompat.widget.LinearLayoutCompat style="@style/SelectableItemStyle">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/versionTableRow"
style="@style/SelectableItemStyle">

<TextView
android:id="@+id/versionLabel"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
<string name="main_no_peers">Нет пиров</string>
<string name="main_one_peer">1 пир</string>
<string name="main_many_peers">%d пира/пиров</string>
<string name="main_add_some_peers_title">Внимание</string>
<string name="main_add_some_peers_message">Не настроено ни одного пира. Если не будет обнаруживаемых пиров в этой сети, то вам надо будет добавить пир вручную, чтобы подключение к Yggdrasil работало как положено.</string>
<string name="peers_add_peer">Добавить пира в конфиг</string>
<string name="peers_add">Добавить</string>
<string name="peers_remove_title">Убрать %s?</string>
Expand Down Expand Up @@ -83,4 +85,5 @@
<string name="private_key_label">Приватный ключ:</string>
<string name="set_keys">Установить свой ключ</string>
<string name="save">Сохранить</string>
<string name="no_browser_found_toast">Не найден браузер для открытия ссылки!</string>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="green">#5FBF9F</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="hintlight">#F2F1F5</color>
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
<string name="main_no_peers">No peers</string>
<string name="main_one_peer">1 peer</string>
<string name="main_many_peers">%d peers</string>
<string name="main_add_some_peers_title">Note</string>
<string name="main_add_some_peers_message">No peers are configured. If there are no multicast peers nearby, you will need to manually configure peers in order for Yggdrasil to connect and work properly.</string>
<string name="peers_add_peer">Add Configured Peer</string>
<string name="peers_add">Add</string>
<string name="peers_remove_title">Remove %s?</string>
Expand Down Expand Up @@ -83,4 +85,5 @@
<string name="private_key_label">Private key:</string>
<string name="set_keys">Set your own key</string>
<string name="save">Save</string>
<string name="no_browser_found_toast">No browser found to open the URL!</string>
</resources>
4 changes: 4 additions & 0 deletions app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
<item name="tableBackgroundColor">@color/white</item>
<item name="textDefault">@color/black</item>
</style>

<style name="YggdrasilDialogs" parent="@style/Theme.MaterialComponents.DayNight.Dialog">
<item name="colorPrimary">@color/green</item>
</style>
</resources>

0 comments on commit 055a74e

Please sign in to comment.