Update to make use of lightning-kmp-appp

This commit is contained in:
Kgothatso Ngako
2026-08-02 20:43:30 +02:00
parent e9510c4ea5
commit 2f06485ec5
11 changed files with 66 additions and 40 deletions

View File

@@ -7,13 +7,14 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.navigation.compose.rememberNavController
import fr.acinq.phoenix.NFCActivity
import press.mantra.compose.PlatformContext
import press.mantra.compose.MantraApp
import press.mantra.compose.MantraGlobal
import fr.acinq.phoenix.PhoenixGlobal
import fr.acinq.phoenix.android.services.HceService
class MainActivity : ComponentActivity() {
class MainActivity : ComponentActivity(), NFCActivity {
private var nfcAdapter: NfcAdapter? = null
@@ -41,11 +42,11 @@ class MainActivity : ComponentActivity() {
}
}
fun stopHceService() {
override fun stopHceService() {
stopService(Intent(this@MainActivity, HceService::class.java))
}
fun stopNfcReader() {
override fun stopNfcReader() {
if (com.machankura.compose.ui.composable.widgets.nfc.NfcStateRepository.isReading()) {
com.machankura.compose.ui.composable.widgets.nfc.NfcStateRepository.updateState(
com.machankura.compose.ui.composable.widgets.nfc.NfcState.Inactive)

View File

@@ -7,22 +7,31 @@ import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import fr.acinq.phoenix.PhoenixGlobal
import fr.acinq.phoenix.android.BusinessManager
import fr.acinq.phoenix.android.LightningApplication
import fr.acinq.phoenix.utils.PlatformContext
import fr.acinq.phoenix.utils.preferences.GlobalPrefs
/** This datastore persists preferences across node ids. */
val Context.globalPrefs: DataStore<Preferences> by preferencesDataStore(name = "globalprefs")
class MantraApplication: Application() {
lateinit var globalPrefs: GlobalPrefs
lateinit var phoenixGlobal: PhoenixGlobal
class MantraApplication: Application(), LightningApplication {
private lateinit var globalPrefs: GlobalPrefs
private lateinit var phoenixGlobal: PhoenixGlobal
override fun onCreate() {
super.onCreate()
phoenixGlobal = PhoenixGlobal(PlatformContext(applicationContext))
globalPrefs = GlobalPrefs(applicationContext.globalPrefs)
BusinessManager.initialize(applicationContext)
BusinessManager.initialize(this)
}
override fun getGlobalPrefs(): GlobalPrefs {
return globalPrefs
}
override fun getPhoenixGlobal(): PhoenixGlobal {
return phoenixGlobal
}
}

View File

@@ -24,10 +24,10 @@ actual fun schedulePlatformLogic(phoenixGlobal: PhoenixGlobal) {
}
actual fun getShowIntroFlow(phoenixGlobal: PhoenixGlobal): Flow<Boolean> {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as MantraApplication
return machankuraApplication.globalPrefs.getShowIntro
return machankuraApplication.getGlobalPrefs().getShowIntro
}
actual fun getGlobalPrefs(phoenixGlobal: PhoenixGlobal): GlobalPrefs {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as MantraApplication
return machankuraApplication.globalPrefs
return machankuraApplication.getGlobalPrefs()
}

View File

@@ -36,12 +36,12 @@ actual fun loadAndDecryptSeed(phoenixGlobal: PhoenixGlobal): DecryptSeedResult {
actual fun getAvailableWalletsMeta(phoenixGlobal: PhoenixGlobal): Flow<Map<WalletId, UserWalletMetadata>> {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as MantraApplication
return machankuraApplication.globalPrefs.getAvailableWalletsMeta
return machankuraApplication.getGlobalPrefs().getAvailableWalletsMeta
}
actual suspend fun saveAvailableWalletMeta(phoenixGlobal: PhoenixGlobal, metadata: UserWalletMetadata) {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as MantraApplication
machankuraApplication.globalPrefs.saveAvailableWalletMeta(metadata)
machankuraApplication.getGlobalPrefs().saveAvailableWalletMeta(metadata)
}
actual suspend fun saveAvailableWalletMeta(
@@ -52,7 +52,7 @@ actual suspend fun saveAvailableWalletMeta(
isHidden: Boolean
) {
val machankuraApplication = phoenixGlobal.ctx.applicationContext as MantraApplication
machankuraApplication.globalPrefs.saveAvailableWalletMeta(
machankuraApplication.getGlobalPrefs().saveAvailableWalletMeta(
walletId = walletId,
name = name,
avatar = avatar,

View File

@@ -361,7 +361,7 @@ abstract class NostrDao(
// MLSGroupEvent handling...
nostrEvent.toKeyPackageEvent()?.let { keyPackageEvent ->
logger.d("KeyPackageEvent: $keyPackageEvent")
logger.d("KeyPackageEvent: ${keyPackageEvent.toJson()}")
database.marmotKeyPackageDao().upsert(
MarmotKeyPackage(
id = keyPackageEvent.id,

View File

@@ -7,23 +7,24 @@ import androidx.room3.Transaction
import androidx.room3.Upsert
import press.mantra.compose.database.model.intermdiate.LocalAccount
import kotlinx.coroutines.flow.Flow
import press.mantra.compose.database.model.UnsignedNostrEvent
@Dao
interface UnsignedNostrEventDao {
@Query("SELECT * FROM UnsignedNostrEvent")
fun getAUnsignedNostrEvents(): List<press.mantra.compose.database.model.UnsignedNostrEvent>
fun getAUnsignedNostrEvents(): List<UnsignedNostrEvent>
@Query("SELECT * FROM UnsignedNostrEvent") // TODO: where nostrEvent.unsignedNostrEventId is 0
fun getAllUnprocessedUnsignedNostrEvents(): List<press.mantra.compose.database.model.UnsignedNostrEvent>
fun getAllUnprocessedUnsignedNostrEvents(): List<UnsignedNostrEvent>
@Query("SELECT * FROM UnsignedNostrEvent WHERE id = :id")
fun getUnsignedNostrEventById(id: Long): Flow<press.mantra.compose.database.model.UnsignedNostrEvent?>
fun getUnsignedNostrEventById(id: Long): Flow<UnsignedNostrEvent?>
@Upsert
suspend fun upsert(unsignedNostrEvent: press.mantra.compose.database.model.UnsignedNostrEvent): Long
suspend fun upsert(unsignedNostrEvent: UnsignedNostrEvent): Long
@Insert
suspend fun insert(unsignedNostrEvents: List<press.mantra.compose.database.model.UnsignedNostrEvent>)
suspend fun insert(unsignedNostrEvents: List<UnsignedNostrEvent>)
@Transaction
@Query("SELECT * FROM UnsignedNostrEvent WHERE kind = 0 AND pubKey = :publicKey")
@@ -33,6 +34,6 @@ interface UnsignedNostrEventDao {
@Query("SELECT * FROM UnsignedNostrEvent WHERE kind = 0")
fun getLocalAccounts(): List<LocalAccount>
@Query("SELECT * FROM UnsignedNostrEvent WHERE pubKey = :publicKey AND signedAt IS NULL")
fun observeUnsignedNostrEvents(publicKey: String): Flow<press.mantra.compose.database.model.UnsignedNostrEvent?>
@Query("SELECT * FROM UnsignedNostrEvent WHERE pubKey = :publicKey AND signedAt IS NULL ORDER BY kind ASC")
fun observeUnsignedNostrEvents(publicKey: String): Flow<UnsignedNostrEvent?>
}

View File

@@ -0,0 +1,12 @@
package press.mantra.compose.extensions
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
import fr.acinq.lightning.crypto.LocalKeyManager
import fr.acinq.phoenix.managers.nostrPrivateKey
fun LocalKeyManager.nostrPublicKey(): String {
return KeyPair(
privKey = nostrPrivateKey().value.toByteArray()
).pubKey.toHexKey()
}

View File

@@ -8,7 +8,6 @@ import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.ReqCmd
import com.vitorpamplona.quartz.nip77Negentropy.NegCloseCmd
import com.vitorpamplona.quartz.nip77Negentropy.NegOpenCmd
import fr.acinq.phoenix.data.ActiveWallet
import fr.acinq.phoenix.managers.nostrPublicKey
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -20,6 +19,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import press.mantra.compose.extensions.nostrPublicKey
/**

View File

@@ -17,7 +17,6 @@ import fr.acinq.bitcoin.byteVector
import fr.acinq.lightning.Lightning
import fr.acinq.lightning.crypto.LocalKeyManager
import fr.acinq.phoenix.managers.NodeParamsManager
import fr.acinq.phoenix.managers.nostrPublicKey
import fr.acinq.phoenix.managers.nsecPassword
import fr.acinq.phoenix.utils.MnemonicLanguage
import kotlinx.coroutines.CoroutineExceptionHandler
@@ -25,6 +24,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import press.mantra.compose.extensions.nostrPublicKey
import kotlin.time.Duration.Companion.seconds
class CreateProfileViewModel(
@@ -129,11 +129,6 @@ class CreateProfileViewModel(
biography = createProfileFormState.biographyField.textFieldState.text.toString(),
onCompletion = {
logger.d("Created: $pubkey" )
marmotRepository.publishMarmotKeyPackageBundle(
publicKey = pubkey,
nsecPassword = localKeyManager.nsecPassword()
)
}
)
}

View File

@@ -9,7 +9,6 @@ import press.mantra.compose.ui.composable.navigation.routes.SovereignWalletStart
import press.mantra.compose.ui.view.state.NavigationUIState
import co.touchlab.kermit.Logger
import fr.acinq.phoenix.data.ActiveWallet
import fr.acinq.phoenix.managers.nostrPublicKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
@@ -21,6 +20,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.launch
import press.mantra.compose.extensions.nostrPublicKey
import kotlin.time.Duration.Companion.milliseconds
class NavigationViewModel(
@@ -181,24 +181,26 @@ class NavigationViewModel(
NavigationUIState.StartupPhoenix
}
} else {
if (activeWallet.business == null) {
_navigationUIState.getAndUpdate {
NavigationUIState.StartupPhoenix
}
} else {
val activeUserPublicKey = activeWallet.business.walletManager.keyManager.value?.nostrPublicKey()
if (activeUserPublicKey == null) {
activeWallet.business.let { business ->
if (business == null) {
_navigationUIState.getAndUpdate {
NavigationUIState.Loading(text = "Couldn't get the nostrKey")
NavigationUIState.StartupPhoenix
}
} else {
logger.i("Observing: $activeUserPublicKey")
val activeUserPublicKey = business.walletManager.keyManager.value?.nostrPublicKey()
loadNostrProfile(activeUserPublicKey)
if (activeUserPublicKey == null) {
_navigationUIState.getAndUpdate {
NavigationUIState.Loading(text = "Couldn't get the nostrKey")
}
} else {
logger.i("Observing: $activeUserPublicKey")
loadNostrProfile(activeUserPublicKey)
}
}
logger.i("Navigation UI State is Landing")
}
logger.i("Navigation UI State is Landing")
}
}
}

View File

@@ -18,6 +18,7 @@ import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -26,6 +27,7 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import press.mantra.compose.database.model.NostrEvent
import kotlin.time.Duration.Companion.seconds
import kotlin.time.Instant
class NotaryViewModel(
@@ -204,8 +206,12 @@ class NotaryViewModel(
marmotRepository.observeActiveMarmotKeyPackageBundle(
publicKey = keyPair.pubKey.toHexKey()
).distinctUntilChanged().collect { marmotKeyPackageBundleOrNull ->
if (marmotKeyPackageBundleOrNull == null) {
guardNotarization("key package bundle for ${keyPair.pubKey.toHexKey()}") {
delay(3.seconds)
// TODO: We shouldn't try to create a key package without profile
// we should be check profile in the query to get updates
logger.d("Need to create new key package bundle")
marmotRepository.publishMarmotKeyPackageBundle(
publicKey = keyPair.pubKey.toHexKey(),