refactor: extract BrightnessUtils, use snackbar instead of toast

This commit is contained in:
2026-06-10 18:18:14 +02:00
parent 9ba408e157
commit e5f8156ecf
3 changed files with 68 additions and 41 deletions
@@ -0,0 +1,41 @@
package com.bitcointxoko.gudariwallet.ui.common
import android.app.Activity
import android.view.WindowManager
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
/**
* Manages screen brightness for QR-display screens.
* Returns a [BrightnessController] with [isOn] state and a [toggle] callback.
* Restores system brightness unconditionally when it leaves composition.
*/
@Composable
fun rememberBrightnessController(): BrightnessController {
val window = (LocalContext.current as? Activity)?.window
var isOn by remember { mutableStateOf(false) }
LaunchedEffect(isOn) {
window?.attributes = window?.attributes?.apply {
screenBrightness = if (isOn) 1f
else WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
}
DisposableEffect(Unit) {
onDispose {
window?.attributes = window?.attributes?.apply {
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
}
}
return remember(isOn) {
BrightnessController(isOn = isOn, toggle = { isOn = !isOn })
}
}
data class BrightnessController(
val isOn : Boolean,
val toggle : () -> Unit
)
@@ -23,35 +23,19 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri import androidx.core.net.toUri
import com.bitcointxoko.gudariwallet.ui.common.rememberBrightnessController
import com.bitcointxoko.gudariwallet.ui.receive.QrDisplayCard import com.bitcointxoko.gudariwallet.ui.receive.QrDisplayCard
@Composable @Composable
internal fun NwcPairingUrlDialog( internal fun NwcPairingUrlDialog(
url : String, url : String,
onDismiss : () -> Unit onDismiss : () -> Unit,
onNoAppFound : () -> Unit
) { ) {
// Brightness state lives here so the dialog owns the screen-brightness side-effect // Brightness state lives here so the dialog owns the screen-brightness side-effect
var brightnessOn by remember { mutableStateOf(false) } val brightness = rememberBrightnessController()
val window = (LocalContext.current as? Activity)?.window
val context = LocalContext.current val context = LocalContext.current
// Boost / restore screen brightness when the toggle changes
LaunchedEffect(brightnessOn) {
window?.attributes = window.attributes?.apply {
screenBrightness = if (brightnessOn) 1f
else WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
}
// Restore brightness unconditionally when the dialog leaves composition
DisposableEffect(Unit) {
onDispose {
window?.attributes = window.attributes?.apply {
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
}
}
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text("Connection created") }, title = { Text("Connection created") },
@@ -63,31 +47,24 @@ internal fun NwcPairingUrlDialog(
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
QrDisplayCard( QrDisplayCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
content = url, content = url,
contentDescription = "NWC pairing QR code", contentDescription = "NWC pairing QR code",
clipLabel = "NWC connection string", clipLabel = "NWC connection string",
shareTitle = "Share NWC connection string", shareTitle = "Share NWC connection string",
textToCopy = url, textToCopy = url,
brightnessOn = brightnessOn, brightnessOn = brightness.isOn,
onToggleBrightness = { brightnessOn = !brightnessOn }, onToggleBrightness = brightness.toggle,
// No NFC for a one-shot pairing string isNfcEmulating = null,
isNfcEmulating = null, qrModifier = Modifier.fillMaxWidth(),
qrModifier = Modifier.fillMaxWidth(), onOpenUri = {
onOpenUri = {
val intent = Intent(Intent.ACTION_VIEW, url.toUri()) val intent = Intent(Intent.ACTION_VIEW, url.toUri())
try { try {
context.startActivity( context.startActivity(
Intent.createChooser(intent, "Open in app") Intent.createChooser(intent, "Open in app")
) )
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
// No app installed that handles nostr+walletconnect:// onNoAppFound() // #17: no Toast — caller handles it
// Show a snackbar / toast as appropriate for your app
Toast.makeText(
context,
"No compatible app found", // "No compatible app found"
Toast.LENGTH_SHORT
).show()
} }
} }
) )
@@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -27,6 +28,8 @@ fun NwcScreen(
val pairingUrl by viewModel.pairingUrl.collectAsStateWithLifecycle() val pairingUrl by viewModel.pairingUrl.collectAsStateWithLifecycle()
val showAddSheet by viewModel.showAddSheet.collectAsStateWithLifecycle() val showAddSheet by viewModel.showAddSheet.collectAsStateWithLifecycle()
val pendingDeletePubkey by viewModel.pendingDeletePubkey.collectAsStateWithLifecycle() val pendingDeletePubkey by viewModel.pendingDeletePubkey.collectAsStateWithLifecycle()
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
// ── Shared refresh lambda (item #13) ────────────────────────────────────── // ── Shared refresh lambda (item #13) ──────────────────────────────────────
val refresh = { viewModel.loadConnections(includeExpired = true) } val refresh = { viewModel.loadConnections(includeExpired = true) }
@@ -46,7 +49,8 @@ fun NwcScreen(
FloatingActionButton(onClick = { viewModel.openAddSheet() }) { FloatingActionButton(onClick = { viewModel.openAddSheet() }) {
Icon(Icons.Default.Add, contentDescription = "Add connection") Icon(Icons.Default.Add, contentDescription = "Add connection")
} }
} },
snackbarHost = { SnackbarHost(snackbarHostState) }
) { innerPadding -> ) { innerPadding ->
val isRefreshing = uiState is NwcUiState.Loading val isRefreshing = uiState is NwcUiState.Loading
@@ -127,7 +131,12 @@ fun NwcScreen(
pairingUrl?.let { url -> pairingUrl?.let { url ->
NwcPairingUrlDialog( NwcPairingUrlDialog(
url = url, url = url,
onDismiss = { viewModel.clearPairingUrl() } onDismiss = { viewModel.clearPairingUrl() },
onNoAppFound = {
scope.launch {
snackbarHostState.showSnackbar("No compatible app found")
}
}
) )
} }