refactor: delete unused files
This commit is contained in:
@@ -1,245 +0,0 @@
|
||||
package com.bitcointxoko.gudariwallet.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Notifications
|
||||
import androidx.compose.material.icons.filled.NotificationsOff
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
// ─── Permission state model ───────────────────────────────────────────────────
|
||||
|
||||
sealed class NotificationPermissionState {
|
||||
data object NeverAsked : NotificationPermissionState()
|
||||
data object Rationale : NotificationPermissionState() // asked once, denied
|
||||
data object PermanentlyDenied: NotificationPermissionState() // "don't ask again"
|
||||
data object Granted : NotificationPermissionState()
|
||||
}
|
||||
|
||||
// ─── Prefs helper ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Persists a flag so we can distinguish between:
|
||||
* - "never asked" → show the first-time request screen
|
||||
* - "asked and denied" → show rationale
|
||||
* - "permanently denied"→ send user to system settings
|
||||
*/
|
||||
object PermissionPrefs {
|
||||
private const val PREFS_NAME = "lnbits_prefs"
|
||||
private const val KEY = "notification_permission_requested"
|
||||
|
||||
fun hasRequestedBefore(context: Context): Boolean =
|
||||
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
.getBoolean(KEY, false)
|
||||
|
||||
fun markRequested(context: Context) =
|
||||
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
.edit().putBoolean(KEY, true).apply()
|
||||
}
|
||||
|
||||
// ─── Main composable ──────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Handles the full POST_NOTIFICATIONS runtime permission flow.
|
||||
*
|
||||
* On Android 12 and below this permission doesn't exist — we skip straight
|
||||
* to onPermissionGranted since notifications are always allowed.
|
||||
*
|
||||
* @param hasRequestedBefore Read from PermissionPrefs — distinguishes
|
||||
* "never asked" from "permanently denied"
|
||||
* @param onPermissionGranted Called when permission is granted
|
||||
* @param onPermissionDenied Called when user skips or permanently denies
|
||||
* @param onRequestedFirstTime Called after the first system prompt fires —
|
||||
* persists the flag via PermissionPrefs
|
||||
*/
|
||||
@Composable
|
||||
fun NotificationPermissionScreen(
|
||||
hasRequestedBefore: Boolean,
|
||||
onPermissionGranted: () -> Unit,
|
||||
onPermissionDenied: () -> Unit,
|
||||
onRequestedFirstTime: () -> Unit
|
||||
) {
|
||||
// Android 12 and below — POST_NOTIFICATIONS doesn't exist, skip entirely
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
LaunchedEffect(Unit) { onPermissionGranted() }
|
||||
return
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
// Tracks whether the system already granted the permission
|
||||
// (e.g. user granted it in a previous session)
|
||||
var permissionState by remember {
|
||||
mutableStateOf<NotificationPermissionState>(
|
||||
when {
|
||||
!hasRequestedBefore -> NotificationPermissionState.NeverAsked
|
||||
else -> NotificationPermissionState.Rationale
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// The system permission launcher
|
||||
val launcher = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { granted ->
|
||||
permissionState = if (granted) {
|
||||
NotificationPermissionState.Granted
|
||||
} else {
|
||||
// If we've already asked before and they denied again → permanent denial
|
||||
if (hasRequestedBefore) NotificationPermissionState.PermanentlyDenied
|
||||
else NotificationPermissionState.Rationale
|
||||
}
|
||||
onRequestedFirstTime()
|
||||
}
|
||||
|
||||
// React to state changes
|
||||
LaunchedEffect(permissionState) {
|
||||
when (permissionState) {
|
||||
is NotificationPermissionState.Granted -> onPermissionGranted()
|
||||
else -> { /* handled by UI below */ }
|
||||
}
|
||||
}
|
||||
|
||||
// ── UI ────────────────────────────────────────────────────────────────────
|
||||
when (permissionState) {
|
||||
|
||||
is NotificationPermissionState.NeverAsked,
|
||||
is NotificationPermissionState.Rationale -> {
|
||||
PermissionRequestCard(
|
||||
onAllow = {
|
||||
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
},
|
||||
onSkip = onPermissionDenied
|
||||
)
|
||||
}
|
||||
|
||||
is NotificationPermissionState.PermanentlyDenied -> {
|
||||
PermanentlyDeniedCard(
|
||||
onOpenSettings = {
|
||||
// Send user to the app's system notification settings
|
||||
context.startActivity(
|
||||
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", context.packageName, null)
|
||||
}
|
||||
)
|
||||
},
|
||||
onSkip = onPermissionDenied
|
||||
)
|
||||
}
|
||||
|
||||
is NotificationPermissionState.Granted -> {
|
||||
// LaunchedEffect above handles this — show nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Sub-composables ──────────────────────────────────────────────────────────
|
||||
|
||||
@Composable
|
||||
private fun PermissionRequestCard(
|
||||
onAllow: () -> Unit,
|
||||
onSkip: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(32.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Notifications,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(72.dp),
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
Text(
|
||||
text = "Stay notified of payments",
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
Text(
|
||||
text = "Allow notifications so you know the moment a Lightning payment arrives, even when the app is in the background.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(Modifier.height(40.dp))
|
||||
Button(
|
||||
onClick = onAllow,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Allow Notifications")
|
||||
}
|
||||
Spacer(Modifier.height(12.dp))
|
||||
TextButton(
|
||||
onClick = onSkip,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Not Now")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PermanentlyDeniedCard(
|
||||
onOpenSettings: () -> Unit,
|
||||
onSkip: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(32.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.NotificationsOff,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(72.dp),
|
||||
tint = MaterialTheme.colorScheme.error
|
||||
)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
Text(
|
||||
text = "Notifications are blocked",
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
Text(
|
||||
text = "You've permanently denied notifications. To receive payment alerts, enable them in system settings.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(Modifier.height(40.dp))
|
||||
Button(
|
||||
onClick = onOpenSettings,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Open Settings")
|
||||
}
|
||||
Spacer(Modifier.height(12.dp))
|
||||
TextButton(
|
||||
onClick = onSkip,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Skip")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package com.bitcointxoko.gudariwallet.ui
|
||||
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Shown when an invoice has been paid.
|
||||
* Displays a pulsing checkmark, the amount received, and the memo.
|
||||
*
|
||||
* @param amountSats Amount received in satoshis
|
||||
* @param memo Invoice memo
|
||||
* @param onDone Called when the user taps "Done" — navigates back to Home
|
||||
* @param onReceiveMore Called when the user taps "Receive More" — resets the screen
|
||||
*/
|
||||
@Composable
|
||||
fun PaymentSuccessScreen(
|
||||
amountSats: Long,
|
||||
memo: String,
|
||||
onDone: () -> Unit,
|
||||
onReceiveMore: () -> Unit
|
||||
) {
|
||||
// Pulsing scale animation on the checkmark icon
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "pulse")
|
||||
val scale by infiniteTransition.animateFloat(
|
||||
initialValue = 1f,
|
||||
targetValue = 1.08f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(durationMillis = 700, easing = EaseInOut),
|
||||
repeatMode = RepeatMode.Reverse
|
||||
),
|
||||
label = "checkScale"
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(32.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// ── Animated checkmark ────────────────────────────────────────────
|
||||
Icon(
|
||||
imageVector = Icons.Default.CheckCircle,
|
||||
contentDescription = "Payment received",
|
||||
tint = MaterialTheme.colorScheme.tertiary, // green role
|
||||
modifier = Modifier
|
||||
.size(96.dp)
|
||||
.scale(scale)
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(32.dp))
|
||||
|
||||
// ── Title ─────────────────────────────────────────────────────────
|
||||
Text(
|
||||
text = "Payment Received!",
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
// ── Amount ────────────────────────────────────────────────────────
|
||||
Text(
|
||||
text = "+$amountSats sats",
|
||||
style = MaterialTheme.typography.displaySmall,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
// ── Memo ──────────────────────────────────────────────────────────
|
||||
if (memo.isNotBlank()) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
text = memo,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(48.dp))
|
||||
|
||||
// ── Actions ───────────────────────────────────────────────────────
|
||||
Button(
|
||||
onClick = onDone,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Done")
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
OutlinedButton(
|
||||
onClick = onReceiveMore,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Receive More")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user