Leave and delete group logic
This commit is contained in:
@@ -8,7 +8,6 @@ import at.torch.compose.database.model.GiftWrapPayload
|
||||
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 co.touchlab.kermit.Logger
|
||||
@@ -348,110 +347,46 @@ class DatabaseChatRepository(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun leaveChatRoom(localChatRoom: LocalChatRoom) {
|
||||
val text = "Left group."
|
||||
|
||||
val mlsGroup = localChatRoom.chatRoom.mlsGroupState?.let { mlsGroupState ->
|
||||
MlsGroup.restore(
|
||||
MlsGroupState.decodeTls(
|
||||
mlsGroupState.hexToByteArray()
|
||||
)
|
||||
override suspend fun leaveChatRoom(
|
||||
localChatRoom: LocalChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
) {
|
||||
database.chatRoomDao().upsert(
|
||||
chatRoom = localChatRoom.chatRoom.copy(
|
||||
leftGroupAt = Clock.System.now()
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (mlsGroup != null) {
|
||||
// Create ChatRumor...
|
||||
val createdAt = Clock.System.now().epochSeconds
|
||||
val marmotInnerEventKind = ChatEvent.KIND
|
||||
// TODO: Process this in the notary...
|
||||
sendChatMessage(
|
||||
text = "Left Group",
|
||||
localChatRoom = localChatRoom,
|
||||
// TODO: Add Information/LeaveChatGroup Message Type...
|
||||
)
|
||||
|
||||
val marmotInnerEventId = EventHasher.hashId(
|
||||
pubKey = localChatRoom.chatRoom.userPublicKey,
|
||||
createdAt = createdAt,
|
||||
tags = emptyArray(),
|
||||
content = text,
|
||||
kind = marmotInnerEventKind
|
||||
)
|
||||
|
||||
database.marmotInnerEventDao().upsert(
|
||||
MarmotInnerEvent(
|
||||
id = marmotInnerEventId,
|
||||
publicKey = localChatRoom.chatRoom.userPublicKey,
|
||||
createdAt = Instant.fromEpochSeconds(createdAt),
|
||||
tags = emptyArray(),
|
||||
content = text,
|
||||
chatRoomId = localChatRoom.chatRoom.id,
|
||||
kind = marmotInnerEventKind
|
||||
)
|
||||
)
|
||||
|
||||
database.chatMessageDao().upsert(
|
||||
ChatMessage(
|
||||
content = text,
|
||||
chatRoomId = localChatRoom.chatRoom.id,
|
||||
senderPublicKey = localChatRoom.chatRoom.userPublicKey,
|
||||
isUserMessage = true,
|
||||
giftWrapPayloadId = null,
|
||||
marmotGroupEventId = null,
|
||||
marmotInnerEventId = marmotInnerEventId,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val innerEventKind = ChatMessageEvent.KIND
|
||||
// Send GiftWrapMessage
|
||||
val receiverTags = localChatRoom.localParticipants.filter { participant ->
|
||||
participant.participant.participantPublicKey != localChatRoom.chatRoom.userPublicKey // TODO: Allow this where it's notes to self...
|
||||
}.map { localParticipant ->
|
||||
PTag.assemble(
|
||||
localParticipant.participant.participantPublicKey,
|
||||
localParticipant.participant.relayHint?.let { NormalizedRelayUrl(it) }
|
||||
)
|
||||
}
|
||||
|
||||
val createdAt = Clock.System.now().epochSeconds
|
||||
val giftWrapPayloadId = EventHasher.hashId(
|
||||
pubKey = localChatRoom.chatRoom.userPublicKey,
|
||||
createdAt = createdAt,
|
||||
tags = receiverTags.toTypedArray(),
|
||||
content = text,
|
||||
kind = innerEventKind
|
||||
)
|
||||
|
||||
database.giftWrapPayloadDao().upsert(
|
||||
GiftWrapPayload(
|
||||
id = giftWrapPayloadId,
|
||||
kind = innerEventKind,
|
||||
tags = receiverTags.toTypedArray(),
|
||||
createdAt = Instant.fromEpochSeconds(createdAt),
|
||||
content = text,
|
||||
chatRoomId = localChatRoom.chatRoom.id,
|
||||
publicKey = localChatRoom.chatRoom.userPublicKey
|
||||
)
|
||||
)
|
||||
|
||||
database.chatMessageDao().upsert(
|
||||
ChatMessage(
|
||||
content = text,
|
||||
chatRoomId = localChatRoom.chatRoom.id,
|
||||
senderPublicKey = localChatRoom.chatRoom.userPublicKey,
|
||||
isUserMessage = true,
|
||||
giftWrapPayloadId = giftWrapPayloadId,
|
||||
marmotGroupEventId = null,
|
||||
marmotInnerEventId = null
|
||||
)
|
||||
)
|
||||
}
|
||||
onCompletion.invoke()
|
||||
}
|
||||
|
||||
override suspend fun softDeleteChatRoom(chatRoom: ChatRoom) {
|
||||
override suspend fun softDeleteChatRoom(
|
||||
chatRoom: ChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
) {
|
||||
database.chatRoomDao().upsert(
|
||||
chatRoom.copy(
|
||||
deletedAt = Clock.System.now()
|
||||
)
|
||||
)
|
||||
|
||||
onCompletion.invoke()
|
||||
}
|
||||
|
||||
override suspend fun deleteChatRoom(chatRoom: ChatRoom) {
|
||||
override suspend fun deleteChatRoom(
|
||||
chatRoom: ChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
) {
|
||||
database.chatRoomDao().delete(chatRoom)
|
||||
|
||||
onCompletion.invoke()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -4,7 +4,6 @@ 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
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatMessage
|
||||
import at.torch.compose.database.model.intermdiate.LocalChatRoom
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
@@ -67,11 +66,20 @@ interface ChatRepository {
|
||||
|
||||
suspend fun sealGiftWrapPayload(giftWrapPayload: GiftWrapPayload, nostrSignerSync: NostrSignerSync)
|
||||
|
||||
suspend fun leaveChatRoom(localChatRoom: LocalChatRoom)
|
||||
suspend fun leaveChatRoom(
|
||||
localChatRoom: LocalChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
)
|
||||
|
||||
suspend fun softDeleteChatRoom(chatRoom: ChatRoom)
|
||||
suspend fun softDeleteChatRoom(
|
||||
chatRoom: ChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
)
|
||||
|
||||
suspend fun deleteChatRoom(chatRoom: ChatRoom)
|
||||
suspend fun deleteChatRoom(
|
||||
chatRoom: ChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
)
|
||||
|
||||
companion object {
|
||||
val NO_OP_CHAT_REPOSITORY = object: ChatRepository {
|
||||
@@ -160,15 +168,24 @@ interface ChatRepository {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun leaveChatRoom(localChatRoom: LocalChatRoom) {
|
||||
override suspend fun leaveChatRoom(
|
||||
localChatRoom: LocalChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun softDeleteChatRoom(chatRoom: ChatRoom) {
|
||||
override suspend fun softDeleteChatRoom(
|
||||
chatRoom: ChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun deleteChatRoom(chatRoom: ChatRoom) {
|
||||
override suspend fun deleteChatRoom(
|
||||
chatRoom: ChatRoom,
|
||||
onCompletion: () -> Unit
|
||||
) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ fun ChatRoomDetailScreen(
|
||||
nostrRepository: NostrRepository,
|
||||
chatRepository: ChatRepository,
|
||||
onNavigateToRoute: (Route) -> Unit,
|
||||
onPopBackToRoute: (Route) -> Unit
|
||||
) {
|
||||
val chatRoomDetailViewModel: ChatRoomDetailViewModel = viewModel(
|
||||
factory = ChatRoomDetailViewModel.factory(
|
||||
@@ -213,10 +214,9 @@ fun ChatRoomDetailScreen(
|
||||
),
|
||||
enabled = chatRoomDetailUIState.localChatRoom.chatRoom.leftGroupAt == null, // Disable after we leave group...
|
||||
onClick = {
|
||||
// Leave group logic
|
||||
chatRoomDetailViewModel.leaveGroup(
|
||||
localChatRoom = chatRoomDetailUIState.localChatRoom,
|
||||
onNavigateToRoute = onNavigateToRoute
|
||||
onPopBackToRoute = onPopBackToRoute
|
||||
)
|
||||
}
|
||||
) {
|
||||
@@ -240,10 +240,9 @@ fun ChatRoomDetailScreen(
|
||||
),
|
||||
enabled = chatRoomDetailUIState.localChatRoom.chatRoom.leftGroupAt != null,
|
||||
onClick = {
|
||||
onNavigateToRoute.invoke(
|
||||
ImplementationPendingRoute(
|
||||
"Delete Group"
|
||||
)
|
||||
chatRoomDetailViewModel.softDeleteGroup(
|
||||
localChatRoom = chatRoomDetailUIState.localChatRoom,
|
||||
onPopBackToRoute = onPopBackToRoute
|
||||
)
|
||||
}
|
||||
) {
|
||||
@@ -345,7 +344,8 @@ private fun ChatRoomMessagingScreenPreview() {
|
||||
),
|
||||
nostrRepository = NostrRepository.NO_OP_NOSTR_REPOSITORY,
|
||||
chatRepository = ChatRepository.NO_OP_CHAT_REPOSITORY,
|
||||
onNavigateToRoute = {}
|
||||
onNavigateToRoute = {},
|
||||
onPopBackToRoute = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ 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.ChatRoomMessagingRoute
|
||||
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.HomeRoute
|
||||
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
|
||||
@@ -444,7 +444,7 @@ fun TorchNavHost(
|
||||
SocialPreconditionScreen(
|
||||
onNavigateToSkipForNow = {
|
||||
navController.navigate(
|
||||
route = FeedRoute(
|
||||
route = HomeRoute(
|
||||
activeUserPublicKey = route.activeUserPubkey
|
||||
)
|
||||
)
|
||||
@@ -465,8 +465,8 @@ fun TorchNavHost(
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<FeedRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<FeedRoute>()
|
||||
composable<HomeRoute> { backStackEntry ->
|
||||
val route = backStackEntry.toRoute<HomeRoute>()
|
||||
HomeScreen(
|
||||
activeUserPublicKey = route.activeUserPublicKey,
|
||||
onNavigateToRoute = { eventRoute ->
|
||||
@@ -594,6 +594,12 @@ fun TorchNavHost(
|
||||
navController.navigate(
|
||||
route = actionRoute
|
||||
)
|
||||
},
|
||||
onPopBackToRoute = { popRoute ->
|
||||
navController.popBackStack(
|
||||
route = popRoute,
|
||||
inclusive = false
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@ package at.torch.compose.ui.composable.navigation.routes
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class FeedRoute(
|
||||
data class HomeRoute(
|
||||
val activeUserPublicKey: String
|
||||
): Route()
|
||||
@@ -9,11 +9,10 @@ import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
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.ImplementationPendingRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.HomeRoute
|
||||
import at.torch.compose.ui.composable.navigation.routes.Route
|
||||
import at.torch.compose.ui.view.state.ChatRoomDetailUIState
|
||||
import co.touchlab.kermit.Logger
|
||||
@@ -46,6 +45,7 @@ class ChatRoomDetailViewModel(
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val localChatRoom = chatRepository.getChatRoomByIdentifier(chatRoomId)
|
||||
|
||||
logger.d("localChatRoom: $localChatRoom")
|
||||
chatRoomDetailUIState = if (localChatRoom == null) {
|
||||
// Initiate new chat... and navigate to new chat...
|
||||
ChatRoomDetailUIState.Error("Missing chat room")
|
||||
@@ -59,20 +59,45 @@ class ChatRoomDetailViewModel(
|
||||
|
||||
fun leaveGroup(
|
||||
localChatRoom: LocalChatRoom,
|
||||
onNavigateToRoute: (Route) -> Unit
|
||||
onPopBackToRoute: (Route) -> Unit
|
||||
) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
chatRepository.leaveChatRoom(localChatRoom)
|
||||
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
onNavigateToRoute.invoke(
|
||||
ImplementationPendingRoute(
|
||||
"Leave Group"
|
||||
)
|
||||
)
|
||||
}
|
||||
chatRepository.leaveChatRoom(
|
||||
localChatRoom,
|
||||
onCompletion = {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
onPopBackToRoute.invoke(
|
||||
HomeRoute(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun softDeleteGroup(
|
||||
localChatRoom: LocalChatRoom,
|
||||
onPopBackToRoute: (Route) -> Unit
|
||||
) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
chatRepository.softDeleteChatRoom(
|
||||
chatRoom = localChatRoom.chatRoom,
|
||||
onCompletion = {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
onPopBackToRoute.invoke(
|
||||
HomeRoute(
|
||||
activeUserPublicKey = activeUserPublicKey,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ChatRoomDetailViewModel"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user