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:
@@ -87,18 +87,27 @@ class SetupActivity : AppCompatActivity() {
|
||||
|
||||
// Scale step (BLE)
|
||||
private lateinit var scaleQuestionCard: LinearLayout
|
||||
private lateinit var scalePowerOnCard: LinearLayout
|
||||
private lateinit var bleSetupCard: LinearLayout
|
||||
private lateinit var scaleTestCard: LinearLayout
|
||||
private lateinit var tvScanStatus: TextView
|
||||
private lateinit var btnScanBle: MaterialButton
|
||||
private lateinit var tvSelectedScale: TextView
|
||||
private lateinit var rvScaleDevices: RecyclerView
|
||||
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 val discoveredDevices = mutableListOf<BleDeviceInfo>()
|
||||
private var selectedDevice: BleDeviceInfo? = null
|
||||
private var deviceAdapter: DeviceAdapter? = null
|
||||
|
||||
// Test-mode state
|
||||
private var isInTestMode = false
|
||||
private var testHasWeight = false
|
||||
|
||||
// Screensaver step
|
||||
private lateinit var setupSwitchScreensaver: SwitchMaterial
|
||||
|
||||
@@ -176,14 +185,15 @@ class SetupActivity : AppCompatActivity() {
|
||||
override fun onDestroy() {
|
||||
bleManager?.stopScan()
|
||||
bleManager?.disconnect()
|
||||
isInTestMode = false
|
||||
discoverCancelled.set(true)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// If we're on step 4 with a saved device, reflect it in the UI
|
||||
if (currentStep == 4) {
|
||||
// If we're on step 4 with a saved device and not in test mode, reflect it in the UI
|
||||
if (currentStep == 4 && !isInTestMode) {
|
||||
val savedName = bleManager?.getSavedDeviceName()
|
||||
if (savedName != null) {
|
||||
tvSelectedScale.text = "✅ $savedName"
|
||||
@@ -214,12 +224,17 @@ class SetupActivity : AppCompatActivity() {
|
||||
|
||||
// Scale step
|
||||
scaleQuestionCard = findViewById(R.id.scaleQuestionCard)
|
||||
scalePowerOnCard = findViewById(R.id.scalePowerOnCard)
|
||||
bleSetupCard = findViewById(R.id.bleSetupCard)
|
||||
scaleTestCard = findViewById(R.id.scaleTestCard)
|
||||
tvScanStatus = findViewById(R.id.tvScanStatus)
|
||||
btnScanBle = findViewById(R.id.btnScanBle)
|
||||
tvSelectedScale = findViewById(R.id.tvSelectedScale)
|
||||
rvScaleDevices = findViewById(R.id.rvScaleDevices)
|
||||
step3NextButtons = findViewById(R.id.step3NextButtons)
|
||||
tvTestStatus = findViewById(R.id.tvTestStatus)
|
||||
tvTestWeight = findViewById(R.id.tvTestWeight)
|
||||
testWeightBox = findViewById(R.id.testWeightBox)
|
||||
|
||||
// Screensaver step
|
||||
setupSwitchScreensaver = findViewById(R.id.setupSwitchScreensaver)
|
||||
@@ -279,9 +294,16 @@ class SetupActivity : AppCompatActivity() {
|
||||
findViewById<MaterialButton>(R.id.btnScaleYes).setOnClickListener {
|
||||
prefs.edit().putBoolean(KEY_HAS_SCALE, true).apply()
|
||||
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
|
||||
step3NextButtons.visibility = View.VISIBLE
|
||||
// Disable Next until device selected
|
||||
// Disable Next until device confirmed
|
||||
val savedName = bleManager?.getSavedDeviceName()
|
||||
if (savedName != null) {
|
||||
tvSelectedScale.text = "✅ $savedName"
|
||||
@@ -300,13 +322,63 @@ class SetupActivity : AppCompatActivity() {
|
||||
btnScanBle.setOnClickListener { startBleScan() }
|
||||
findViewById<MaterialButton>(R.id.btnScaleBack).setOnClickListener {
|
||||
bleManager?.stopScan()
|
||||
bleManager?.disconnect()
|
||||
isInTestMode = false
|
||||
showStep(3)
|
||||
}
|
||||
findViewById<MaterialButton>(R.id.btnScaleNext).setOnClickListener {
|
||||
bleManager?.stopScan()
|
||||
bleManager?.disconnect()
|
||||
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 ───────────────────────────────────────────────────
|
||||
findViewById<MaterialButton>(R.id.btnScreensaverBack).setOnClickListener { showStep(4) }
|
||||
findViewById<MaterialButton>(R.id.btnScreensaverNext).setOnClickListener {
|
||||
@@ -356,10 +428,15 @@ class SetupActivity : AppCompatActivity() {
|
||||
|
||||
// Reset scale step when entering it
|
||||
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)
|
||||
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
|
||||
scalePowerOnCard.visibility = View.GONE
|
||||
bleSetupCard.visibility = View.VISIBLE
|
||||
step3NextButtons.visibility = View.VISIBLE
|
||||
val savedName = bleManager?.getSavedDeviceName()
|
||||
@@ -374,6 +451,7 @@ class SetupActivity : AppCompatActivity() {
|
||||
}
|
||||
} else {
|
||||
scaleQuestionCard.visibility = View.VISIBLE
|
||||
scalePowerOnCard.visibility = View.GONE
|
||||
bleSetupCard.visibility = View.GONE
|
||||
step3NextButtons.visibility = View.GONE
|
||||
}
|
||||
@@ -751,15 +829,33 @@ class SetupActivity : AppCompatActivity() {
|
||||
bleManager?.saveDevice(info.device.address, info.name)
|
||||
tvSelectedScale.text = "✅ ${info.name}"
|
||||
tvSelectedScale.visibility = View.VISIBLE
|
||||
tvScanStatus.text = "Bilancia selezionata. Premi Avanti per continuare."
|
||||
tvScanStatus.setTextColor(0xFF34d399.toInt())
|
||||
btnScanBle.isEnabled = true
|
||||
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 {
|
||||
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 }
|
||||
if (existing >= 0) {
|
||||
discoveredDevices[existing] = info
|
||||
@@ -769,12 +865,50 @@ class SetupActivity : AppCompatActivity() {
|
||||
deviceAdapter?.notifyItemInserted(discoveredDevices.size - 1)
|
||||
}
|
||||
}
|
||||
override fun onConnecting(device: BluetoothDevice) {}
|
||||
override fun onConnected(deviceName: String) {}
|
||||
override fun onDisconnected() {}
|
||||
override fun onWeightReceived(reading: WeightReading) {}
|
||||
override fun onConnecting(device: BluetoothDevice) {
|
||||
if (!isInTestMode) return
|
||||
tvTestStatus.text = "🔗 Connessione in corso…"
|
||||
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 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.setTextColor(0xFFf87171.toInt())
|
||||
btnScanBle.isEnabled = true
|
||||
@@ -782,7 +916,7 @@ class SetupActivity : AppCompatActivity() {
|
||||
override fun onScanStopped() {
|
||||
btnScanBle.isEnabled = true
|
||||
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())
|
||||
} else {
|
||||
tvScanStatus.text = "Seleziona la tua bilancia dall'elenco."
|
||||
|
||||
@@ -807,6 +807,56 @@
|
||||
android:textColor="#64748b" />
|
||||
</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) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/bleSetupCard"
|
||||
@@ -858,6 +908,114 @@
|
||||
|
||||
</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) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/step3NextButtons"
|
||||
|
||||
Reference in New Issue
Block a user