fix(kiosk): real-time download progress bar + ErrorReporter on failures
Problem: tapping 'Aggiorna Scale Gateway' gave no visible feedback after
the button was pressed — user could not tell if the download was
happening, stuck, or had silently failed.
Changes:
- layout: add horizontal ProgressBar (determinate) + percentage TextView
inside the wizard step-3 status card
- layout: add thin ProgressBar (4 dp) at the bottom of the update banner
(banner changed to vertical orientation to accommodate it)
- startDownloadProgressPoll(downloadId): polls DownloadManager every
500 ms, reads COLUMN_BYTES_DOWNLOADED_SO_FAR and COLUMN_TOTAL_SIZE_BYTES,
updates status card + banner with 'Download: 45% (18.2 MB / 40.5 MB)'
- setInstallUI(): new 'progress' parameter (-2 = hide, -1 = indeterminate,
0-100 = determinate) and 'progressText' for the label under the bar
— both bars updated in sync
- Status transitions now visible:
⏳ Download: 45% [====----] 18.2 MB / 40.5 MB
⏳ Installazione in corso… [~~~~] (indeterminate)
⏳ + 'Conferma nel dialog…'
✅ Installato! → bar hidden, gateway status re-checked after 3 s
❌ + error detail → bar hidden, button re-enabled as '↩ Riprova'
- All error paths (download fail, PackageInstaller exception, installer
failure status) now call ErrorReporter.report() → GitHub Issue created
automatically so failures are tracked without user intervention
- Dismiss button also cancels the progress poll + hides the bar
This commit is contained in:
@@ -41,6 +41,7 @@ import android.widget.LinearLayout
|
|||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import android.widget.ProgressBar
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@@ -79,16 +80,22 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
private lateinit var scaleStatusDetail: TextView
|
private lateinit var scaleStatusDetail: TextView
|
||||||
private lateinit var scaleQuestionLayout: LinearLayout
|
private lateinit var scaleQuestionLayout: LinearLayout
|
||||||
private lateinit var step3BottomButtons: LinearLayout
|
private lateinit var step3BottomButtons: LinearLayout
|
||||||
// Update banner (native, shown at the top over the WebView)
|
// Update banner
|
||||||
private lateinit var updateBanner: LinearLayout
|
private lateinit var updateBanner: LinearLayout
|
||||||
private lateinit var tvUpdateMessage: TextView
|
private lateinit var tvUpdateMessage: TextView
|
||||||
private lateinit var btnInstallUpdate: MaterialButton
|
private lateinit var btnInstallUpdate: MaterialButton
|
||||||
private lateinit var btnDismissUpdate: MaterialButton
|
private lateinit var btnDismissUpdate: MaterialButton
|
||||||
|
private lateinit var downloadProgressBar: ProgressBar
|
||||||
|
private lateinit var downloadProgressText: TextView
|
||||||
|
private lateinit var bannerProgressBar: ProgressBar
|
||||||
private var pendingApkDownloadUrl: String = ""
|
private var pendingApkDownloadUrl: String = ""
|
||||||
private var pendingInstallFile: java.io.File? = null
|
private var pendingInstallFile: java.io.File? = null
|
||||||
private var pendingInstallPkg: String = ""
|
private var pendingInstallPkg: String = ""
|
||||||
/** The button that triggered the current download/install — updated throughout the flow. */
|
/** The button that triggered the current download/install — updated throughout the flow. */
|
||||||
private var activeInstallBtn: MaterialButton? = null
|
private var activeInstallBtn: MaterialButton? = null
|
||||||
|
/** Handler for the 500 ms download-progress polling loop. */
|
||||||
|
private val pollHandler = Handler(Looper.getMainLooper())
|
||||||
|
private var activeDownloadId: Long = -1
|
||||||
|
|
||||||
// Triple-tap to exit
|
// Triple-tap to exit
|
||||||
private var tapCount = 0
|
private var tapCount = 0
|
||||||
@@ -175,11 +182,18 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
step3BottomButtons = findViewById(R.id.step3BottomButtons)
|
step3BottomButtons = findViewById(R.id.step3BottomButtons)
|
||||||
|
|
||||||
// Update banner
|
// Update banner
|
||||||
updateBanner = findViewById(R.id.updateBanner)
|
updateBanner = findViewById(R.id.updateBanner)
|
||||||
tvUpdateMessage = findViewById(R.id.tvUpdateMessage)
|
tvUpdateMessage = findViewById(R.id.tvUpdateMessage)
|
||||||
btnInstallUpdate = findViewById(R.id.btnInstallUpdate)
|
btnInstallUpdate = findViewById(R.id.btnInstallUpdate)
|
||||||
btnDismissUpdate = findViewById(R.id.btnDismissUpdate)
|
btnDismissUpdate = findViewById(R.id.btnDismissUpdate)
|
||||||
btnDismissUpdate.setOnClickListener { updateBanner.visibility = View.GONE }
|
downloadProgressBar = findViewById(R.id.downloadProgressBar)
|
||||||
|
downloadProgressText = findViewById(R.id.downloadProgressText)
|
||||||
|
bannerProgressBar = findViewById(R.id.bannerProgressBar)
|
||||||
|
btnDismissUpdate.setOnClickListener {
|
||||||
|
updateBanner.visibility = View.GONE
|
||||||
|
bannerProgressBar.visibility = View.GONE
|
||||||
|
pollHandler.removeCallbacksAndMessages(null)
|
||||||
|
}
|
||||||
btnInstallUpdate.setOnClickListener {
|
btnInstallUpdate.setOnClickListener {
|
||||||
activeInstallBtn = btnInstallUpdate
|
activeInstallBtn = btnInstallUpdate
|
||||||
triggerApkDownload(pendingApkDownloadUrl)
|
triggerApkDownload(pendingApkDownloadUrl)
|
||||||
@@ -520,10 +534,14 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
* @param detail Secondary detail line (status card only)
|
* @param detail Secondary detail line (status card only)
|
||||||
* @param color ARGB color for the detail text
|
* @param color ARGB color for the detail text
|
||||||
* @param btnEnabled Whether to re-enable the active button after this state
|
* @param btnEnabled Whether to re-enable the active button after this state
|
||||||
|
* @param progress 0-100 to show determinate bar; -1 = indeterminate; -2 = hide bar
|
||||||
|
* @param progressText optional text shown under the bar (e.g. "18.2 MB / 40.5 MB")
|
||||||
*/
|
*/
|
||||||
private fun setInstallUI(
|
private fun setInstallUI(
|
||||||
icon: String, title: String, detail: String, color: Int,
|
icon: String, title: String, detail: String, color: Int,
|
||||||
btnEnabled: Boolean = false
|
btnEnabled: Boolean = false,
|
||||||
|
progress: Int = -2,
|
||||||
|
progressText: String = ""
|
||||||
) = runOnUiThread {
|
) = runOnUiThread {
|
||||||
// Wizard status card (step 3)
|
// Wizard status card (step 3)
|
||||||
val statusCard = try { findViewById<LinearLayout>(R.id.scaleStatusCard) } catch (_: Exception) { null }
|
val statusCard = try { findViewById<LinearLayout>(R.id.scaleStatusCard) } catch (_: Exception) { null }
|
||||||
@@ -532,11 +550,42 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
scaleStatusText.text = title
|
scaleStatusText.text = title
|
||||||
scaleStatusDetail.text = detail
|
scaleStatusDetail.text = detail
|
||||||
scaleStatusDetail.setTextColor(color)
|
scaleStatusDetail.setTextColor(color)
|
||||||
|
when {
|
||||||
|
progress == -2 -> {
|
||||||
|
downloadProgressBar.visibility = View.GONE
|
||||||
|
downloadProgressText.visibility = View.GONE
|
||||||
|
}
|
||||||
|
progress == -1 -> {
|
||||||
|
downloadProgressBar.isIndeterminate = true
|
||||||
|
downloadProgressBar.visibility = View.VISIBLE
|
||||||
|
downloadProgressText.text = progressText
|
||||||
|
downloadProgressText.visibility = if (progressText.isEmpty()) View.GONE else View.VISIBLE
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
downloadProgressBar.isIndeterminate = false
|
||||||
|
downloadProgressBar.progress = progress
|
||||||
|
downloadProgressBar.visibility = View.VISIBLE
|
||||||
|
downloadProgressText.text = progressText
|
||||||
|
downloadProgressText.visibility = if (progressText.isEmpty()) View.GONE else View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Update banner (kiosk / gateway auto-update outside wizard)
|
// Update banner (kiosk / gateway auto-update outside wizard)
|
||||||
if (updateBanner.visibility == View.VISIBLE) {
|
if (updateBanner.visibility == View.VISIBLE) {
|
||||||
tvUpdateMessage.text = "$icon $title"
|
tvUpdateMessage.text = "$icon $title"
|
||||||
if (detail.isNotEmpty()) tvUpdateMessage.text = "${tvUpdateMessage.text}\n$detail"
|
if (detail.isNotEmpty()) tvUpdateMessage.text = "${tvUpdateMessage.text}\n$detail"
|
||||||
|
when {
|
||||||
|
progress == -2 -> bannerProgressBar.visibility = View.GONE
|
||||||
|
progress == -1 -> {
|
||||||
|
bannerProgressBar.isIndeterminate = true
|
||||||
|
bannerProgressBar.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
bannerProgressBar.isIndeterminate = false
|
||||||
|
bannerProgressBar.progress = progress
|
||||||
|
bannerProgressBar.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Button state
|
// Button state
|
||||||
val btn = activeInstallBtn
|
val btn = activeInstallBtn
|
||||||
@@ -546,6 +595,46 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polls DownloadManager every 500 ms to report actual byte-level progress
|
||||||
|
* in the status card and banner. Stops automatically when download is no
|
||||||
|
* longer RUNNING or PENDING.
|
||||||
|
*/
|
||||||
|
private fun startDownloadProgressPoll(downloadId: Long) {
|
||||||
|
activeDownloadId = downloadId
|
||||||
|
pollHandler.removeCallbacksAndMessages(null)
|
||||||
|
fun tick() {
|
||||||
|
if (activeDownloadId != downloadId) return // superseded download
|
||||||
|
val dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
val c = dm.query(DownloadManager.Query().setFilterById(downloadId))
|
||||||
|
if (!c.moveToFirst()) { c.close(); return }
|
||||||
|
val status = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))
|
||||||
|
if (status == DownloadManager.STATUS_RUNNING ||
|
||||||
|
status == DownloadManager.STATUS_PENDING) {
|
||||||
|
val dl = c.getLong(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
|
||||||
|
val tot = c.getLong(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
|
||||||
|
c.close()
|
||||||
|
val pct = if (tot > 0) (dl * 100 / tot).toInt() else 0
|
||||||
|
val dlMb = dl / 1_048_576f
|
||||||
|
val totMb = tot / 1_048_576f
|
||||||
|
val txt = if (tot > 0) "%.1f MB / %.1f MB".format(dlMb, totMb) else ""
|
||||||
|
setInstallUI(
|
||||||
|
"\u23F3",
|
||||||
|
getString(R.string.install_downloading) + if (tot > 0) " ($pct%)" else "",
|
||||||
|
txt,
|
||||||
|
0xFF94a3b8.toInt(),
|
||||||
|
btnEnabled = false,
|
||||||
|
progress = pct,
|
||||||
|
progressText = txt
|
||||||
|
)
|
||||||
|
pollHandler.postDelayed({ tick() }, 500)
|
||||||
|
} else {
|
||||||
|
c.close() // terminal state — BroadcastReceiver will handle success/failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pollHandler.post { tick() }
|
||||||
|
}
|
||||||
|
|
||||||
// ── Connection Test ───────────────────────────────────────────────────
|
// ── Connection Test ───────────────────────────────────────────────────
|
||||||
|
|
||||||
private fun testConnection() {
|
private fun testConnection() {
|
||||||
@@ -947,6 +1036,7 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
setMimeType("application/vnd.android.package-archive")
|
setMimeType("application/vnd.android.package-archive")
|
||||||
}
|
}
|
||||||
val downloadId = dm.enqueue(req)
|
val downloadId = dm.enqueue(req)
|
||||||
|
startDownloadProgressPoll(downloadId)
|
||||||
|
|
||||||
val receiver = object : BroadcastReceiver() {
|
val receiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(ctx: Context?, intent: Intent?) {
|
override fun onReceive(ctx: Context?, intent: Intent?) {
|
||||||
@@ -963,23 +1053,31 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
c.close()
|
c.close()
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
pollHandler.removeCallbacksAndMessages(null)
|
||||||
|
activeDownloadId = -1
|
||||||
setInstallUI(
|
setInstallUI(
|
||||||
"\u23F3",
|
"\u23F3",
|
||||||
getString(R.string.install_installing),
|
getString(R.string.install_installing),
|
||||||
getString(R.string.install_installing),
|
getString(R.string.install_installing),
|
||||||
0xFF94a3b8.toInt(),
|
0xFF94a3b8.toInt(),
|
||||||
btnEnabled = false
|
btnEnabled = false,
|
||||||
|
progress = -1
|
||||||
)
|
)
|
||||||
installApk(destFile)
|
installApk(destFile)
|
||||||
} else {
|
} else {
|
||||||
|
pollHandler.removeCallbacksAndMessages(null)
|
||||||
|
activeDownloadId = -1
|
||||||
setInstallUI(
|
setInstallUI(
|
||||||
"\u274C",
|
"\u274C",
|
||||||
getString(R.string.install_error_download),
|
getString(R.string.install_error_download),
|
||||||
getString(R.string.install_error_download_detail),
|
getString(R.string.install_error_download_detail),
|
||||||
0xFFf87171.toInt(),
|
0xFFf87171.toInt(),
|
||||||
btnEnabled = true
|
btnEnabled = true,
|
||||||
|
progress = -2
|
||||||
)
|
)
|
||||||
runOnUiThread { activeInstallBtn?.text = getString(R.string.install_btn_retry) }
|
runOnUiThread { activeInstallBtn?.text = getString(R.string.install_btn_retry) }
|
||||||
|
ErrorReporter.report(this@KioskActivity, "install_download_failed",
|
||||||
|
"DownloadManager returned failure for URL: $apkUrl")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1073,13 +1171,15 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
getString(R.string.install_success),
|
getString(R.string.install_success),
|
||||||
getString(R.string.install_success_detail),
|
getString(R.string.install_success_detail),
|
||||||
0xFF34d399.toInt(),
|
0xFF34d399.toInt(),
|
||||||
btnEnabled = false
|
btnEnabled = false,
|
||||||
|
progress = -2
|
||||||
)
|
)
|
||||||
// Re-check gateway status after 3 s so the wizard reflects reality
|
// Re-check gateway status after 3 s so the wizard reflects reality
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
val card = try { findViewById<LinearLayout>(R.id.scaleStatusCard) } catch (_: Exception) { null }
|
val card = try { findViewById<LinearLayout>(R.id.scaleStatusCard) } catch (_: Exception) { null }
|
||||||
if (card?.visibility == View.VISIBLE) checkGatewayStatus()
|
if (card?.visibility == View.VISIBLE) checkGatewayStatus()
|
||||||
updateBanner.visibility = View.GONE
|
updateBanner.visibility = View.GONE
|
||||||
|
bannerProgressBar.visibility = View.GONE
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
android.content.pm.PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
|
android.content.pm.PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
|
||||||
@@ -1110,9 +1210,12 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
getString(R.string.install_error_download),
|
getString(R.string.install_error_download),
|
||||||
msg,
|
msg,
|
||||||
0xFFf87171.toInt(),
|
0xFFf87171.toInt(),
|
||||||
btnEnabled = true
|
btnEnabled = true,
|
||||||
|
progress = -2
|
||||||
)
|
)
|
||||||
runOnUiThread { activeInstallBtn?.text = getString(R.string.install_btn_retry) }
|
runOnUiThread { activeInstallBtn?.text = getString(R.string.install_btn_retry) }
|
||||||
|
ErrorReporter.report(this@KioskActivity, "install_failure",
|
||||||
|
"PackageInstaller status=$status msg=$msg pkg=$targetPkg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1134,7 +1237,8 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
getString(R.string.install_installing),
|
getString(R.string.install_installing),
|
||||||
getString(R.string.install_installing),
|
getString(R.string.install_installing),
|
||||||
0xFF94a3b8.toInt(),
|
0xFF94a3b8.toInt(),
|
||||||
btnEnabled = false
|
btnEnabled = false,
|
||||||
|
progress = -1
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
setInstallUI(
|
setInstallUI(
|
||||||
@@ -1142,9 +1246,12 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
getString(R.string.install_error_download),
|
getString(R.string.install_error_download),
|
||||||
e.message ?: "",
|
e.message ?: "",
|
||||||
0xFFf87171.toInt(),
|
0xFFf87171.toInt(),
|
||||||
btnEnabled = true
|
btnEnabled = true,
|
||||||
|
progress = -2
|
||||||
)
|
)
|
||||||
runOnUiThread { activeInstallBtn?.text = getString(R.string.install_btn_retry) }
|
runOnUiThread { activeInstallBtn?.text = getString(R.string.install_btn_retry) }
|
||||||
|
ErrorReporter.report(this, "install_packager_exception",
|
||||||
|
"installWithPackageInstaller exception for $targetPkg: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1241,12 +1348,14 @@ class KioskActivity : AppCompatActivity() {
|
|||||||
getString(R.string.install_success),
|
getString(R.string.install_success),
|
||||||
getString(R.string.install_success_detail),
|
getString(R.string.install_success_detail),
|
||||||
0xFF34d399.toInt(),
|
0xFF34d399.toInt(),
|
||||||
btnEnabled = false
|
btnEnabled = false,
|
||||||
|
progress = -2
|
||||||
)
|
)
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
val card = try { findViewById<LinearLayout>(R.id.scaleStatusCard) } catch (_: Exception) { null }
|
val card = try { findViewById<LinearLayout>(R.id.scaleStatusCard) } catch (_: Exception) { null }
|
||||||
if (card?.visibility == View.VISIBLE) checkGatewayStatus()
|
if (card?.visibility == View.VISIBLE) checkGatewayStatus()
|
||||||
updateBanner.visibility = View.GONE
|
updateBanner.visibility = View.GONE
|
||||||
|
bannerProgressBar.visibility = View.GONE
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
// Not OK = install failed (possibly signature conflict).
|
// Not OK = install failed (possibly signature conflict).
|
||||||
|
|||||||
@@ -398,6 +398,31 @@
|
|||||||
android:textColor="#64748b"
|
android:textColor="#64748b"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
|
<!-- Download / install progress bar — shown only during active download -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/downloadProgressBar"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:progressTint="#7c3aed"
|
||||||
|
android:progressBackgroundTint="#334155"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="0"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/downloadProgressText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#94a3b8"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Bottom nav (Back / Launch) — hidden until user answers the question -->
|
<!-- Bottom nav (Back / Launch) — hidden until user answers the question -->
|
||||||
@@ -479,46 +504,66 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
android:orientation="horizontal"
|
android:orientation="vertical"
|
||||||
android:background="#1e293b"
|
android:background="#1e293b"
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="8dp"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:paddingBottom="10dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
<TextView
|
<!-- Banner row: message + buttons -->
|
||||||
android:id="@+id/tvUpdateMessage"
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:orientation="horizontal"
|
||||||
android:textColor="#fbbf24"
|
android:paddingStart="16dp"
|
||||||
android:textSize="13sp"
|
android:paddingEnd="8dp"
|
||||||
android:text=""
|
android:paddingTop="10dp"
|
||||||
android:drawablePadding="6dp" />
|
android:paddingBottom="10dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<TextView
|
||||||
android:id="@+id/btnInstallUpdate"
|
android:id="@+id/tvUpdateMessage"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_weight="1"
|
||||||
android:text="⬇ Scarica"
|
android:textColor="#fbbf24"
|
||||||
android:textSize="12sp"
|
android:textSize="13sp"
|
||||||
android:textColor="#1e293b"
|
android:text=""
|
||||||
android:backgroundTint="#fbbf24"
|
android:drawablePadding="6dp" />
|
||||||
style="@style/Widget.MaterialComponents.Button" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnDismissUpdate"
|
android:id="@+id/btnInstallUpdate"
|
||||||
android:layout_width="36dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="8dp"
|
||||||
android:text="✕"
|
android:text="⬇ Scarica"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="#94a3b8"
|
android:textColor="#1e293b"
|
||||||
android:backgroundTint="@android:color/transparent"
|
android:backgroundTint="#fbbf24"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton" />
|
style="@style/Widget.MaterialComponents.Button" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnDismissUpdate"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:text="✕"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#94a3b8"
|
||||||
|
android:backgroundTint="@android:color/transparent"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Thin progress bar at the bottom of the banner — visible during download/install -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/bannerProgressBar"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:progressTint="#7c3aed"
|
||||||
|
android:progressBackgroundTint="#334155"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="0"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user