rename example
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package com.bitcointxoko.gudariwallet
|
||||
|
||||
import android.Manifest
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
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 com.bitcointxoko.gudariwallet.security.EncryptedSecretStore
|
||||
import com.bitcointxoko.gudariwallet.service.WalletNotificationService
|
||||
import com.bitcointxoko.gudariwallet.ui.OnboardingScreen
|
||||
import com.bitcointxoko.gudariwallet.ui.WalletScreen
|
||||
import com.bitcointxoko.gudariwallet.ui.WalletViewModel
|
||||
import com.bitcointxoko.gudariwallet.ui.WalletViewModelFactory
|
||||
import com.bitcointxoko.gudariwallet.ui.theme.GudariWalletTheme
|
||||
import com.bitcointxoko.gudariwallet.util.NotificationHelper
|
||||
import com.bitcointxoko.gudariwallet.util.IntentUtils
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var secretStore: EncryptedSecretStore
|
||||
|
||||
private val vm: WalletViewModel by viewModels {
|
||||
WalletViewModelFactory(application)
|
||||
}
|
||||
|
||||
// Holds a paymentHash that arrived via notification tap.
|
||||
// WalletScreen observes this and navigates to the detail screen.
|
||||
// MutableState so Compose recomposes when it changes.
|
||||
private val pendingPaymentHash = mutableStateOf<String?>(null)
|
||||
|
||||
// Holds a payment URI that arrived via deep link / intent (BTCPay, external apps).
|
||||
private val pendingPaymentUri = mutableStateOf<String?>(null)
|
||||
|
||||
private val requestNotificationPermission =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { /* informational */ }
|
||||
|
||||
// Broadcasts window focus gains to any observer in the composition
|
||||
val windowFocusEvents = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus) windowFocusEvents.tryEmit(Unit)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
secretStore = EncryptedSecretStore(applicationContext)
|
||||
|
||||
// Must be first — before any notification is posted
|
||||
NotificationHelper.createChannels(applicationContext)
|
||||
|
||||
// Read hash from the intent that launched the activity (cold start from notification)
|
||||
pendingPaymentHash.value = intent.getStringExtra(NotificationHelper.EXTRA_PAYMENT_HASH)
|
||||
// Read payment URI from the intent that launched the activity (cold start from deep link)
|
||||
pendingPaymentUri.value = IntentUtils.extractPaymentUri(intent)
|
||||
|
||||
enableEdgeToEdge()
|
||||
|
||||
setContent {
|
||||
GudariWalletTheme {
|
||||
var isOnboarded by remember { mutableStateOf(secretStore.isOnboarded) }
|
||||
|
||||
if (isOnboarded) {
|
||||
LaunchedEffect(Unit) {
|
||||
WalletNotificationService.start(this@MainActivity)
|
||||
requestNotificationPermissionIfNeeded()
|
||||
promptBatteryOptimizationIfNeeded()
|
||||
}
|
||||
// Pass pendingPaymentHash so WalletScreen can consume it
|
||||
WalletScreen(
|
||||
vm = vm,
|
||||
pendingPaymentHash = pendingPaymentHash,
|
||||
pendingPaymentUri = pendingPaymentUri
|
||||
)
|
||||
} else {
|
||||
OnboardingScreen(
|
||||
secretStore = secretStore,
|
||||
onComplete = { isOnboarded = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the activity is already running and a notification is tapped
|
||||
// (FLAG_ACTIVITY_SINGLE_TOP prevents a new instance being created)
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
val hash = intent.getStringExtra(NotificationHelper.EXTRA_PAYMENT_HASH)
|
||||
if (hash != null) {
|
||||
pendingPaymentHash.value = hash
|
||||
}
|
||||
val uri = IntentUtils.extractPaymentUri(intent)
|
||||
if (uri != null) {
|
||||
pendingPaymentUri.value = uri
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ── Permission / battery helpers (unchanged) ──────────────────────────────
|
||||
|
||||
private fun requestNotificationPermissionIfNeeded() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
requestNotificationPermission.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun promptBatteryOptimizationIfNeeded() {
|
||||
val pm = getSystemService(POWER_SERVICE) as PowerManager
|
||||
if (pm.isIgnoringBatteryOptimizations(packageName)) return
|
||||
|
||||
val prefs = getSharedPreferences("gudari_ui_prefs", MODE_PRIVATE)
|
||||
if (prefs.getBoolean("battery_opt_prompted", false)) return
|
||||
prefs.edit { putBoolean("battery_opt_prompted", true) }
|
||||
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle("Enable background notifications")
|
||||
.setMessage(
|
||||
"To receive payment alerts when the app is closed, allow Gudari Wallet " +
|
||||
"to run without battery restrictions.\n\n" +
|
||||
"Tap 'Open Settings', then select Battery → Unrestricted."
|
||||
)
|
||||
.setPositiveButton("Open Settings") { _, _ -> openBatterySettings() }
|
||||
.setNegativeButton("Not now", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun openBatterySettings() {
|
||||
val appDetailsIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = "package:$packageName".toUri()
|
||||
}
|
||||
if (tryStartActivity(appDetailsIntent)) return
|
||||
tryStartActivity(Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS))
|
||||
}
|
||||
|
||||
private fun tryStartActivity(intent: Intent): Boolean {
|
||||
return try { startActivity(intent); true } catch (e: ActivityNotFoundException) { false }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user