summaryrefslogtreecommitdiffhomepage
path: root/ui/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/main')
-rw-r--r--ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt23
-rw-r--r--ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt58
-rw-r--r--ui/src/main/res/layout/tunnel_detail_peer.xml28
-rw-r--r--ui/src/main/res/values/strings.xml6
4 files changed, 110 insertions, 5 deletions
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..fad1b5d4 100644
--- a/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt
+++ b/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.kt
@@ -20,6 +20,9 @@ import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.QuantityFormatter
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.
@@ -99,6 +102,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 +114,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,6 +135,8 @@ class TunnelDetailFragment : BaseFragment() {
?: continue
peer.transferLabel.visibility = View.GONE
peer.transferText.visibility = View.GONE
+ peer.lastHandshakeLabel.visibility = View.GONE
+ peer.lastHandshakeText.visibility = View.GONE
}
}
}
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..cd2adbcb 100644
--- a/ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt
+++ b/ui/src/main/java/com/wireguard/android/util/QuantityFormatter.kt
@@ -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/res/layout/tunnel_detail_peer.xml b/ui/src/main/res/layout/tunnel_detail_peer.xml
index 0fbee8f1..f295bb13 100644
--- a/ui/src/main/res/layout/tunnel_detail_peer.xml
+++ b/ui/src/main/res/layout/tunnel_detail_peer.xml
@@ -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/values/strings.xml b/ui/src/main/res/values/strings.xml
index c10c4ea7..3b32ab79 100644
--- a/ui/src/main/res/values/strings.xml
+++ b/ui/src/main/res/values/strings.xml
@@ -113,6 +113,10 @@
<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>
@@ -141,6 +145,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>