feat: kiosk setup improvements + webapp scale indicator fixes

kiosk setup wizard:
- Scale step: ask user to power on the scale before scanning (new
  'Accendi la bilancia' card with 'Bilancia accesa → Cerca' button)
- BLE scan: filter results to only show compatible scales (scaleScore>0)
  hiding clearly non-scale BLE devices from the list
- After device selection: run a live connection test — connect to the
  scale, display the live weight, ask 'Corrisponde al peso sulla bilancia?'
  with  Sì /  Riprova / Skip buttons before confirming the device

webapp:
- Scale indicator not live on first load: scaleInit() was firing before
  syncSettingsFromDB() resolved; fixed by chaining .then(scaleInit)
- Scale icon green-on-green: connected state dot changed from #22c55e
  (green, invisible on dark-green header) to white with green border+glow,
  visible on any background color
This commit is contained in:
dadaloop82
2026-05-05 18:11:51 +00:00
parent 7ea5505a0d
commit 754f13111f
4 changed files with 315 additions and 21 deletions
+8 -7
View File
@@ -284,18 +284,19 @@ body {
width: 9px; width: 9px;
height: 9px; height: 9px;
border-radius: 50%; border-radius: 50%;
border: 1.5px solid #0f172a; border: 1.5px solid rgba(0,0,0,0.35);
background: #475569; background: #94a3b8;
transition: background 0.4s, box-shadow 0.4s; transition: background 0.4s, box-shadow 0.4s, border-color 0.4s;
pointer-events: none; pointer-events: none;
} }
.scale-status-connected .scale-status-dot { background: #22c55e; box-shadow: 0 0 5px #22c55eaa; } /* Connected: white dot with green glow — always visible regardless of header color */
.scale-status-connected .scale-status-dot { background: #ffffff; border-color: #22c55e; box-shadow: 0 0 6px #22c55e; }
.scale-status-connected .scale-icon-emoji { filter: none; opacity: 1; } .scale-status-connected .scale-icon-emoji { filter: none; opacity: 1; }
.scale-status-searching .scale-status-dot { background: #f59e0b; animation: scaleStatusPulse 1.4s infinite; } .scale-status-searching .scale-status-dot { background: #f59e0b; border-color: rgba(0,0,0,0.35); animation: scaleStatusPulse 1.4s infinite; }
.scale-status-searching .scale-icon-emoji { filter: none; opacity: 0.85; } .scale-status-searching .scale-icon-emoji { filter: none; opacity: 0.85; }
.scale-status-disconnected .scale-status-dot { background: #475569; } .scale-status-disconnected .scale-status-dot { background: #64748b; border-color: rgba(0,0,0,0.35); }
.scale-status-disconnected .scale-icon-emoji { filter: grayscale(0.5); opacity: 0.55; } .scale-status-disconnected .scale-icon-emoji { filter: grayscale(0.5); opacity: 0.55; }
.scale-status-error .scale-status-dot { background: #ef4444; box-shadow: 0 0 5px #ef4444aa; } .scale-status-error .scale-status-dot { background: #ef4444; border-color: rgba(0,0,0,0.35); box-shadow: 0 0 5px #ef4444aa; }
.scale-status-error .scale-icon-emoji { filter: none; opacity: 1; } .scale-status-error .scale-icon-emoji { filter: none; opacity: 1; }
@keyframes scaleStatusPulse { @keyframes scaleStatusPulse {
0%, 100% { box-shadow: 0 0 3px #f59e0b88; } 0%, 100% { box-shadow: 0 0 3px #f59e0b88; }
+3 -2
View File
@@ -12177,13 +12177,14 @@ async function _initApp() {
localStorage.removeItem('_bgBringSyncTs'); localStorage.removeItem('_bgBringSyncTs');
localStorage.setItem('_bgBringSyncReset_v1', '1'); localStorage.setItem('_bgBringSyncReset_v1', '1');
} }
syncSettingsFromDB(); syncSettingsFromDB().then(() => {
scaleInit(); // connect to smart scale gateway if configured (needs settings)
});
showPage('dashboard'); showPage('dashboard');
initInactivityWatcher(); initInactivityWatcher();
initSpesaMode(); initSpesaMode();
initScreensaverShortcuts(); initScreensaverShortcuts();
startBgShoppingRefresh(); startBgShoppingRefresh();
scaleInit(); // connect to smart scale gateway if configured
_injectKioskOverlay(); // kiosk X / refresh buttons (only when running inside Android WebView) _injectKioskOverlay(); // kiosk X / refresh buttons (only when running inside Android WebView)
// Hide preloader once the dashboard is rendered // Hide preloader once the dashboard is rendered
@@ -87,18 +87,27 @@ class SetupActivity : AppCompatActivity() {
// Scale step (BLE) // Scale step (BLE)
private lateinit var scaleQuestionCard: LinearLayout private lateinit var scaleQuestionCard: LinearLayout
private lateinit var scalePowerOnCard: LinearLayout
private lateinit var bleSetupCard: LinearLayout private lateinit var bleSetupCard: LinearLayout
private lateinit var scaleTestCard: LinearLayout
private lateinit var tvScanStatus: TextView private lateinit var tvScanStatus: TextView
private lateinit var btnScanBle: MaterialButton private lateinit var btnScanBle: MaterialButton
private lateinit var tvSelectedScale: TextView private lateinit var tvSelectedScale: TextView
private lateinit var rvScaleDevices: RecyclerView private lateinit var rvScaleDevices: RecyclerView
private lateinit var step3NextButtons: LinearLayout private lateinit var step3NextButtons: LinearLayout
private lateinit var tvTestStatus: TextView
private lateinit var tvTestWeight: TextView
private lateinit var testWeightBox: android.widget.LinearLayout
private var bleManager: BleScaleManager? = null private var bleManager: BleScaleManager? = null
private val discoveredDevices = mutableListOf<BleDeviceInfo>() private val discoveredDevices = mutableListOf<BleDeviceInfo>()
private var selectedDevice: BleDeviceInfo? = null private var selectedDevice: BleDeviceInfo? = null
private var deviceAdapter: DeviceAdapter? = null private var deviceAdapter: DeviceAdapter? = null
// Test-mode state
private var isInTestMode = false
private var testHasWeight = false
// Screensaver step // Screensaver step
private lateinit var setupSwitchScreensaver: SwitchMaterial private lateinit var setupSwitchScreensaver: SwitchMaterial
@@ -176,14 +185,15 @@ class SetupActivity : AppCompatActivity() {
override fun onDestroy() { override fun onDestroy() {
bleManager?.stopScan() bleManager?.stopScan()
bleManager?.disconnect() bleManager?.disconnect()
isInTestMode = false
discoverCancelled.set(true) discoverCancelled.set(true)
super.onDestroy() super.onDestroy()
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
// If we're on step 4 with a saved device, reflect it in the UI // If we're on step 4 with a saved device and not in test mode, reflect it in the UI
if (currentStep == 4) { if (currentStep == 4 && !isInTestMode) {
val savedName = bleManager?.getSavedDeviceName() val savedName = bleManager?.getSavedDeviceName()
if (savedName != null) { if (savedName != null) {
tvSelectedScale.text = "$savedName" tvSelectedScale.text = "$savedName"
@@ -214,12 +224,17 @@ class SetupActivity : AppCompatActivity() {
// Scale step // Scale step
scaleQuestionCard = findViewById(R.id.scaleQuestionCard) scaleQuestionCard = findViewById(R.id.scaleQuestionCard)
scalePowerOnCard = findViewById(R.id.scalePowerOnCard)
bleSetupCard = findViewById(R.id.bleSetupCard) bleSetupCard = findViewById(R.id.bleSetupCard)
scaleTestCard = findViewById(R.id.scaleTestCard)
tvScanStatus = findViewById(R.id.tvScanStatus) tvScanStatus = findViewById(R.id.tvScanStatus)
btnScanBle = findViewById(R.id.btnScanBle) btnScanBle = findViewById(R.id.btnScanBle)
tvSelectedScale = findViewById(R.id.tvSelectedScale) tvSelectedScale = findViewById(R.id.tvSelectedScale)
rvScaleDevices = findViewById(R.id.rvScaleDevices) rvScaleDevices = findViewById(R.id.rvScaleDevices)
step3NextButtons = findViewById(R.id.step3NextButtons) step3NextButtons = findViewById(R.id.step3NextButtons)
tvTestStatus = findViewById(R.id.tvTestStatus)
tvTestWeight = findViewById(R.id.tvTestWeight)
testWeightBox = findViewById(R.id.testWeightBox)
// Screensaver step // Screensaver step
setupSwitchScreensaver = findViewById(R.id.setupSwitchScreensaver) setupSwitchScreensaver = findViewById(R.id.setupSwitchScreensaver)
@@ -279,9 +294,16 @@ class SetupActivity : AppCompatActivity() {
findViewById<MaterialButton>(R.id.btnScaleYes).setOnClickListener { findViewById<MaterialButton>(R.id.btnScaleYes).setOnClickListener {
prefs.edit().putBoolean(KEY_HAS_SCALE, true).apply() prefs.edit().putBoolean(KEY_HAS_SCALE, true).apply()
scaleQuestionCard.visibility = View.GONE scaleQuestionCard.visibility = View.GONE
// Show power-on instruction first
scalePowerOnCard.visibility = View.VISIBLE
}
// "Bilancia accesa — Cerca" button
findViewById<MaterialButton>(R.id.btnPowerOnReady).setOnClickListener {
scalePowerOnCard.visibility = View.GONE
bleSetupCard.visibility = View.VISIBLE bleSetupCard.visibility = View.VISIBLE
step3NextButtons.visibility = View.VISIBLE step3NextButtons.visibility = View.VISIBLE
// Disable Next until device selected // Disable Next until device confirmed
val savedName = bleManager?.getSavedDeviceName() val savedName = bleManager?.getSavedDeviceName()
if (savedName != null) { if (savedName != null) {
tvSelectedScale.text = "$savedName" tvSelectedScale.text = "$savedName"
@@ -300,13 +322,63 @@ class SetupActivity : AppCompatActivity() {
btnScanBle.setOnClickListener { startBleScan() } btnScanBle.setOnClickListener { startBleScan() }
findViewById<MaterialButton>(R.id.btnScaleBack).setOnClickListener { findViewById<MaterialButton>(R.id.btnScaleBack).setOnClickListener {
bleManager?.stopScan() bleManager?.stopScan()
bleManager?.disconnect()
isInTestMode = false
showStep(3) showStep(3)
} }
findViewById<MaterialButton>(R.id.btnScaleNext).setOnClickListener { findViewById<MaterialButton>(R.id.btnScaleNext).setOnClickListener {
bleManager?.stopScan() bleManager?.stopScan()
bleManager?.disconnect()
showStep(5) showStep(5)
} }
// Test card buttons
findViewById<MaterialButton>(R.id.btnTestConfirm).setOnClickListener {
// User confirms weight matches → scale is good, proceed
isInTestMode = false
bleManager?.stopScan()
bleManager?.disconnect()
scaleTestCard.visibility = View.GONE
bleSetupCard.visibility = View.GONE
step3NextButtons.visibility = View.VISIBLE
val name = selectedDevice?.name ?: bleManager?.getSavedDeviceName() ?: "Bilancia"
tvSelectedScale.text = "$name"
tvSelectedScale.visibility = View.VISIBLE
findViewById<MaterialButton>(R.id.btnScaleNext).isEnabled = true
// Put scan card back (hidden) and show only nav buttons
bleSetupCard.visibility = View.GONE
}
findViewById<MaterialButton>(R.id.btnTestRetry).setOnClickListener {
// User says weight doesn't match → disconnect, go back to scan
isInTestMode = false
testHasWeight = false
bleManager?.disconnect()
selectedDevice = null
bleManager?.clearSavedDevice()
scaleTestCard.visibility = View.GONE
testWeightBox.visibility = View.GONE
bleSetupCard.visibility = View.VISIBLE
tvSelectedScale.text = ""
tvSelectedScale.visibility = View.GONE
tvScanStatus.text = "Bilancia non confermata. Riprova la scansione."
tvScanStatus.setTextColor(0xFFfbbf24.toInt())
btnScanBle.isEnabled = true
btnScanBle.text = "🔍 Cerca bilancia"
findViewById<MaterialButton>(R.id.btnScaleNext).isEnabled = false
}
findViewById<MaterialButton>(R.id.btnTestSkip).setOnClickListener {
// User skips test — trust the selection
isInTestMode = false
bleManager?.disconnect()
scaleTestCard.visibility = View.GONE
bleSetupCard.visibility = View.GONE
step3NextButtons.visibility = View.VISIBLE
val name = selectedDevice?.name ?: bleManager?.getSavedDeviceName() ?: "Bilancia"
tvSelectedScale.text = "$name"
tvSelectedScale.visibility = View.VISIBLE
findViewById<MaterialButton>(R.id.btnScaleNext).isEnabled = true
}
// ── Screensaver ─────────────────────────────────────────────────── // ── Screensaver ───────────────────────────────────────────────────
findViewById<MaterialButton>(R.id.btnScreensaverBack).setOnClickListener { showStep(4) } findViewById<MaterialButton>(R.id.btnScreensaverBack).setOnClickListener { showStep(4) }
findViewById<MaterialButton>(R.id.btnScreensaverNext).setOnClickListener { findViewById<MaterialButton>(R.id.btnScreensaverNext).setOnClickListener {
@@ -356,10 +428,15 @@ class SetupActivity : AppCompatActivity() {
// Reset scale step when entering it // Reset scale step when entering it
if (step == 4) { if (step == 4) {
isInTestMode = false
testHasWeight = false
scaleTestCard.visibility = View.GONE
testWeightBox.visibility = View.GONE
val hasScaleYes = prefs.contains(KEY_HAS_SCALE) && prefs.getBoolean(KEY_HAS_SCALE, false) val hasScaleYes = prefs.contains(KEY_HAS_SCALE) && prefs.getBoolean(KEY_HAS_SCALE, false)
if (hasScaleYes) { if (hasScaleYes) {
// Already said YES — go straight to BLE scan card // Already said YES — skip power-on card, go straight to BLE scan
scaleQuestionCard.visibility = View.GONE scaleQuestionCard.visibility = View.GONE
scalePowerOnCard.visibility = View.GONE
bleSetupCard.visibility = View.VISIBLE bleSetupCard.visibility = View.VISIBLE
step3NextButtons.visibility = View.VISIBLE step3NextButtons.visibility = View.VISIBLE
val savedName = bleManager?.getSavedDeviceName() val savedName = bleManager?.getSavedDeviceName()
@@ -374,6 +451,7 @@ class SetupActivity : AppCompatActivity() {
} }
} else { } else {
scaleQuestionCard.visibility = View.VISIBLE scaleQuestionCard.visibility = View.VISIBLE
scalePowerOnCard.visibility = View.GONE
bleSetupCard.visibility = View.GONE bleSetupCard.visibility = View.GONE
step3NextButtons.visibility = View.GONE step3NextButtons.visibility = View.GONE
} }
@@ -751,15 +829,33 @@ class SetupActivity : AppCompatActivity() {
bleManager?.saveDevice(info.device.address, info.name) bleManager?.saveDevice(info.device.address, info.name)
tvSelectedScale.text = "${info.name}" tvSelectedScale.text = "${info.name}"
tvSelectedScale.visibility = View.VISIBLE tvSelectedScale.visibility = View.VISIBLE
tvScanStatus.text = "Bilancia selezionata. Premi Avanti per continuare."
tvScanStatus.setTextColor(0xFF34d399.toInt())
btnScanBle.isEnabled = true btnScanBle.isEnabled = true
btnScanBle.text = "🔄 Scansiona di nuovo" btnScanBle.text = "🔄 Scansiona di nuovo"
findViewById<MaterialButton>(R.id.btnScaleNext).isEnabled = true // Start connection test
startScaleTest(info)
}
private fun startScaleTest(info: BleDeviceInfo) {
isInTestMode = true
testHasWeight = false
// Show test card, hide scan card
bleSetupCard.visibility = View.GONE
scaleTestCard.visibility = View.VISIBLE
testWeightBox.visibility = View.GONE
step3NextButtons.visibility = View.GONE
tvTestStatus.text = "🔗 Connessione a ${info.name}"
tvTestStatus.setTextColor(0xFF94a3b8.toInt())
tvTestWeight.text = "— g"
// Disable confirm/retry until we have data
findViewById<MaterialButton>(R.id.btnTestConfirm).isEnabled = false
findViewById<MaterialButton>(R.id.btnTestRetry).isEnabled = false
bleManager?.connect(info.device)
} }
private fun makeBleListener() = object : BleScaleListener { private fun makeBleListener() = object : BleScaleListener {
override fun onDeviceFound(info: BleDeviceInfo) { override fun onDeviceFound(info: BleDeviceInfo) {
// Only show devices that look like scales (positive score)
if (info.scaleScore <= 0) return
val existing = discoveredDevices.indexOfFirst { it.device.address == info.device.address } val existing = discoveredDevices.indexOfFirst { it.device.address == info.device.address }
if (existing >= 0) { if (existing >= 0) {
discoveredDevices[existing] = info discoveredDevices[existing] = info
@@ -769,12 +865,50 @@ class SetupActivity : AppCompatActivity() {
deviceAdapter?.notifyItemInserted(discoveredDevices.size - 1) deviceAdapter?.notifyItemInserted(discoveredDevices.size - 1)
} }
} }
override fun onConnecting(device: BluetoothDevice) {} override fun onConnecting(device: BluetoothDevice) {
override fun onConnected(deviceName: String) {} if (!isInTestMode) return
override fun onDisconnected() {} tvTestStatus.text = "🔗 Connessione in corso…"
override fun onWeightReceived(reading: WeightReading) {} tvTestStatus.setTextColor(0xFF94a3b8.toInt())
}
override fun onConnected(deviceName: String) {
if (!isInTestMode) return
tvTestStatus.text = "⚖️ Connesso! Posiziona un oggetto sulla bilancia…"
tvTestStatus.setTextColor(0xFF34d399.toInt())
testWeightBox.visibility = View.VISIBLE
findViewById<MaterialButton>(R.id.btnTestRetry).isEnabled = true
}
override fun onDisconnected() {
if (!isInTestMode) return
tvTestStatus.text = "⚠️ Connessione persa. Riprova."
tvTestStatus.setTextColor(0xFFfbbf24.toInt())
testWeightBox.visibility = View.GONE
testHasWeight = false
findViewById<MaterialButton>(R.id.btnTestConfirm).isEnabled = false
}
override fun onWeightReceived(reading: WeightReading) {
if (!isInTestMode) return
testHasWeight = true
val display = if (reading.unit == "kg")
"%.3f kg".format(reading.value)
else
"%g ${reading.unit}".format(reading.value)
tvTestWeight.text = display
testWeightBox.visibility = View.VISIBLE
tvTestStatus.text = "Peso ricevuto — coincide con quello sulla bilancia?"
tvTestStatus.setTextColor(0xFF94a3b8.toInt())
findViewById<MaterialButton>(R.id.btnTestConfirm).isEnabled = true
findViewById<MaterialButton>(R.id.btnTestRetry).isEnabled = true
}
override fun onBatteryReceived(level: Int) {} override fun onBatteryReceived(level: Int) {}
override fun onError(message: String) { override fun onError(message: String) {
if (isInTestMode) {
tvTestStatus.text = "⚠️ $message"
tvTestStatus.setTextColor(0xFFf87171.toInt())
testWeightBox.visibility = View.GONE
testHasWeight = false
findViewById<MaterialButton>(R.id.btnTestRetry).isEnabled = true
return
}
tvScanStatus.text = "⚠️ $message" tvScanStatus.text = "⚠️ $message"
tvScanStatus.setTextColor(0xFFf87171.toInt()) tvScanStatus.setTextColor(0xFFf87171.toInt())
btnScanBle.isEnabled = true btnScanBle.isEnabled = true
@@ -782,7 +916,7 @@ class SetupActivity : AppCompatActivity() {
override fun onScanStopped() { override fun onScanStopped() {
btnScanBle.isEnabled = true btnScanBle.isEnabled = true
if (discoveredDevices.isEmpty()) { if (discoveredDevices.isEmpty()) {
tvScanStatus.text = "Nessuna bilancia trovata. Assicurati che sia accesa e vicina." tvScanStatus.text = "Nessuna bilancia trovata. Assicurati che sia accesa e vicina, poi riprova."
tvScanStatus.setTextColor(0xFFfbbf24.toInt()) tvScanStatus.setTextColor(0xFFfbbf24.toInt())
} else { } else {
tvScanStatus.text = "Seleziona la tua bilancia dall'elenco." tvScanStatus.text = "Seleziona la tua bilancia dall'elenco."
@@ -807,6 +807,56 @@
android:textColor="#64748b" /> android:textColor="#64748b" />
</LinearLayout> </LinearLayout>
<!-- Power-on instruction card (shown after YES, before scan) -->
<LinearLayout
android:id="@+id/scalePowerOnCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/card_background"
android:padding="20dp"
android:layout_marginBottom="16dp"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="🔋"
android:textSize="40sp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="12dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Accendi la bilancia"
android:textColor="#f1f5f9"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="10dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Assicurati che la bilancia sia accesa e vicina al tablet, poi avvia la scansione."
android:textColor="#94a3b8"
android:textSize="14sp"
android:gravity="center"
android:lineSpacingExtra="3dp"
android:layout_marginBottom="20dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnPowerOnReady"
android:layout_width="match_parent"
android:layout_height="52dp"
android:text="✅ Bilancia accesa — Cerca"
android:textSize="15sp"
android:textAllCaps="false"
android:backgroundTint="#059669" />
</LinearLayout>
<!-- BLE scan card (shown after YES) --> <!-- BLE scan card (shown after YES) -->
<LinearLayout <LinearLayout
android:id="@+id/bleSetupCard" android:id="@+id/bleSetupCard"
@@ -858,6 +908,114 @@
</LinearLayout> </LinearLayout>
<!-- Scale test card (shown after device is selected) -->
<LinearLayout
android:id="@+id/scaleTestCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/card_background"
android:padding="20dp"
android:layout_marginBottom="16dp"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="🔗 Test connessione"
android:textColor="#f1f5f9"
android:textSize="17sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="12dp" />
<TextView
android:id="@+id/tvTestStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Connessione in corso…"
android:textColor="#94a3b8"
android:textSize="14sp"
android:gravity="center"
android:layout_marginBottom="16dp" />
<!-- Weight display -->
<LinearLayout
android:id="@+id/testWeightBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:background="#1a7c3aed"
android:padding="16dp"
android:layout_marginBottom="16dp"
android:visibility="gone">
<TextView
android:id="@+id/tvTestWeight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="— g"
android:textColor="#f1f5f9"
android:textSize="36sp"
android:textStyle="bold"
android:layout_marginBottom="4dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Il peso che vedi coincide con quello sulla bilancia?"
android:textColor="#94a3b8"
android:textSize="13sp"
android:gravity="center" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="10dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnTestRetry"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:text="❌ No, riprova"
android:textSize="13sp"
android:textAllCaps="false"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:strokeColor="#ef4444"
android:textColor="#ef4444"
android:enabled="false"
android:layout_marginEnd="8dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnTestConfirm"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:text="✅ Sì, coincide"
android:textSize="13sp"
android:textAllCaps="false"
android:backgroundTint="#059669"
android:enabled="false" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnTestSkip"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="Salta il test"
android:textSize="13sp"
android:textAllCaps="false"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:textColor="#475569" />
</LinearLayout>
<!-- Step 4 navigation (shown after YES) --> <!-- Step 4 navigation (shown after YES) -->
<LinearLayout <LinearLayout
android:id="@+id/step3NextButtons" android:id="@+id/step3NextButtons"