fix(kiosk): permissions button transforms to 'Continue' after grant + fix subnet detection

Permissions step:
- Add btnGrantPerms as class field (was only inline findViewById)
- Extract onPermissionsGranted() helper: transforms button to green ' Permessi
  concessi — Continua →' and sets click listener to showStep(3)
  instead of calling onPermissionsGranted() which advances to step 3 (Server)
- Remove the 600ms auto-advance; user controls when to proceed
- Add setup_perms_granted_next string in EN/IT/DE

Network discovery — wrong subnet fix:
- Skip virtual/VPN/cellular interfaces: tun, ppp, rmnet, pdp, ccmni, dummy, sit,
  gre, v4-, v6-, p2p, ham, nordlynx prefixes
- Also skip intf.isVirtual interfaces
- Sort: wlan*/eth* interfaces first (highest priority), others after
- Show detected subnet(s) in UI immediately before scan starts
This commit is contained in:
dadaloop82
2026-05-04 17:11:17 +00:00
parent 09fd122718
commit cfcba32c45
4 changed files with 42 additions and 18 deletions
@@ -102,6 +102,7 @@ class SetupActivity : AppCompatActivity() {
// Permissions step // Permissions step
private lateinit var permsGrantedCard: LinearLayout private lateinit var permsGrantedCard: LinearLayout
private lateinit var btnGrantPerms: MaterialButton
// APK install state (for gateway) // APK install state (for gateway)
private var pendingApkDownloadUrl = "" private var pendingApkDownloadUrl = ""
@@ -221,7 +222,8 @@ class SetupActivity : AppCompatActivity() {
summaryText = findViewById(R.id.setupSummaryText) summaryText = findViewById(R.id.setupSummaryText)
// Permissions step // Permissions step
permsGrantedCard = findViewById(R.id.permsGrantedCard) permsGrantedCard = findViewById(R.id.permsGrantedCard)
btnGrantPerms = findViewById(R.id.btnGrantPerms)
// Pre-fill saved URL // Pre-fill saved URL
val savedUrl = prefs.getString(KEY_URL, "") ?: "" val savedUrl = prefs.getString(KEY_URL, "") ?: ""
@@ -239,7 +241,7 @@ class SetupActivity : AppCompatActivity() {
findViewById<MaterialButton>(R.id.btnWelcomeStart).setOnClickListener { showStep(2) } findViewById<MaterialButton>(R.id.btnWelcomeStart).setOnClickListener { showStep(2) }
// ── Permissions ────────────────────────────────────────────────── // ── Permissions ──────────────────────────────────────────────────
findViewById<MaterialButton>(R.id.btnGrantPerms).setOnClickListener { requestPermissions() } btnGrantPerms.setOnClickListener { requestPermissions() }
findViewById<MaterialButton>(R.id.btnPermsBack).setOnClickListener { showStep(1) } findViewById<MaterialButton>(R.id.btnPermsBack).setOnClickListener { showStep(1) }
findViewById<MaterialButton>(R.id.btnPermsNext).setOnClickListener { showStep(3) } findViewById<MaterialButton>(R.id.btnPermsNext).setOnClickListener { showStep(3) }
@@ -408,8 +410,7 @@ class SetupActivity : AppCompatActivity() {
needed.add(Manifest.permission.READ_EXTERNAL_STORAGE) needed.add(Manifest.permission.READ_EXTERNAL_STORAGE)
} }
if (needed.isEmpty()) { if (needed.isEmpty()) {
// Already granted — show confirmation and allow next onPermissionsGranted()
permsGrantedCard.visibility = View.VISIBLE
} else { } else {
ActivityCompat.requestPermissions(this, needed.toTypedArray(), PERMISSION_REQUEST_CODE) ActivityCompat.requestPermissions(this, needed.toTypedArray(), PERMISSION_REQUEST_CODE)
} }
@@ -418,12 +419,18 @@ class SetupActivity : AppCompatActivity() {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST_CODE) { if (requestCode == PERMISSION_REQUEST_CODE) {
permsGrantedCard.visibility = View.VISIBLE onPermissionsGranted()
// Proceed to next step regardless — user can always grant later
Handler(Looper.getMainLooper()).postDelayed({ showStep(2) }, 600)
} }
} }
private fun onPermissionsGranted() {
permsGrantedCard.visibility = View.GONE
btnGrantPerms.text = getString(R.string.setup_perms_granted_next)
btnGrantPerms.backgroundTintList = android.content.res.ColorStateList.valueOf(0xFF34d399.toInt())
btnGrantPerms.setTextColor(0xFF0f172a.toInt())
btnGrantPerms.setOnClickListener { showStep(3) }
}
// ── Connection Test ─────────────────────────────────────────────────── // ── Connection Test ───────────────────────────────────────────────────
private fun testConnection() { private fun testConnection() {
@@ -516,27 +523,47 @@ class SetupActivity : AppCompatActivity() {
discoverStatus.setTextColor(0xFF94a3b8.toInt()) discoverStatus.setTextColor(0xFF94a3b8.toInt())
Thread { Thread {
// ── 1. Detect subnets via NetworkInterface (not deprecated WifiManager) ── // ── 1. Detect subnets — prefer Wi-Fi/Ethernet, skip VPN/cellular ──────
val subnets = mutableListOf<String>() // Prefixes to skip: VPN tunnels, cellular data, hotspot virtuals, etc.
val skipPrefixes = listOf("tun", "ppp", "rmnet", "pdp", "ccmni",
"dummy", "sit", "gre", "v4-", "v6-", "p2p", "ham", "nordlynx")
val wifiSubnets = mutableListOf<String>() // wlan/eth — highest priority
val otherSubnets = mutableListOf<String>() // everything else that is real
try { try {
val interfaces = NetworkInterface.getNetworkInterfaces() val interfaces = NetworkInterface.getNetworkInterfaces()
while (interfaces != null && interfaces.hasMoreElements()) { while (interfaces != null && interfaces.hasMoreElements()) {
val intf = interfaces.nextElement() val intf = interfaces.nextElement()
if (!intf.isUp || intf.isLoopback) continue if (!intf.isUp || intf.isLoopback || intf.isVirtual) continue
val name = intf.name.lowercase()
if (skipPrefixes.any { name.startsWith(it) }) continue
for (addr in intf.interfaceAddresses) { for (addr in intf.interfaceAddresses) {
val ip = addr.address val ip = addr.address
if (ip is java.net.Inet4Address && !ip.isLoopbackAddress) { if (ip is java.net.Inet4Address && !ip.isLoopbackAddress) {
val parts = ip.hostAddress?.split(".") ?: continue val parts = ip.hostAddress?.split(".") ?: continue
if (parts.size == 4) subnets += "${parts[0]}.${parts[1]}.${parts[2]}" if (parts.size == 4) {
val subnet = "${parts[0]}.${parts[1]}.${parts[2]}"
if (name.startsWith("wlan") || name.startsWith("eth")) {
if (!wifiSubnets.contains(subnet)) wifiSubnets += subnet
} else {
if (!otherSubnets.contains(subnet)) otherSubnets += subnet
}
}
} }
} }
} }
} catch (_: Exception) {} } catch (_: Exception) {}
// Append common fallback subnets (deduped) // WiFi first, then others, then hardcoded fallbacks (deduped)
val subnets = (wifiSubnets + otherSubnets).toMutableList()
for (s in listOf("192.168.1", "192.168.0", "192.168.2", "10.0.0", "10.0.1")) { for (s in listOf("192.168.1", "192.168.0", "192.168.2", "10.0.0", "10.0.1")) {
if (!subnets.contains(s)) subnets += s if (!subnets.contains(s)) subnets += s
} }
// Show detected subnets in status
val detectedLabel = if (wifiSubnets.isNotEmpty())
wifiSubnets.joinToString(", ") { "$it.x" }
else getString(R.string.setup_discovering_detail)
runOnUiThread { discoverStatus.text = "📡 $detectedLabel" }
val ports = listOf(80, 8080) val ports = listOf(80, 8080)
val paths = listOf( val paths = listOf(
"/api/index.php?action=get_settings", "/api/index.php?action=get_settings",
@@ -8,8 +8,7 @@
<string name="setup_server_found">EverShelf-Server gefunden und API aktiv!</string> <string name="setup_server_found">EverShelf-Server gefunden und API aktiv!</string>
<string name="setup_api_not_found">Server erreichbar, aber EverShelf-API nicht gefunden. Pfad prüfen.</string> <string name="setup_api_not_found">Server erreichbar, aber EverShelf-API nicht gefunden. Pfad prüfen.</string>
<string name="setup_unreachable">Server nicht erreichbar</string> <string name="setup_unreachable">Server nicht erreichbar</string>
<string name="setup_discover_btn">🔍 Lokales Netzwerk durchsuchen</string> <string name="setup_discover_btn">🔍 Lokales Netzwerk durchsuchen</string> <string name="setup_perms_granted_next">✅ Berechtigungen erteilt — Weiter →</string> <string name="setup_discovering">Suche läuft…</string>
<string name="setup_discovering">Suche läuft…</string>
<string name="setup_discovering_detail">Suche nach EverShelf-Servern im lokalen Netzwerk…</string> <string name="setup_discovering_detail">Suche nach EverShelf-Servern im lokalen Netzwerk…</string>
<string name="setup_discover_not_found">Kein EverShelf-Server automatisch gefunden. URL manuell eingeben.</string> <string name="setup_discover_not_found">Kein EverShelf-Server automatisch gefunden. URL manuell eingeben.</string>
<string name="setup_exit_title">Setup beenden?</string> <string name="setup_exit_title">Setup beenden?</string>
@@ -8,8 +8,7 @@
<string name="setup_server_found">Server EverShelf trovato e API attiva!</string> <string name="setup_server_found">Server EverShelf trovato e API attiva!</string>
<string name="setup_api_not_found">Server raggiungibile ma API EverShelf non trovata. Verifica il percorso.</string> <string name="setup_api_not_found">Server raggiungibile ma API EverShelf non trovata. Verifica il percorso.</string>
<string name="setup_unreachable">Impossibile raggiungere il server</string> <string name="setup_unreachable">Impossibile raggiungere il server</string>
<string name="setup_discover_btn">🔍 Cerca nella rete locale</string> <string name="setup_discover_btn">🔍 Cerca nella rete locale</string> <string name="setup_perms_granted_next">✅ Permessi concessi — Continua →</string> <string name="setup_discovering">Scansione in corso…</string>
<string name="setup_discovering">Scansione in corso…</string>
<string name="setup_discovering_detail">Ricerca server EverShelf nella rete locale…</string> <string name="setup_discovering_detail">Ricerca server EverShelf nella rete locale…</string>
<string name="setup_discover_not_found">Nessun server EverShelf trovato automaticamente. Inserisci l\'URL manualmente.</string> <string name="setup_discover_not_found">Nessun server EverShelf trovato automaticamente. Inserisci l\'URL manualmente.</string>
<string name="setup_exit_title">Uscire dalla configurazione?</string> <string name="setup_exit_title">Uscire dalla configurazione?</string>
@@ -7,8 +7,7 @@
<string name="setup_server_found">EverShelf server found and API active!</string> <string name="setup_server_found">EverShelf server found and API active!</string>
<string name="setup_api_not_found">Server reachable but EverShelf API not found. Check the path.</string> <string name="setup_api_not_found">Server reachable but EverShelf API not found. Check the path.</string>
<string name="setup_unreachable">Cannot reach server</string> <string name="setup_unreachable">Cannot reach server</string>
<string name="setup_discover_btn">🔍 Search local network</string> <string name="setup_discover_btn">🔍 Search local network</string> <string name="setup_perms_granted_next">✅ Permissions granted — Continue →</string> <string name="setup_discovering">Scanning…</string>
<string name="setup_discovering">Scanning…</string>
<string name="setup_discovering_detail">Searching for EverShelf servers on the local network…</string> <string name="setup_discovering_detail">Searching for EverShelf servers on the local network…</string>
<string name="setup_discover_not_found">No EverShelf server found automatically. Enter the URL manually.</string> <string name="setup_discover_not_found">No EverShelf server found automatically. Enter the URL manually.</string>
<string name="setup_exit_title">Exit setup?</string> <string name="setup_exit_title">Exit setup?</string>