refactor: BrightnessController and QrDisplayCard to ui/common

This commit is contained in:
2026-06-10 19:05:53 +02:00
parent e71a0ffdb9
commit 8405f33c47
4 changed files with 37 additions and 63 deletions
@@ -15,10 +15,11 @@ fun rememberBrightnessController(): BrightnessController {
val window = (LocalContext.current as? Activity)?.window
var isOn by remember { mutableStateOf(false) }
LaunchedEffect(isOn) {
// Sync side-effect: no coroutine needed
SideEffect {
window?.attributes = window?.attributes?.apply {
screenBrightness = if (isOn) 1f
else WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
screenBrightness = if (isOn) WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
else WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
}
}
@@ -30,9 +31,9 @@ fun rememberBrightnessController(): BrightnessController {
}
}
return remember(isOn) {
BrightnessController(isOn = isOn, toggle = { isOn = !isOn })
}
// No remember needed — BrightnessController is a tiny data class,
// and this composable already recomposes only when isOn changes.
return BrightnessController(isOn = isOn, toggle = { isOn = !isOn })
}
data class BrightnessController(
@@ -1,4 +1,4 @@
package com.bitcointxoko.gudariwallet.ui.receive
package com.bitcointxoko.gudariwallet.ui.common
import android.content.ClipData
import android.graphics.Bitmap
@@ -1,10 +1,7 @@
package com.bitcointxoko.gudariwallet.ui.nwc
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.view.WindowManager
import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@@ -13,18 +10,12 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import com.bitcointxoko.gudariwallet.ui.common.rememberBrightnessController
import com.bitcointxoko.gudariwallet.ui.receive.QrDisplayCard
import com.bitcointxoko.gudariwallet.ui.common.QrDisplayCard
@Composable
internal fun NwcPairingUrlDialog(
@@ -1,7 +1,5 @@
package com.bitcointxoko.gudariwallet.ui.receive
import android.app.Activity
import android.view.WindowManager
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -58,14 +56,13 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitcointxoko.gudariwallet.LocalAppStrings
import com.bitcointxoko.gudariwallet.ui.ReceiveState
import com.bitcointxoko.gudariwallet.ui.SendState
import com.bitcointxoko.gudariwallet.ui.WalletViewModel
import com.bitcointxoko.gudariwallet.ui.common.QrDisplayCard
import com.bitcointxoko.gudariwallet.ui.common.rememberBrightnessController
import com.bitcointxoko.gudariwallet.ui.components.UnitWheelPicker
import com.bitcointxoko.gudariwallet.ui.nfc.NfcViewModel
import com.bitcointxoko.gudariwallet.util.buildUpTaps
import com.bitcointxoko.gudariwallet.util.doubleTap
import com.bitcointxoko.gudariwallet.util.fiatLabel
import com.bitcointxoko.gudariwallet.util.heavyClick
import kotlinx.coroutines.delay
@Composable
@@ -74,32 +71,17 @@ fun ReceiveScreen(
nfcVm : NfcViewModel,
onNavigateToPaymentDetail: (checkingId: String) -> Unit
) {
val strings = LocalAppStrings.current
val strings = LocalAppStrings.current
val context = LocalContext.current
val brightness = rememberBrightnessController()
var showAddress by remember { mutableStateOf(false) }
val receiveState by vm.receiveState.collectAsStateWithLifecycle()
val lightningAddress by vm.lightningAddress.collectAsStateWithLifecycle()
val fiatRate by vm.fiatSatsPerUnit.collectAsStateWithLifecycle()
val fiatCurrency by vm.selectedCurrency.collectAsStateWithLifecycle()
val context = LocalContext.current
val window = (context as Activity).window
val originalBrightness = remember { window.attributes.screenBrightness }
var brightnessOn by remember { mutableStateOf(false) }
var showAddress by remember { mutableStateOf(false) }
val onToggleBrightness = {
val lp = window.attributes
lp.screenBrightness = if (!brightnessOn)
WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
else originalBrightness
window.attributes = lp
brightnessOn = !brightnessOn
}
DisposableEffect(Unit) {
onDispose {
val lp = window.attributes
lp.screenBrightness = originalBrightness
window.attributes = lp
nfcVm.stopEmulating()
vm.resetReceiveState()
}
@@ -141,8 +123,8 @@ fun ReceiveScreen(
lightningAddress = lightningAddress,
showAddress = showAddress,
onToggleAddress = { showAddress = !showAddress },
brightnessOn = brightnessOn,
onToggleBrightness = onToggleBrightness,
brightnessOn = brightness.isOn,
onToggleBrightness = brightness.toggle,
isLoading = receiveState is ReceiveState.AwaitingInvoice,
onCreateInvoice = { amountSats, memo ->
vm.createInvoice(
@@ -216,8 +198,8 @@ fun ReceiveScreen(
state = receiveState as ReceiveState.InvoiceReady,
fiatRate = fiatRate,
fiatCurrency = fiatCurrency,
brightnessOn = brightnessOn,
onToggleBrightness = onToggleBrightness,
brightnessOn = brightness.isOn,
onToggleBrightness = brightness.toggle,
nfcVm = nfcVm,
onReset = { vm.resetReceiveState() }
)
@@ -438,12 +420,12 @@ private fun ReceiveIdleContent(
Spacer(Modifier.height(12.dp))
QrDisplayCard(
content = lightningAddress,
content = lightningAddress,
contentDescription = strings.lightningAddressQrCode, // ← "Lightning address QR code"
clipLabel = strings.lightningAddressLabel, // ← "Lightning Address"
shareTitle = strings.shareLightningAddress, // ← "Share Lightning Address"
textToCopy = lightningAddress,
brightnessOn = brightnessOn,
clipLabel = strings.lightningAddressLabel, // ← "Lightning Address"
shareTitle = strings.shareLightningAddress, // ← "Share Lightning Address"
textToCopy = lightningAddress,
brightnessOn = brightnessOn,
onToggleBrightness = onToggleBrightness
)
}
@@ -512,7 +494,7 @@ private fun AmountStepContent(
val number = amountText.trim().toDoubleOrNull() ?: return@remember null
when (activeUnit) {
AmountUnit.SATS -> fiatLabel(number.toLong(), fiatRate, fiatCurrency)
AmountUnit.FIAT -> "${(number * fiatRate!!).toLong()} sats"
AmountUnit.FIAT -> "${(number * fiatRate).toLong()} sats"
}
}
@@ -560,7 +542,7 @@ private fun AmountStepContent(
)
UnitWheelPicker(
units = if (showFiatToggle) listOf(strings.sats, fiatCurrency!!) else listOf(strings.sats),
units = if (showFiatToggle) listOf(strings.sats, fiatCurrency) else listOf(strings.sats),
selectedIndex = if (activeUnit == AmountUnit.SATS) 0 else 1,
onIndexSelected = { newIndex ->
val newUnit = if (newIndex == 0) AmountUnit.SATS else AmountUnit.FIAT
@@ -682,23 +664,23 @@ private fun ReceiveInvoiceContent(
}
QrDisplayCard(
content = state.bolt11.uppercase(),
content = state.bolt11.uppercase(),
contentDescription = strings.lightningInvoiceQrCode, // ← "Lightning invoice QR code"
clipLabel = strings.invoiceLabel, // ← "Invoice"
shareTitle = strings.shareInvoice, // ← "Share Invoice"
textToCopy = state.bolt11,
brightnessOn = brightnessOn,
clipLabel = strings.invoiceLabel, // ← "Invoice"
shareTitle = strings.shareInvoice, // ← "Share Invoice"
textToCopy = state.bolt11,
brightnessOn = brightnessOn,
onToggleBrightness = onToggleBrightness,
isNfcEmulating = isEmulating,
onToggleNfc = {
isNfcEmulating = isEmulating,
onToggleNfc = {
if (isEmulating) nfcVm.stopEmulating()
else nfcVm.startEmulating("lightning:${state.bolt11}")
else nfcVm.startEmulating("lightning:${state.bolt11}")
},
nfcEnabled = !isExpired,
modifier = Modifier
nfcEnabled = !isExpired,
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
qrModifier = Modifier
qrModifier = Modifier
.fillMaxWidth()
.weight(1f)
)