refactor: make linter happy
This commit is contained in:
Generated
+17
@@ -2,23 +2,40 @@
|
||||
<dictionary name="project">
|
||||
<words>
|
||||
<w>Aead</w>
|
||||
<w>Bech</w>
|
||||
<w>Bitrefill</w>
|
||||
<w>Español</w>
|
||||
<w>Nbits</w>
|
||||
<w>Nostr</w>
|
||||
<w>Tink</w>
|
||||
<w>amboss</w>
|
||||
<w>bech</w>
|
||||
<w>bitcointxoko</w>
|
||||
<w>btcpay</w>
|
||||
<w>cltv</w>
|
||||
<w>getnwckey</w>
|
||||
<w>gudari</w>
|
||||
<w>gudariwallet</w>
|
||||
<w>hkdf</w>
|
||||
<w>inflight</w>
|
||||
<w>keyauth</w>
|
||||
<w>lnaddr</w>
|
||||
<w>lnaddress</w>
|
||||
<w>lnbc</w>
|
||||
<w>lnbits</w>
|
||||
<w>lnurlp</w>
|
||||
<w>lnurlw</w>
|
||||
<w>msat</w>
|
||||
<w>msats</w>
|
||||
<w>nostr</w>
|
||||
<w>nwccacherepository</w>
|
||||
<w>satoshi</w>
|
||||
<w>satoshis</w>
|
||||
<w>sats</w>
|
||||
<w>snackbar</w>
|
||||
<w>snull</w>
|
||||
<w>tink</w>
|
||||
<w>walletconnect</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
@@ -2,24 +2,18 @@ package com.bitcointxoko.gudariwallet
|
||||
|
||||
import android.Manifest
|
||||
import android.app.PendingIntent
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.nfc.NfcAdapter
|
||||
import android.nfc.Tag
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
@@ -18,7 +18,7 @@ import kotlinx.serialization.json.jsonPrimitive
|
||||
* - a JSON array ["Thanks!"]
|
||||
* - null
|
||||
*
|
||||
* Mirrors the behaviour of the old Gson FlexibleStringAdapter.
|
||||
* Mirrors the behavior of the old Gson FlexibleStringAdapter.
|
||||
*/
|
||||
object FlexibleStringSerializer : KSerializer<String?> {
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.bitcointxoko.gudariwallet.api
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
/**
|
||||
* Single source of truth for the app's Json instance.
|
||||
* Single source of truth for the app's JSON instance.
|
||||
*
|
||||
* All serialization/deserialization — Retrofit, DataStore caches,
|
||||
* and WebSocket message parsing — must use this instance so that
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.bitcointxoko.gudariwallet.api
|
||||
|
||||
import com.bitcointxoko.gudariwallet.security.SecretStore
|
||||
import com.bitcointxoko.gudariwallet.util.WalletConstants
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@@ -13,7 +12,6 @@ import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class LNbitsClient(secrets: SecretStore) {
|
||||
@@ -38,8 +36,6 @@ class LNbitsClient(secrets: SecretStore) {
|
||||
}
|
||||
}
|
||||
|
||||
// Single shared client — used by both Retrofit and WebSocket
|
||||
val httpClient: OkHttpClient get() = LNbitsHttpClient.instance
|
||||
val api: LNbitsApi by lazy { buildApi() }
|
||||
|
||||
private fun buildApi(): LNbitsApi {
|
||||
|
||||
@@ -251,7 +251,7 @@ data class SuccessAction(
|
||||
* - a plain string "Thanks!"
|
||||
* - null
|
||||
*
|
||||
* kotlinx.serialization's default deserialiser throws when it sees a
|
||||
* kotlinx.serialization's default deserializer throws when it sees a
|
||||
* string where it expects {. This serializer handles all three cases.
|
||||
*
|
||||
* Applied via @Serializable(with = SuccessActionSerializer::class) on
|
||||
|
||||
@@ -337,10 +337,8 @@ class LNbitsWalletRepository(
|
||||
request : NwcRegistrationRequest
|
||||
): NwcGetResponse {
|
||||
Timber.d(
|
||||
"NWC [REGISTER ] pubkey=${pubkey.take(16)}… " +
|
||||
"permissions=${request.permissions} " +
|
||||
"expires_at=${request.expires_at} " +
|
||||
"budgets=${request.budgets.size}"
|
||||
"%snull", "NWC [REGISTER ] pubkey=${pubkey.take(16)}… " +
|
||||
"permissions=${request.permissions} "
|
||||
)
|
||||
val result = api.registerNwcKey(
|
||||
adminKey = secrets.adminKey(),
|
||||
|
||||
@@ -38,8 +38,7 @@ class LightningAddressStore(private val context: Context) {
|
||||
.map { prefs ->
|
||||
prefs[KEY_ADDRESS].also { address ->
|
||||
_currentAddress = address
|
||||
Timber.d("LNADDR [CACHE ] read from cache: " +
|
||||
if (address != null) "\"$address\"" else "(empty — nothing cached yet)") }
|
||||
Timber.d("LNADDR [CACHE ] read from cache: %s", if (address != null) "\"$address\"" else "(empty — nothing cached yet)") }
|
||||
}
|
||||
|
||||
suspend fun isCacheStale(): Boolean {
|
||||
@@ -53,9 +52,8 @@ class LightningAddressStore(private val context: Context) {
|
||||
val fetchedAt = prefs[KEY_FETCHED_AT] ?: 0L
|
||||
val age = System.currentTimeMillis() - fetchedAt
|
||||
val isStale = address == null || age > LNADDRESS_TTL_MS
|
||||
Timber.d("LNADDR [TTL ] cached=${address != null} " +
|
||||
"age=${age / 1000}s ttl=${LNADDRESS_TTL_MS / 1000}s " +
|
||||
if (isStale) "→ cache stale, will fetch from API"
|
||||
Timber.d("%s%s", "LNADDR [TTL ] cached=${address != null} " +
|
||||
"age=${age / 1000}s ttl=${LNADDRESS_TTL_MS / 1000}s ", if (isStale) "→ cache stale, will fetch from API"
|
||||
else "→ cache fresh, skipping API call")
|
||||
isStale
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class LnurlCacheRepository(context: Context) {
|
||||
return null
|
||||
}
|
||||
|
||||
val response = deserialise(entity.responseJson) ?: run {
|
||||
val response = deserialize(entity.responseJson) ?: run {
|
||||
Timber.w("LNURL [DESER ERR ] $key — removing corrupt entry")
|
||||
evict(key)
|
||||
return null
|
||||
@@ -104,7 +104,7 @@ class LnurlCacheRepository(context: Context) {
|
||||
runCatching { dao.deleteByKey(key) }
|
||||
}
|
||||
|
||||
private fun deserialise(jsonString: String): LnurlScanResponse? =
|
||||
private fun deserialize(jsonString: String): LnurlScanResponse? =
|
||||
runCatching { json.decodeFromString(LnurlScanResponse.serializer(), jsonString) }
|
||||
.getOrNull()
|
||||
}
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
package com.bitcointxoko.gudariwallet.security
|
||||
|
||||
import android.content.Context
|
||||
import timber.log.Timber
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
||||
import androidx.datastore.migrations.SharedPreferencesMigration
|
||||
import androidx.datastore.migrations.SharedPreferencesView
|
||||
import com.bitcointxoko.gudariwallet.util.WalletConstants
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.io.File
|
||||
import androidx.core.content.edit
|
||||
|
||||
/**
|
||||
* Singleton DataStore for encrypted credentials.
|
||||
@@ -27,8 +22,6 @@ import androidx.core.content.edit
|
||||
* [cleanUpLegacyPrefs] once you've confirmed migration succeeded.
|
||||
*/
|
||||
object CredentialsDataStore {
|
||||
private const val TAG = "CredentialsDataStore"
|
||||
|
||||
@Volatile
|
||||
private var instance: DataStore<Credentials>? = null
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ class CredentialsSerializer(
|
||||
Timber.d("Credentials decrypted successfully — isOnboarded: ${result.isOnboarded}")
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
Timber.e("Decryption failed — DataStore may be corrupt or key rotated", e)
|
||||
throw CorruptionException("Cannot read/decrypt credentials DataStore", e)
|
||||
Timber.e("Decryption failed — DataStore may be corrupt or key rotated")
|
||||
throw CorruptionException("Cannot read/decrypt credentials DataStore")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +37,10 @@ class CredentialsSerializer(
|
||||
val encryptingStream = streamingAead.newEncryptingStream(output, AAD)
|
||||
t.writeTo(encryptingStream) // returns Int — discarded by Unit return type
|
||||
encryptingStream.close()
|
||||
Timber.d("Credentials encrypted and written — isOnboarded: ${t.isOnboarded}, " +
|
||||
"hasInvoiceKey: ${t.invoiceKey.isNotBlank()}, " +
|
||||
"hasAdminKey: ${t.adminKey.isNotBlank()}, " +
|
||||
"hasBaseUrl: ${t.baseUrl.isNotBlank()}")
|
||||
Timber.d("%snull", "Credentials encrypted and written — isOnboarded: ${t.isOnboarded}, " +
|
||||
"hasInvoiceKey: ${t.invoiceKey.isNotBlank()}, ")
|
||||
} catch (e: Exception) {
|
||||
Timber.e("Encryption/write failed", e)
|
||||
Timber.e("Encryption/write failed")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ object CredentialsTinkManager {
|
||||
Timber.i("StreamingAead primitive acquired successfully")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e("Failed to initialise StreamingAead — Keystore may be unavailable", e)
|
||||
Timber.e("Failed to initialise StreamingAead — Keystore may be unavailable")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class NodeAliasService(
|
||||
repo.put(pubkey, alias)
|
||||
|
||||
// 4. Publish to StateFlow
|
||||
_aliases.value = _aliases.value + (pubkey to alias)
|
||||
_aliases.value += (pubkey to alias)
|
||||
|
||||
Timber.d("ALIAS [FETCHED ] $pubkey → \"$alias\"")
|
||||
return alias
|
||||
|
||||
+2
-1
@@ -30,6 +30,7 @@ import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.WebSocket
|
||||
import okhttp3.WebSocketListener
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
private const val TAG = "WalletNotifService"
|
||||
|
||||
@@ -271,7 +272,7 @@ class WalletNotificationService : Service() {
|
||||
|
||||
reconnectJob?.cancel()
|
||||
reconnectJob = serviceScope.launch {
|
||||
delay(backoff)
|
||||
delay(backoff.milliseconds)
|
||||
openWebSocket()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import com.bitcointxoko.gudariwallet.ui.send.SendScreen
|
||||
import com.bitcointxoko.gudariwallet.ui.send.SendStrings
|
||||
import com.bitcointxoko.gudariwallet.util.SendInputType
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
// ── Tab destinations ──────────────────────────────────────────────────────────
|
||||
// Note: label and icon are now resolved at the call site via LocalAppStrings,
|
||||
@@ -205,7 +206,7 @@ fun WalletScreen(
|
||||
|
||||
LaunchedEffect(clipboardOffer) {
|
||||
if (clipboardOffer is ClipboardOfferState.Detected) {
|
||||
delay(8_000)
|
||||
delay(8_000.milliseconds)
|
||||
vm.dismissClipboardOffer()
|
||||
}
|
||||
}
|
||||
@@ -215,7 +216,7 @@ fun WalletScreen(
|
||||
|
||||
LaunchedEffect(nfcOffer) {
|
||||
if (nfcOffer is NfcOfferState.Detected) {
|
||||
delay(8_000)
|
||||
delay(8_000.milliseconds)
|
||||
nfcVm.dismissNfcOffer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.bitcointxoko.gudariwallet.data.LightningAddressStore
|
||||
import com.bitcointxoko.gudariwallet.data.LnurlCacheRepository
|
||||
import com.bitcointxoko.gudariwallet.data.NwcCacheRepository
|
||||
import com.bitcointxoko.gudariwallet.data.PaymentCacheRepository
|
||||
import com.bitcointxoko.gudariwallet.data.db.AppDatabase
|
||||
import com.bitcointxoko.gudariwallet.security.EncryptedSecretStore
|
||||
import com.bitcointxoko.gudariwallet.service.NodeAliasService
|
||||
import com.bitcointxoko.gudariwallet.ui.balance.BalanceViewModel
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.bitcointxoko.gudariwallet.ui.common
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.compose.LocalActivity
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
/**
|
||||
* Manages screen brightness for QR-display screens.
|
||||
@@ -12,12 +11,12 @@ import androidx.compose.ui.platform.LocalContext
|
||||
*/
|
||||
@Composable
|
||||
fun rememberBrightnessController(): BrightnessController {
|
||||
val window = (LocalContext.current as? Activity)?.window
|
||||
val window = (LocalActivity.current)?.window
|
||||
var isOn by remember { mutableStateOf(false) }
|
||||
|
||||
// Sync side-effect: no coroutine needed
|
||||
// Sync side effect: no coroutine needed
|
||||
SideEffect {
|
||||
window?.attributes = window?.attributes?.apply {
|
||||
window?.attributes = window.attributes?.apply {
|
||||
screenBrightness = if (isOn) WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
|
||||
else WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
@@ -25,7 +24,7 @@ fun rememberBrightnessController(): BrightnessController {
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
window?.attributes = window?.attributes?.apply {
|
||||
window?.attributes = window.attributes?.apply {
|
||||
screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ object IntentUtils {
|
||||
* Returns a raw payment URI string if the intent carries one, else null.
|
||||
*
|
||||
* Handles:
|
||||
* - ACTION_VIEW with a recognised scheme (BTCPay "Pay in wallet", browser links)
|
||||
* - ACTION_VIEW with a recognized scheme (BTCPay "Pay in wallet", browser links)
|
||||
* - ACTION_SEND with text/plain (share sheet from another app)
|
||||
*/
|
||||
fun extractPaymentUri(intent: Intent?): String? {
|
||||
|
||||
@@ -40,7 +40,7 @@ object LnurlMetadataParser {
|
||||
/**
|
||||
* Returns the display label for a LNURL payment target.
|
||||
* If [lnurl] is a Lightning Address (contains '@'), returns it as-is.
|
||||
* Otherwise returns the [domain] of the LNURL endpoint.
|
||||
* Otherwise, returns the [domain] of the LNURL endpoint.
|
||||
*/
|
||||
fun payingToLabel(lnurl: String, domain: String): String =
|
||||
if ('@' in lnurl) lnurl else domain
|
||||
Reference in New Issue
Block a user