Clean up code for some of the imports
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package at.torch.compose.database.converters
|
||||
|
||||
import androidx.room3.TypeConverter
|
||||
import at.torch.compose.database.model.types.SynchronizationFilter
|
||||
import co.touchlab.kermit.Logger
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.time.Instant
|
||||
@@ -72,7 +73,7 @@ class TorchConverters {
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromFilterArray(value: Array<at.torch.compose.database.model.types.SynchronizationFilter>?): String? = try {
|
||||
fun fromFilterArray(value: Array<SynchronizationFilter>?): String? = try {
|
||||
return value?.let {
|
||||
Json.encodeToString(value)
|
||||
}
|
||||
@@ -82,9 +83,9 @@ class TorchConverters {
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toFilterArray(value: String?): Array<at.torch.compose.database.model.types.SynchronizationFilter>? = try {
|
||||
fun toFilterArray(value: String?): Array<SynchronizationFilter>? = try {
|
||||
return value?.let {
|
||||
Json.decodeFromString<Array<at.torch.compose.database.model.types.SynchronizationFilter>>(it)
|
||||
Json.decodeFromString<Array<SynchronizationFilter>>(it)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logger.e("Failed to convert to FilterArray $value", e)
|
||||
@@ -92,7 +93,7 @@ class TorchConverters {
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromSynchronizationFilter(value: at.torch.compose.database.model.types.SynchronizationFilter?): String? = try {
|
||||
fun fromSynchronizationFilter(value: SynchronizationFilter?): String? = try {
|
||||
return value?.let {
|
||||
Json.encodeToString(value)
|
||||
}
|
||||
@@ -102,9 +103,9 @@ class TorchConverters {
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toSynchronizationFilter(value: String?): at.torch.compose.database.model.types.SynchronizationFilter? = try {
|
||||
fun toSynchronizationFilter(value: String?): SynchronizationFilter? = try {
|
||||
return value?.let {
|
||||
Json.decodeFromString<at.torch.compose.database.model.types.SynchronizationFilter>(it)
|
||||
Json.decodeFromString<SynchronizationFilter>(it)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logger.e("Failed to convert to SynchronizationFilter $value", e)
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.room3.Insert
|
||||
import androidx.room3.OnConflictStrategy.Companion.IGNORE
|
||||
import androidx.room3.Query
|
||||
import androidx.room3.Upsert
|
||||
import at.torch.compose.database.model.NegentropySynchronizeRequest
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
@@ -12,16 +13,16 @@ import kotlin.time.Instant
|
||||
@Dao
|
||||
interface NegentropySynchronizeRequestDao {
|
||||
@Query("SELECT * FROM NegentropySynchronizeRequest WHERE status = :status AND createdAt > :createdAt")
|
||||
fun observeNegentropySynchronizeRequestsByStatus(status: String, createdAt: Instant = Clock.System.now()): Flow<at.torch.compose.database.model.NegentropySynchronizeRequest?>
|
||||
fun observeNegentropySynchronizeRequestsByStatus(status: String, createdAt: Instant = Clock.System.now()): Flow<NegentropySynchronizeRequest?>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM NegentropySynchronizeRequest WHERE purpose = :purpose AND status IN (:status) AND createdAt > :createdAt")
|
||||
fun observeNegentropySynchronizeRequestByPurposeAndStatusCount(purpose: String, status: List<String>, createdAt: Instant = Clock.System.now()): Flow<Int>
|
||||
|
||||
@Upsert
|
||||
fun upsert(negentropySynchronizeRequest: at.torch.compose.database.model.NegentropySynchronizeRequest)
|
||||
fun upsert(negentropySynchronizeRequest: NegentropySynchronizeRequest)
|
||||
|
||||
@Insert(
|
||||
onConflict = IGNORE
|
||||
)
|
||||
fun insert(negentropySynchronizeRequests: List<at.torch.compose.database.model.NegentropySynchronizeRequest>)
|
||||
fun insert(negentropySynchronizeRequests: List<NegentropySynchronizeRequest>)
|
||||
}
|
||||
@@ -4,6 +4,10 @@ import androidx.room3.Entity
|
||||
import androidx.room3.ForeignKey
|
||||
import androidx.room3.Ignore
|
||||
import androidx.room3.PrimaryKey
|
||||
import at.torch.compose.database.model.traits.LocalStoreEntity
|
||||
import at.torch.compose.database.model.traits.SoftDeletableEntity
|
||||
import at.torch.compose.database.model.traits.TimestampedEntity
|
||||
import at.torch.compose.database.model.traits.UserViewableEntity
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||
@@ -74,10 +78,7 @@ data class GiftWrapPayload(
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null, // Who this message should be seen by (used to derive conversationId)
|
||||
): at.torch.compose.database.model.traits.TimestampedEntity,
|
||||
at.torch.compose.database.model.traits.LocalStoreEntity,
|
||||
at.torch.compose.database.model.traits.UserViewableEntity,
|
||||
at.torch.compose.database.model.traits.SoftDeletableEntity {
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
@Ignore
|
||||
private val logger = Logger.withTag(TAG)
|
||||
|
||||
|
||||
@@ -90,10 +90,7 @@ data class MarmotInnerEvent( // TODO: Rename this to GiftWrapPayload...
|
||||
override val savedAt: Instant = Clock.System.now(),
|
||||
override val viewedAt: Instant? = null,
|
||||
override val deletedAt: Instant? = null, // Who this message should be seen by (used to derive conversationId)
|
||||
): TimestampedEntity,
|
||||
LocalStoreEntity,
|
||||
UserViewableEntity,
|
||||
SoftDeletableEntity {
|
||||
): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity {
|
||||
@Ignore
|
||||
private val logger = Logger.withTag(TAG)
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.room3.Embedded
|
||||
import androidx.room3.Relation
|
||||
import at.torch.compose.database.model.ChatRoom
|
||||
import at.torch.compose.database.model.Participant
|
||||
import at.torch.compose.ui.composable.widgets.profile.ProfileColor
|
||||
|
||||
data class LocalChatRoom(
|
||||
@Embedded val chatRoom: at.torch.compose.database.model.ChatRoom,
|
||||
@Embedded val chatRoom: ChatRoom,
|
||||
|
||||
@Relation(
|
||||
entity = at.torch.compose.database.model.Participant::class,
|
||||
entity = Participant::class,
|
||||
parentColumns = ["id"],
|
||||
entityColumns = ["chatRoomId"],
|
||||
)
|
||||
@@ -23,7 +26,7 @@ data class LocalChatRoom(
|
||||
if (chatRoom.subject != null) {
|
||||
Text(
|
||||
text = chatRoom.subject,
|
||||
color = at.torch.compose.ui.composable.widgets.profile.ProfileColor.fromPublicKey(chatRoom.id)
|
||||
color = ProfileColor.fromPublicKey(chatRoom.id)
|
||||
)
|
||||
} else {
|
||||
if (localParticipants.size == 1) {
|
||||
@@ -33,7 +36,7 @@ data class LocalChatRoom(
|
||||
} else {
|
||||
// Remove the active user publicKey from participants...
|
||||
val participantNames = localParticipants.filter { it.participant.participantPublicKey != chatRoom.userPublicKey }.map { buildAnnotatedString {
|
||||
withStyle(style = SpanStyle(color = at.torch.compose.ui.composable.widgets.profile.ProfileColor.fromPublicKey(it.participant.participantPublicKey))) {
|
||||
withStyle(style = SpanStyle(color = ProfileColor.fromPublicKey(it.participant.participantPublicKey))) {
|
||||
append(it.profile?.humanReadableNameOrPubkey() ?: "unknown participant")
|
||||
}
|
||||
} }
|
||||
|
||||
@@ -2,13 +2,15 @@ package at.torch.compose.database.model.intermdiate
|
||||
|
||||
import androidx.room3.Embedded
|
||||
import androidx.room3.Relation
|
||||
import at.torch.compose.database.model.NostrEvent
|
||||
import at.torch.compose.database.model.Profile
|
||||
|
||||
data class LocalProfile(
|
||||
@Embedded val nostrEvent: at.torch.compose.database.model.NostrEvent,
|
||||
@Embedded val nostrEvent: NostrEvent,
|
||||
|
||||
@Relation(
|
||||
parentColumns = ["pubKey"],
|
||||
entityColumns = ["publicKey"]
|
||||
)
|
||||
val profile: at.torch.compose.database.model.Profile,
|
||||
val profile: Profile,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package at.torch.compose.database.repository
|
||||
|
||||
import at.torch.compose.database.GENESIS_AT
|
||||
import at.torch.compose.database.TorchDatabase
|
||||
import at.torch.compose.database.model.ChatMessage
|
||||
import at.torch.compose.database.model.ChatRoom
|
||||
import at.torch.compose.database.model.GiftWrapPayload
|
||||
@@ -7,6 +9,8 @@ import at.torch.compose.database.model.MarmotInnerEvent
|
||||
import at.torch.compose.database.model.MarmotKeyPackage
|
||||
import at.torch.compose.database.model.Participant
|
||||
import at.torch.compose.database.model.Profile
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatMessage
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatRoom
|
||||
import at.torch.compose.database.model.intermdiate.LocalProfile
|
||||
import at.torch.compose.extensions.toHex
|
||||
import at.torch.compose.nostr.Relays
|
||||
@@ -39,30 +43,30 @@ import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
|
||||
class DatabaseChatRepository(
|
||||
private val database: at.torch.compose.database.TorchDatabase,
|
||||
private val database: TorchDatabase,
|
||||
private val scope: CoroutineScope
|
||||
): at.torch.compose.repository.ChatRepository {
|
||||
val logger = Logger.withTag(TAG)
|
||||
override suspend fun observeChatRoomListByPublicKey(publicKey: String): Flow<List<at.torch.compose.database.model.intermdiate.LocalChatRoom>> {
|
||||
override suspend fun observeChatRoomListByPublicKey(publicKey: String): Flow<List<LocalChatRoom>> {
|
||||
return database.chatRoomDao().observeChatRoomListByUserPublicKey(publicKey)
|
||||
}
|
||||
|
||||
override suspend fun getChatRoomListByPublicKey(publicKey: String): List<at.torch.compose.database.model.intermdiate.LocalChatRoom> {
|
||||
override suspend fun getChatRoomListByPublicKey(publicKey: String): List<LocalChatRoom> {
|
||||
return database.chatRoomDao().getChatRoomListByUserPublicKey(publicKey)
|
||||
}
|
||||
|
||||
override suspend fun getChatRoomByIdentifier(id: HexKey): at.torch.compose.database.model.intermdiate.LocalChatRoom? {
|
||||
override suspend fun getChatRoomByIdentifier(id: HexKey): LocalChatRoom? {
|
||||
return database.chatRoomDao().findChatRoomById(id)
|
||||
}
|
||||
|
||||
override suspend fun getAllParticipantsWithPubKey(publicKey: HexKey): List<Participant> {
|
||||
return database.participantDao().findParticipantByPublicKey(publicKey)
|
||||
}
|
||||
override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<at.torch.compose.database.model.intermdiate.LocalChatMessage> {
|
||||
override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<LocalChatMessage> {
|
||||
return database.chatMessageDao().getChatMessagesByChatRoomId(chatRoomId)
|
||||
}
|
||||
|
||||
override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<at.torch.compose.database.model.intermdiate.LocalChatMessage>> {
|
||||
override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<LocalChatMessage>> {
|
||||
return database.chatMessageDao().observeChatMessagesByChatRoomId(chatRoomId)
|
||||
}
|
||||
|
||||
@@ -73,7 +77,7 @@ class DatabaseChatRepository(
|
||||
relayHint: String?,
|
||||
defaultSubject: String?,
|
||||
mlsGroupState: String?
|
||||
): at.torch.compose.database.model.intermdiate.LocalChatRoom? = try {
|
||||
): LocalChatRoom? = try {
|
||||
return database.nostrNip17Dao().getOrCreateChatRoom(
|
||||
chatRoomId = chatRoomId,
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
@@ -95,7 +99,7 @@ class DatabaseChatRepository(
|
||||
authors = arrayOf(
|
||||
publicKey
|
||||
),
|
||||
since = _root_ide_package_.at.torch.compose.database.GENESIS_AT,
|
||||
since = GENESIS_AT,
|
||||
limit = 5
|
||||
).firstOrNull()?.let { nostrEvent ->
|
||||
if (nostrEvent.kind != ChatMessageRelayListEvent.KIND) {
|
||||
@@ -136,7 +140,7 @@ class DatabaseChatRepository(
|
||||
|
||||
override suspend fun sendChatMessage(
|
||||
text: String,
|
||||
localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom,
|
||||
localChatRoom: LocalChatRoom,
|
||||
messageType: Kind
|
||||
) {
|
||||
logger.i("sendChatMessage($text): $localChatRoom")
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package at.torch.compose.repository
|
||||
|
||||
import at.torch.compose.database.model.ChatRoom
|
||||
import at.torch.compose.database.model.GiftWrapPayload
|
||||
import at.torch.compose.database.model.MarmotKeyPackage
|
||||
import at.torch.compose.database.model.Participant
|
||||
import at.torch.compose.database.model.Profile
|
||||
@@ -54,11 +56,11 @@ interface ChatRepository {
|
||||
messageType: Kind = ChatMessageEvent.KIND
|
||||
)
|
||||
|
||||
fun updateChatRoomSubject(publicKey: String, subject: String): at.torch.compose.database.model.ChatRoom?
|
||||
fun updateChatRoomSubject(publicKey: String, subject: String): ChatRoom?
|
||||
|
||||
suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow<at.torch.compose.database.model.GiftWrapPayload?>
|
||||
suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow<GiftWrapPayload?>
|
||||
|
||||
suspend fun sealGiftWrapPayload(giftWrapPayload: at.torch.compose.database.model.GiftWrapPayload, nostrSignerSync: NostrSignerSync)
|
||||
suspend fun sealGiftWrapPayload(giftWrapPayload: GiftWrapPayload, nostrSignerSync: NostrSignerSync)
|
||||
|
||||
companion object {
|
||||
val NO_OP_CHAT_REPOSITORY = object: ChatRepository {
|
||||
@@ -125,16 +127,16 @@ interface ChatRepository {
|
||||
// TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun updateChatRoomSubject(publicKey: String, subject: String): at.torch.compose.database.model.ChatRoom? {
|
||||
override fun updateChatRoomSubject(publicKey: String, subject: String): ChatRoom? {
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow<at.torch.compose.database.model.GiftWrapPayload?> {
|
||||
override suspend fun observeUnsealedGiftWrapPayloads(publicKey: HexKey): Flow<GiftWrapPayload?> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun sealGiftWrapPayload(
|
||||
giftWrapPayload: at.torch.compose.database.model.GiftWrapPayload,
|
||||
giftWrapPayload: GiftWrapPayload,
|
||||
nostrSignerSync: NostrSignerSync
|
||||
) {
|
||||
TODO("Not yet implemented")
|
||||
|
||||
@@ -37,10 +37,13 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.torch.compose.database.model.ChatRoom
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatRoom
|
||||
import at.torch.compose.repository.ChatRepository
|
||||
import at.torch.compose.repository.NostrRepository
|
||||
import at.torch.compose.ui.composable.navigation.routes.Route
|
||||
import at.torch.compose.ui.composable.widgets.LoadingDataIndicator
|
||||
import at.torch.compose.ui.theme.TorchTheme
|
||||
import at.torch.compose.ui.view.model.ChatRoomDetailViewModel
|
||||
import at.torch.compose.ui.view.state.ChatRoomDetailUIState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
@@ -312,7 +315,7 @@ fun ChatRoomDetailScreen(
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ChatRoomDetailScreenPreview() {
|
||||
_root_ide_package_.at.torch.compose.ui.theme.TorchTheme {
|
||||
TorchTheme {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
@@ -321,8 +324,8 @@ private fun ChatRoomDetailScreenPreview() {
|
||||
chatRoomId = "publicKey",
|
||||
relayHint = null,
|
||||
initialChatRoomDetailUIState = ChatRoomDetailUIState.Loaded(
|
||||
localChatRoom = _root_ide_package_.at.torch.compose.database.model.intermdiate.LocalChatRoom(
|
||||
chatRoom = _root_ide_package_.at.torch.compose.database.model.ChatRoom(
|
||||
localChatRoom = LocalChatRoom(
|
||||
chatRoom = ChatRoom(
|
||||
id = "",
|
||||
userPublicKey = "",
|
||||
subject = "Message title",
|
||||
|
||||
@@ -32,9 +32,19 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.torch.compose.database.model.NostrEvent
|
||||
import at.torch.compose.database.model.Profile
|
||||
import at.torch.compose.database.model.intermdiate.LocalProfileWithFollowing
|
||||
import at.torch.compose.repository.ChatRepository
|
||||
import at.torch.compose.repository.NostrRepository
|
||||
import at.torch.compose.ui.composable.navigation.routes.ActiveProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.NostrEventDetailRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.Route
|
||||
import at.torch.compose.ui.composable.widgets.LoadingDataIndicator
|
||||
import at.torch.compose.ui.theme.TorchTheme
|
||||
import at.torch.compose.ui.view.model.HomeScreenType
|
||||
import at.torch.compose.ui.view.model.HomeViewModel
|
||||
import at.torch.compose.ui.view.state.HomeScreenUIState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -43,18 +53,18 @@ import kotlinx.coroutines.launch
|
||||
@Composable
|
||||
fun HomeScreen(
|
||||
activeUserPublicKey: HexKey,
|
||||
initialHomeScreenUIState: at.torch.compose.ui.view.state.HomeScreenUIState = at.torch.compose.ui.view.state.HomeScreenUIState.Loading,
|
||||
onNavigateToEvent: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit,
|
||||
onNavigateToDirectMessageDetail: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit,
|
||||
initialHomeScreenUIState: HomeScreenUIState = HomeScreenUIState.Loading,
|
||||
onNavigateToEvent: (Route) -> Unit,
|
||||
onNavigateToDirectMessageDetail: (Route) -> Unit,
|
||||
onNavigateToChatRoomCreation: () -> Unit,
|
||||
onNavigateToSearch: () -> Unit,
|
||||
nostrRepository: at.torch.compose.repository.NostrRepository,
|
||||
chatRepository: at.torch.compose.repository.ChatRepository
|
||||
nostrRepository: NostrRepository,
|
||||
chatRepository: ChatRepository
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val homeScreenViewModel: at.torch.compose.ui.view.model.HomeViewModel = viewModel(
|
||||
factory = at.torch.compose.ui.view.model.HomeViewModel.factory(
|
||||
val homeScreenViewModel: HomeViewModel = viewModel(
|
||||
factory = HomeViewModel.factory(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
initialHomeScreenUIState = initialHomeScreenUIState,
|
||||
nostrRepository = nostrRepository,
|
||||
@@ -63,7 +73,7 @@ fun HomeScreen(
|
||||
)
|
||||
|
||||
when(val homeScreenUIState = homeScreenViewModel.homeScreenUIState) {
|
||||
at.torch.compose.ui.view.state.HomeScreenUIState.Error -> {
|
||||
HomeScreenUIState.Error -> {
|
||||
Scaffold { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier.padding(innerPadding).fillMaxSize(),
|
||||
@@ -84,7 +94,7 @@ fun HomeScreen(
|
||||
}
|
||||
|
||||
}
|
||||
is at.torch.compose.ui.view.state.HomeScreenUIState.Loaded -> {
|
||||
is HomeScreenUIState.Loaded -> {
|
||||
Scaffold(
|
||||
modifier = Modifier,
|
||||
topBar = {
|
||||
@@ -206,8 +216,8 @@ fun HomeScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
at.torch.compose.ui.view.state.HomeScreenUIState.Loading -> {
|
||||
_root_ide_package_.at.torch.compose.ui.composable.widgets.LoadingDataIndicator()
|
||||
HomeScreenUIState.Loading -> {
|
||||
LoadingDataIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,15 +229,15 @@ fun HomeScreen(
|
||||
@Preview
|
||||
@Composable
|
||||
private fun HomeScreenPreview() {
|
||||
_root_ide_package_.at.torch.compose.ui.theme.TorchTheme {
|
||||
TorchTheme {
|
||||
Surface(
|
||||
modifier = Modifier.padding(20.dp)
|
||||
) {
|
||||
HomeScreen(
|
||||
activeUserPublicKey = "",
|
||||
initialHomeScreenUIState = at.torch.compose.ui.view.state.HomeScreenUIState.Loaded(
|
||||
profileWithFollowing = _root_ide_package_.at.torch.compose.database.model.intermdiate.LocalProfileWithFollowing(
|
||||
nostrEvent = _root_ide_package_.at.torch.compose.database.model.NostrEvent(
|
||||
initialHomeScreenUIState = HomeScreenUIState.Loaded(
|
||||
profileWithFollowing = LocalProfileWithFollowing(
|
||||
nostrEvent = NostrEvent(
|
||||
id = "eventId",
|
||||
pubKey = "publicKey",
|
||||
content = """Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|
||||
@@ -239,7 +249,7 @@ It has survived not only five centuries, but also the leap into electronic types
|
||||
sig = "",
|
||||
kind = TextNoteEvent.KIND
|
||||
),
|
||||
profile = _root_ide_package_.at.torch.compose.database.model.Profile(
|
||||
profile = Profile(
|
||||
publicKey = "pubKey",
|
||||
displayName = "John Doe",
|
||||
nostrEventId = "nostrEventId"
|
||||
@@ -251,8 +261,8 @@ It has survived not only five centuries, but also the leap into electronic types
|
||||
onNavigateToChatRoomCreation = {},
|
||||
onNavigateToSearch = {},
|
||||
onNavigateToDirectMessageDetail = {},
|
||||
nostrRepository = at.torch.compose.repository.NostrRepository.NO_OP_NOSTR_REPOSITORY,
|
||||
chatRepository = at.torch.compose.repository.ChatRepository.NO_OP_CHAT_REPOSITORY
|
||||
nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY,
|
||||
chatRepository = ChatRepository.NO_OP_CHAT_REPOSITORY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,17 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.torch.compose.database.model.NostrEvent
|
||||
import at.torch.compose.database.model.Profile
|
||||
import at.torch.compose.database.model.intermdiate.LocalNostrEvent
|
||||
import at.torch.compose.repository.NostrRepository
|
||||
import at.torch.compose.ui.composable.navigation.routes.Route
|
||||
import at.torch.compose.ui.composable.widgets.LoadingDataIndicator
|
||||
import at.torch.compose.ui.composable.widgets.detail.MetadataEventDetail
|
||||
import at.torch.compose.ui.composable.widgets.detail.TextNoteEventDetail
|
||||
import at.torch.compose.ui.theme.TorchTheme
|
||||
import at.torch.compose.ui.view.model.NostrEventDetailViewModel
|
||||
import at.torch.compose.ui.view.state.NostrEventDetailUIState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
@@ -25,10 +34,10 @@ import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun NostrEventDetailScreen(
|
||||
initialNostrEventDetailUIState: at.torch.compose.ui.view.state.NostrEventDetailUIState,
|
||||
initialNostrEventDetailUIState: NostrEventDetailUIState,
|
||||
activeUserPublicKey: HexKey,
|
||||
nostrEventId: HexKey,
|
||||
nostrRepository: at.torch.compose.repository.NostrRepository,
|
||||
nostrRepository: NostrRepository,
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateToEvent: (Route) -> Unit,
|
||||
onNavigateToDirectMessage: (Route) -> Unit,
|
||||
@@ -36,8 +45,8 @@ fun NostrEventDetailScreen(
|
||||
onNavigateToWriteAReply: (String) -> Unit,
|
||||
onNavigateToQuoteNostrEvent: (String) -> Unit,
|
||||
) {
|
||||
val nostrEventDetailViewModel: at.torch.compose.ui.view.model.NostrEventDetailViewModel = viewModel(
|
||||
factory = at.torch.compose.ui.view.model.NostrEventDetailViewModel.factory(
|
||||
val nostrEventDetailViewModel: NostrEventDetailViewModel = viewModel(
|
||||
factory = NostrEventDetailViewModel.factory(
|
||||
nostrEventId = nostrEventId,
|
||||
initialNostrEventDetailUIState = initialNostrEventDetailUIState,
|
||||
nostrRepository = nostrRepository,
|
||||
@@ -46,7 +55,7 @@ fun NostrEventDetailScreen(
|
||||
)
|
||||
|
||||
when(val feedListUIState = nostrEventDetailViewModel.nostrEventDetailUIState) {
|
||||
at.torch.compose.ui.view.state.NostrEventDetailUIState.Error -> {
|
||||
NostrEventDetailUIState.Error -> {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
@@ -55,7 +64,7 @@ fun NostrEventDetailScreen(
|
||||
Text("Something went wrong")
|
||||
}
|
||||
}
|
||||
is at.torch.compose.ui.view.state.NostrEventDetailUIState.Loaded -> {
|
||||
is NostrEventDetailUIState.Loaded -> {
|
||||
|
||||
when(feedListUIState.localNostrEvent.nostrEvent.kind) {
|
||||
MetadataEvent.KIND -> {
|
||||
@@ -70,7 +79,7 @@ fun NostrEventDetailScreen(
|
||||
)
|
||||
}
|
||||
TextNoteEvent.KIND -> {
|
||||
at.torch.compose.ui.composable.widgets.detail.TextNoteEventDetail(
|
||||
TextNoteEventDetail(
|
||||
feedListUIState.localNostrEvent,
|
||||
onNavigateBack = onNavigateBack,
|
||||
onNavigateToWriteAReply = onNavigateToWriteAReply,
|
||||
@@ -109,14 +118,14 @@ fun NostrEventDetailScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
at.torch.compose.ui.view.state.NostrEventDetailUIState.Loading -> {
|
||||
at.torch.compose.ui.composable.widgets.LoadingDataIndicator()
|
||||
NostrEventDetailUIState.Loading -> {
|
||||
LoadingDataIndicator()
|
||||
|
||||
LaunchedEffect(true) {
|
||||
nostrEventDetailViewModel.loadNostrFeed()
|
||||
}
|
||||
}
|
||||
at.torch.compose.ui.view.state.NostrEventDetailUIState.NotFound -> {
|
||||
NostrEventDetailUIState.NotFound -> {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
@@ -131,14 +140,14 @@ fun NostrEventDetailScreen(
|
||||
@Preview
|
||||
@Composable
|
||||
private fun NostrEventDetailScreenPreview() {
|
||||
at.torch.compose.ui.theme.TorchTheme {
|
||||
TorchTheme {
|
||||
Surface(
|
||||
modifier = Modifier.padding(20.dp)
|
||||
) {
|
||||
NostrEventDetailScreen(
|
||||
initialNostrEventDetailUIState = at.torch.compose.ui.view.state.NostrEventDetailUIState.Loaded(
|
||||
localNostrEvent = at.torch.compose.database.model.intermdiate.LocalNostrEvent(
|
||||
nostrEvent = at.torch.compose.database.model.NostrEvent(
|
||||
initialNostrEventDetailUIState = NostrEventDetailUIState.Loaded(
|
||||
localNostrEvent = LocalNostrEvent(
|
||||
nostrEvent = NostrEvent(
|
||||
id = "eventId",
|
||||
pubKey = "publicKey",
|
||||
content = """Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|
||||
@@ -150,7 +159,7 @@ It has survived not only five centuries, but also the leap into electronic types
|
||||
sig = "",
|
||||
kind = TextNoteEvent.KIND
|
||||
),
|
||||
profile = at.torch.compose.database.model.Profile(
|
||||
profile = Profile(
|
||||
publicKey = "pubKey",
|
||||
displayName = "John Doe",
|
||||
nostrEventId = "nostrEventId"
|
||||
@@ -159,7 +168,7 @@ It has survived not only five centuries, but also the leap into electronic types
|
||||
),
|
||||
nostrEventId = "",
|
||||
activeUserPublicKey = "",
|
||||
nostrRepository = at.torch.compose.repository.NostrRepository.NO_OP_NOSTR_REPOSITORY,
|
||||
nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY,
|
||||
onNavigateBack = {},
|
||||
onNavigateToEvent = {},
|
||||
onNavigateToWriteAReply = {},
|
||||
|
||||
@@ -12,26 +12,61 @@ import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.toRoute
|
||||
import at.torch.compose.TorchGlobal
|
||||
import at.torch.compose.database.repository.DatabaseChatRepository
|
||||
import at.torch.compose.database.repository.DatabaseMarmotRepository
|
||||
import at.torch.compose.database.repository.DatabaseNostrRepository
|
||||
import at.torch.compose.database.repository.DatabaseSearchRepository
|
||||
import at.torch.compose.ui.composable.ActiveProfileScreen
|
||||
import at.torch.compose.ui.composable.ChatRoomCreationScreen
|
||||
import at.torch.compose.ui.composable.ChatRoomDetailScreen
|
||||
import at.torch.compose.ui.composable.HomeScreen
|
||||
import at.torch.compose.ui.composable.ImplementationPendingScreen
|
||||
import at.torch.compose.ui.composable.KeyPackageManagementScreen
|
||||
import at.torch.compose.ui.composable.NostrEventDetailScreen
|
||||
import at.torch.compose.ui.composable.SearchResultScreen
|
||||
import at.torch.compose.ui.composable.SearchScreen
|
||||
import at.torch.compose.ui.composable.ShareProfileScreen
|
||||
import at.torch.compose.ui.composable.SignInToProfileScreen
|
||||
import at.torch.compose.ui.composable.SocialPreconditionScreen
|
||||
import at.torch.compose.ui.composable.UnannouncedProfileScreen
|
||||
import at.torch.compose.ui.composable.UnindexedProfileScreen
|
||||
import at.torch.compose.ui.composable.UnqueuedProfileScreen
|
||||
import at.torch.compose.ui.composable.UnqueuedProfileSynchronizationScreen
|
||||
import at.torch.compose.ui.composable.UnsignedProfileScreen
|
||||
import at.torch.compose.ui.composable.UnsyncedProfileScreen
|
||||
import at.torch.compose.ui.composable.WriteNewNoteScreen
|
||||
import at.torch.compose.ui.composable.navigation.routes.ActiveProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.BlankRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.ChatRoomCreationRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.ChatRoomDetailRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.CreateProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.FeedRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.KeyPackageManagementRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.LandingRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.LoadingRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.NostrEventDetailRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.SearchResultRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.SearchRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.ShareProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.SignInRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.SocialPreconditionRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.SovereignWalletStartupRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.UnindexedProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.WriteNewNoteRoute
|
||||
import at.torch.compose.ui.view.model.NavigationViewModel
|
||||
import at.torch.compose.ui.view.model.NotaryViewModel
|
||||
import at.torch.compose.ui.view.model.SovereignWalletViewModel
|
||||
import at.torch.compose.ui.view.model.SynchronizationViewModel
|
||||
import at.torch.compose.ui.view.state.NavigationUIState
|
||||
import at.torch.compose.ui.view.state.NostrEventDetailUIState
|
||||
import at.torch.compose.ui.view.state.SearchUIState
|
||||
import co.touchlab.kermit.Logger
|
||||
import fr.acinq.phoenix.PhoenixGlobal
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
@@ -43,16 +78,15 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun TorchNavHost(
|
||||
torchGlobal: at.torch.compose.TorchGlobal,
|
||||
torchGlobal: TorchGlobal,
|
||||
phoenixGlobal: PhoenixGlobal,
|
||||
navController: NavHostController
|
||||
) {
|
||||
val logger = Logger.withTag("AuxNavHost")
|
||||
// TODO
|
||||
val exceptionHandler =
|
||||
CoroutineExceptionHandler { _, throwable ->
|
||||
logger.e("Caught exception: ${throwable.message}", throwable)
|
||||
}
|
||||
|
||||
val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
||||
logger.e("Caught exception: ${throwable.message}", throwable)
|
||||
}
|
||||
|
||||
val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob() + exceptionHandler)
|
||||
val applicationMainScope = CoroutineScope(Dispatchers.Main)
|
||||
@@ -62,33 +96,33 @@ fun TorchNavHost(
|
||||
val auxDatabaseManager =
|
||||
at.torch.compose.managers.AuxDatabaseManager(torchGlobal)
|
||||
|
||||
val databaseNostrRepository =
|
||||
at.torch.compose.database.repository.DatabaseNostrRepository(
|
||||
database = auxDatabaseManager.auxDatabase,
|
||||
applicationIOScope
|
||||
)
|
||||
val databaseChatRepository =
|
||||
at.torch.compose.database.repository.DatabaseChatRepository(
|
||||
database = auxDatabaseManager.auxDatabase,
|
||||
applicationIOScope
|
||||
)
|
||||
val databaseNostrRepository = DatabaseNostrRepository(
|
||||
database = auxDatabaseManager.auxDatabase,
|
||||
applicationIOScope
|
||||
)
|
||||
|
||||
val databaseChatRepository = DatabaseChatRepository(
|
||||
database = auxDatabaseManager.auxDatabase,
|
||||
applicationIOScope
|
||||
)
|
||||
|
||||
val databaseMarmotRepository = DatabaseMarmotRepository(
|
||||
database = auxDatabaseManager.auxDatabase,
|
||||
applicationIOScope
|
||||
)
|
||||
|
||||
val searchRepository =
|
||||
at.torch.compose.database.repository.DatabaseSearchRepository(
|
||||
database = auxDatabaseManager.auxDatabase
|
||||
val searchRepository = DatabaseSearchRepository(
|
||||
database = auxDatabaseManager.auxDatabase
|
||||
)
|
||||
|
||||
val sovereignWalletViewModel: SovereignWalletViewModel = viewModel(
|
||||
factory = SovereignWalletViewModel.factory(
|
||||
phoenixGlobal = phoenixGlobal
|
||||
)
|
||||
)
|
||||
|
||||
val sovereignWalletViewModel: at.torch.compose.ui.view.model.SovereignWalletViewModel = viewModel(factory = at.torch.compose.ui.view.model.SovereignWalletViewModel.factory(
|
||||
phoenixGlobal = phoenixGlobal
|
||||
))
|
||||
|
||||
val navigationViewModel: at.torch.compose.ui.view.model.NavigationViewModel = viewModel (
|
||||
factory = at.torch.compose.ui.view.model.NavigationViewModel.factory(
|
||||
val navigationViewModel: NavigationViewModel = viewModel (
|
||||
factory = NavigationViewModel.factory(
|
||||
activeWallet = sovereignWalletViewModel.activeWalletInUI,
|
||||
initialNavigationUIState = NavigationUIState.Loading(),
|
||||
nostrRepository = databaseNostrRepository,
|
||||
@@ -96,9 +130,8 @@ fun TorchNavHost(
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
val notaryViewModel: at.torch.compose.ui.view.model.NotaryViewModel = viewModel(
|
||||
factory = at.torch.compose.ui.view.model.NotaryViewModel.factory(
|
||||
val notaryViewModel: NotaryViewModel = viewModel(
|
||||
factory = NotaryViewModel.factory(
|
||||
activeWalletStateFlow = sovereignWalletViewModel.activeWalletInUI,
|
||||
nostrRepository = databaseNostrRepository,
|
||||
chatRepository = databaseChatRepository,
|
||||
@@ -108,8 +141,8 @@ fun TorchNavHost(
|
||||
)
|
||||
|
||||
// TODO: Produce a notary UI Element...
|
||||
val synchronizationViewModel: at.torch.compose.ui.view.model.SynchronizationViewModel = viewModel(
|
||||
factory = at.torch.compose.ui.view.model.SynchronizationViewModel.factory(
|
||||
val synchronizationViewModel: SynchronizationViewModel = viewModel(
|
||||
factory = SynchronizationViewModel.factory(
|
||||
activeWalletStateFlow = sovereignWalletViewModel.activeWalletInUI,
|
||||
nostrRepository = databaseNostrRepository,
|
||||
chatRepository = databaseChatRepository,
|
||||
@@ -117,6 +150,7 @@ fun TorchNavHost(
|
||||
scope = applicationIOScope
|
||||
)
|
||||
)
|
||||
|
||||
// TODO: Produce a synchronization UI element...
|
||||
|
||||
LaunchedEffect(lifecycleOwner) {
|
||||
@@ -124,7 +158,7 @@ fun TorchNavHost(
|
||||
when (state) {
|
||||
is NavigationUIState.Error -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute(
|
||||
route = ImplementationPendingRoute(
|
||||
"Error screen"
|
||||
)
|
||||
) {
|
||||
@@ -149,14 +183,14 @@ fun TorchNavHost(
|
||||
}
|
||||
is NavigationUIState.Landing -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.LandingRoute
|
||||
route = LandingRoute
|
||||
) {
|
||||
popUpTo(0)
|
||||
}
|
||||
}
|
||||
is NavigationUIState.UnsignedProfile -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute(
|
||||
route = UnsignedProfileRoute(
|
||||
state.unsignedNostrEvent.id
|
||||
)
|
||||
) {
|
||||
@@ -165,7 +199,7 @@ fun TorchNavHost(
|
||||
}
|
||||
is NavigationUIState.UnsyncedProfile -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute(
|
||||
route = UnsyncedProfileRoute(
|
||||
state.unsignedNostrEvent.pubKey
|
||||
)
|
||||
) {
|
||||
@@ -174,7 +208,7 @@ fun TorchNavHost(
|
||||
}
|
||||
is NavigationUIState.UnqueuedProfileSynchronization -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute(
|
||||
route = UnqueuedProfileSynchronizationRoute(
|
||||
unsignedNostrEventId = state.unsignedNostrEvent.id,
|
||||
publicKey = state.unsignedNostrEvent.pubKey
|
||||
)
|
||||
@@ -184,7 +218,7 @@ fun TorchNavHost(
|
||||
}
|
||||
is NavigationUIState.UnindexedProfile -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.UnindexedProfileRoute(
|
||||
route = UnindexedProfileRoute(
|
||||
state.nostrEvent.id
|
||||
)
|
||||
) {
|
||||
@@ -193,14 +227,14 @@ fun TorchNavHost(
|
||||
}
|
||||
is NavigationUIState.UnqueuedProfile -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileRoute(
|
||||
route = UnqueuedProfileRoute(
|
||||
state.profile.nostrEventId
|
||||
)
|
||||
)
|
||||
}
|
||||
is NavigationUIState.UnannouncedProfile -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute(
|
||||
route = UnannouncedProfileRoute(
|
||||
state.broadcastNostrEventRequest.nostrEventId
|
||||
)
|
||||
) {
|
||||
@@ -218,7 +252,7 @@ fun TorchNavHost(
|
||||
}
|
||||
else -> {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute(
|
||||
route = ImplementationPendingRoute(
|
||||
"Unsupported $state"
|
||||
)
|
||||
) {
|
||||
@@ -270,32 +304,32 @@ fun TorchNavHost(
|
||||
text = route.text
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.LandingRoute> {
|
||||
composable<LandingRoute> {
|
||||
at.torch.compose.ui.composable.LandingScreen(
|
||||
onNavigateToLearnMore = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute(
|
||||
route = ImplementationPendingRoute(
|
||||
"Learn more"
|
||||
)
|
||||
)
|
||||
},
|
||||
onNavigateToSignIn = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.SignInRoute
|
||||
route = SignInRoute
|
||||
)
|
||||
},
|
||||
onNavigateToCreateProfile = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.CreateProfileRoute()
|
||||
route = CreateProfileRoute()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.CreateProfileRoute> {
|
||||
composable<CreateProfileRoute> {
|
||||
at.torch.compose.ui.composable.CreateProfileScreen(
|
||||
onNavigateToEndThis = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.BlankRoute
|
||||
route = BlankRoute
|
||||
) {
|
||||
popUpTo(0)
|
||||
}
|
||||
@@ -339,7 +373,7 @@ fun TorchNavHost(
|
||||
}
|
||||
composable<WriteNewNoteRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<WriteNewNoteRoute>()
|
||||
at.torch.compose.ui.composable.WriteNewNoteScreen(
|
||||
WriteNewNoteScreen(
|
||||
replyToNostrEventId = route.inReplyToEventId,
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
quotedNostrEventId = route.quotedEventId,
|
||||
@@ -359,69 +393,69 @@ fun TorchNavHost(
|
||||
nostrRepository = databaseNostrRepository
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.SignInRoute> {
|
||||
at.torch.compose.ui.composable.SignInToProfileScreen(
|
||||
composable<SignInRoute> {
|
||||
SignInToProfileScreen(
|
||||
nostrRepository = databaseNostrRepository
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute> { backStackEntry ->
|
||||
backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnsignedProfileRoute>()
|
||||
composable<UnsignedProfileRoute> { backStackEntry ->
|
||||
backStackEntry.toRoute<UnsignedProfileRoute>()
|
||||
|
||||
at.torch.compose.ui.composable.UnsignedProfileScreen()
|
||||
UnsignedProfileScreen()
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnsyncedProfileRoute>()
|
||||
composable<UnsyncedProfileRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<UnsyncedProfileRoute>()
|
||||
UnsyncedProfileScreen(
|
||||
unsyncedProfilePublicKey = route.publicKey
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileSynchronizationRoute>()
|
||||
at.torch.compose.ui.composable.UnqueuedProfileSynchronizationScreen(
|
||||
composable<UnqueuedProfileSynchronizationRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<UnqueuedProfileSynchronizationRoute>()
|
||||
UnqueuedProfileSynchronizationScreen(
|
||||
unsignedNostrEventId = route.unsignedNostrEventId,
|
||||
profilePublicKey = route.publicKey,
|
||||
nostrRepository = databaseNostrRepository
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.UnindexedProfileRoute> {
|
||||
at.torch.compose.ui.composable.UnindexedProfileScreen()
|
||||
composable<UnindexedProfileRoute> {
|
||||
UnindexedProfileScreen()
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.UnqueuedProfileRoute> {
|
||||
at.torch.compose.ui.composable.UnqueuedProfileScreen()
|
||||
composable<UnqueuedProfileRoute> {
|
||||
UnqueuedProfileScreen()
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute> { backStackEntry ->
|
||||
backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.UnannouncedProfileRoute>()
|
||||
composable<UnannouncedProfileRoute> { backStackEntry ->
|
||||
backStackEntry.toRoute<UnannouncedProfileRoute>()
|
||||
|
||||
at.torch.compose.ui.composable.UnannouncedProfileScreen()
|
||||
UnannouncedProfileScreen()
|
||||
}
|
||||
composable<SocialPreconditionRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<SocialPreconditionRoute>()
|
||||
at.torch.compose.ui.composable.SocialPreconditionScreen(
|
||||
SocialPreconditionScreen(
|
||||
onNavigateToSkipForNow = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.FeedRoute(
|
||||
route = FeedRoute(
|
||||
activeUserPublicKey = route.activeUserPubkey
|
||||
)
|
||||
)
|
||||
},
|
||||
onNavigateToInviteFriend = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute(
|
||||
route = ImplementationPendingRoute(
|
||||
"Invite Friend"
|
||||
)
|
||||
)
|
||||
},
|
||||
onNavigateToViewInvites = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute(
|
||||
route = ImplementationPendingRoute(
|
||||
"View invites"
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.FeedRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.FeedRoute>()
|
||||
composable<FeedRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<FeedRoute>()
|
||||
HomeScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
onNavigateToEvent = { eventRoute ->
|
||||
@@ -438,7 +472,7 @@ fun TorchNavHost(
|
||||
},
|
||||
onNavigateToSearch = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.SearchRoute(
|
||||
route = SearchRoute(
|
||||
activeUserPublicKey = route.activeUserPublicKey
|
||||
)
|
||||
)
|
||||
@@ -452,7 +486,7 @@ fun TorchNavHost(
|
||||
chatRepository = databaseChatRepository
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.BlankRoute> {
|
||||
composable<BlankRoute> {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = Color.Black
|
||||
@@ -531,12 +565,12 @@ fun TorchNavHost(
|
||||
},
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.SearchRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.SearchRoute>()
|
||||
composable<SearchRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<SearchRoute>()
|
||||
|
||||
at.torch.compose.ui.composable.SearchScreen(
|
||||
SearchScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
initialSearchUIState = at.torch.compose.ui.view.state.SearchUIState.Prompt,
|
||||
initialSearchUIState = SearchUIState.Prompt,
|
||||
nostrRepository = databaseNostrRepository,
|
||||
searchRepository = searchRepository,
|
||||
onNavigateToProfile = { route ->
|
||||
@@ -551,10 +585,10 @@ fun TorchNavHost(
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.SearchResultRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<at.torch.compose.ui.composable.navigation.routes.SearchResultRoute>()
|
||||
composable<SearchResultRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<SearchResultRoute>()
|
||||
|
||||
at.torch.compose.ui.composable.SearchResultScreen(
|
||||
SearchResultScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
searchQuery = route.query,
|
||||
nostrRepository = databaseNostrRepository,
|
||||
@@ -574,7 +608,7 @@ fun TorchNavHost(
|
||||
|
||||
NostrEventDetailScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
initialNostrEventDetailUIState = at.torch.compose.ui.view.state.NostrEventDetailUIState.Loading,
|
||||
initialNostrEventDetailUIState = NostrEventDetailUIState.Loading,
|
||||
nostrEventId = route.nostrEventId,
|
||||
nostrRepository = databaseNostrRepository,
|
||||
onNavigateBack = {
|
||||
@@ -595,7 +629,7 @@ fun TorchNavHost(
|
||||
},
|
||||
onNavigateToEditProfile = {
|
||||
navController.navigate(
|
||||
route = at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute(
|
||||
route = ImplementationPendingRoute(
|
||||
"Edit Profile"
|
||||
)
|
||||
)
|
||||
@@ -619,9 +653,9 @@ fun TorchNavHost(
|
||||
},
|
||||
)
|
||||
}
|
||||
composable<at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute> { backStackEntry ->
|
||||
val route: at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute = backStackEntry.toRoute()
|
||||
at.torch.compose.ui.composable.ImplementationPendingScreen(
|
||||
composable<ImplementationPendingRoute> { backStackEntry ->
|
||||
val route: ImplementationPendingRoute = backStackEntry.toRoute()
|
||||
ImplementationPendingScreen(
|
||||
route.name
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,8 +46,18 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import at.torch.compose.database.model.NostrEvent
|
||||
import at.torch.compose.database.model.Profile
|
||||
import at.torch.compose.database.model.intermdiate.LocalNostrEvent
|
||||
import at.torch.compose.repository.NostrRepository
|
||||
import at.torch.compose.ui.composable.navigation.routes.ChatRoomDetailRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.ImplementationPendingRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.Route
|
||||
import at.torch.compose.ui.composable.widgets.profile.ProfileAvatar
|
||||
import at.torch.compose.ui.theme.TorchTheme
|
||||
import at.torch.compose.ui.view.model.MetadataEventDetailType
|
||||
import at.torch.compose.ui.view.model.MetadataEventDetailViewModel
|
||||
import at.torch.compose.ui.view.state.MetadataEventDetailUIState
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -55,25 +65,25 @@ import kotlinx.coroutines.launch
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun MetadataEventDetail(
|
||||
localNostrEvent: at.torch.compose.database.model.intermdiate.LocalNostrEvent,
|
||||
localNostrEvent: LocalNostrEvent,
|
||||
activeUserPublicKey: HexKey,
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateToEvent: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit,
|
||||
onNavigateToEvent: (Route) -> Unit,
|
||||
onNavigateToEditProfile: () -> Unit,
|
||||
onNavigateToChatRoom: (at.torch.compose.ui.composable.navigation.routes.Route) -> Unit,
|
||||
nostrRepository: at.torch.compose.repository.NostrRepository
|
||||
onNavigateToChatRoom: (Route) -> Unit,
|
||||
nostrRepository: NostrRepository
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val profile = localNostrEvent.profile
|
||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
val metadataEventDetailViewModel: at.torch.compose.ui.view.model.MetadataEventDetailViewModel = viewModel(
|
||||
factory = at.torch.compose.ui.view.model.MetadataEventDetailViewModel.factory(
|
||||
val metadataEventDetailViewModel: MetadataEventDetailViewModel = viewModel(
|
||||
factory = MetadataEventDetailViewModel.factory(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
publicKey = localNostrEvent.nostrEvent.pubKey,
|
||||
nostrRepository = nostrRepository,
|
||||
pagerState = rememberPagerState { at.torch.compose.ui.view.model.MetadataEventDetailType.entries.size }
|
||||
pagerState = rememberPagerState { MetadataEventDetailType.entries.size }
|
||||
),
|
||||
)
|
||||
|
||||
@@ -146,7 +156,7 @@ fun MetadataEventDetail(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
_root_ide_package_.at.torch.compose.ui.composable.widgets.profile.ProfileAvatar(
|
||||
ProfileAvatar(
|
||||
size = 75.dp,
|
||||
profile = profile,
|
||||
publicKey = localNostrEvent.nostrEvent.pubKey
|
||||
@@ -158,13 +168,13 @@ fun MetadataEventDetail(
|
||||
)
|
||||
|
||||
when(val metadataEventDetailUIState = metadataEventDetailViewModel.metadataEventDetailUIState) {
|
||||
at.torch.compose.ui.view.state.MetadataEventDetailUIState.Error -> {
|
||||
MetadataEventDetailUIState.Error -> {
|
||||
Icon(
|
||||
Icons.Default.Error,
|
||||
contentDescription = "Something went wrong"
|
||||
)
|
||||
}
|
||||
is at.torch.compose.ui.view.state.MetadataEventDetailUIState.Loaded -> {
|
||||
is MetadataEventDetailUIState.Loaded -> {
|
||||
|
||||
if (metadataEventDetailViewModel.isActionPending.value) {
|
||||
LoadingIndicator()
|
||||
@@ -211,7 +221,7 @@ fun MetadataEventDetail(
|
||||
|
||||
|
||||
}
|
||||
at.torch.compose.ui.view.state.MetadataEventDetailUIState.Loading -> {
|
||||
MetadataEventDetailUIState.Loading -> {
|
||||
LoadingIndicator()
|
||||
}
|
||||
}
|
||||
@@ -306,14 +316,14 @@ fun MetadataEventDetail(
|
||||
@Composable
|
||||
private fun MetadataEventEventDetailPreview() {
|
||||
|
||||
_root_ide_package_.at.torch.compose.ui.theme.TorchTheme {
|
||||
TorchTheme {
|
||||
Surface(
|
||||
modifier = Modifier.padding(20.dp)
|
||||
) {
|
||||
MetadataEventDetail(
|
||||
activeUserPublicKey = "",
|
||||
localNostrEvent = _root_ide_package_.at.torch.compose.database.model.intermdiate.LocalNostrEvent(
|
||||
nostrEvent = _root_ide_package_.at.torch.compose.database.model.NostrEvent(
|
||||
localNostrEvent = LocalNostrEvent(
|
||||
nostrEvent = NostrEvent(
|
||||
id = "eventId",
|
||||
pubKey = "publicKey",
|
||||
content = """Profile""".trimIndent(),
|
||||
@@ -321,7 +331,7 @@ private fun MetadataEventEventDetailPreview() {
|
||||
sig = "",
|
||||
kind = MetadataEvent.KIND
|
||||
),
|
||||
profile = _root_ide_package_.at.torch.compose.database.model.Profile(
|
||||
profile = Profile(
|
||||
publicKey = "pubKey",
|
||||
displayName = "John Doe",
|
||||
nip05 = "john@doe.com",
|
||||
@@ -333,7 +343,7 @@ private fun MetadataEventEventDetailPreview() {
|
||||
onNavigateToEvent = {},
|
||||
onNavigateToEditProfile = {},
|
||||
onNavigateToChatRoom = {},
|
||||
nostrRepository = at.torch.compose.repository.NostrRepository.NO_OP_NOSTR_REPOSITORY
|
||||
nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,13 @@ import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import at.torch.compose.database.model.NegentropySynchronizeRequest
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatRoom
|
||||
import at.torch.compose.database.model.types.SynchronizationFilter
|
||||
import at.torch.compose.extensions.toFormattedTimeAndDateString
|
||||
import at.torch.compose.nostr.Relays
|
||||
import at.torch.compose.repository.ChatRepository
|
||||
import at.torch.compose.repository.NostrRepository
|
||||
import at.torch.compose.ui.composable.widgets.profile.ProfileColor
|
||||
import at.torch.compose.ui.view.state.ChatRoomDetailMessageListUIState
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent
|
||||
@@ -57,9 +61,9 @@ import kotlinx.coroutines.launch
|
||||
|
||||
class ChatRoomDetailMessageListViewModel(
|
||||
initialChatRoomDetailMessageListUIState: ChatRoomDetailMessageListUIState,
|
||||
val localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom,
|
||||
val nostrRepository: at.torch.compose.repository.NostrRepository,
|
||||
val chatRepository: at.torch.compose.repository.ChatRepository
|
||||
val localChatRoom: LocalChatRoom,
|
||||
val nostrRepository: NostrRepository,
|
||||
val chatRepository: ChatRepository
|
||||
): ViewModel() {
|
||||
val logger = Logger.withTag(TAG)
|
||||
var chatRoomDetailMessageListUIState: ChatRoomDetailMessageListUIState by mutableStateOf(initialChatRoomDetailMessageListUIState)
|
||||
@@ -290,7 +294,7 @@ class ChatRoomDetailMessageListViewModel(
|
||||
text = localChatMessage.profile?.humanReadableNameOrPubkey() ?: localChatMessage.chatMessage.senderPublicKey,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.MiddleEllipsis,
|
||||
color = at.torch.compose.ui.composable.widgets.profile.ProfileColor.fromPublicKey(localChatMessage.chatMessage.senderPublicKey),
|
||||
color = ProfileColor.fromPublicKey(localChatMessage.chatMessage.senderPublicKey),
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
}
|
||||
@@ -389,9 +393,9 @@ class ChatRoomDetailMessageListViewModel(
|
||||
|
||||
fun factory(
|
||||
initialChatRoomDetailMessageListUIState: ChatRoomDetailMessageListUIState = ChatRoomDetailMessageListUIState.Loading,
|
||||
localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom,
|
||||
nostrRepository: at.torch.compose.repository.NostrRepository,
|
||||
chatRepository: at.torch.compose.repository.ChatRepository
|
||||
localChatRoom: LocalChatRoom,
|
||||
nostrRepository: NostrRepository,
|
||||
chatRepository: ChatRepository
|
||||
): ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
ChatRoomDetailMessageListViewModel(
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import at.torch.compose.repository.ChatRepository
|
||||
import at.torch.compose.repository.NostrRepository
|
||||
import at.torch.compose.ui.composable.navigation.routes.ChatRoomDetailRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.Route
|
||||
import at.torch.compose.ui.view.state.ChatRoomDetailUIState
|
||||
@@ -25,7 +26,7 @@ class ChatRoomDetailViewModel(
|
||||
val activeUserPublicKey: HexKey,
|
||||
val relayHint: String?,
|
||||
initialChatRoomDetailUIState: ChatRoomDetailUIState,
|
||||
val nostrRepository: at.torch.compose.repository.NostrRepository,
|
||||
val nostrRepository: NostrRepository,
|
||||
val chatRepository: ChatRepository
|
||||
): ViewModel() {
|
||||
|
||||
@@ -135,7 +136,7 @@ class ChatRoomDetailViewModel(
|
||||
chatRoomId: String,
|
||||
relayHint: String?,
|
||||
initialChatRoomDetailUIState: ChatRoomDetailUIState = ChatRoomDetailUIState.Loading,
|
||||
nostrRepository: at.torch.compose.repository.NostrRepository,
|
||||
nostrRepository: NostrRepository,
|
||||
chatRepository: ChatRepository
|
||||
): ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package at.torch.compose.ui.view.state
|
||||
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatRoom
|
||||
|
||||
sealed interface ChatRoomDetailUIState {
|
||||
data class Loaded(
|
||||
val localChatRoom: at.torch.compose.database.model.intermdiate.LocalChatRoom
|
||||
val localChatRoom: LocalChatRoom
|
||||
): ChatRoomDetailUIState
|
||||
|
||||
data class Error(
|
||||
|
||||
Reference in New Issue
Block a user